chiark / gitweb /
networkd: dhcp - avoid null pointer dereference
[elogind.git] / src / network / networkd-link.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 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.h"
26 #include "libudev-private.h"
27 #include "util.h"
28
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30         _cleanup_link_free_ Link *link = NULL;
31         const char *mac;
32         struct ether_addr *mac_addr;
33         const char *ifname;
34         int r;
35
36         assert(device);
37         assert(ret);
38
39         link = new0(Link, 1);
40         if (!link)
41                 return -ENOMEM;
42
43         link->manager = manager;
44         link->state = _LINK_STATE_INVALID;
45
46         link->ifindex = udev_device_get_ifindex(device);
47         if (link->ifindex <= 0)
48                 return -EINVAL;
49
50         mac = udev_device_get_sysattr_value(device, "address");
51         if (mac) {
52                 mac_addr = ether_aton(mac);
53                 if (mac_addr)
54                         memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55         }
56
57         ifname = udev_device_get_sysname(device);
58         link->ifname = strdup(ifname);
59
60         r = hashmap_put(manager->links, &link->ifindex, link);
61         if (r < 0)
62                 return r;
63
64         *ret = link;
65         link = NULL;
66
67         return 0;
68 }
69
70 void link_free(Link *link) {
71         if (!link)
72                 return;
73
74         assert(link->manager);
75
76         if (link->dhcp)
77                 sd_dhcp_client_free(link->dhcp);
78
79         route_free(link->dhcp_route);
80         link->dhcp_route = NULL;
81
82         address_free(link->dhcp_address);
83         link->dhcp_address = NULL;
84
85         hashmap_remove(link->manager->links, &link->ifindex);
86
87         free(link->ifname);
88
89         free(link);
90 }
91
92 int link_add(Manager *m, struct udev_device *device) {
93         Link *link;
94         Network *network;
95         int r;
96         uint64_t ifindex;
97         const char *devtype;
98
99         assert(m);
100         assert(device);
101
102         ifindex = udev_device_get_ifindex(device);
103         link = hashmap_get(m->links, &ifindex);
104         if (link)
105                 return 0;
106
107         r = link_new(m, device, &link);
108         if (r < 0) {
109                 log_error("Could not create link: %s", strerror(-r));
110                 return r;
111         }
112
113         devtype = udev_device_get_devtype(device);
114         if (streq_ptr(devtype, "bridge")) {
115                 r = bridge_set_link(m, link);
116                 if (r < 0)
117                         return r == -ENOENT ? 0 : r;
118         }
119
120         r = network_get(m, device, &network);
121         if (r < 0)
122                 return r == -ENOENT ? 0 : r;
123
124         r = network_apply(m, network, link);
125         if (r < 0)
126                 return r;
127
128         return 0;
129 }
130
131 static int link_enter_configured(Link *link) {
132         assert(link);
133         assert(link->state == LINK_STATE_SETTING_ROUTES);
134
135         log_info("%s: link configured", link->ifname);
136
137         link->state = LINK_STATE_CONFIGURED;
138
139         return 0;
140 }
141
142 static void link_enter_failed(Link *link) {
143         assert(link);
144
145         log_warning("%s: failed", link->ifname);
146
147         link->state = LINK_STATE_FAILED;
148 }
149
150 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
151         Link *link = userdata;
152         int r;
153
154         assert(link->route_messages > 0);
155         assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
156                link->state == LINK_STATE_SETTING_ROUTES ||
157                link->state == LINK_STATE_FAILED);
158
159         link->route_messages --;
160
161         if (link->state == LINK_STATE_FAILED)
162                 return 1;
163
164         r = sd_rtnl_message_get_errno(m);
165         if (r < 0 && r != -EEXIST)
166                 log_warning("%s: could not set route: %s",
167                             link->ifname, strerror(-r));
168
169         /* we might have received an old reply after moving back to SETTING_ADDRESSES,
170          * ignore it */
171         if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
172                 log_debug("%s: routes set", link->ifname);
173                 link_enter_configured(link);
174         }
175
176         return 1;
177 }
178
179 static int link_enter_set_routes(Link *link) {
180         Route *route;
181         int r;
182
183         assert(link);
184         assert(link->network);
185         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
186
187         link->state = LINK_STATE_SETTING_ROUTES;
188
189         if (!link->network->static_routes && !link->dhcp_route)
190                 return link_enter_configured(link);
191
192         log_debug("%s: setting routes", link->ifname);
193
194         LIST_FOREACH(static_routes, route, link->network->static_routes) {
195                 r = route_configure(route, link, &route_handler);
196                 if (r < 0) {
197                         log_warning("%s: could not set routes", link->ifname);
198                         link_enter_failed(link);
199                         return r;
200                 }
201
202                 link->route_messages ++;
203         }
204
205         if (link->dhcp_route) {
206                 r = route_configure(link->dhcp_route, link, &route_handler);
207                 if (r < 0) {
208                         log_warning("%s: could not set routes", link->ifname);
209                         link_enter_failed(link);
210                         return r;
211                 }
212
213                 link->route_messages ++;
214         }
215
216         return 0;
217 }
218
219 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
220         Link *link = userdata;
221         int r;
222
223         assert(m);
224         assert(link);
225         assert(link->ifname);
226         assert(link->addr_messages > 0);
227         assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
228
229         link->addr_messages --;
230
231         if (link->state == LINK_STATE_FAILED)
232                 return 1;
233
234         r = sd_rtnl_message_get_errno(m);
235         if (r < 0 && r != -EEXIST)
236                 log_warning("%s: could not set address: %s",
237                             link->ifname, strerror(-r));
238
239         if (link->addr_messages == 0) {
240                 log_debug("%s: addresses set", link->ifname);
241                 link_enter_set_routes(link);
242         }
243
244         return 1;
245 }
246
247 static int link_enter_set_addresses(Link *link) {
248         Address *address;
249         int r;
250
251         assert(link);
252         assert(link->network);
253         assert(link->state != _LINK_STATE_INVALID);
254
255         link->state = LINK_STATE_SETTING_ADDRESSES;
256
257         if (!link->network->static_addresses && !link->dhcp_address)
258                 return link_enter_set_routes(link);
259
260         log_debug("%s: setting addresses", link->ifname);
261
262         LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
263                 r = address_configure(address, link, &address_handler);
264                 if (r < 0) {
265                         log_warning("%s: could not set addresses", link->ifname);
266                         link_enter_failed(link);
267                         return r;
268                 }
269
270                 link->addr_messages ++;
271         }
272
273         if (link->dhcp_address) {
274                 r = address_configure(link->dhcp_address, link, &address_handler);
275                 if (r < 0) {
276                         log_warning("%s: could not set addresses", link->ifname);
277                         link_enter_failed(link);
278                         return r;
279                 }
280
281                 link->addr_messages ++;
282         }
283
284         return 0;
285 }
286
287 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
288         Link *link = userdata;
289         int r;
290
291         assert(link);
292
293         if (link->state == LINK_STATE_FAILED)
294                 return 1;
295
296         r = sd_rtnl_message_get_errno(m);
297         if (r < 0) {
298                 log_warning("%s: could not bring up interface: %s",
299                             link->ifname, strerror(-r));
300                 link_enter_failed(link);
301         }
302
303         log_debug("%s: brought up interface", link->ifname);
304
305         return 1;
306 }
307
308 static int link_up(Link *link) {
309         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
310         int r;
311
312         assert(link);
313         assert(link->manager);
314         assert(link->manager->rtnl);
315
316         log_debug("%s: bringing up link", link->ifname);
317
318         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
319         if (r < 0) {
320                 log_error("Could not allocate RTM_SETLINK message");
321                 return r;
322         }
323
324         r = sd_rtnl_message_link_set_flags(req, IFF_UP);
325         if (r < 0) {
326                 log_error("Could not set link flags");
327                 return r;
328         }
329
330         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
331         if (r < 0) {
332                 log_error("Could not send rtnetlink message: %s", strerror(-r));
333                 return r;
334         }
335
336         return 0;
337 }
338
339 static int link_bridge_joined(Link *link) {
340         int r;
341
342         assert(link);
343         assert(link->state == LINK_STATE_JOINING_BRIDGE);
344         assert(link->network);
345
346         r = link_up(link);
347         if (r < 0) {
348                 link_enter_failed(link);
349                 return r;
350         }
351
352         if (!link->network->dhcp)
353                 return link_enter_set_addresses(link);
354
355         return 0;
356 }
357
358 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
359         Link *link = userdata;
360         int r;
361
362         assert(link);
363         assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
364         assert(link->network);
365
366         if (link->state == LINK_STATE_FAILED)
367                 return 1;
368
369         r = sd_rtnl_message_get_errno(m);
370         if (r < 0) {
371                 log_warning("%s: could not join bridge '%s': %s",
372                             link->ifname, link->network->bridge->name, strerror(-r));
373                 link_enter_failed(link);
374                 return 1;
375         } else
376                 log_debug("%s: joined bridge '%s'",
377                             link->ifname, link->network->bridge->name);
378
379         link_bridge_joined(link);
380
381         return 1;
382 }
383
384 static int link_enter_join_bridge(Link *link) {
385         int r;
386
387         assert(link);
388         assert(link->network);
389         assert(link->state == _LINK_STATE_INVALID);
390
391         link->state = LINK_STATE_JOINING_BRIDGE;
392
393         if (!link->network->bridge)
394                 return link_bridge_joined(link);
395
396         log_debug("%s: joining bridge", link->ifname);
397
398         r = bridge_join(link->network->bridge, link, &bridge_handler);
399         if (r < 0) {
400                 log_warning("%s: could not join bridge '%s'", link->ifname,
401                             link->network->bridge->name);
402                 link_enter_failed(link);
403                 return r;
404         }
405
406         return 0;
407 }
408
409 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
410         Link *link = userdata;
411         int r;
412
413         assert(link);
414
415         if (link->state == LINK_STATE_FAILED)
416                 return 1;
417
418         r = sd_rtnl_message_get_errno(m);
419         if (r < 0) {
420                 log_warning("%s: could not get state: %s",
421                             link->ifname, strerror(-r));
422                 link_enter_failed(link);
423         }
424
425         log_debug("%s: got link state", link->ifname);
426
427         link_update(link, m);
428
429         return 1;
430 }
431
432 static int link_get(Link *link) {
433         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
434         int r;
435
436         assert(link);
437         assert(link->manager);
438         assert(link->manager->rtnl);
439
440         log_debug("%s: requesting link status", link->ifname);
441
442         r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
443         if (r < 0) {
444                 log_error("Could not allocate RTM_GETLINK message");
445                 return r;
446         }
447
448         r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
449         if (r < 0) {
450                 log_error("Could not send rtnetlink message: %s", strerror(-r));
451                 return r;
452         }
453
454         return 0;
455 }
456
457 int link_configure(Link *link) {
458         int r;
459
460         assert(link);
461         assert(link->network);
462         assert(link->state == _LINK_STATE_INVALID);
463
464         r = link_get(link);
465         if (r < 0) {
466                 link_enter_failed(link);
467                 return r;
468         }
469
470         return link_enter_join_bridge(link);
471 }
472
473 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
474         Link *link = userdata;
475         int r;
476
477         assert(m);
478         assert(link);
479         assert(link->ifname);
480
481         if (link->state == LINK_STATE_FAILED)
482                 return 1;
483
484         r = sd_rtnl_message_get_errno(m);
485         if (r < 0 && r != -EEXIST)
486                 log_warning("%s: could not drop address: %s",
487                             link->ifname, strerror(-r));
488
489         return 1;
490 }
491
492 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
493         Link *link = userdata;
494         struct in_addr address;
495         struct in_addr netmask;
496         struct in_addr gateway;
497         int prefixlen;
498         int r;
499
500         assert(link);
501
502         if (link->state == LINK_STATE_FAILED)
503                 return;
504
505         if (event < 0) {
506                 log_warning("%s: DHCP error: %s", link->ifname, strerror(-event));
507                 link_enter_failed(link);
508                 return;
509         }
510
511         if (event == DHCP_EVENT_NO_LEASE)
512                 log_debug("%s: IP address in use.", link->ifname);
513
514         if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
515             event == DHCP_EVENT_STOP) {
516                 if (link->dhcp_address) {
517                         address_drop(link->dhcp_address, link, address_drop_handler);
518
519                         address_free(link->dhcp_address);
520                         link->dhcp_address = NULL;
521                 }
522
523                 if (link->dhcp_route) {
524                         route_free(link->dhcp_route);
525                         link->dhcp_route = NULL;
526                 }
527         }
528
529         r = sd_dhcp_client_get_address(client, &address);
530         if (r < 0) {
531                 log_warning("%s: DHCP error: no address", link->ifname);
532                 link_enter_failed(link);
533                 return;
534         }
535
536         r = sd_dhcp_client_get_netmask(client, &netmask);
537         if (r < 0) {
538                 log_warning("%s: DHCP error: no netmask", link->ifname);
539                 link_enter_failed(link);
540                 return;
541         }
542
543         prefixlen = sd_dhcp_client_prefixlen(&netmask);
544         if (prefixlen < 0) {
545                 log_warning("%s: DHCP error: no prefixlen", link->ifname);
546                 link_enter_failed(link);
547                 return;
548         }
549
550         r = sd_dhcp_client_get_router(client, &gateway);
551         if (r < 0) {
552                 log_warning("%s: DHCP error: no router", link->ifname);
553                 link_enter_failed(link);
554                 return;
555         }
556
557         if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
558                 _cleanup_address_free_ Address *addr = NULL;
559                 _cleanup_route_free_ Route *rt = NULL;
560
561                 log_info("%s: received config over DHCPv4", link->ifname);
562
563                 r = address_new_dynamic(&addr);
564                 if (r < 0) {
565                         log_error("Could not allocate address");
566                         link_enter_failed(link);
567                         return;
568                 }
569
570                 addr->family = AF_INET;
571                 addr->in_addr.in = address;
572                 addr->prefixlen = prefixlen;
573                 addr->netmask = netmask;
574
575                 r = route_new_dynamic(&rt);
576                 if (r < 0) {
577                         log_error("Could not allocate route");
578                         link_enter_failed(link);
579                         return;
580                 }
581
582                 rt->family = AF_INET;
583                 rt->in_addr.in = gateway;
584
585                 link->dhcp_address = addr;
586                 link->dhcp_route = rt;
587                 addr = NULL;
588                 rt = NULL;
589
590                 link_enter_set_addresses(link);
591         }
592
593         return;
594 }
595
596 static int link_acquire_conf(Link *link) {
597         int r;
598
599         assert(link);
600         assert(link->network);
601         assert(link->network->dhcp);
602         assert(link->manager);
603         assert(link->manager->event);
604
605         if (!link->dhcp) {
606                 link->dhcp = sd_dhcp_client_new(link->manager->event);
607                 if (!link->dhcp)
608                         return -ENOMEM;
609
610                 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
611                 if (r < 0)
612                         return r;
613
614                 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
615                 if (r < 0)
616                         return r;
617
618                 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
619                 if (r < 0)
620                         return r;
621         }
622
623         r = sd_dhcp_client_start(link->dhcp);
624         if (r < 0)
625                 return r;
626
627         return 0;
628 }
629
630 int link_update(Link *link, sd_rtnl_message *m) {
631         unsigned flags;
632         int r;
633
634         assert(link);
635         assert(link->network);
636         assert(m);
637
638         if (link->state == LINK_STATE_FAILED)
639                 return 0;
640
641         r = sd_rtnl_message_link_get_flags(m, &flags);
642         if (r < 0) {
643                 log_warning("%s: could not get link flags", link->ifname);
644                 return r;
645         }
646
647         if (link->flags & IFF_UP && !(flags & IFF_UP))
648                 log_info("%s: interface is down", link->ifname);
649         else if (!(link->flags & IFF_UP) && flags & IFF_UP)
650                 log_info("%s: interface is up", link->ifname);
651
652         if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
653                 log_info("%s: disconnected", link->ifname);
654
655                 if (link->network->dhcp) {
656                         r = sd_dhcp_client_stop(link->dhcp);
657                         if (r < 0) {
658                                 link_enter_failed(link);
659                                 return r;
660                         }
661                 }
662         } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
663                 log_info("%s: connected", link->ifname);
664
665                 if (link->network->dhcp) {
666                         r = link_acquire_conf(link);
667                         if (r < 0) {
668                                 link_enter_failed(link);
669                                 return r;
670                         }
671                 }
672         }
673
674         link->flags = flags;
675
676         log_debug("%s: updated link state", link->ifname);
677
678         return 0;
679 }