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