]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/loopback-setup.c
Merge pull request #5600 from fbuihuu/make-logind-restartable
[thirdparty/systemd.git] / src / core / loopback-setup.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <net/if.h>
21 #include <stdlib.h>
22
23 #include "sd-netlink.h"
24
25 #include "loopback-setup.h"
26 #include "missing.h"
27 #include "netlink-util.h"
28
29 struct state {
30 unsigned n_messages;
31 int rcode;
32 };
33
34 static int start_loopback_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
35 struct state *s = userdata;
36
37 assert(s);
38 assert(s->n_messages > 0);
39 s->n_messages--;
40
41 errno = 0;
42 log_debug_errno(sd_netlink_message_get_errno(m), "Got start error code: %m");
43
44 s->rcode = sd_netlink_message_get_errno(m);
45
46 return 0;
47 }
48
49 static int start_loopback(sd_netlink *rtnl, struct state *s) {
50 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
51 int r;
52
53 assert(rtnl);
54 assert(s);
55
56 r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, LOOPBACK_IFINDEX);
57 if (r < 0)
58 return r;
59
60 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
61 if (r < 0)
62 return r;
63
64 r = sd_netlink_call_async(rtnl, req, start_loopback_handler, s, USEC_INFINITY, NULL);
65 if (r < 0)
66 return r;
67
68 s->n_messages ++;
69 return 0;
70 }
71
72 static int generic_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
73 struct state *s = userdata;
74
75 assert(s);
76 assert(s->n_messages > 0);
77 s->n_messages--;
78
79 /* Note that we don't really care whether the addresses could be added or not */
80 errno = 0;
81 log_debug_errno(sd_netlink_message_get_errno(m), "Got address error code: %m");
82
83 return 0;
84 }
85
86 static int add_ipv4_address(sd_netlink *rtnl, struct state *s) {
87 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
88 int r;
89
90 assert(rtnl);
91 assert(s);
92
93 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_NEWADDR, LOOPBACK_IFINDEX, AF_INET);
94 if (r < 0)
95 return r;
96
97 r = sd_rtnl_message_addr_set_prefixlen(req, 8);
98 if (r < 0)
99 return r;
100
101 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
102 if (r < 0)
103 return r;
104
105 r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_HOST);
106 if (r < 0)
107 return r;
108
109 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &(struct in_addr) { .s_addr = htobe32(INADDR_LOOPBACK) } );
110 if (r < 0)
111 return r;
112
113 r = sd_netlink_call_async(rtnl, req, generic_handler, s, USEC_INFINITY, NULL);
114 if (r < 0)
115 return r;
116
117 s->n_messages ++;
118 return 0;
119 }
120
121 static int add_ipv6_address(sd_netlink *rtnl, struct state *s) {
122 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
123 int r;
124
125 assert(rtnl);
126 assert(s);
127
128 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_NEWADDR, LOOPBACK_IFINDEX, AF_INET6);
129 if (r < 0)
130 return r;
131
132 r = sd_rtnl_message_addr_set_prefixlen(req, 128);
133 if (r < 0)
134 return r;
135
136 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
137 if (r < 0)
138 return r;
139
140 r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_HOST);
141 if (r < 0)
142 return r;
143
144 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &in6addr_loopback);
145 if (r < 0)
146 return r;
147
148 r = sd_netlink_call_async(rtnl, req, generic_handler, s, USEC_INFINITY, NULL);
149 if (r < 0)
150 return r;
151
152 s->n_messages ++;
153 return 0;
154 }
155
156 static bool check_loopback(sd_netlink *rtnl) {
157 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
158 unsigned flags;
159 int r;
160
161 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, LOOPBACK_IFINDEX);
162 if (r < 0)
163 return false;
164
165 r = sd_netlink_call(rtnl, req, USEC_INFINITY, &reply);
166 if (r < 0)
167 return false;
168
169 r = sd_rtnl_message_link_get_flags(reply, &flags);
170 if (r < 0)
171 return false;
172
173 return flags & IFF_UP;
174 }
175
176 int loopback_setup(void) {
177 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
178 struct state state = {};
179 int r;
180
181 r = sd_netlink_open(&rtnl);
182 if (r < 0)
183 return log_error_errno(r, "Failed to open netlink: %m");
184
185 /* Note that we add the IP addresses here explicitly even though the kernel does that too implicitly when
186 * setting up the loopback device. The reason we do this here a second time (and possibly race against the
187 * kernel) is that we want to synchronously wait until the IP addresses are set up correctly, see
188 *
189 * https://github.com/systemd/systemd/issues/5641 */
190
191 r = add_ipv4_address(rtnl, &state);
192 if (r < 0)
193 return log_error_errno(r, "Failed to enqueue IPv4 loopback address add request: %m");
194
195 r = add_ipv6_address(rtnl, &state);
196 if (r < 0)
197 return log_error_errno(r, "Failed to enqueue IPv4 loopback address add request: %m");
198
199 r = start_loopback(rtnl, &state);
200 if (r < 0)
201 return log_error_errno(r, "Failed to enqueue loopback interface start request: %m");
202
203 while (state.n_messages > 0) {
204 r = sd_netlink_wait(rtnl, USEC_INFINITY);
205 if (r < 0)
206 return log_error_errno(r, "Failed to wait for netlink event: %m");
207
208 r = sd_netlink_process(rtnl, NULL);
209 if (r < 0)
210 return log_warning_errno(r, "Failed to process netlink event: %m");
211 }
212
213 if (state.rcode != 0) {
214
215 /* If we lack the permissions to configure the
216 * loopback device, but we find it to be already
217 * configured, let's exit cleanly, in order to
218 * supported unprivileged containers. */
219 if (state.rcode == -EPERM && check_loopback(rtnl))
220 return 0;
221
222 return log_warning_errno(state.rcode, "Failed to configure loopback device: %m");
223 }
224
225 return 0;
226 }