1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "sd-netlink.h"
26 #include "loopback-setup.h"
28 #include "netlink-util.h"
30 #define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
38 static int generic_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
39 struct state
*s
= userdata
;
42 assert(s
->n_messages
> 0);
46 log_debug_errno(sd_netlink_message_get_errno(m
), "Failed to %s: %m", s
->title
);
48 s
->rcode
= sd_netlink_message_get_errno(m
);
53 static int start_loopback(sd_netlink
*rtnl
, struct state
*s
) {
54 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
60 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_SETLINK
, LOOPBACK_IFINDEX
);
64 r
= sd_rtnl_message_link_set_flags(req
, IFF_UP
, IFF_UP
);
68 r
= sd_netlink_call_async(rtnl
, req
, generic_handler
, s
, LOOPBACK_SETUP_TIMEOUT_USEC
, NULL
);
76 static int add_ipv4_address(sd_netlink
*rtnl
, struct state
*s
) {
77 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
83 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET
);
87 r
= sd_rtnl_message_addr_set_prefixlen(req
, 8);
91 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
95 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
99 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &(struct in_addr
) { .s_addr
= htobe32(INADDR_LOOPBACK
) } );
103 r
= sd_netlink_call_async(rtnl
, req
, generic_handler
, s
, USEC_INFINITY
, NULL
);
111 static int add_ipv6_address(sd_netlink
*rtnl
, struct state
*s
) {
112 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
118 r
= sd_rtnl_message_new_addr(rtnl
, &req
, RTM_NEWADDR
, LOOPBACK_IFINDEX
, AF_INET6
);
122 r
= sd_rtnl_message_addr_set_prefixlen(req
, 128);
126 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
130 r
= sd_rtnl_message_addr_set_scope(req
, RT_SCOPE_HOST
);
134 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &in6addr_loopback
);
138 r
= sd_netlink_call_async(rtnl
, req
, generic_handler
, s
, USEC_INFINITY
, NULL
);
146 static bool check_loopback(sd_netlink
*rtnl
) {
147 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
151 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, LOOPBACK_IFINDEX
);
155 r
= sd_netlink_call(rtnl
, req
, USEC_INFINITY
, &reply
);
159 r
= sd_rtnl_message_link_get_flags(reply
, &flags
);
163 return flags
& IFF_UP
;
166 int loopback_setup(void) {
167 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
168 struct state state_4
= { .title
= "add address 127.0.0.1 to loopback interface" },
169 state_6
= { .title
= "add address ::1 to loopback interface"},
170 state_up
= { .title
= "bring loopback interface up" };
173 r
= sd_netlink_open(&rtnl
);
175 return log_error_errno(r
, "Failed to open netlink: %m");
177 /* Note that we add the IP addresses here explicitly even though the kernel does that too implicitly when
178 * setting up the loopback device. The reason we do this here a second time (and possibly race against the
179 * kernel) is that we want to synchronously wait until the IP addresses are set up correctly, see
181 * https://github.com/systemd/systemd/issues/5641 */
183 r
= add_ipv4_address(rtnl
, &state_4
);
185 return log_error_errno(r
, "Failed to enqueue IPv4 loopback address add request: %m");
187 r
= add_ipv6_address(rtnl
, &state_6
);
189 return log_error_errno(r
, "Failed to enqueue IPv6 loopback address add request: %m");
191 r
= start_loopback(rtnl
, &state_up
);
193 return log_error_errno(r
, "Failed to enqueue loopback interface start request: %m");
195 while (state_4
.n_messages
+ state_6
.n_messages
+ state_up
.n_messages
> 0) {
196 r
= sd_netlink_wait(rtnl
, LOOPBACK_SETUP_TIMEOUT_USEC
);
198 return log_error_errno(r
, "Failed to wait for netlink event: %m");
200 r
= sd_netlink_process(rtnl
, NULL
);
202 return log_warning_errno(r
, "Failed to process netlink event: %m");
205 /* Note that we don't really care whether the addresses could be added or not */
206 if (state_up
.rcode
!= 0) {
207 /* If we lack the permissions to configure the loopback device,
208 * but we find it to be already configured, let's exit cleanly,
209 * in order to supported unprivileged containers. */
210 if (state_up
.rcode
== -EPERM
&& check_loopback(rtnl
))
213 return log_warning_errno(state_up
.rcode
, "Failed to configure loopback device: %m");