]> git.ozlabs.org Git - petitboot/blob - discover/network.c
discover/paths: Set suffix to default value on error.
[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+1];
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                         have_ifname = true;
584                         break;
585
586                 case IFLA_MTU:
587                         mtu = *(unsigned int *)data;
588                         break;
589                 }
590         }
591
592         if (!have_ifaddr || !have_ifname)
593                 return -1;
594
595         if (type == RTM_DELLINK || mtu == 0) {
596                 interface = find_interface_by_ifindex(network, info->ifi_index);
597                 if (!interface)
598                         return 0;
599                 pb_log("network: interface %s removed\n", interface->name);
600                 remove_interface(network, interface);
601                 return 0;
602         }
603
604         /* ignore the default tun device in some environments */
605         if (strncmp(ifname, "tun", strlen("tun")) == 0)
606                 return 0;
607
608         interface = find_interface_by_ifindex(network, info->ifi_index);
609         if (!interface) {
610                 interface = talloc_zero(network, struct interface);
611                 interface->ifindex = info->ifi_index;
612                 interface->state = IFSTATE_NEW;
613                 memcpy(interface->hwaddr, ifaddr, sizeof(interface->hwaddr));
614                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
615
616                 list_for_each_entry(&network->interfaces, tmp, list)
617                         if (memcmp(interface->hwaddr, tmp->hwaddr,
618                                    sizeof(interface->hwaddr)) == 0) {
619                                 pb_log("%s: %s has duplicate MAC address, ignoring\n",
620                                        __func__, interface->name);
621                                 talloc_free(interface);
622                                 return -1;
623                         }
624
625                 list_add(&network->interfaces, &interface->list);
626                 create_interface_dev(network, interface);
627         }
628
629         /* A repeated RTM_NEWLINK can represent an interface name change */
630         if (strncmp(interface->name, ifname, IFNAMSIZ)) {
631                 pb_debug("ifname update: %s -> %s\n", interface->name, ifname);
632                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
633                 talloc_free(interface->dev->device->id);
634                 interface->dev->device->id =
635                         talloc_strdup(interface->dev->device, ifname);
636         }
637
638         /* notify the sysinfo code about changes to this interface */
639         if (strcmp(interface->name, "lo"))
640                 system_info_register_interface(
641                                 sizeof(interface->hwaddr),
642                                 interface->hwaddr, interface->name,
643                                 info->ifi_flags & IFF_LOWER_UP);
644
645         if (!interface->dev)
646                 create_interface_dev(network, interface);
647
648         if (!interface->ready && strncmp(interface->name, "lo", strlen("lo"))) {
649                 pb_log("%s not marked ready yet\n", interface->name);
650                 return 0;
651         }
652
653         configure_interface(network, interface,
654                         info->ifi_flags & IFF_UP,
655                         info->ifi_flags & IFF_LOWER_UP);
656
657         return 0;
658 }
659
660 void network_mark_interface_ready(struct device_handler *handler,
661                 int ifindex, const char *ifname, uint8_t *mac, int hwsize)
662 {
663         struct network *network = device_handler_get_network(handler);
664         struct interface *interface, *tmp = NULL;
665         char *macstr;
666
667         if (!network) {
668                 pb_log("Network not ready - can not mark interface ready\n");
669                 return;
670         }
671
672         if (hwsize != HWADDR_SIZE)
673                 return;
674
675         if (strncmp(ifname, "lo", strlen("lo")) == 0)
676                 return;
677
678         interface = find_interface_by_ifindex(network, ifindex);
679         if (!interface) {
680                 pb_debug("Creating ready interface %d - %s\n",
681                                 ifindex, ifname);
682                 interface = talloc_zero(network, struct interface);
683                 interface->ifindex = ifindex;
684                 interface->state = IFSTATE_NEW;
685                 memcpy(interface->hwaddr, mac, HWADDR_SIZE);
686                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
687
688                 list_for_each_entry(&network->interfaces, tmp, list)
689                         if (memcmp(interface->hwaddr, tmp->hwaddr,
690                                    sizeof(interface->hwaddr)) == 0) {
691                                 pb_log("%s: %s has duplicate MAC address, ignoring\n",
692                                        __func__, interface->name);
693                                 talloc_free(interface);
694                                 return;
695                         }
696
697                 list_add(&network->interfaces, &interface->list);
698                 create_interface_dev(network, interface);
699         }
700
701         if (interface->ready) {
702                 pb_log("%s already ready\n", interface->name);
703                 return;
704         }
705
706         if (strncmp(interface->name, ifname, strlen(ifname)) != 0) {
707                 pb_debug("ifname update from udev: %s -> %s\n", interface->name, ifname);
708                 strncpy(interface->name, ifname, sizeof(interface->name) - 1);
709                 talloc_free(interface->dev->device->id);
710                 interface->dev->device->id =
711                         talloc_strdup(interface->dev->device, ifname);
712         }
713
714         if (memcmp(interface->hwaddr, mac, HWADDR_SIZE) != 0) {
715                 macstr = mac_bytes_to_string(interface, mac, hwsize);
716                 pb_log("Warning - new MAC for interface %d does not match: %s\n",
717                                 ifindex, macstr);
718                 talloc_free(macstr);
719         }
720
721         pb_log("Interface %s ready\n", ifname);
722         interface->ready = true;
723         configure_interface(network, interface, false, false);
724 }
725
726 static int network_netlink_process(void *arg)
727 {
728         struct network *network = arg;
729         struct nlmsghdr *nlmsg;
730         struct msghdr msg;
731         struct iovec iov;
732         unsigned int len;
733         int rc, flags;
734
735         memset(&msg, 0, sizeof(msg));
736         msg.msg_iov = &iov;
737         msg.msg_iovlen = 1;
738
739         flags = MSG_PEEK;
740
741 retry:
742         iov.iov_len = network->netlink_buf_size;
743         iov.iov_base = network->netlink_buf;
744
745         rc = recvmsg(network->netlink_sd, &msg, flags);
746
747         if (rc < 0) {
748                 perror("netlink recv header");
749                 return -1;
750         }
751
752         len = rc;
753
754         /* if the netlink message was larger than our buffer, realloc
755          * before reading again */
756         if (len > network->netlink_buf_size || msg.msg_flags & MSG_TRUNC) {
757                 network->netlink_buf_size *= 2;
758                 network->netlink_buf = talloc_realloc(network,
759                                         network->netlink_buf,
760                                         char *,
761                                         network->netlink_buf_size);
762                 goto retry;
763         }
764
765         /* otherwise, we're good to read the entire message without PEEK */
766         if (flags == MSG_PEEK) {
767                 flags = 0;
768                 goto retry;
769         }
770
771         for_each_nlmsg(network->netlink_buf, nlmsg, len)
772                 network_handle_nlmsg(network, nlmsg);
773
774         return 0;
775 }
776
777 static void network_init_dns(struct network *network)
778 {
779         const struct config *config;
780         unsigned int i;
781         int rc, len;
782         bool modified;
783         char *buf;
784
785         if (network->dry_run)
786                 return;
787
788         config = config_get();
789         if (!config || !config->network.n_dns_servers)
790                 return;
791
792         rc = read_file(network, "/etc/resolv.conf", &buf, &len);
793
794         if (rc) {
795                 buf = talloc_strdup(network, "");
796                 len = 0;
797         }
798
799         modified = false;
800
801         for (i = 0; i < config->network.n_dns_servers; i++) {
802                 int dns_conf_len;
803                 char *dns_conf;
804
805                 dns_conf = talloc_asprintf(network, "nameserver %s\n",
806                                 config->network.dns_servers[i]);
807
808                 if (strstr(buf, dns_conf)) {
809                         talloc_free(dns_conf);
810                         continue;
811                 }
812
813                 dns_conf_len = strlen(dns_conf);
814                 buf = talloc_realloc(network, buf, char, len + dns_conf_len + 1);
815                 memcpy(buf + len, dns_conf, dns_conf_len);
816                 len += dns_conf_len;
817                 buf[len] = '\0';
818                 modified = true;
819
820                 talloc_free(dns_conf);
821         }
822
823         if (modified) {
824                 rc = replace_file("/etc/resolv.conf", buf, len);
825                 if (rc)
826                         pb_log("error replacing resolv.conf: %s\n",
827                                         strerror(errno));
828         }
829
830         talloc_free(buf);
831 }
832
833 struct network *network_init(struct device_handler *handler,
834                 struct waitset *waitset, bool dry_run)
835 {
836         struct network *network;
837         int rc;
838
839         network = talloc(handler, struct network);
840         list_init(&network->interfaces);
841         network->handler = handler;
842         network->dry_run = dry_run;
843         network->manual_config = config_get()->network.n_interfaces != 0;
844
845         network_init_dns(network);
846
847         rc = network_init_netlink(network);
848         if (rc)
849                 goto err;
850
851         network->waiter = waiter_register_io(waitset, network->netlink_sd,
852                         WAIT_IN, network_netlink_process, network);
853
854         if (!network->waiter)
855                 goto err;
856
857         rc = network_send_link_query(network);
858         if (rc)
859                 goto err;
860
861         return network;
862
863 err:
864         network_shutdown(network);
865         return NULL;
866 }
867
868 int network_shutdown(struct network *network)
869 {
870         struct interface *interface;
871
872         if (network->waiter)
873                 waiter_remove(network->waiter);
874
875         list_for_each_entry(&network->interfaces, interface, list) {
876                 if (interface->state == IFSTATE_IGNORED)
877                         continue;
878                 if (!strcmp(interface->name, "lo"))
879                         continue;
880                 interface_down(interface);
881         }
882
883         close(network->netlink_sd);
884         talloc_free(network);
885         return 0;
886 }