]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-sysctl.c
Merge pull request #32684 from YHNdnzj/pr-followups
[thirdparty/systemd.git] / src / network / networkd-sysctl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5 #include <linux/if_arp.h>
6
7 #include "af-list.h"
8 #include "missing_network.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-network.h"
12 #include "networkd-sysctl.h"
13 #include "socket-util.h"
14 #include "string-table.h"
15 #include "sysctl-util.h"
16
17 static void manager_set_ip_forwarding(Manager *manager, int family) {
18 int r, t;
19
20 assert(manager);
21 assert(IN_SET(family, AF_INET, AF_INET6));
22
23 if (family == AF_INET6 && !socket_ipv6_is_supported())
24 return;
25
26 t = manager->ip_forwarding[family == AF_INET6];
27 if (t < 0)
28 return; /* keep */
29
30 /* First, set the default value. */
31 r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t);
32 if (r < 0)
33 log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
34 enable_disable(t), af_to_ipv4_ipv6(family));
35
36 /* Then, set the value to all interfaces. */
37 r = sysctl_write_ip_property_boolean(family, "all", "forwarding", t);
38 if (r < 0)
39 log_warning_errno(r, "Failed to %s %s forwarding for all interfaces: %m",
40 enable_disable(t), af_to_ipv4_ipv6(family));
41 }
42
43 void manager_set_sysctl(Manager *manager) {
44 assert(manager);
45 assert(!manager->test_mode);
46
47 manager_set_ip_forwarding(manager, AF_INET);
48 manager_set_ip_forwarding(manager, AF_INET6);
49 }
50
51 static bool link_is_configured_for_family(Link *link, int family) {
52 assert(link);
53
54 if (!link->network)
55 return false;
56
57 if (link->flags & IFF_LOOPBACK)
58 return false;
59
60 /* CAN devices do not support IP layer. Most of the functions below are never called for CAN devices,
61 * but link_set_ipv6_mtu() may be called after setting interface MTU, and warn about the failure. For
62 * safety, let's unconditionally check if the interface is not a CAN device. */
63 if (IN_SET(family, AF_INET, AF_INET6) && link->iftype == ARPHRD_CAN)
64 return false;
65
66 if (family == AF_INET6 && !socket_ipv6_is_supported())
67 return false;
68
69 return true;
70 }
71
72 static int link_update_ipv6_sysctl(Link *link) {
73 assert(link);
74
75 if (!link_is_configured_for_family(link, AF_INET6))
76 return 0;
77
78 if (!link_ipv6_enabled(link))
79 return 0;
80
81 return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
82 }
83
84 static int link_set_proxy_arp(Link *link) {
85 assert(link);
86
87 if (!link_is_configured_for_family(link, AF_INET))
88 return 0;
89
90 if (link->network->proxy_arp < 0)
91 return 0;
92
93 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
94 }
95
96 static int link_set_proxy_arp_pvlan(Link *link) {
97 assert(link);
98
99 if (!link_is_configured_for_family(link, AF_INET))
100 return 0;
101
102 if (link->network->proxy_arp_pvlan < 0)
103 return 0;
104
105 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp_pvlan", link->network->proxy_arp_pvlan > 0);
106 }
107
108 int link_get_ip_forwarding(Link *link, int family) {
109 assert(link);
110 assert(link->manager);
111 assert(link->network);
112 assert(IN_SET(family, AF_INET, AF_INET6));
113
114 /* If it is explicitly specified, then honor the setting. */
115 int t = link->network->ip_forwarding[family == AF_INET6];
116 if (t >= 0)
117 return t;
118
119 /* If IPMasquerade= is enabled, also enable IP forwarding. */
120 if (family == AF_INET && FLAGS_SET(link->network->ip_masquerade, ADDRESS_FAMILY_IPV4))
121 return true;
122 if (family == AF_INET6 && FLAGS_SET(link->network->ip_masquerade, ADDRESS_FAMILY_IPV6))
123 return true;
124
125 /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
126 if (family == AF_INET6 && link_radv_enabled(link))
127 return true;
128
129 /* Otherwise, use the global setting. */
130 return link->manager->ip_forwarding[family == AF_INET6];
131 }
132
133 static int link_set_ip_forwarding(Link *link, int family) {
134 int r, t;
135
136 assert(link);
137 assert(IN_SET(family, AF_INET, AF_INET6));
138
139 if (!link_is_configured_for_family(link, family))
140 return 0;
141
142 t = link_get_ip_forwarding(link, family);
143 if (t < 0)
144 return 0; /* keep */
145
146 r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t);
147 if (r < 0)
148 return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
149 enable_disable(t), af_to_ipv4_ipv6(family));
150
151 return 0;
152 }
153
154 static int link_set_ipv4_rp_filter(Link *link) {
155 assert(link);
156
157 if (!link_is_configured_for_family(link, AF_INET))
158 return 0;
159
160 if (link->network->ipv4_rp_filter < 0)
161 return 0;
162
163 return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter);
164 }
165
166 static int link_set_ipv6_privacy_extensions(Link *link) {
167 IPv6PrivacyExtensions val;
168
169 assert(link);
170 assert(link->manager);
171
172 if (!link_is_configured_for_family(link, AF_INET6))
173 return 0;
174
175 val = link->network->ipv6_privacy_extensions;
176 if (val < 0) /* If not specified, then use the global setting. */
177 val = link->manager->ipv6_privacy_extensions;
178
179 /* When "kernel", do not update the setting. */
180 if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
181 return 0;
182
183 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val);
184 }
185
186 static int link_set_ipv6_accept_ra(Link *link) {
187 assert(link);
188
189 if (!link_is_configured_for_family(link, AF_INET6))
190 return 0;
191
192 return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
193 }
194
195 static int link_set_ipv6_dad_transmits(Link *link) {
196 assert(link);
197
198 if (!link_is_configured_for_family(link, AF_INET6))
199 return 0;
200
201 if (link->network->ipv6_dad_transmits < 0)
202 return 0;
203
204 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
205 }
206
207 static int link_set_ipv6_hop_limit(Link *link) {
208 assert(link);
209
210 if (!link_is_configured_for_family(link, AF_INET6))
211 return 0;
212
213 if (link->network->ipv6_hop_limit <= 0)
214 return 0;
215
216 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
217 }
218
219 static int link_set_ipv6_retransmission_time(Link *link) {
220 usec_t retrans_time_ms;
221
222 assert(link);
223
224 if (!link_is_configured_for_family(link, AF_INET6))
225 return 0;
226
227 if (!timestamp_is_set(link->network->ipv6_retransmission_time))
228 return 0;
229
230 retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
231 if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
232 return 0;
233
234 return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms);
235 }
236
237 static int link_set_ipv6_proxy_ndp(Link *link) {
238 bool v;
239
240 assert(link);
241
242 if (!link_is_configured_for_family(link, AF_INET6))
243 return 0;
244
245 if (link->network->ipv6_proxy_ndp >= 0)
246 v = link->network->ipv6_proxy_ndp;
247 else
248 v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
249
250 return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
251 }
252
253 int link_set_ipv6_mtu(Link *link, int log_level) {
254 uint32_t mtu = 0;
255
256 assert(link);
257
258 if (!link_is_configured_for_family(link, AF_INET6))
259 return 0;
260
261 assert(link->network);
262
263 if (link->network->ndisc_use_mtu)
264 mtu = link->ndisc_mtu;
265 if (mtu == 0)
266 mtu = link->network->ipv6_mtu;
267 if (mtu == 0)
268 return 0;
269
270 if (mtu > link->mtu) {
271 log_link_full(link, log_level,
272 "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
273 mtu, link->mtu);
274 mtu = link->mtu;
275 }
276
277 return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu);
278 }
279
280 static int link_set_ipv4_accept_local(Link *link) {
281 assert(link);
282
283 if (!link_is_configured_for_family(link, AF_INET))
284 return 0;
285
286 if (link->network->ipv4_accept_local < 0)
287 return 0;
288
289 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0);
290 }
291
292 static int link_set_ipv4_route_localnet(Link *link) {
293 assert(link);
294
295 if (!link_is_configured_for_family(link, AF_INET))
296 return 0;
297
298 if (link->network->ipv4_route_localnet < 0)
299 return 0;
300
301 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0);
302 }
303
304 static int link_set_ipv4_promote_secondaries(Link *link) {
305 assert(link);
306
307 if (!link_is_configured_for_family(link, AF_INET))
308 return 0;
309
310 /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
311 * changes between leases. The kernel will remove all secondary IP addresses of an interface
312 * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
313 * secondary IP and when the primary one expires it relies on the kernel to promote the
314 * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
315 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true);
316 }
317
318 int link_set_sysctl(Link *link) {
319 int r;
320
321 assert(link);
322
323 /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
324 * for this interface, then enable IPv6 */
325 r = link_update_ipv6_sysctl(link);
326 if (r < 0)
327 log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
328
329 r = link_set_proxy_arp(link);
330 if (r < 0)
331 log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
332
333 r = link_set_proxy_arp_pvlan(link);
334 if (r < 0)
335 log_link_warning_errno(link, r, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
336
337 (void) link_set_ip_forwarding(link, AF_INET);
338 (void) link_set_ip_forwarding(link, AF_INET6);
339
340 r = link_set_ipv6_privacy_extensions(link);
341 if (r < 0)
342 log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
343
344 r = link_set_ipv6_accept_ra(link);
345 if (r < 0)
346 log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
347
348 r = link_set_ipv6_dad_transmits(link);
349 if (r < 0)
350 log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
351
352 r = link_set_ipv6_hop_limit(link);
353 if (r < 0)
354 log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
355
356 r = link_set_ipv6_retransmission_time(link);
357 if (r < 0)
358 log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
359
360 r = link_set_ipv6_proxy_ndp(link);
361 if (r < 0)
362 log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
363
364 r = link_set_ipv6_mtu(link, LOG_INFO);
365 if (r < 0)
366 log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
367
368 r = link_set_ipv6ll_stable_secret(link);
369 if (r < 0)
370 log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
371
372 r = link_set_ipv4_accept_local(link);
373 if (r < 0)
374 log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
375
376 r = link_set_ipv4_route_localnet(link);
377 if (r < 0)
378 log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
379
380 r = link_set_ipv4_rp_filter(link);
381 if (r < 0)
382 log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
383
384 r = link_set_ipv4_promote_secondaries(link);
385 if (r < 0)
386 log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
387
388 return 0;
389 }
390
391 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
392 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
393 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
394 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
395 [IPV6_PRIVACY_EXTENSIONS_KERNEL] = "kernel",
396 };
397
398 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
399 IPV6_PRIVACY_EXTENSIONS_YES);
400 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions,
401 "Failed to parse IPv6 privacy extensions option");
402
403 static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
404 [IP_REVERSE_PATH_FILTER_NO] = "no",
405 [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
406 [IP_REVERSE_PATH_FILTER_LOOSE] = "loose",
407 };
408
409 DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
410 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter,
411 "Failed to parse IP reverse path filter option");
412
413 int config_parse_ip_forward_deprecated(
414 const char* unit,
415 const char *filename,
416 unsigned line,
417 const char *section,
418 unsigned section_line,
419 const char *lvalue,
420 int ltype,
421 const char *rvalue,
422 void *data,
423 void *userdata) {
424
425 assert(filename);
426
427 log_syntax(unit, LOG_WARNING, filename, line, 0,
428 "IPForward= setting is deprecated. "
429 "Please use IPv4Forwarding= and/or IPv6Forwarding= in networkd.conf for global setting, "
430 "and the same settings in .network files for per-interface setting.");
431 return 0;
432 }