1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
5 #include <linux/if_arp.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"
17 static void manager_set_ip_forwarding(Manager
*manager
, int family
) {
21 assert(IN_SET(family
, AF_INET
, AF_INET6
));
23 if (family
== AF_INET6
&& !socket_ipv6_is_supported())
26 t
= manager
->ip_forwarding
[family
== AF_INET6
];
30 /* First, set the default value. */
31 r
= sysctl_write_ip_property_boolean(family
, "default", "forwarding", t
);
33 log_warning_errno(r
, "Failed to %s the default %s forwarding: %m",
34 enable_disable(t
), af_to_ipv4_ipv6(family
));
36 /* Then, set the value to all interfaces. */
37 r
= sysctl_write_ip_property_boolean(family
, "all", "forwarding", t
);
39 log_warning_errno(r
, "Failed to %s %s forwarding for all interfaces: %m",
40 enable_disable(t
), af_to_ipv4_ipv6(family
));
43 void manager_set_sysctl(Manager
*manager
) {
45 assert(!manager
->test_mode
);
47 manager_set_ip_forwarding(manager
, AF_INET
);
48 manager_set_ip_forwarding(manager
, AF_INET6
);
51 static bool link_is_configured_for_family(Link
*link
, int family
) {
57 if (link
->flags
& IFF_LOOPBACK
)
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
)
66 if (family
== AF_INET6
&& !socket_ipv6_is_supported())
72 static int link_update_ipv6_sysctl(Link
*link
) {
75 if (!link_is_configured_for_family(link
, AF_INET6
))
78 if (!link_ipv6_enabled(link
))
81 return sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "disable_ipv6", false);
84 static int link_set_proxy_arp(Link
*link
) {
87 if (!link_is_configured_for_family(link
, AF_INET
))
90 if (link
->network
->proxy_arp
< 0)
93 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "proxy_arp", link
->network
->proxy_arp
> 0);
96 static int link_set_proxy_arp_pvlan(Link
*link
) {
99 if (!link_is_configured_for_family(link
, AF_INET
))
102 if (link
->network
->proxy_arp_pvlan
< 0)
105 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "proxy_arp_pvlan", link
->network
->proxy_arp_pvlan
> 0);
108 int link_get_ip_forwarding(Link
*link
, int family
) {
110 assert(link
->manager
);
111 assert(link
->network
);
112 assert(IN_SET(family
, AF_INET
, AF_INET6
));
114 /* If it is explicitly specified, then honor the setting. */
115 int t
= link
->network
->ip_forwarding
[family
== AF_INET6
];
119 /* If IPMasquerade= is enabled, also enable IP forwarding. */
120 if (family
== AF_INET
&& FLAGS_SET(link
->network
->ip_masquerade
, ADDRESS_FAMILY_IPV4
))
122 if (family
== AF_INET6
&& FLAGS_SET(link
->network
->ip_masquerade
, ADDRESS_FAMILY_IPV6
))
125 /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
126 if (family
== AF_INET6
&& link_radv_enabled(link
))
129 /* Otherwise, use the global setting. */
130 return link
->manager
->ip_forwarding
[family
== AF_INET6
];
133 static int link_set_ip_forwarding(Link
*link
, int family
) {
137 assert(IN_SET(family
, AF_INET
, AF_INET6
));
139 if (!link_is_configured_for_family(link
, family
))
142 t
= link_get_ip_forwarding(link
, family
);
146 r
= sysctl_write_ip_property_boolean(family
, link
->ifname
, "forwarding", t
);
148 return log_link_warning_errno(link
, r
, "Failed to %s %s forwarding, ignoring: %m",
149 enable_disable(t
), af_to_ipv4_ipv6(family
));
154 static int link_set_ipv4_rp_filter(Link
*link
) {
157 if (!link_is_configured_for_family(link
, AF_INET
))
160 if (link
->network
->ipv4_rp_filter
< 0)
163 return sysctl_write_ip_property_int(AF_INET
, link
->ifname
, "rp_filter", link
->network
->ipv4_rp_filter
);
166 static int link_set_ipv6_privacy_extensions(Link
*link
) {
167 IPv6PrivacyExtensions val
;
170 assert(link
->manager
);
172 if (!link_is_configured_for_family(link
, AF_INET6
))
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
;
179 /* When "kernel", do not update the setting. */
180 if (val
== IPV6_PRIVACY_EXTENSIONS_KERNEL
)
183 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "use_tempaddr", (int) val
);
186 static int link_set_ipv6_accept_ra(Link
*link
) {
189 if (!link_is_configured_for_family(link
, AF_INET6
))
192 return sysctl_write_ip_property(AF_INET6
, link
->ifname
, "accept_ra", "0");
195 static int link_set_ipv6_dad_transmits(Link
*link
) {
198 if (!link_is_configured_for_family(link
, AF_INET6
))
201 if (link
->network
->ipv6_dad_transmits
< 0)
204 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "dad_transmits", link
->network
->ipv6_dad_transmits
);
207 static int link_set_ipv6_hop_limit(Link
*link
) {
210 if (!link_is_configured_for_family(link
, AF_INET6
))
213 if (link
->network
->ipv6_hop_limit
<= 0)
216 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "hop_limit", link
->network
->ipv6_hop_limit
);
219 static int link_set_ipv6_retransmission_time(Link
*link
) {
220 usec_t retrans_time_ms
;
224 if (!link_is_configured_for_family(link
, AF_INET6
))
227 if (!timestamp_is_set(link
->network
->ipv6_retransmission_time
))
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
)
234 return sysctl_write_ip_neighbor_property_uint32(AF_INET6
, link
->ifname
, "retrans_time_ms", retrans_time_ms
);
237 static int link_set_ipv6_proxy_ndp(Link
*link
) {
242 if (!link_is_configured_for_family(link
, AF_INET6
))
245 if (link
->network
->ipv6_proxy_ndp
>= 0)
246 v
= link
->network
->ipv6_proxy_ndp
;
248 v
= !set_isempty(link
->network
->ipv6_proxy_ndp_addresses
);
250 return sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "proxy_ndp", v
);
253 int link_set_ipv6_mtu(Link
*link
, int log_level
) {
258 if (!link_is_configured_for_family(link
, AF_INET6
))
261 assert(link
->network
);
263 if (link
->network
->ndisc_use_mtu
)
264 mtu
= link
->ndisc_mtu
;
266 mtu
= link
->network
->ipv6_mtu
;
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
".",
277 return sysctl_write_ip_property_uint32(AF_INET6
, link
->ifname
, "mtu", mtu
);
280 static int link_set_ipv4_accept_local(Link
*link
) {
283 if (!link_is_configured_for_family(link
, AF_INET
))
286 if (link
->network
->ipv4_accept_local
< 0)
289 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "accept_local", link
->network
->ipv4_accept_local
> 0);
292 static int link_set_ipv4_route_localnet(Link
*link
) {
295 if (!link_is_configured_for_family(link
, AF_INET
))
298 if (link
->network
->ipv4_route_localnet
< 0)
301 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "route_localnet", link
->network
->ipv4_route_localnet
> 0);
304 static int link_set_ipv4_promote_secondaries(Link
*link
) {
307 if (!link_is_configured_for_family(link
, AF_INET
))
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);
318 int link_set_sysctl(Link
*link
) {
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
);
327 log_link_warning_errno(link
, r
, "Cannot enable IPv6, ignoring: %m");
329 r
= link_set_proxy_arp(link
);
331 log_link_warning_errno(link
, r
, "Cannot configure proxy ARP for interface, ignoring: %m");
333 r
= link_set_proxy_arp_pvlan(link
);
335 log_link_warning_errno(link
, r
, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
337 (void) link_set_ip_forwarding(link
, AF_INET
);
338 (void) link_set_ip_forwarding(link
, AF_INET6
);
340 r
= link_set_ipv6_privacy_extensions(link
);
342 log_link_warning_errno(link
, r
, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
344 r
= link_set_ipv6_accept_ra(link
);
346 log_link_warning_errno(link
, r
, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
348 r
= link_set_ipv6_dad_transmits(link
);
350 log_link_warning_errno(link
, r
, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
352 r
= link_set_ipv6_hop_limit(link
);
354 log_link_warning_errno(link
, r
, "Cannot set IPv6 hop limit for interface, ignoring: %m");
356 r
= link_set_ipv6_retransmission_time(link
);
358 log_link_warning_errno(link
, r
, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
360 r
= link_set_ipv6_proxy_ndp(link
);
362 log_link_warning_errno(link
, r
, "Cannot set IPv6 proxy NDP, ignoring: %m");
364 r
= link_set_ipv6_mtu(link
, LOG_INFO
);
366 log_link_warning_errno(link
, r
, "Cannot set IPv6 MTU, ignoring: %m");
368 r
= link_set_ipv6ll_stable_secret(link
);
370 log_link_warning_errno(link
, r
, "Cannot set stable secret address for IPv6 link-local address: %m");
372 r
= link_set_ipv4_accept_local(link
);
374 log_link_warning_errno(link
, r
, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
376 r
= link_set_ipv4_route_localnet(link
);
378 log_link_warning_errno(link
, r
, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
380 r
= link_set_ipv4_rp_filter(link
);
382 log_link_warning_errno(link
, r
, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
384 r
= link_set_ipv4_promote_secondaries(link
);
386 log_link_warning_errno(link
, r
, "Cannot enable promote_secondaries for interface, ignoring: %m");
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",
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");
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",
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");
413 int config_parse_ip_forward_deprecated(
415 const char *filename
,
418 unsigned section_line
,
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.");