1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
5 #include <linux/if_arp.h>
7 #include "missing_network.h"
8 #include "networkd-link.h"
9 #include "networkd-manager.h"
10 #include "networkd-network.h"
11 #include "networkd-sysctl.h"
12 #include "socket-util.h"
13 #include "string-table.h"
14 #include "sysctl-util.h"
16 static bool link_is_configured_for_family(Link
*link
, int family
) {
22 if (link
->flags
& IFF_LOOPBACK
)
25 /* CAN devices do not support IP layer. Most of the functions below are never called for CAN devices,
26 * but link_set_ipv6_mtu() may be called after setting interface MTU, and warn about the failure. For
27 * safety, let's unconditionally check if the interface is not a CAN device. */
28 if (IN_SET(family
, AF_INET
, AF_INET6
) && link
->iftype
== ARPHRD_CAN
)
31 if (family
== AF_INET6
&& !socket_ipv6_is_supported())
37 static int link_update_ipv6_sysctl(Link
*link
) {
40 if (!link_is_configured_for_family(link
, AF_INET6
))
43 if (!link_ipv6_enabled(link
))
46 return sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "disable_ipv6", false);
49 static int link_set_proxy_arp(Link
*link
) {
52 if (!link_is_configured_for_family(link
, AF_INET
))
55 if (link
->network
->proxy_arp
< 0)
58 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "proxy_arp", link
->network
->proxy_arp
> 0);
61 static int link_set_proxy_arp_pvlan(Link
*link
) {
64 if (!link_is_configured_for_family(link
, AF_INET
))
67 if (link
->network
->proxy_arp_pvlan
< 0)
70 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "proxy_arp_pvlan", link
->network
->proxy_arp_pvlan
> 0);
73 static bool link_ip_forward_enabled(Link
*link
, int family
) {
75 assert(IN_SET(family
, AF_INET
, AF_INET6
));
77 if (!link_is_configured_for_family(link
, family
))
80 return link
->network
->ip_forward
& (family
== AF_INET
? ADDRESS_FAMILY_IPV4
: ADDRESS_FAMILY_IPV6
);
83 static int link_set_ipv4_forward(Link
*link
) {
86 if (!link_ip_forward_enabled(link
, AF_INET
))
89 /* We propagate the forwarding flag from one interface to the
90 * global setting one way. This means: as long as at least one
91 * interface was configured at any time that had IP forwarding
92 * enabled the setting will stay on for good. We do this
93 * primarily to keep IPv4 and IPv6 packet forwarding behaviour
94 * somewhat in sync (see below). */
96 return sysctl_write_ip_property(AF_INET
, NULL
, "ip_forward", "1");
99 static int link_set_ipv6_forward(Link
*link
) {
102 if (!link_ip_forward_enabled(link
, AF_INET6
))
105 /* On Linux, the IPv6 stack does not know a per-interface
106 * packet forwarding setting: either packet forwarding is on
107 * for all, or off for all. We hence don't bother with a
108 * per-interface setting, but simply propagate the interface
109 * flag, if it is set, to the global flag, one-way. Note that
110 * while IPv4 would allow a per-interface flag, we expose the
111 * same behaviour there and also propagate the setting from
112 * one to all, to keep things simple (see above). */
114 return sysctl_write_ip_property(AF_INET6
, "all", "forwarding", "1");
117 static int link_set_ipv4_rp_filter(Link
*link
) {
120 if (!link_is_configured_for_family(link
, AF_INET
))
123 if (link
->network
->ipv4_rp_filter
< 0)
126 return sysctl_write_ip_property_int(AF_INET
, link
->ifname
, "rp_filter", link
->network
->ipv4_rp_filter
);
129 static int link_set_ipv6_privacy_extensions(Link
*link
) {
130 IPv6PrivacyExtensions val
;
133 assert(link
->manager
);
135 if (!link_is_configured_for_family(link
, AF_INET6
))
138 val
= link
->network
->ipv6_privacy_extensions
;
139 if (val
< 0) /* If not specified, then use the global setting. */
140 val
= link
->manager
->ipv6_privacy_extensions
;
142 /* When "kernel", do not update the setting. */
143 if (val
== IPV6_PRIVACY_EXTENSIONS_KERNEL
)
146 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "use_tempaddr", (int) val
);
149 static int link_set_ipv6_accept_ra(Link
*link
) {
152 if (!link_is_configured_for_family(link
, AF_INET6
))
155 return sysctl_write_ip_property(AF_INET6
, link
->ifname
, "accept_ra", "0");
158 static int link_set_ipv6_dad_transmits(Link
*link
) {
161 if (!link_is_configured_for_family(link
, AF_INET6
))
164 if (link
->network
->ipv6_dad_transmits
< 0)
167 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "dad_transmits", link
->network
->ipv6_dad_transmits
);
170 static int link_set_ipv6_hop_limit(Link
*link
) {
173 if (!link_is_configured_for_family(link
, AF_INET6
))
176 if (link
->network
->ipv6_hop_limit
<= 0)
179 return sysctl_write_ip_property_int(AF_INET6
, link
->ifname
, "hop_limit", link
->network
->ipv6_hop_limit
);
182 static int link_set_ipv6_retransmission_time(Link
*link
) {
183 usec_t retrans_time_ms
;
187 if (!link_is_configured_for_family(link
, AF_INET6
))
190 if (!timestamp_is_set(link
->network
->ipv6_retransmission_time
))
193 retrans_time_ms
= DIV_ROUND_UP(link
->network
->ipv6_retransmission_time
, USEC_PER_MSEC
);
194 if (retrans_time_ms
<= 0 || retrans_time_ms
> UINT32_MAX
)
197 return sysctl_write_ip_neighbor_property_uint32(AF_INET6
, link
->ifname
, "retrans_time_ms", retrans_time_ms
);
200 static int link_set_ipv6_proxy_ndp(Link
*link
) {
205 if (!link_is_configured_for_family(link
, AF_INET6
))
208 if (link
->network
->ipv6_proxy_ndp
>= 0)
209 v
= link
->network
->ipv6_proxy_ndp
;
211 v
= !set_isempty(link
->network
->ipv6_proxy_ndp_addresses
);
213 return sysctl_write_ip_property_boolean(AF_INET6
, link
->ifname
, "proxy_ndp", v
);
216 int link_set_ipv6_mtu(Link
*link
) {
221 if (!link_is_configured_for_family(link
, AF_INET6
))
224 if (link
->network
->ipv6_mtu
== 0)
227 mtu
= link
->network
->ipv6_mtu
;
228 if (mtu
> link
->max_mtu
) {
229 log_link_warning(link
, "Reducing requested IPv6 MTU %"PRIu32
" to the interface's maximum MTU %"PRIu32
".",
234 return sysctl_write_ip_property_uint32(AF_INET6
, link
->ifname
, "mtu", mtu
);
237 static int link_set_ipv4_accept_local(Link
*link
) {
240 if (!link_is_configured_for_family(link
, AF_INET
))
243 if (link
->network
->ipv4_accept_local
< 0)
246 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "accept_local", link
->network
->ipv4_accept_local
> 0);
249 static int link_set_ipv4_route_localnet(Link
*link
) {
252 if (!link_is_configured_for_family(link
, AF_INET
))
255 if (link
->network
->ipv4_route_localnet
< 0)
258 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "route_localnet", link
->network
->ipv4_route_localnet
> 0);
261 static int link_set_ipv4_promote_secondaries(Link
*link
) {
264 if (!link_is_configured_for_family(link
, AF_INET
))
267 /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
268 * changes between leases. The kernel will remove all secondary IP addresses of an interface
269 * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
270 * secondary IP and when the primary one expires it relies on the kernel to promote the
271 * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
272 return sysctl_write_ip_property_boolean(AF_INET
, link
->ifname
, "promote_secondaries", true);
275 int link_set_sysctl(Link
*link
) {
280 /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
281 * for this interface, then enable IPv6 */
282 r
= link_update_ipv6_sysctl(link
);
284 log_link_warning_errno(link
, r
, "Cannot enable IPv6, ignoring: %m");
286 r
= link_set_proxy_arp(link
);
288 log_link_warning_errno(link
, r
, "Cannot configure proxy ARP for interface, ignoring: %m");
290 r
= link_set_proxy_arp_pvlan(link
);
292 log_link_warning_errno(link
, r
, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
294 r
= link_set_ipv4_forward(link
);
296 log_link_warning_errno(link
, r
, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
298 r
= link_set_ipv6_forward(link
);
300 log_link_warning_errno(link
, r
, "Cannot configure IPv6 packet forwarding, ignoring: %m");
302 r
= link_set_ipv6_privacy_extensions(link
);
304 log_link_warning_errno(link
, r
, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
306 r
= link_set_ipv6_accept_ra(link
);
308 log_link_warning_errno(link
, r
, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
310 r
= link_set_ipv6_dad_transmits(link
);
312 log_link_warning_errno(link
, r
, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
314 r
= link_set_ipv6_hop_limit(link
);
316 log_link_warning_errno(link
, r
, "Cannot set IPv6 hop limit for interface, ignoring: %m");
318 r
= link_set_ipv6_retransmission_time(link
);
320 log_link_warning_errno(link
, r
, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
322 r
= link_set_ipv6_proxy_ndp(link
);
324 log_link_warning_errno(link
, r
, "Cannot set IPv6 proxy NDP, ignoring: %m");
326 r
= link_set_ipv6_mtu(link
);
328 log_link_warning_errno(link
, r
, "Cannot set IPv6 MTU, ignoring: %m");
330 r
= link_set_ipv6ll_stable_secret(link
);
332 log_link_warning_errno(link
, r
, "Cannot set stable secret address for IPv6 link-local address: %m");
334 r
= link_set_ipv4_accept_local(link
);
336 log_link_warning_errno(link
, r
, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
338 r
= link_set_ipv4_route_localnet(link
);
340 log_link_warning_errno(link
, r
, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
342 r
= link_set_ipv4_rp_filter(link
);
344 log_link_warning_errno(link
, r
, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
346 r
= link_set_ipv4_promote_secondaries(link
);
348 log_link_warning_errno(link
, r
, "Cannot enable promote_secondaries for interface, ignoring: %m");
353 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
354 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
355 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
356 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
357 [IPV6_PRIVACY_EXTENSIONS_KERNEL
] = "kernel",
360 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions
, IPv6PrivacyExtensions
,
361 IPV6_PRIVACY_EXTENSIONS_YES
);
362 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions
, ipv6_privacy_extensions
, IPv6PrivacyExtensions
,
363 "Failed to parse IPv6 privacy extensions option");
365 static const char* const ip_reverse_path_filter_table
[_IP_REVERSE_PATH_FILTER_MAX
] = {
366 [IP_REVERSE_PATH_FILTER_NO
] = "no",
367 [IP_REVERSE_PATH_FILTER_STRICT
] = "strict",
368 [IP_REVERSE_PATH_FILTER_LOOSE
] = "loose",
371 DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter
, IPReversePathFilter
);
372 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter
, ip_reverse_path_filter
, IPReversePathFilter
,
373 "Failed to parse IP reverse path filter option");