]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp4.c
core,network: major per-object logging rework
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/if.h>
24
25 #include "networkd-link.h"
26 #include "network-internal.h"
27 #include "dhcp-lease-internal.h"
28
29 static int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
30 void *userdata) {
31 _cleanup_link_unref_ Link *link = userdata;
32 int r;
33
34 assert(link);
35 assert(link->dhcp4_messages);
36
37 link->dhcp4_messages --;
38
39 r = sd_rtnl_message_get_errno(m);
40 if (r < 0 && r != -EEXIST) {
41 log_link_error(link, "could not set DHCPv4 route: %s",
42 strerror(-r));
43 link_enter_failed(link);
44 }
45
46 if (!link->dhcp4_messages) {
47 link->dhcp4_configured = true;
48 link_client_handler(link);
49 }
50
51 return 1;
52 }
53
54 static int link_set_dhcp_routes(Link *link) {
55 struct in_addr gateway;
56 struct sd_dhcp_route *static_routes;
57 int r, n, i;
58
59 assert(link);
60 assert(link->dhcp_lease);
61
62 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
63 if (r < 0 && r != -ENOENT) {
64 log_link_warning(link,
65 "DHCP error: could not get gateway: %s",
66 strerror(-r));
67 return r;
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 log_link_warning(link,
77 "DHCP error: could not get address: %s",
78 strerror(-r));
79 return r;
80 }
81
82 r = route_new_dynamic(&route, RTPROT_DHCP);
83 if (r < 0) {
84 log_link_error(link,
85 "Could not allocate route: %s",
86 strerror(-r));
87 return r;
88 }
89
90 r = route_new_dynamic(&route_gw, RTPROT_DHCP);
91 if (r < 0) {
92 log_link_error(link,
93 "Could not allocate route: %s",
94 strerror(-r));
95 return r;
96 }
97
98 /* The dhcp netmask may mask out the gateway. Add an explicit
99 * route for the gw host so that we can route no matter the
100 * netmask or existing kernel route tables. */
101 route_gw->family = AF_INET;
102 route_gw->dst_addr.in = gateway;
103 route_gw->dst_prefixlen = 32;
104 route_gw->prefsrc_addr.in = address;
105 route_gw->scope = RT_SCOPE_LINK;
106 route_gw->metrics = link->network->dhcp_route_metric;
107
108 r = route_configure(route_gw, link, &dhcp4_route_handler);
109 if (r < 0) {
110 log_link_warning(link,
111 "could not set host route: %s",
112 strerror(-r));
113 return r;
114 }
115
116 link->dhcp4_messages ++;
117
118 route->family = AF_INET;
119 route->in_addr.in = gateway;
120 route->prefsrc_addr.in = address;
121 route->metrics = link->network->dhcp_route_metric;
122
123 r = route_configure(route, link, &dhcp4_route_handler);
124 if (r < 0) {
125 log_link_warning(link,
126 "could not set routes: %s",
127 strerror(-r));
128 link_enter_failed(link);
129 return r;
130 }
131
132 link->dhcp4_messages ++;
133 }
134
135 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
136 if (n == -ENOENT)
137 return 0;
138 if (n < 0) {
139 log_link_warning(link,
140 "DHCP error: could not get routes: %s",
141 strerror(-n));
142
143 return n;
144 }
145
146 for (i = 0; i < n; i++) {
147 _cleanup_route_free_ Route *route = NULL;
148
149 r = route_new_dynamic(&route, RTPROT_DHCP);
150 if (r < 0) {
151 log_link_error(link, "Could not allocate route: %s",
152 strerror(-r));
153 return r;
154 }
155
156 route->family = AF_INET;
157 route->in_addr.in = static_routes[i].gw_addr;
158 route->dst_addr.in = static_routes[i].dst_addr;
159 route->dst_prefixlen = static_routes[i].dst_prefixlen;
160 route->metrics = link->network->dhcp_route_metric;
161
162 r = route_configure(route, link, &dhcp4_route_handler);
163 if (r < 0) {
164 log_link_warning(link,
165 "could not set host route: %s",
166 strerror(-r));
167 return r;
168 }
169
170 link->dhcp4_messages ++;
171 }
172
173 return 0;
174 }
175
176 static int dhcp_lease_lost(Link *link) {
177 _cleanup_address_free_ Address *address = NULL;
178 struct in_addr addr;
179 struct in_addr netmask;
180 struct in_addr gateway;
181 unsigned prefixlen = 0;
182 int r;
183
184 assert(link);
185 assert(link->dhcp_lease);
186
187 log_link_warning(link, "DHCP lease lost");
188
189 if (link->network->dhcp_routes) {
190 struct sd_dhcp_route *routes;
191 int n, i;
192
193 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
194 if (n >= 0) {
195 for (i = 0; i < n; i++) {
196 _cleanup_route_free_ Route *route = NULL;
197
198 r = route_new_dynamic(&route, RTPROT_UNSPEC);
199 if (r >= 0) {
200 route->family = AF_INET;
201 route->in_addr.in = routes[i].gw_addr;
202 route->dst_addr.in = routes[i].dst_addr;
203 route->dst_prefixlen = routes[i].dst_prefixlen;
204
205 route_drop(route, link,
206 &link_route_drop_handler);
207 }
208 }
209 }
210 }
211
212 r = address_new_dynamic(&address);
213 if (r >= 0) {
214 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
215 if (r >= 0) {
216 _cleanup_route_free_ Route *route_gw = NULL;
217 _cleanup_route_free_ Route *route = NULL;
218
219 r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
220 if (r >= 0) {
221 route_gw->family = AF_INET;
222 route_gw->dst_addr.in = gateway;
223 route_gw->dst_prefixlen = 32;
224 route_gw->scope = RT_SCOPE_LINK;
225
226 route_drop(route_gw, link,
227 &link_route_drop_handler);
228 }
229
230 r = route_new_dynamic(&route, RTPROT_UNSPEC);
231 if (r >= 0) {
232 route->family = AF_INET;
233 route->in_addr.in = gateway;
234
235 route_drop(route, link,
236 &link_route_drop_handler);
237 }
238 }
239
240 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
241 if (r >= 0) {
242 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
243 if (r >= 0)
244 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
245
246 address->family = AF_INET;
247 address->in_addr.in = addr;
248 address->prefixlen = prefixlen;
249
250 address_drop(address, link, &link_address_drop_handler);
251 }
252 }
253
254 if (link->network->dhcp_mtu) {
255 uint16_t mtu;
256
257 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
258 if (r >= 0 && link->original_mtu != mtu) {
259 r = link_set_mtu(link, link->original_mtu);
260 if (r < 0) {
261 log_link_warning(link,
262 "DHCP error: could not reset MTU");
263 link_enter_failed(link);
264 return r;
265 }
266 }
267 }
268
269 if (link->network->dhcp_hostname) {
270 const char *hostname = NULL;
271
272 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
273 if (r >= 0 && hostname) {
274 r = link_set_hostname(link, "");
275 if (r < 0)
276 log_link_error(link,
277 "Failed to reset transient hostname");
278 }
279 }
280
281 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
282 link->dhcp4_configured = false;
283
284 return 0;
285 }
286
287 static int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
288 void *userdata) {
289 _cleanup_link_unref_ Link *link = userdata;
290 int r;
291
292 assert(link);
293
294 r = sd_rtnl_message_get_errno(m);
295 if (r < 0 && r != -EEXIST) {
296 log_link_error(link, "could not set DHCPv4 address: %s",
297 strerror(-r));
298 link_enter_failed(link);
299 } else if (r >= 0)
300 link_rtnl_process_address(rtnl, m, link->manager);
301
302 link_set_dhcp_routes(link);
303
304 return 1;
305 }
306
307 static int dhcp4_update_address(Link *link,
308 struct in_addr *address,
309 struct in_addr *netmask,
310 uint32_t lifetime) {
311 _cleanup_address_free_ Address *addr = NULL;
312 unsigned prefixlen;
313 int r;
314
315 assert(address);
316 assert(netmask);
317 assert(lifetime);
318
319 prefixlen = in_addr_netmask_to_prefixlen(netmask);
320
321 r = address_new_dynamic(&addr);
322 if (r < 0)
323 return r;
324
325 addr->family = AF_INET;
326 addr->in_addr.in.s_addr = address->s_addr;
327 addr->cinfo.ifa_prefered = lifetime;
328 addr->cinfo.ifa_valid = lifetime;
329 addr->prefixlen = prefixlen;
330 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
331
332 /* use update rather than configure so that we will update the
333 * lifetime of an existing address if it has already been configured */
334 r = address_update(addr, link, &dhcp4_address_handler);
335 if (r < 0)
336 return r;
337
338 return 0;
339 }
340
341 static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
342 sd_dhcp_lease *lease;
343 struct in_addr address;
344 struct in_addr netmask;
345 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
346 int r;
347
348 assert(link);
349 assert(client);
350 assert(link->network);
351
352 r = sd_dhcp_client_get_lease(client, &lease);
353 if (r < 0) {
354 log_link_warning(link, "DHCP error: no lease %s",
355 strerror(-r));
356 return r;
357 }
358
359 sd_dhcp_lease_unref(link->dhcp_lease);
360 link->dhcp4_configured = false;
361 link->dhcp_lease = lease;
362
363 r = sd_dhcp_lease_get_address(lease, &address);
364 if (r < 0) {
365 log_link_warning(link, "DHCP error: no address: %s",
366 strerror(-r));
367 return r;
368 }
369
370 r = sd_dhcp_lease_get_netmask(lease, &netmask);
371 if (r < 0) {
372 log_link_warning(link, "DHCP error: no netmask: %s",
373 strerror(-r));
374 return r;
375 }
376
377 if (!link->network->dhcp_critical) {
378 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
379 &lifetime);
380 if (r < 0) {
381 log_link_warning(link,
382 "DHCP error: no lifetime: %s",
383 strerror(-r));
384 return r;
385 }
386 }
387
388 r = dhcp4_update_address(link, &address, &netmask, lifetime);
389 if (r < 0) {
390 log_link_warning(link, "could not update IP address: %s",
391 strerror(-r));
392 link_enter_failed(link);
393 return r;
394 }
395
396 return 0;
397 }
398
399 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
400 sd_dhcp_lease *lease;
401 struct in_addr address;
402 struct in_addr netmask;
403 struct in_addr gateway;
404 unsigned prefixlen;
405 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
406 int r;
407
408 assert(client);
409 assert(link);
410
411 r = sd_dhcp_client_get_lease(client, &lease);
412 if (r < 0)
413 return log_link_error_errno(link, r, "DHCP error: no lease: %m");
414
415 r = sd_dhcp_lease_get_address(lease, &address);
416 if (r < 0)
417 return log_link_error_errno(link, r, "DHCP error: no address: %m");
418
419 r = sd_dhcp_lease_get_netmask(lease, &netmask);
420 if (r < 0)
421 return log_link_error_errno(link, r, "DHCP error: no netmask: %m");
422
423 prefixlen = in_addr_netmask_to_prefixlen(&netmask);
424
425 r = sd_dhcp_lease_get_router(lease, &gateway);
426 if (r < 0 && r != -ENOENT)
427 return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
428
429 if (r >= 0)
430 log_struct(LOG_INFO,
431 LOG_LINK_INTERFACE(link),
432 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
433 ADDRESS_FMT_VAL(address),
434 prefixlen,
435 ADDRESS_FMT_VAL(gateway)),
436 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
437 "PREFIXLEN=%u", prefixlen,
438 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
439 NULL);
440 else
441 log_struct(LOG_INFO,
442 LOG_LINK_INTERFACE(link),
443 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
444 ADDRESS_FMT_VAL(address),
445 prefixlen),
446 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
447 "PREFIXLEN=%u", prefixlen,
448 NULL);
449
450 link->dhcp_lease = lease;
451
452 if (link->network->dhcp_mtu) {
453 uint16_t mtu;
454
455 r = sd_dhcp_lease_get_mtu(lease, &mtu);
456 if (r >= 0) {
457 r = link_set_mtu(link, mtu);
458 if (r < 0)
459 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
460 }
461 }
462
463 if (link->network->dhcp_hostname) {
464 const char *hostname;
465
466 r = sd_dhcp_lease_get_hostname(lease, &hostname);
467 if (r >= 0) {
468 r = link_set_hostname(link, hostname);
469 if (r < 0)
470 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
471 }
472 }
473
474 if (!link->network->dhcp_critical) {
475 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
476 if (r < 0) {
477 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
478 return r;
479 }
480 }
481
482 r = dhcp4_update_address(link, &address, &netmask, lifetime);
483 if (r < 0) {
484 log_link_warning_errno(link, r, "Could not update IP address: %m");
485 link_enter_failed(link);
486 return r;
487 }
488
489 return 0;
490 }
491 static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
492 Link *link = userdata;
493 int r = 0;
494
495 assert(link);
496 assert(link->network);
497 assert(link->manager);
498
499 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
500 return;
501
502 switch (event) {
503 case DHCP_EVENT_EXPIRED:
504 case DHCP_EVENT_STOP:
505 case DHCP_EVENT_IP_CHANGE:
506 if (link->network->dhcp_critical) {
507 log_link_error(link,
508 "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
509 return;
510 }
511
512 if (link->dhcp_lease) {
513 r = dhcp_lease_lost(link);
514 if (r < 0) {
515 link_enter_failed(link);
516 return;
517 }
518 }
519
520 if (event == DHCP_EVENT_IP_CHANGE) {
521 r = dhcp_lease_acquired(client, link);
522 if (r < 0) {
523 link_enter_failed(link);
524 return;
525 }
526 }
527
528 break;
529 case DHCP_EVENT_RENEW:
530 r = dhcp_lease_renew(client, link);
531 if (r < 0) {
532 link_enter_failed(link);
533 return;
534 }
535 break;
536 case DHCP_EVENT_IP_ACQUIRE:
537 r = dhcp_lease_acquired(client, link);
538 if (r < 0) {
539 link_enter_failed(link);
540 return;
541 }
542 break;
543 default:
544 if (event < 0)
545 log_link_warning(link,
546 "DHCP error: client failed: %s",
547 strerror(-event));
548 else
549 log_link_warning(link,
550 "DHCP unknown event: %d",
551 event);
552 break;
553 }
554
555 return;
556 }
557
558 int dhcp4_configure(Link *link) {
559 int r;
560
561 assert(link);
562 assert(link->network);
563 assert(IN_SET(link->network->dhcp, ADDRESS_FAMILY_YES, ADDRESS_FAMILY_IPV4));
564
565 r = sd_dhcp_client_new(&link->dhcp_client);
566 if (r < 0)
567 return r;
568
569 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
570 if (r < 0)
571 return r;
572
573 r = sd_dhcp_client_set_mac(link->dhcp_client,
574 (const uint8_t *) &link->mac,
575 sizeof (link->mac), ARPHRD_ETHER);
576 if (r < 0)
577 return r;
578
579 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
580 if (r < 0)
581 return r;
582
583 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
584 if (r < 0)
585 return r;
586
587 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
588 link->network->dhcp_broadcast);
589 if (r < 0)
590 return r;
591
592 if (link->mtu) {
593 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
594 if (r < 0)
595 return r;
596 }
597
598 if (link->network->dhcp_mtu) {
599 r = sd_dhcp_client_set_request_option(link->dhcp_client,
600 DHCP_OPTION_INTERFACE_MTU);
601 if (r < 0)
602 return r;
603 }
604
605 if (link->network->dhcp_routes) {
606 r = sd_dhcp_client_set_request_option(link->dhcp_client,
607 DHCP_OPTION_STATIC_ROUTE);
608 if (r < 0)
609 return r;
610 r = sd_dhcp_client_set_request_option(link->dhcp_client,
611 DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
612 if (r < 0)
613 return r;
614 }
615
616 if (link->network->dhcp_sendhost) {
617 _cleanup_free_ char *hostname = NULL;
618
619 hostname = gethostname_malloc();
620 if (!hostname)
621 return -ENOMEM;
622
623 if (!is_localhost(hostname)) {
624 r = sd_dhcp_client_set_hostname(link->dhcp_client,
625 hostname);
626 if (r < 0)
627 return r;
628 }
629 }
630
631 if (link->network->dhcp_vendor_class_identifier) {
632 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
633 link->network->dhcp_vendor_class_identifier);
634 if (r < 0)
635 return r;
636 }
637
638 switch (link->network->dhcp_client_identifier) {
639 case DHCP_CLIENT_ID_DUID:
640 /* Library defaults to this. */
641 break;
642 case DHCP_CLIENT_ID_MAC:
643 r = sd_dhcp_client_set_client_id(link->dhcp_client,
644 ARPHRD_ETHER,
645 (const uint8_t *) &link->mac,
646 sizeof (link->mac));
647 if (r < 0)
648 return r;
649 break;
650 default:
651 assert_not_reached("Unknown client identifier type.");
652 }
653
654 return 0;
655 }