]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/loopback-setup.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / loopback-setup.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
af5bc85d
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
af5bc85d
LP
10 (at your option) any later version.
11
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
5430f7f2 15 Lesser General Public License for more details.
af5bc85d 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
af5bc85d
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
af5bc85d 21#include <net/if.h>
af5bc85d 22#include <stdlib.h>
af5bc85d 23
1c4baffc 24#include "sd-netlink.h"
07630cea 25
9ca903cc 26#include "loopback-setup.h"
07630cea
LP
27#include "missing.h"
28#include "netlink-util.h"
5a723174 29
2d2a815c
ZJS
30#define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
31
fb893927
LP
32struct state {
33 unsigned n_messages;
34 int rcode;
c23218ae 35 const char *title;
fb893927
LP
36};
37
c23218ae 38static int generic_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
fb893927
LP
39 struct state *s = userdata;
40
41 assert(s);
42 assert(s->n_messages > 0);
43 s->n_messages--;
44
45 errno = 0;
c23218ae 46 log_debug_errno(sd_netlink_message_get_errno(m), "Failed to %s: %m", s->title);
fb893927
LP
47
48 s->rcode = sd_netlink_message_get_errno(m);
49
50 return 0;
51}
52
53static int start_loopback(sd_netlink *rtnl, struct state *s) {
4afd3348 54 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
81eca919 55 int r;
af5bc85d 56
fb893927
LP
57 assert(rtnl);
58 assert(s);
59
f3fc4815 60 r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, LOOPBACK_IFINDEX);
fc25d7f8
TG
61 if (r < 0)
62 return r;
63
5d4795f3 64 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
81eca919
TG
65 if (r < 0)
66 return r;
af5bc85d 67
c23218ae 68 r = sd_netlink_call_async(rtnl, req, generic_handler, s, LOOPBACK_SETUP_TIMEOUT_USEC, NULL);
fb893927
LP
69 if (r < 0)
70 return r;
71
72 s->n_messages ++;
73 return 0;
74}
75
fb893927
LP
76static int add_ipv4_address(sd_netlink *rtnl, struct state *s) {
77 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
78 int r;
79
80 assert(rtnl);
81 assert(s);
82
83 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_NEWADDR, LOOPBACK_IFINDEX, AF_INET);
84 if (r < 0)
85 return r;
86
87 r = sd_rtnl_message_addr_set_prefixlen(req, 8);
88 if (r < 0)
89 return r;
90
91 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
92 if (r < 0)
93 return r;
94
95 r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_HOST);
96 if (r < 0)
97 return r;
98
99 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &(struct in_addr) { .s_addr = htobe32(INADDR_LOOPBACK) } );
100 if (r < 0)
101 return r;
102
103 r = sd_netlink_call_async(rtnl, req, generic_handler, s, USEC_INFINITY, NULL);
104 if (r < 0)
105 return r;
106
107 s->n_messages ++;
108 return 0;
109}
110
111static int add_ipv6_address(sd_netlink *rtnl, struct state *s) {
112 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
113 int r;
114
115 assert(rtnl);
116 assert(s);
117
118 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_NEWADDR, LOOPBACK_IFINDEX, AF_INET6);
119 if (r < 0)
120 return r;
121
122 r = sd_rtnl_message_addr_set_prefixlen(req, 128);
123 if (r < 0)
124 return r;
125
126 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
127 if (r < 0)
128 return r;
129
130 r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_HOST);
131 if (r < 0)
132 return r;
133
134 r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &in6addr_loopback);
81eca919
TG
135 if (r < 0)
136 return r;
af5bc85d 137
fb893927
LP
138 r = sd_netlink_call_async(rtnl, req, generic_handler, s, USEC_INFINITY, NULL);
139 if (r < 0)
140 return r;
141
142 s->n_messages ++;
af5bc85d
LP
143 return 0;
144}
145
1c4baffc 146static bool check_loopback(sd_netlink *rtnl) {
4afd3348 147 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
e95e909d 148 unsigned flags;
e62d8c39 149 int r;
e95e909d
TG
150
151 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, LOOPBACK_IFINDEX);
152 if (r < 0)
2f0af4e1 153 return false;
e95e909d 154
fb893927 155 r = sd_netlink_call(rtnl, req, USEC_INFINITY, &reply);
e95e909d 156 if (r < 0)
2f0af4e1 157 return false;
e95e909d
TG
158
159 r = sd_rtnl_message_link_get_flags(reply, &flags);
160 if (r < 0)
2f0af4e1 161 return false;
e95e909d
TG
162
163 return flags & IFF_UP;
2c3ff76e
LP
164}
165
af5bc85d 166int loopback_setup(void) {
4afd3348 167 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
c23218ae
ZJS
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" };
f3fc4815 171 int r;
0a0dc69b 172
1c4baffc 173 r = sd_netlink_open(&rtnl);
2c3ff76e 174 if (r < 0)
fb893927
LP
175 return log_error_errno(r, "Failed to open netlink: %m");
176
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
180 *
181 * https://github.com/systemd/systemd/issues/5641 */
182
c23218ae 183 r = add_ipv4_address(rtnl, &state_4);
fb893927 184 if (r < 0)
3561eafa 185 return log_error_errno(r, "Failed to enqueue IPv4 loopback address add request: %m");
fb893927 186
c23218ae 187 r = add_ipv6_address(rtnl, &state_6);
fb893927 188 if (r < 0)
c23218ae 189 return log_error_errno(r, "Failed to enqueue IPv6 loopback address add request: %m");
fb893927 190
c23218ae 191 r = start_loopback(rtnl, &state_up);
fb893927 192 if (r < 0)
3561eafa 193 return log_error_errno(r, "Failed to enqueue loopback interface start request: %m");
fb893927 194
c23218ae 195 while (state_4.n_messages + state_6.n_messages + state_up.n_messages > 0) {
2d2a815c 196 r = sd_netlink_wait(rtnl, LOOPBACK_SETUP_TIMEOUT_USEC);
fb893927
LP
197 if (r < 0)
198 return log_error_errno(r, "Failed to wait for netlink event: %m");
199
200 r = sd_netlink_process(rtnl, NULL);
201 if (r < 0)
202 return log_warning_errno(r, "Failed to process netlink event: %m");
203 }
af5bc85d 204
c23218ae
ZJS
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))
8f084002 211 return 0;
af5bc85d 212
c23218ae 213 return log_warning_errno(state_up.rcode, "Failed to configure loopback device: %m");
8f084002 214 }
2c3ff76e 215
e62d8c39 216 return 0;
af5bc85d 217}