1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include "sd-netlink.h"
8 #include "loopback-setup.h"
10 #include "netlink-util.h"
12 #define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
17 const char *error_message
;
18 const char *success_message
;
21 static int generic_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
22 struct state
*s
= userdata
;
26 assert(s
->n_messages
> 0);
31 r
= sd_netlink_message_get_errno(m
);
33 log_debug_errno(r
, "%s: %m", s
->error_message
);
35 log_debug("%s", s
->success_message
);
41 static int start_loopback(sd_netlink
*rtnl
, struct state
*s
) {
42 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
48 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_SETLINK
, LOOPBACK_IFINDEX
);
52 r
= sd_rtnl_message_link_set_flags(req
, IFF_UP
, IFF_UP
);
56 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, LOOPBACK_SETUP_TIMEOUT_USEC
, "systemd-start-loopback");
64 static int add_ipv4_address(sd_netlink
*rtnl
, struct state
*s
) {
65 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
71 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET
);
75 r
= sd_rtnl_message_addr_set_prefixlen(req
, 8);
79 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
83 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
87 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &(struct in_addr
) { .s_addr
= htobe32(INADDR_LOOPBACK
) } );
91 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, USEC_INFINITY
, "systemd-loopback-ipv4");
99 static int add_ipv6_address(sd_netlink
*rtnl
, struct state
*s
) {
100 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
106 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET6
);
110 r
= sd_rtnl_message_addr_set_prefixlen(req
, 128);
114 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
118 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
122 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &in6addr_loopback
);
126 r
= sd_netlink_call_async(rtnl
, NULL
, req
, generic_handler
, NULL
, s
, USEC_INFINITY
, "systemd-loopback-ipv6");
134 static bool check_loopback(sd_netlink
*rtnl
) {
135 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
139 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, LOOPBACK_IFINDEX
);
143 r
= sd_netlink_call(rtnl
, req
, USEC_INFINITY
, &reply
);
147 r
= sd_rtnl_message_link_get_flags(reply
, &flags
);
151 return flags
& IFF_UP
;
154 int loopback_setup(void) {
155 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
156 struct state state_4
= {
157 .error_message
= "Failed to add address 127.0.0.1 to loopback interface",
158 .success_message
= "Successfully added address 127.0.0.1 to loopback interface",
160 .error_message
= "Failed to add address ::1 to loopback interface",
161 .success_message
= "Successfully added address ::1 to loopback interface",
163 .error_message
= "Failed to bring loopback interface up",
164 .success_message
= "Successfully brought loopback interface up",
168 r
= sd_netlink_open(&rtnl
);
170 return log_error_errno(r
, "Failed to open netlink: %m");
172 /* Note that we add the IP addresses here explicitly even though the kernel does that too implicitly when
173 * setting up the loopback device. The reason we do this here a second time (and possibly race against the
174 * kernel) is that we want to synchronously wait until the IP addresses are set up correctly, see
176 * https://github.com/systemd/systemd/issues/5641 */
178 r
= add_ipv4_address(rtnl
, &state_4
);
180 return log_error_errno(r
, "Failed to enqueue IPv4 loopback address add request: %m");
182 r
= add_ipv6_address(rtnl
, &state_6
);
184 return log_error_errno(r
, "Failed to enqueue IPv6 loopback address add request: %m");
186 r
= start_loopback(rtnl
, &state_up
);
188 return log_error_errno(r
, "Failed to enqueue loopback interface start request: %m");
190 while (state_4
.n_messages
+ state_6
.n_messages
+ state_up
.n_messages
> 0) {
191 r
= sd_netlink_wait(rtnl
, LOOPBACK_SETUP_TIMEOUT_USEC
);
193 return log_error_errno(r
, "Failed to wait for netlink event: %m");
195 r
= sd_netlink_process(rtnl
, NULL
);
197 return log_warning_errno(r
, "Failed to process netlink event: %m");
200 /* Note that we don't really care whether the addresses could be added or not */
201 if (state_up
.rcode
!= 0) {
202 /* If we lack the permissions to configure the loopback device,
203 * but we find it to be already configured, let's exit cleanly,
204 * in order to supported unprivileged containers. */
205 if (state_up
.rcode
== -EPERM
&& check_loopback(rtnl
))
208 return log_warning_errno(state_up
.rcode
, "Failed to configure loopback device: %m");