]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp4.c
0b2f88b70619e9174e4be5201c64df321a9f367e
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <netinet/ether.h>
21 #include <linux/if.h>
22
23 #include "alloc-util.h"
24 #include "dhcp-lease-internal.h"
25 #include "hostname-util.h"
26 #include "netdev/vrf.h"
27 #include "network-internal.h"
28 #include "networkd-link.h"
29 #include "networkd-manager.h"
30 #include "networkd-network.h"
31
32 static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
33 void *userdata) {
34 _cleanup_link_unref_ Link *link = userdata;
35 int r;
36
37 assert(link);
38 assert(link->dhcp4_messages > 0);
39
40 link->dhcp4_messages--;
41
42 r = sd_netlink_message_get_errno(m);
43 if (r < 0 && r != -EEXIST) {
44 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
45 link_enter_failed(link);
46 }
47
48 if (link->dhcp4_messages == 0) {
49 link->dhcp4_configured = true;
50 link_check_ready(link);
51 }
52
53 return 1;
54 }
55
56 static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
57 assert(route);
58 assert(self_addr);
59
60 if (in_addr_is_localhost(AF_INET, &route->dst) ||
61 (self_addr->s_addr && route->dst.in.s_addr == self_addr->s_addr))
62 return RT_SCOPE_HOST;
63 else if (in4_addr_is_null(&route->gw.in))
64 return RT_SCOPE_LINK;
65 else
66 return RT_SCOPE_UNIVERSE;
67 }
68
69 static int link_set_dhcp_routes(Link *link) {
70 struct in_addr gateway, address;
71 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
72 int r, n, i;
73 uint32_t table;
74
75 assert(link);
76
77 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
78 return 0;
79
80 if (!link->network) /* link went down while we configured the IP addresses? */
81 return 0;
82
83 if (!link->network->dhcp_use_routes)
84 return 0;
85
86 /* When the interface is part of an VRF use the VRFs routing table, unless
87 * there is a another table specified. */
88 table = link->network->dhcp_route_table;
89 if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
90 table = VRF(link->network->vrf)->table;
91
92 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
93 if (r < 0)
94 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
95
96 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
97 if (r < 0 && r != -ENODATA)
98 return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
99
100 if (r >= 0) {
101 _cleanup_route_free_ Route *route = NULL;
102 _cleanup_route_free_ Route *route_gw = NULL;
103
104 r = route_new(&route);
105 if (r < 0)
106 return log_link_error_errno(link, r, "Could not allocate route: %m");
107
108 route->protocol = RTPROT_DHCP;
109
110 r = route_new(&route_gw);
111 if (r < 0)
112 return log_link_error_errno(link, r, "Could not allocate route: %m");
113
114 /* The dhcp netmask may mask out the gateway. Add an explicit
115 * route for the gw host so that we can route no matter the
116 * netmask or existing kernel route tables. */
117 route_gw->family = AF_INET;
118 route_gw->dst.in = gateway;
119 route_gw->dst_prefixlen = 32;
120 route_gw->prefsrc.in = address;
121 route_gw->scope = RT_SCOPE_LINK;
122 route_gw->protocol = RTPROT_DHCP;
123 route_gw->priority = link->network->dhcp_route_metric;
124 route_gw->table = table;
125
126 r = route_configure(route_gw, link, dhcp4_route_handler);
127 if (r < 0)
128 return log_link_warning_errno(link, r, "Could not set host route: %m");
129
130 link->dhcp4_messages++;
131
132 route->family = AF_INET;
133 route->gw.in = gateway;
134 route->prefsrc.in = address;
135 route->priority = link->network->dhcp_route_metric;
136 route->table = table;
137
138 r = route_configure(route, link, dhcp4_route_handler);
139 if (r < 0) {
140 log_link_warning_errno(link, r, "Could not set routes: %m");
141 link_enter_failed(link);
142 return r;
143 }
144
145 link->dhcp4_messages++;
146 }
147
148 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
149 if (n == -ENODATA)
150 return 0;
151 if (n < 0)
152 return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");
153
154 for (i = 0; i < n; i++) {
155 _cleanup_route_free_ Route *route = NULL;
156
157 r = route_new(&route);
158 if (r < 0)
159 return log_link_error_errno(link, r, "Could not allocate route: %m");
160
161 route->family = AF_INET;
162 route->protocol = RTPROT_DHCP;
163 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
164 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
165 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
166 route->priority = link->network->dhcp_route_metric;
167 route->table = table;
168 route->scope = route_scope_from_address(route, &address);
169
170 r = route_configure(route, link, dhcp4_route_handler);
171 if (r < 0)
172 return log_link_warning_errno(link, r, "Could not set host route: %m");
173
174 link->dhcp4_messages++;
175 }
176
177 return 0;
178 }
179
180 static int dhcp_lease_lost(Link *link) {
181 _cleanup_address_free_ Address *address = NULL;
182 struct in_addr addr;
183 struct in_addr netmask;
184 struct in_addr gateway;
185 unsigned prefixlen = 0;
186 int r;
187
188 assert(link);
189 assert(link->dhcp_lease);
190
191 log_link_warning(link, "DHCP lease lost");
192
193 if (link->network->dhcp_use_routes) {
194 _cleanup_free_ sd_dhcp_route **routes = NULL;
195 int n, i;
196
197 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
198 if (n >= 0) {
199 for (i = 0; i < n; i++) {
200 _cleanup_route_free_ Route *route = NULL;
201
202 r = route_new(&route);
203 if (r >= 0) {
204 route->family = AF_INET;
205 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
206 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
207 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
208
209 route_remove(route, link,
210 link_route_remove_handler);
211 }
212 }
213 }
214 }
215
216 r = address_new(&address);
217 if (r >= 0) {
218 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
219 if (r >= 0) {
220 _cleanup_route_free_ Route *route_gw = NULL;
221 _cleanup_route_free_ Route *route = NULL;
222
223 r = route_new(&route_gw);
224 if (r >= 0) {
225 route_gw->family = AF_INET;
226 route_gw->dst.in = gateway;
227 route_gw->dst_prefixlen = 32;
228 route_gw->scope = RT_SCOPE_LINK;
229
230 route_remove(route_gw, link,
231 link_route_remove_handler);
232 }
233
234 r = route_new(&route);
235 if (r >= 0) {
236 route->family = AF_INET;
237 route->gw.in = gateway;
238
239 route_remove(route, link,
240 link_route_remove_handler);
241 }
242 }
243
244 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
245 if (r >= 0) {
246 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
247 if (r >= 0)
248 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
249
250 address->family = AF_INET;
251 address->in_addr.in = addr;
252 address->prefixlen = prefixlen;
253
254 address_remove(address, link, link_address_remove_handler);
255 }
256 }
257
258 if (link->network->dhcp_use_mtu) {
259 uint16_t mtu;
260
261 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
262 if (r >= 0 && link->original_mtu != mtu) {
263 r = link_set_mtu(link, link->original_mtu);
264 if (r < 0) {
265 log_link_warning(link,
266 "DHCP error: could not reset MTU");
267 link_enter_failed(link);
268 return r;
269 }
270 }
271 }
272
273 if (link->network->dhcp_use_hostname) {
274 const char *hostname = NULL;
275
276 if (link->network->dhcp_hostname)
277 hostname = link->network->dhcp_hostname;
278 else
279 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
280
281 if (hostname) {
282 /* If a hostname was set due to the lease, then unset it now. */
283 r = manager_set_hostname(link->manager, NULL);
284 if (r < 0)
285 log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
286 }
287 }
288
289 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
290 link_dirty(link);
291 link->dhcp4_configured = false;
292
293 return 0;
294 }
295
296 static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
297 void *userdata) {
298 _cleanup_link_unref_ Link *link = userdata;
299 int r;
300
301 assert(link);
302
303 r = sd_netlink_message_get_errno(m);
304 if (r < 0 && r != -EEXIST) {
305 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
306 link_enter_failed(link);
307 } else if (r >= 0)
308 manager_rtnl_process_address(rtnl, m, link->manager);
309
310 link_set_dhcp_routes(link);
311
312 return 1;
313 }
314
315 static int dhcp4_update_address(Link *link,
316 struct in_addr *address,
317 struct in_addr *netmask,
318 uint32_t lifetime) {
319 _cleanup_address_free_ Address *addr = NULL;
320 unsigned prefixlen;
321 int r;
322
323 assert(address);
324 assert(netmask);
325 assert(lifetime);
326
327 prefixlen = in4_addr_netmask_to_prefixlen(netmask);
328
329 r = address_new(&addr);
330 if (r < 0)
331 return r;
332
333 addr->family = AF_INET;
334 addr->in_addr.in.s_addr = address->s_addr;
335 addr->cinfo.ifa_prefered = lifetime;
336 addr->cinfo.ifa_valid = lifetime;
337 addr->prefixlen = prefixlen;
338 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
339
340 /* allow reusing an existing address and simply update its lifetime
341 * in case it already exists */
342 r = address_configure(addr, link, dhcp4_address_handler, true);
343 if (r < 0)
344 return r;
345
346 return 0;
347 }
348
349 static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
350 sd_dhcp_lease *lease;
351 struct in_addr address;
352 struct in_addr netmask;
353 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
354 int r;
355
356 assert(link);
357 assert(client);
358 assert(link->network);
359
360 r = sd_dhcp_client_get_lease(client, &lease);
361 if (r < 0)
362 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
363
364 sd_dhcp_lease_unref(link->dhcp_lease);
365 link->dhcp4_configured = false;
366 link->dhcp_lease = sd_dhcp_lease_ref(lease);
367 link_dirty(link);
368
369 r = sd_dhcp_lease_get_address(lease, &address);
370 if (r < 0)
371 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
372
373 r = sd_dhcp_lease_get_netmask(lease, &netmask);
374 if (r < 0)
375 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
376
377 if (!link->network->dhcp_critical) {
378 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
379 if (r < 0)
380 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
381 }
382
383 r = dhcp4_update_address(link, &address, &netmask, lifetime);
384 if (r < 0) {
385 log_link_warning_errno(link, r, "Could not update IP address: %m");
386 link_enter_failed(link);
387 return r;
388 }
389
390 return 0;
391 }
392
393 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
394 sd_dhcp_lease *lease;
395 struct in_addr address;
396 struct in_addr netmask;
397 struct in_addr gateway;
398 unsigned prefixlen;
399 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
400 int r;
401
402 assert(client);
403 assert(link);
404
405 r = sd_dhcp_client_get_lease(client, &lease);
406 if (r < 0)
407 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
408
409 r = sd_dhcp_lease_get_address(lease, &address);
410 if (r < 0)
411 return log_link_error_errno(link, r, "DHCP error: No address: %m");
412
413 r = sd_dhcp_lease_get_netmask(lease, &netmask);
414 if (r < 0)
415 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
416
417 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
418
419 r = sd_dhcp_lease_get_router(lease, &gateway);
420 if (r < 0 && r != -ENODATA)
421 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
422
423 if (r >= 0)
424 log_struct(LOG_INFO,
425 LOG_LINK_INTERFACE(link),
426 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
427 ADDRESS_FMT_VAL(address),
428 prefixlen,
429 ADDRESS_FMT_VAL(gateway)),
430 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
431 "PREFIXLEN=%u", prefixlen,
432 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
433 NULL);
434 else
435 log_struct(LOG_INFO,
436 LOG_LINK_INTERFACE(link),
437 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
438 ADDRESS_FMT_VAL(address),
439 prefixlen),
440 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
441 "PREFIXLEN=%u", prefixlen,
442 NULL);
443
444 link->dhcp_lease = sd_dhcp_lease_ref(lease);
445 link_dirty(link);
446
447 if (link->network->dhcp_use_mtu) {
448 uint16_t mtu;
449
450 r = sd_dhcp_lease_get_mtu(lease, &mtu);
451 if (r >= 0) {
452 r = link_set_mtu(link, mtu);
453 if (r < 0)
454 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
455 }
456 }
457
458 if (link->network->dhcp_use_hostname) {
459 const char *hostname = NULL;
460
461 if (link->network->dhcp_hostname)
462 hostname = link->network->dhcp_hostname;
463 else
464 (void) sd_dhcp_lease_get_hostname(lease, &hostname);
465
466 if (hostname) {
467 r = manager_set_hostname(link->manager, hostname);
468 if (r < 0)
469 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
470 }
471 }
472
473 if (link->network->dhcp_use_timezone) {
474 const char *tz = NULL;
475
476 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
477
478 if (tz) {
479 r = manager_set_timezone(link->manager, tz);
480 if (r < 0)
481 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
482 }
483 }
484
485 if (!link->network->dhcp_critical) {
486 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
487 if (r < 0) {
488 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
489 return r;
490 }
491 }
492
493 r = dhcp4_update_address(link, &address, &netmask, lifetime);
494 if (r < 0) {
495 log_link_warning_errno(link, r, "Could not update IP address: %m");
496 link_enter_failed(link);
497 return r;
498 }
499
500 return 0;
501 }
502 static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
503 Link *link = userdata;
504 int r = 0;
505
506 assert(link);
507 assert(link->network);
508 assert(link->manager);
509
510 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
511 return;
512
513 switch (event) {
514 case SD_DHCP_CLIENT_EVENT_EXPIRED:
515 case SD_DHCP_CLIENT_EVENT_STOP:
516 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
517 if (link->network->dhcp_critical) {
518 log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
519 return;
520 }
521
522 if (link->dhcp_lease) {
523 r = dhcp_lease_lost(link);
524 if (r < 0) {
525 link_enter_failed(link);
526 return;
527 }
528 }
529
530 if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
531 r = dhcp_lease_acquired(client, link);
532 if (r < 0) {
533 link_enter_failed(link);
534 return;
535 }
536 }
537
538 break;
539 case SD_DHCP_CLIENT_EVENT_RENEW:
540 r = dhcp_lease_renew(client, link);
541 if (r < 0) {
542 link_enter_failed(link);
543 return;
544 }
545 break;
546 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
547 r = dhcp_lease_acquired(client, link);
548 if (r < 0) {
549 link_enter_failed(link);
550 return;
551 }
552 break;
553 default:
554 if (event < 0)
555 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
556 else
557 log_link_warning(link, "DHCP unknown event: %i", event);
558 break;
559 }
560
561 return;
562 }
563
564 static int dhcp4_set_hostname(Link *link) {
565 _cleanup_free_ char *hostname = NULL;
566 const char *hn;
567 int r;
568
569 assert(link);
570
571 if (!link->network->dhcp_send_hostname)
572 hn = NULL;
573 else if (link->network->dhcp_hostname)
574 hn = link->network->dhcp_hostname;
575 else {
576 r = gethostname_strict(&hostname);
577 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
578 return r;
579
580 hn = hostname;
581 }
582
583 return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
584 }
585
586 int dhcp4_configure(Link *link) {
587 int r;
588
589 assert(link);
590 assert(link->network);
591 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
592
593 if (!link->dhcp_client) {
594 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
595 if (r < 0)
596 return r;
597 }
598
599 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
600 if (r < 0)
601 return r;
602
603 r = sd_dhcp_client_set_mac(link->dhcp_client,
604 (const uint8_t *) &link->mac,
605 sizeof (link->mac), ARPHRD_ETHER);
606 if (r < 0)
607 return r;
608
609 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
610 if (r < 0)
611 return r;
612
613 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
614 if (r < 0)
615 return r;
616
617 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
618 link->network->dhcp_broadcast);
619 if (r < 0)
620 return r;
621
622 if (link->mtu) {
623 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
624 if (r < 0)
625 return r;
626 }
627
628 if (link->network->dhcp_use_mtu) {
629 r = sd_dhcp_client_set_request_option(link->dhcp_client,
630 SD_DHCP_OPTION_INTERFACE_MTU);
631 if (r < 0)
632 return r;
633 }
634
635 /* NOTE: even if this variable is called "use", it also "sends" PRL
636 * options, maybe there should be a different configuration variable
637 * to send or not route options?. */
638 /* NOTE: when using Anonymize=yes, routes PRL options are sent
639 * by default, so they don't need to be added here. */
640 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
641 r = sd_dhcp_client_set_request_option(link->dhcp_client,
642 SD_DHCP_OPTION_STATIC_ROUTE);
643 if (r < 0)
644 return r;
645 r = sd_dhcp_client_set_request_option(link->dhcp_client,
646 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
647 if (r < 0)
648 return r;
649 }
650
651 if (link->network->dhcp_use_ntp) {
652 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
653 if (r < 0)
654 return r;
655 }
656
657 if (link->network->dhcp_use_timezone) {
658 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
659 if (r < 0)
660 return r;
661 }
662
663 r = dhcp4_set_hostname(link);
664 if (r < 0)
665 return r;
666
667 if (link->network->dhcp_vendor_class_identifier) {
668 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
669 link->network->dhcp_vendor_class_identifier);
670 if (r < 0)
671 return r;
672 }
673
674 if (link->network->dhcp_client_port) {
675 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
676 if (r < 0)
677 return r;
678 }
679
680 switch (link->network->dhcp_client_identifier) {
681 case DHCP_CLIENT_ID_DUID: {
682 /* If configured, apply user specified DUID and/or IAID */
683 const DUID *duid = link_duid(link);
684
685 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
686 link->network->iaid,
687 duid->type,
688 duid->raw_data_len > 0 ? duid->raw_data : NULL,
689 duid->raw_data_len);
690 if (r < 0)
691 return r;
692 break;
693 }
694 case DHCP_CLIENT_ID_MAC:
695 r = sd_dhcp_client_set_client_id(link->dhcp_client,
696 ARPHRD_ETHER,
697 (const uint8_t *) &link->mac,
698 sizeof(link->mac));
699 if (r < 0)
700 return r;
701 break;
702 default:
703 assert_not_reached("Unknown client identifier type.");
704 }
705
706 return 0;
707 }