1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include "sd-netlink.h"
8 #include "loopback-setup.h"
10 #include "netlink-util.h"
11 #include "time-util.h"
13 #define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
18 const char *error_message
;
19 const char *success_message
;
22 static int generic_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
23 struct state
*s
= userdata
;
27 assert(s
->n_messages
> 0);
32 r
= sd_netlink_message_get_errno(m
);
34 log_debug_errno(r
, "%s: %m", s
->error_message
);
36 log_debug("%s", s
->success_message
);
42 static int start_loopback(sd_netlink
*rtnl
, struct state
*s
) {
43 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
49 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_SETLINK
, LOOPBACK_IFINDEX
);
53 r
= sd_rtnl_message_link_set_flags(req
, IFF_UP
, IFF_UP
);
57 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, LOOPBACK_SETUP_TIMEOUT_USEC
, "systemd-start-loopback");
65 static int add_ipv4_address(sd_netlink
*rtnl
, struct state
*s
) {
66 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
72 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET
);
76 r
= sd_rtnl_message_addr_set_prefixlen(req
, 8);
80 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
84 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
88 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &(struct in_addr
) { .s_addr
= htobe32(INADDR_LOOPBACK
) } );
92 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, USEC_INFINITY
, "systemd-loopback-ipv4");
100 static int add_ipv6_address(sd_netlink
*rtnl
, struct state
*s
) {
101 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
107 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET6
);
111 r
= sd_rtnl_message_addr_set_prefixlen(req
, 128);
115 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
119 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
123 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &in6addr_loopback
);
127 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, USEC_INFINITY
, "systemd-loopback-ipv6");
135 static bool check_loopback(sd_netlink
*rtnl
) {
136 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
140 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, LOOPBACK_IFINDEX
);
144 r
= sd_netlink_call(rtnl
, req
, USEC_INFINITY
, &reply
);
148 r
= sd_rtnl_message_link_get_flags(reply
, &flags
);
152 return flags
& IFF_UP
;
155 int loopback_setup(void) {
156 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
157 struct state state_4
= {
158 .error_message
= "Failed to add address 127.0.0.1 to loopback interface",
159 .success_message
= "Successfully added address 127.0.0.1 to loopback interface",
161 .error_message
= "Failed to add address ::1 to loopback interface",
162 .success_message
= "Successfully added address ::1 to loopback interface",
164 .error_message
= "Failed to bring loopback interface up",
165 .success_message
= "Successfully brought loopback interface up",
169 r
= sd_netlink_open(&rtnl
);
171 return log_error_errno(r
, "Failed to open netlink: %m");
173 /* Note that we add the IP addresses here explicitly even though the kernel does that too implicitly when
174 * setting up the loopback device. The reason we do this here a second time (and possibly race against the
175 * kernel) is that we want to synchronously wait until the IP addresses are set up correctly, see
177 * https://github.com/systemd/systemd/issues/5641 */
179 r
= add_ipv4_address(rtnl
, &state_4
);
181 return log_error_errno(r
, "Failed to enqueue IPv4 loopback address add request: %m");
183 r
= add_ipv6_address(rtnl
, &state_6
);
185 return log_error_errno(r
, "Failed to enqueue IPv6 loopback address add request: %m");
187 r
= start_loopback(rtnl
, &state_up
);
189 return log_error_errno(r
, "Failed to enqueue loopback interface start request: %m");
191 while (state_4
.n_messages
+ state_6
.n_messages
+ state_up
.n_messages
> 0) {
192 r
= sd_netlink_wait(rtnl
, LOOPBACK_SETUP_TIMEOUT_USEC
);
194 return log_error_errno(r
, "Failed to wait for netlink event: %m");
196 r
= sd_netlink_process(rtnl
, NULL
);
198 return log_warning_errno(r
, "Failed to process netlink event: %m");
201 /* Note that we don't really care whether the addresses could be added or not */
202 if (state_up
.rcode
!= 0) {
203 /* If we lack the permissions to configure the loopback device,
204 * but we find it to be already configured, let's exit cleanly,
205 * in order to supported unprivileged containers. */
206 if (state_up
.rcode
== -EPERM
&& check_loopback(rtnl
))
209 return log_warning_errno(state_up
.rcode
, "Failed to configure loopback device: %m");