]> git.ozlabs.org Git - petitboot/blob - discover/network.c
ui/ncurses: Implement F10-F12 for autoboot device control
[petitboot] / discover / network.c
1
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <sys/socket.h>
8 #include <linux/if.h>
9 #include <linux/netlink.h>
10 #include <linux/rtnetlink.h>
11 #include <i18n/i18n.h>
12
13 #include <log/log.h>
14 #include <list/list.h>
15 #include <file/file.h>
16 #include <types/types.h>
17 #include <talloc/talloc.h>
18 #include <waiter/waiter.h>
19 #include <process/process.h>
20 #include <system/system.h>
21
22 #include "network.h"
23 #include "sysinfo.h"
24 #include "platform.h"
25 #include "device-handler.h"
26 #include "paths.h"
27
28 #define HWADDR_SIZE     6
29 #define PIDFILE_BASE    (LOCAL_STATE_DIR "/petitboot/")
30 #define INITIAL_BUFSIZE 4096
31
32 #define for_each_nlmsg(buf, nlmsg, len) \
33         for (nlmsg = (struct nlmsghdr *)buf; \
34                 NLMSG_OK(nlmsg, len) && nlmsg->nlmsg_type != NLMSG_DONE; \
35                 nlmsg = NLMSG_NEXT(nlmsg, len))
36
37 #define for_each_rta(buf, rta, attrlen) \
38         for (rta = (struct rtattr *)(buf); RTA_OK(rta, attrlen); \
39                         rta = RTA_NEXT(rta, attrlen))
40
41
42 struct interface {
43         int     ifindex;
44         char    name[IFNAMSIZ];
45         uint8_t hwaddr[HWADDR_SIZE];
46
47         enum {
48                 IFSTATE_NEW,
49                 IFSTATE_UP_WAITING_LINK,
50                 IFSTATE_CONFIGURED,
51                 IFSTATE_IGNORED,
52         } state;
53
54         struct list_item list;
55         struct process *udhcpc_process;
56         struct discover_device *dev;
57         bool ready;
58 };
59
60 struct network {
61         struct list             interfaces;
62         struct device_handler   *handler;
63         struct waiter           *waiter;
64         int                     netlink_sd;
65         void                    *netlink_buf;
66         unsigned int            netlink_buf_size;
67         bool                    manual_config;
68         bool                    dry_run;
69 };
70
71 static char *mac_bytes_to_string(void *ctx, uint8_t *addr, int len)
72 {
73         const int l = strlen("xx:");
74         char *buf;
75         int i;
76
77         if (len <= 0)
78                 return talloc_strdup(ctx, "");
79
80         buf = talloc_array(ctx, char, (len * l) + 1);
81
82         for (i = 0; i < len; i++)
83                 sprintf(buf + (l * i), "%02x:", addr[i]);
84
85         *(buf + (l * len) - 1) = '\0';
86
87         return buf;
88 }
89
90 static const struct interface_config *find_config_by_hwaddr(
91                 uint8_t *hwaddr)
92 {
93         const struct config *config;
94         unsigned int i;
95
96         config = config_get();
97         if (!config)
98                 return NULL;
99
100         for (i = 0; i < config->network.n_interfaces; i++) {
101                 struct interface_config *ifconf = config->network.interfaces[i];
102
103                 if (!memcmp(ifconf->hwaddr, hwaddr, HWADDR_SIZE))
104                         return ifconf;
105         }
106
107         return NULL;
108 }
109
110 static struct interface *find_interface_by_ifindex(struct network *network,
111                 int ifindex)
112 {
113         struct interface *interface;
114
115         list_for_each_entry(&network->interfaces, interface, list)
116                 if (interface->ifindex == ifindex)
117                         return interface;
118
119         return NULL;
120 }
121
122 static struct interface *find_interface_by_name(struct network *network,
123                 const char *name)
124 {
125         struct interface *interface;
126
127         list_for_each_entry(&network->interfaces, interface, list)
128                 if (!strcmp(interface->name, name))
129                         return interface;
130
131         return NULL;
132 }
133
134 static struct interface *find_interface_by_uuid(struct network *network,
135                 const char *uuid)
136 {
137         struct interface *interface;
138         char *mac;
139
140         list_for_each_entry(&network->interfaces, interface, list) {
141                 mac = mac_bytes_to_string(interface, interface->hwaddr,
142                                         sizeof(interface->hwaddr));
143                 if (!strcmp(mac, uuid)) {
144                         talloc_free(mac);
145                         return interface;
146                 }
147                 talloc_free(mac);
148         }
149
150         return NULL;
151 }
152
153 uint8_t *find_mac_by_name(void *ctx, struct network *network,
154                 const char *name)
155 {
156         struct interface *interface;
157
158         interface = find_interface_by_name(network, name);
159         if (!interface)
160                 return NULL;
161
162         return talloc_memdup(ctx, &interface->hwaddr,
163                              sizeof(uint8_t) * HWADDR_SIZE);
164 }
165
166 static int network_init_netlink(struct network *network)
167 {
168         struct sockaddr_nl addr;
169         int rc;
170
171         memset(&addr, 0, sizeof(addr));
172         addr.nl_family = AF_NETLINK;
173         addr.nl_groups = RTMGRP_LINK;
174
175         network->netlink_sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
176         if (network->netlink_sd < 0) {
177                 perror("socket(AF_NETLINK)");
178                 return -1;
179         }
180
181         rc = bind(network->netlink_sd, (struct sockaddr *)&addr, sizeof(addr));
182         if (rc) {
183                 perror("bind(sockaddr_nl)");
184                 close(network->netlink_sd);
185                 return -1;
186         }
187
188         network->netlink_buf_size = INITIAL_BUFSIZE;
189         network->netlink_buf = talloc_array(network, char,
190                                 network->netlink_buf_size);
191
192         return 0;
193 }
194
195 static int network_send_link_query(struct network *network)
196 {
197         int rc;
198         struct {
199                 struct nlmsghdr nlmsg;
200                 struct rtgenmsg rtmsg;
201         } msg;
202
203         memset(&msg, 0, sizeof(msg));
204
205         msg.nlmsg.nlmsg_len = sizeof(msg);
206         msg.nlmsg.nlmsg_type = RTM_GETLINK;
207         msg.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
208         msg.nlmsg.nlmsg_seq = 0;
209         msg.nlmsg.nlmsg_pid = 0;
210         msg.rtmsg.rtgen_family = AF_UNSPEC;
211
212         rc = send(network->netlink_sd, &msg, sizeof(msg), MSG_NOSIGNAL);
213         if (rc != sizeof(msg))
214                 return -1;
215
216         return 0;
217 }
218
219 static void create_interface_dev(struct network *network,
220                 struct interface *interface)
221 {
222         char *uuid = mac_bytes_to_string(interface, interface->hwaddr,
223                                                 sizeof(interface->hwaddr));
224
225         interface->dev = discover_device_create(network->handler, uuid,
226                                                 interface->name);
227         interface->dev->device->type = DEVICE_TYPE_NETWORK;
228         device_handler_add_device(network->handler, interface->dev);
229         talloc_free(uuid);
230 }
231
232 static void remove_interface(struct network *network,
233                 struct interface *interface)
234 {
235         if (interface->dev)
236                 device_handler_remove(network->handler, interface->dev);
237         list_remove(&interface->list);
238         talloc_free(interface);
239 }
240
241 void network_register_device(struct network *network,
242                 struct discover_device *dev)
243 {
244         struct interface *iface;
245
246         if (dev->uuid)
247                 iface = find_interface_by_uuid(network, dev->uuid);
248         else
249                 iface = find_interface_by_name(network, dev->label);
250         if (!iface)
251                 return;
252
253         iface->dev = dev;
254         dev->uuid = mac_bytes_to_string(iface->dev, iface->hwaddr,
255                         sizeof(iface->hwaddr));
256 }
257
258 void network_unregister_device(struct network *network,
259                 struct discover_device *dev)
260 {
261         struct interface *iface;
262
263         iface = find_interface_by_uuid(network, dev->uuid);
264         if (!iface)
265                 return;
266
267         iface->dev = NULL;
268 }
269
270 static int interface_change(struct interface *interface, bool up)
271 {
272         const char *statestr = up ? "up" : "down";
273         int rc;
274
275         if (!up && interface->udhcpc_process) {
276                 /* we don't care about the callback from here */
277                 interface->udhcpc_process->exit_cb = NULL;
278                 interface->udhcpc_process->data = NULL;
279                 process_stop_async(interface->udhcpc_process);
280                 process_release(interface->udhcpc_process);
281         }
282
283         if (!up) {
284                 rc = process_run_simple(interface, pb_system_apps.ip,
285                                 "address", "flush", "dev", interface->name,
286                                 NULL);
287                 if (rc)
288                         pb_log("failed to flush addresses from interface %s\n",
289                                 interface->name);
290         }
291
292         rc = process_run_simple(interface, pb_system_apps.ip,
293                         "link", "set", interface->name, statestr, NULL);
294         if (rc) {
295                 pb_log("failed to bring interface %s %s\n", interface->name,
296                                 statestr);
297                 return -1;
298         }
299         return 0;
300 }
301
302 static int interface_up(struct interface *interface)
303 {
304         return interface_change(interface, true);
305 }
306
307 static int interface_down(struct interface *interface)
308 {
309         return interface_change(interface, false);
310 }
311
312 static void udhcpc_process_exit(struct process *process)
313 {
314         struct interface *interface = process->data;
315         pb_debug("udhcp client [pid %d] for interface %s exited, rc %d\n",
316                         process->pid, interface->name, process->exit_status);
317         interface->udhcpc_process = NULL;
318         process_release(process);
319 }
320
321 static void configure_interface_dhcp(struct network *network,
322                 struct interface *interface)
323 {
324         const struct platform *platform;
325         char pidfile[256], id[10];
326         struct process *process;
327         int rc;
328         const char *argv[] = {
329                 pb_system_apps.udhcpc,
330                 "-R",
331                 "-f",
332                 "-O", "pxeconffile",
333                 "-O", "pxepathprefix",
334                 "-O", "reboottime",
335                 "-p", pidfile,
336                 "-i", interface->name,
337                 "-x", id, /* [11,12] - dhcp client identifier */
338                 NULL,
339         };
340
341         device_handler_status_dev_info(network->handler, interface->dev,
342                         _("Configuring with DHCP"));
343
344         snprintf(pidfile, sizeof(pidfile), "%s/udhcpc-%s.pid",
345                         PIDFILE_BASE, interface->name);
346
347         platform = platform_get();
348         if (platform && platform->dhcp_arch_id != 0xffff)
349                 snprintf(id, sizeof(id), "0x5d:%04x", platform->dhcp_arch_id);
350         else
351                 argv[11] = NULL;
352
353         process = process_create(interface);
354
355         process->path = pb_system_apps.udhcpc;
356         process->argv = argv;
357         process->exit_cb = udhcpc_process_exit;
358         process->data = interface;
359
360         rc = process_run_async(process);
361
362         if (rc)
363                 process_release(process);
364         else
365                 interface->udhcpc_process = process;
366
367         return;
368 }
369
370 static void configure_interface_static(struct network *network,
371                 struct interface *interface,
372                 const struct interface_config *config)
373 {
374         int rc;
375
376         device_handler_status_dev_info(network->handler, interface->dev,
377                         _("Configuring with static address (ip: %s)"),
378                         config->static_config.address);
379
380         rc = process_run_simple(interface, pb_system_apps.ip,
381                         "address", "add", config->static_config.address,
382                         "dev", interface->name, NULL);
383
384
385         if (rc) {
386                 pb_log("failed to add address %s to interface %s\n",
387                                 config->static_config.address,
388                                 interface->name);
389                 return;
390         }
391
392         system_info_set_interface_address(sizeof(interface->hwaddr),
393                                 interface->hwaddr,
394                                 config->static_config.address);
395
396         /* we need the interface up before we can route through it */
397         rc = interface_up(interface);
398         if (rc)
399                 return;
400
401         if (config->static_config.gateway)
402                 rc = process_run_simple(interface, pb_system_apps.ip,
403                                 "route", "add", "default",
404                                 "via", config->static_config.gateway,
405                                 NULL);
406
407         if (rc) {
408                 pb_log("failed to add default route %s on interface %s\n",
409                                 config->static_config.gateway,
410                                 interface->name);
411         }
412
413         if (config->static_config.url) {
414                 pb_log("config URL %s\n", config->static_config.url);
415                 device_handler_process_url(network->handler,
416                                 config->static_config.url,
417                                 mac_bytes_to_string(interface->dev,
418                                                 interface->hwaddr,
419                                                 sizeof(interface->hwaddr)),
420                                 config->static_config.address);
421                 device_handler_start_requery_timeout(network->handler,
422                                 interface->dev, -1);
423         }
424
425         return;
426 }
427
428 static void configure_interface(struct network *network,
429                 struct interface *interface, bool up, bool link)
430 {
431         const struct interface_config *config = NULL;
432
433         if (interface->state == IFSTATE_IGNORED)
434                 return;
435
436         /* old interface? check that we're still up and running */
437         if (interface->state == IFSTATE_CONFIGURED) {
438                 if (!up)
439                         interface->state = IFSTATE_NEW;
440                 else if (!link)
441                         interface->state = IFSTATE_UP_WAITING_LINK;
442                 else {
443                         pb_debug("network: skipping configured interface %s\n",
444                                         interface->name);
445                         return;
446                 }
447         }
448
449         /* always up the lookback, no other handling required */
450         if (!strcmp(interface->name, "lo")) {
451                 if (interface->state == IFSTATE_NEW)
452                         interface_up(interface);
453                 interface->state = IFSTATE_CONFIGURED;
454                 return;
455         }
456
457         config = find_config_by_hwaddr(interface->hwaddr);
458         if (config && config->ignore) {
459                 pb_log("network: ignoring interface %s\n", interface->name);
460                 interface->state = IFSTATE_IGNORED;
461                 return;
462         }
463
464         /* if we're in manual config mode, we need an interface configuration */
465         if (network->manual_config && !config) {
466                 interface->state = IFSTATE_IGNORED;
467                 pb_log("network: skipping %s: manual config mode, "
468                                 "but no config for this interface\n",
469                                 interface->name);
470                 return;
471         }
472
473         /* new interface? bring up to the point so we can detect a link */
474         if (interface->state == IFSTATE_NEW) {
475                 if (!up) {
476                         interface_up(interface);
477                         pb_log("network: bringing up interface %s\n",
478                                         interface->name);
479                         return;
480
481                 } else if (!link) {
482                         interface->state = IFSTATE_UP_WAITING_LINK;
483                 }
484         }
485
486         /* no link? wait for a notification */
487         if (interface->state == IFSTATE_UP_WAITING_LINK && !link)
488                 return;
489
490         pb_log("network: configuring interface %s\n", interface->name);
491
492         if (!config || config->method == CONFIG_METHOD_DHCP) {
493                 configure_interface_dhcp(network, interface);
494
495         } else if (config->method == CONFIG_METHOD_STATIC) {
496                 configure_interface_static(network, interface, config);
497                 /* Nothing left to do for static interfaces */
498                 pending_network_jobs_start();
499         }
500
501         interface->state = IFSTATE_CONFIGURED;
502 }
503
504 void network_requery_device(struct network *network,
505                 struct discover_device *dev)
506 {
507         const struct interface_config *config;
508         struct interface *interface;
509
510         interface = find_interface_by_uuid(network, dev->uuid);
511         if (!interface)
512                 return;
513
514         if (interface->udhcpc_process) {
515                 interface->udhcpc_process->exit_cb = NULL;
516                 interface->udhcpc_process->data = NULL;
517                 process_stop_async(interface->udhcpc_process);
518                 process_release(interface->udhcpc_process);
519         }
520
521         config = find_config_by_hwaddr(interface->hwaddr);
522
523         if (config && config->ignore)
524                 return;
525
526         if (!config || config->method == CONFIG_METHOD_DHCP) {
527                 /* Restart DHCP. Once we acquire a lease, we'll re-start
528                  * the requery timeout (based on any reboottime DHCP option)
529                  */
530                 configure_interface_dhcp(network, interface);
531
532         } else if (config->method == CONFIG_METHOD_STATIC &&
533                         config->static_config.url) {
534                 /* Redownload statically-provided URL, and manually restart
535                  * requery timeout */
536                 device_handler_process_url(network->handler,
537                                 config->static_config.url,
538                                 mac_bytes_to_string(interface->dev,
539                                                 interface->hwaddr,
540                                                 sizeof(interface->hwaddr)),
541                                 config->static_config.address);
542                 device_handler_start_requery_timeout(network->handler,
543                                 dev, -1);
544         }
545 }
546
547 static int network_handle_nlmsg(struct network *network, struct nlmsghdr *nlmsg)
548 {
549         bool have_ifaddr, have_ifname;
550         struct interface *interface, *tmp;
551         struct ifinfomsg *info;
552         struct rtattr *attr;
553         unsigned int mtu;
554         uint8_t ifaddr[6];
555         char ifname[IFNAMSIZ];
556         int attrlen, type;
557
558
559         /* we're only interested in NEWLINK messages */
560         type = nlmsg->nlmsg_type;
561         if (!(type == RTM_NEWLINK || type == RTM_DELLINK))
562                 return 0;
563
564         info = NLMSG_DATA(nlmsg);
565
566         have_ifaddr = have_ifname = false;
567         mtu = 1;
568
569         attrlen = nlmsg->nlmsg_len - sizeof(*info);
570
571         /* extract the interface name and hardware address attributes */
572         for_each_rta(info + 1, attr, attrlen) {
573                 void *data = RTA_DATA(attr);
574
575                 switch (attr->rta_type) {
576                 case IFLA_ADDRESS:
577                         memcpy(ifaddr, data, sizeof(ifaddr));
578                         have_ifaddr = true;
579                         break;
580
581                 case IFLA_IFNAME:
582                         strncpy(ifname, data, IFNAMSIZ);
583                         ifname[IFNAMSIZ - 1] = '\0';
584                         have_ifname = true;
585                         break;
586
587                 case IFLA_MTU:
588                         mtu = *(unsigned int *)data;
589                         break;
590                 }
591         }
592
593         if (!have_ifaddr || !have_ifname)
594                 return -1;
595
596         if (type == RTM_DELLINK || mtu == 0) {
597                 interface = find_interface_by_ifindex(network, info->ifi_index);
598                 if (!interface)
599                         return 0;
600                 pb_log("network: interface %s removed\n", interface->name);
601                 remove_interface(network, interface);
602                 return 0;
603         }
604
605         /* ignore the default tun device in some environments */
606         if (strncmp(ifname, "tun", strlen("tun")) == 0)
607                 return 0;
608
609         interface = find_interface_by_ifindex(network, info->ifi_index);
610         if (!interface) {
611                 interface = talloc_zero(network, struct interface);
612                 interface->ifindex = info->ifi_index;
613                 interface->state = IFSTATE_NEW;
614                 memcpy(interface->hwaddr, ifaddr, sizeof(interface->hwaddr));
615                 strncpy(interface->name, ifname, sizeof(interface->name));
616
617                 list_for_each_entry(&network->interfaces, tmp, list)
618                         if (memcmp(interface->hwaddr, tmp->hwaddr,
619                                    sizeof(interface->hwaddr)) == 0) {
620                                 pb_log("%s: %s has duplicate MAC address, ignoring\n",
621                                        __func__, interface->name);
622                                 talloc_free(interface);
623                                 return -1;
624                         }
625
626                 list_add(&network->interfaces, &interface->list);
627                 create_interface_dev(network, interface);
628         }
629
630         /* A repeated RTM_NEWLINK can represent an interface name change */
631         if (strncmp(interface->name, ifname, IFNAMSIZ)) {
632                 pb_debug("ifname update: %s -> %s\n", interface->name, ifname);
633                 strncpy(interface->name, ifname, sizeof(interface->name));
634                 talloc_free(interface->dev->device->id);
635                 interface->dev->device->id =
636                         talloc_strdup(interface->dev->device, ifname);
637         }
638
639         /* notify the sysinfo code about changes to this interface */
640         if (strcmp(interface->name, "lo"))
641                 system_info_register_interface(
642                                 sizeof(interface->hwaddr),
643                                 interface->hwaddr, interface->name,
644                                 info->ifi_flags & IFF_LOWER_UP);
645
646         if (!interface->dev)
647                 create_interface_dev(network, interface);
648
649         if (!interface->ready && strncmp(interface->name, "lo", strlen("lo"))) {
650                 pb_log("%s not marked ready yet\n", interface->name);
651                 return 0;
652         }
653
654         configure_interface(network, interface,
655                         info->ifi_flags & IFF_UP,
656                         info->ifi_flags & IFF_LOWER_UP);
657
658         return 0;
659 }
660
661 void network_mark_interface_ready(struct device_handler *handler,
662                 int ifindex, const char *ifname, uint8_t *mac, int hwsize)
663 {
664         struct network *network = device_handler_get_network(handler);
665         struct interface *interface, *tmp = NULL;
666         char *macstr;
667
668         if (!network) {
669                 pb_log("Network not ready - can not mark interface ready\n");
670                 return;
671         }
672
673         if (hwsize != HWADDR_SIZE)
674                 return;
675
676         if (strncmp(ifname, "lo", strlen("lo")) == 0)
677                 return;
678
679         interface = find_interface_by_ifindex(network, ifindex);
680         if (!interface) {
681                 pb_debug("Creating ready interface %d - %s\n",
682                                 ifindex, ifname);
683                 interface = talloc_zero(network, struct interface);
684                 interface->ifindex = ifindex;
685                 interface->state = IFSTATE_NEW;
686                 memcpy(interface->hwaddr, mac, HWADDR_SIZE);
687                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
688
689                 list_for_each_entry(&network->interfaces, tmp, list)
690                         if (memcmp(interface->hwaddr, tmp->hwaddr,
691                                    sizeof(interface->hwaddr)) == 0) {
692                                 pb_log("%s: %s has duplicate MAC address, ignoring\n",
693                                        __func__, interface->name);
694                                 talloc_free(interface);
695                                 return;
696                         }
697
698                 list_add(&network->interfaces, &interface->list);
699                 create_interface_dev(network, interface);
700         }
701
702         if (interface->ready) {
703                 pb_log("%s already ready\n", interface->name);
704                 return;
705         }
706
707         if (strncmp(interface->name, ifname, strlen(ifname)) != 0) {
708                 pb_debug("ifname update from udev: %s -> %s\n", interface->name, ifname);
709                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
710                 talloc_free(interface->dev->device->id);
711                 interface->dev->device->id =
712                         talloc_strdup(interface->dev->device, ifname);
713         }
714
715         if (memcmp(interface->hwaddr, mac, HWADDR_SIZE) != 0) {
716                 macstr = mac_bytes_to_string(interface, mac, hwsize);
717                 pb_log("Warning - new MAC for interface %d does not match: %s\n",
718                                 ifindex, macstr);
719                 talloc_free(macstr);
720         }
721
722         pb_log("Interface %s ready\n", ifname);
723         interface->ready = true;
724         configure_interface(network, interface, false, false);
725 }
726
727 static int network_netlink_process(void *arg)
728 {
729         struct network *network = arg;
730         struct nlmsghdr *nlmsg;
731         struct msghdr msg;
732         struct iovec iov;
733         unsigned int len;
734         int rc, flags;
735
736         memset(&msg, 0, sizeof(msg));
737         msg.msg_iov = &iov;
738         msg.msg_iovlen = 1;
739
740         flags = MSG_PEEK;
741
742 retry:
743         iov.iov_len = network->netlink_buf_size;
744         iov.iov_base = network->netlink_buf;
745
746         rc = recvmsg(network->netlink_sd, &msg, flags);
747
748         if (rc < 0) {
749                 perror("netlink recv header");
750                 return -1;
751         }
752
753         len = rc;
754
755         /* if the netlink message was larger than our buffer, realloc
756          * before reading again */
757         if (len > network->netlink_buf_size || msg.msg_flags & MSG_TRUNC) {
758                 network->netlink_buf_size *= 2;
759                 network->netlink_buf = talloc_realloc(network,
760                                         network->netlink_buf,
761                                         char *,
762                                         network->netlink_buf_size);
763                 goto retry;
764         }
765
766         /* otherwise, we're good to read the entire message without PEEK */
767         if (flags == MSG_PEEK) {
768                 flags = 0;
769                 goto retry;
770         }
771
772         for_each_nlmsg(network->netlink_buf, nlmsg, len)
773                 network_handle_nlmsg(network, nlmsg);
774
775         return 0;
776 }
777
778 static void network_init_dns(struct network *network)
779 {
780         const struct config *config;
781         unsigned int i;
782         int rc, len;
783         bool modified;
784         char *buf;
785
786         if (network->dry_run)
787                 return;
788
789         config = config_get();
790         if (!config || !config->network.n_dns_servers)
791                 return;
792
793         rc = read_file(network, "/etc/resolv.conf", &buf, &len);
794
795         if (rc) {
796                 buf = talloc_strdup(network, "");
797                 len = 0;
798         }
799
800         modified = false;
801
802         for (i = 0; i < config->network.n_dns_servers; i++) {
803                 int dns_conf_len;
804                 char *dns_conf;
805
806                 dns_conf = talloc_asprintf(network, "nameserver %s\n",
807                                 config->network.dns_servers[i]);
808
809                 if (strstr(buf, dns_conf)) {
810                         talloc_free(dns_conf);
811                         continue;
812                 }
813
814                 dns_conf_len = strlen(dns_conf);
815                 buf = talloc_realloc(network, buf, char, len + dns_conf_len + 1);
816                 memcpy(buf + len, dns_conf, dns_conf_len);
817                 len += dns_conf_len;
818                 buf[len] = '\0';
819                 modified = true;
820
821                 talloc_free(dns_conf);
822         }
823
824         if (modified) {
825                 rc = replace_file("/etc/resolv.conf", buf, len);
826                 if (rc)
827                         pb_log("error replacing resolv.conf: %s\n",
828                                         strerror(errno));
829         }
830
831         talloc_free(buf);
832 }
833
834 struct network *network_init(struct device_handler *handler,
835                 struct waitset *waitset, bool dry_run)
836 {
837         struct network *network;
838         int rc;
839
840         network = talloc(handler, struct network);
841         list_init(&network->interfaces);
842         network->handler = handler;
843         network->dry_run = dry_run;
844         network->manual_config = config_get()->network.n_interfaces != 0;
845
846         network_init_dns(network);
847
848         rc = network_init_netlink(network);
849         if (rc)
850                 goto err;
851
852         network->waiter = waiter_register_io(waitset, network->netlink_sd,
853                         WAIT_IN, network_netlink_process, network);
854
855         if (!network->waiter)
856                 goto err;
857
858         rc = network_send_link_query(network);
859         if (rc)
860                 goto err;
861
862         return network;
863
864 err:
865         network_shutdown(network);
866         return NULL;
867 }
868
869 int network_shutdown(struct network *network)
870 {
871         struct interface *interface;
872
873         if (network->waiter)
874                 waiter_remove(network->waiter);
875
876         list_for_each_entry(&network->interfaces, interface, list) {
877                 if (interface->state == IFSTATE_IGNORED)
878                         continue;
879                 if (!strcmp(interface->name, "lo"))
880                         continue;
881                 interface_down(interface);
882         }
883
884         close(network->netlink_sd);
885         talloc_free(network);
886         return 0;
887 }