]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-sysctl.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[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 "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"
15
16 static bool link_is_configured_for_family(Link *link, int family) {
17 assert(link);
18
19 if (!link->network)
20 return false;
21
22 if (link->flags & IFF_LOOPBACK)
23 return false;
24
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)
29 return false;
30
31 if (family == AF_INET6 && !socket_ipv6_is_supported())
32 return false;
33
34 return true;
35 }
36
37 static int link_update_ipv6_sysctl(Link *link) {
38 assert(link);
39
40 if (!link_is_configured_for_family(link, AF_INET6))
41 return 0;
42
43 if (!link_ipv6_enabled(link))
44 return 0;
45
46 return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
47 }
48
49 static int link_set_proxy_arp(Link *link) {
50 assert(link);
51
52 if (!link_is_configured_for_family(link, AF_INET))
53 return 0;
54
55 if (link->network->proxy_arp < 0)
56 return 0;
57
58 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
59 }
60
61 static bool link_ip_forward_enabled(Link *link, int family) {
62 assert(link);
63 assert(IN_SET(family, AF_INET, AF_INET6));
64
65 if (!link_is_configured_for_family(link, family))
66 return false;
67
68 return link->network->ip_forward & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
69 }
70
71 static int link_set_ipv4_forward(Link *link) {
72 assert(link);
73
74 if (!link_ip_forward_enabled(link, AF_INET))
75 return 0;
76
77 /* We propagate the forwarding flag from one interface to the
78 * global setting one way. This means: as long as at least one
79 * interface was configured at any time that had IP forwarding
80 * enabled the setting will stay on for good. We do this
81 * primarily to keep IPv4 and IPv6 packet forwarding behaviour
82 * somewhat in sync (see below). */
83
84 return sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
85 }
86
87 static int link_set_ipv6_forward(Link *link) {
88 assert(link);
89
90 if (!link_ip_forward_enabled(link, AF_INET6))
91 return 0;
92
93 /* On Linux, the IPv6 stack does not know a per-interface
94 * packet forwarding setting: either packet forwarding is on
95 * for all, or off for all. We hence don't bother with a
96 * per-interface setting, but simply propagate the interface
97 * flag, if it is set, to the global flag, one-way. Note that
98 * while IPv4 would allow a per-interface flag, we expose the
99 * same behaviour there and also propagate the setting from
100 * one to all, to keep things simple (see above). */
101
102 return sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
103 }
104
105 static int link_set_ipv4_rp_filter(Link *link) {
106 assert(link);
107
108 if (!link_is_configured_for_family(link, AF_INET))
109 return 0;
110
111 if (link->network->ipv4_rp_filter < 0)
112 return 0;
113
114 return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter);
115 }
116
117 static int link_set_ipv6_privacy_extensions(Link *link) {
118 IPv6PrivacyExtensions val;
119
120 assert(link);
121 assert(link->manager);
122
123 if (!link_is_configured_for_family(link, AF_INET6))
124 return 0;
125
126 val = link->network->ipv6_privacy_extensions;
127 if (val < 0) /* If not specified, then use the global setting. */
128 val = link->manager->ipv6_privacy_extensions;
129
130 /* When "kernel", do not update the setting. */
131 if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
132 return 0;
133
134 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val);
135 }
136
137 static int link_set_ipv6_accept_ra(Link *link) {
138 assert(link);
139
140 if (!link_is_configured_for_family(link, AF_INET6))
141 return 0;
142
143 return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
144 }
145
146 static int link_set_ipv6_dad_transmits(Link *link) {
147 assert(link);
148
149 if (!link_is_configured_for_family(link, AF_INET6))
150 return 0;
151
152 if (link->network->ipv6_dad_transmits < 0)
153 return 0;
154
155 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
156 }
157
158 static int link_set_ipv6_hop_limit(Link *link) {
159 assert(link);
160
161 if (!link_is_configured_for_family(link, AF_INET6))
162 return 0;
163
164 if (link->network->ipv6_hop_limit <= 0)
165 return 0;
166
167 return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
168 }
169
170 static int link_set_ipv6_proxy_ndp(Link *link) {
171 bool v;
172
173 assert(link);
174
175 if (!link_is_configured_for_family(link, AF_INET6))
176 return 0;
177
178 if (link->network->ipv6_proxy_ndp >= 0)
179 v = link->network->ipv6_proxy_ndp;
180 else
181 v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
182
183 return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
184 }
185
186 int link_set_ipv6_mtu(Link *link) {
187 uint32_t mtu;
188
189 assert(link);
190
191 if (!link_is_configured_for_family(link, AF_INET6))
192 return 0;
193
194 if (link->network->ipv6_mtu == 0)
195 return 0;
196
197 mtu = link->network->ipv6_mtu;
198 if (mtu > link->max_mtu) {
199 log_link_warning(link, "Reducing requested IPv6 MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
200 mtu, link->max_mtu);
201 mtu = link->max_mtu;
202 }
203
204 return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu);
205 }
206
207 static int link_set_ipv4_accept_local(Link *link) {
208 assert(link);
209
210 if (!link_is_configured_for_family(link, AF_INET))
211 return 0;
212
213 if (link->network->ipv4_accept_local < 0)
214 return 0;
215
216 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0);
217 }
218
219 static int link_set_ipv4_route_localnet(Link *link) {
220 assert(link);
221
222 if (!link_is_configured_for_family(link, AF_INET))
223 return 0;
224
225 if (link->network->ipv4_route_localnet < 0)
226 return 0;
227
228 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0);
229 }
230
231 static int link_set_ipv4_promote_secondaries(Link *link) {
232 assert(link);
233
234 if (!link_is_configured_for_family(link, AF_INET))
235 return 0;
236
237 /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not
238 * changes between leases. The kernel will remove all secondary IP addresses of an interface
239 * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
240 * secondary IP and when the primary one expires it relies on the kernel to promote the
241 * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
242 return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true);
243 }
244
245 int link_set_sysctl(Link *link) {
246 int r;
247
248 assert(link);
249
250 /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
251 * for this interface, then enable IPv6 */
252 r = link_update_ipv6_sysctl(link);
253 if (r < 0)
254 log_link_warning_errno(link, r, "Cannot enable IPv6, ignoring: %m");
255
256 r = link_set_proxy_arp(link);
257 if (r < 0)
258 log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface, ignoring: %m");
259
260 r = link_set_ipv4_forward(link);
261 if (r < 0)
262 log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
263
264 r = link_set_ipv6_forward(link);
265 if (r < 0)
266 log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
267
268 r = link_set_ipv6_privacy_extensions(link);
269 if (r < 0)
270 log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extensions for interface, ignoring: %m");
271
272 r = link_set_ipv6_accept_ra(link);
273 if (r < 0)
274 log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface, ignoring: %m");
275
276 r = link_set_ipv6_dad_transmits(link);
277 if (r < 0)
278 log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface, ignoring: %m");
279
280 r = link_set_ipv6_hop_limit(link);
281 if (r < 0)
282 log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
283
284 r = link_set_ipv6_proxy_ndp(link);
285 if (r < 0)
286 log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
287
288 r = link_set_ipv6_mtu(link);
289 if (r < 0)
290 log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
291
292 r = link_set_ipv6ll_stable_secret(link);
293 if (r < 0)
294 log_link_warning_errno(link, r, "Cannot set stable secret address for IPv6 link-local address: %m");
295
296 r = link_set_ipv4_accept_local(link);
297 if (r < 0)
298 log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m");
299
300 r = link_set_ipv4_route_localnet(link);
301 if (r < 0)
302 log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m");
303
304 r = link_set_ipv4_rp_filter(link);
305 if (r < 0)
306 log_link_warning_errno(link, r, "Cannot set IPv4 reverse path filtering for interface, ignoring: %m");
307
308 r = link_set_ipv4_promote_secondaries(link);
309 if (r < 0)
310 log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m");
311
312 return 0;
313 }
314
315 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
316 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
317 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
318 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
319 [IPV6_PRIVACY_EXTENSIONS_KERNEL] = "kernel",
320 };
321
322 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
323 IPV6_PRIVACY_EXTENSIONS_YES);
324 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_privacy_extensions, ipv6_privacy_extensions, IPv6PrivacyExtensions,
325 "Failed to parse IPv6 privacy extensions option");
326
327 static const char* const ip_reverse_path_filter_table[_IP_REVERSE_PATH_FILTER_MAX] = {
328 [IP_REVERSE_PATH_FILTER_NO] = "no",
329 [IP_REVERSE_PATH_FILTER_STRICT] = "strict",
330 [IP_REVERSE_PATH_FILTER_LOOSE] = "loose",
331 };
332
333 DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
334 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter,
335 "Failed to parse IP reverse path filter option");