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