Respect interface "ignore" settings as documented.
[project/odhcpd.git] / src / router.c
1 /**
2  * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License v2 as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #include <resolv.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <stdbool.h>
23 #include <net/route.h>
24
25 #include "router.h"
26 #include "odhcpd.h"
27
28
29 static void forward_router_solicitation(const struct interface *iface);
30 static void forward_router_advertisement(uint8_t *data, size_t len);
31
32 static void handle_icmpv6(void *addr, void *data, size_t len,
33                 struct interface *iface, void *dest);
34 static void trigger_router_advert(struct uloop_timeout *event);
35 static void sigusr1_refresh(int signal);
36
37 static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6, NULL};
38
39 static FILE *fp_route = NULL;
40 #define RA_IOV_LEN 6
41
42 #define TIME_LEFT(t1, now) ((t1) != UINT32_MAX ? (t1) - (now) : UINT32_MAX)
43
44 int init_router(void)
45 {
46         // Open ICMPv6 socket
47         int sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
48         if (sock < 0 && errno != EAFNOSUPPORT) {
49                 syslog(LOG_ERR, "Failed to open RAW-socket: %s", strerror(errno));
50                 return -1;
51         }
52
53         // Let the kernel compute our checksums
54         int val = 2;
55         setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
56
57         // This is required by RFC 4861
58         val = 255;
59         setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
60         setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
61
62         // We need to know the source interface
63         val = 1;
64         setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
65         setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
66
67         // Don't loop back
68         val = 0;
69         setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(val));
70
71         // Filter ICMPv6 package types
72         struct icmp6_filter filt;
73         ICMP6_FILTER_SETBLOCKALL(&filt);
74         ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
75         ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
76         setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt));
77
78         // Register socket
79         router_event.uloop.fd = sock;
80         odhcpd_register(&router_event);
81
82         if (!(fp_route = fopen("/proc/net/ipv6_route", "r")))
83                 syslog(LOG_ERR, "Failed to open routing table: %s",
84                                 strerror(errno));
85
86         signal(SIGUSR1, sigusr1_refresh);
87         return 0;
88 }
89
90
91 int setup_router_interface(struct interface *iface, bool enable)
92 {
93         if (!fp_route || router_event.uloop.fd < 0)
94                 return -1;
95
96         struct ipv6_mreq all_nodes = {ALL_IPV6_NODES, iface->ifindex};
97         struct ipv6_mreq all_routers = {ALL_IPV6_ROUTERS, iface->ifindex};
98
99         uloop_timeout_cancel(&iface->timer_rs);
100         iface->timer_rs.cb = NULL;
101
102         if (iface->ifindex <= 0)
103                 return -1;
104
105         setsockopt(router_event.uloop.fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
106                         &all_nodes, sizeof(all_nodes));
107         setsockopt(router_event.uloop.fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
108                         &all_routers, sizeof(all_routers));
109
110         if (!enable) {
111                 if (iface->ra)
112                         trigger_router_advert(&iface->timer_rs);
113         } else {
114                 void *mreq = &all_routers;
115
116                 if (iface->ra == RELAYD_RELAY && iface->master) {
117                         mreq = &all_nodes;
118                         forward_router_solicitation(iface);
119                 } else if (iface->ra == RELAYD_SERVER && !iface->master) {
120                         iface->timer_rs.cb = trigger_router_advert;
121                         uloop_timeout_set(&iface->timer_rs, 1000);
122                 }
123
124                 if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master))
125                         setsockopt(router_event.uloop.fd, IPPROTO_IPV6,
126                                         IPV6_ADD_MEMBERSHIP, mreq, sizeof(all_nodes));
127         }
128         return 0;
129 }
130
131
132 // Signal handler to resend all RDs
133 static void sigusr1_refresh(_unused int signal)
134 {
135         struct interface *iface;
136         list_for_each_entry(iface, &interfaces, head)
137                 if (iface->ra == RELAYD_SERVER && !iface->master)
138                         uloop_timeout_set(&iface->timer_rs, 1000);
139 }
140
141 static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len)
142 {
143         struct icmp6_hdr *hdr = (struct icmp6_hdr *)data;
144         struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len];
145
146         /* Hoplimit is already checked in odhcpd_receive_packets */
147         if (len < sizeof(*hdr) || hdr->icmp6_code)
148                 return false;
149
150         switch (hdr->icmp6_type) {
151         case ND_ROUTER_ADVERT:
152                 if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr))
153                         return false;
154
155                 opt = (struct icmpv6_opt *)((struct nd_router_advert *)data + 1);
156                 break;
157
158         case ND_ROUTER_SOLICIT:
159                 opt = (struct icmpv6_opt *)((struct nd_router_solicit *)data + 1);
160                 break;
161
162         default:
163                 return false;
164         }
165
166         icmpv6_for_each_option(opt, opt, end)
167                 if (opt->type == ND_OPT_SOURCE_LINKADDR &&
168                                 IN6_IS_ADDR_UNSPECIFIED(&source->sin6_addr) &&
169                                 hdr->icmp6_type == ND_ROUTER_SOLICIT)
170                         return false;
171
172         // Check all options parsed successfully
173         return opt == end;
174 }
175
176
177 // Detect whether a default route exists, also find the source prefixes
178 static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
179 {
180         rewind(fp_route);
181
182         char line[512], ifname[16];
183         bool found_default = false;
184         struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, 0, 0, 0};
185         while (fgets(line, sizeof(line), fp_route)) {
186                 uint32_t rflags;
187                 if (sscanf(line, "00000000000000000000000000000000 00 "
188                                 "%*s %*s %*s %*s %*s %*s %*s %15s", ifname) &&
189                                 strcmp(ifname, "lo")) {
190                         found_default = true;
191                 } else if (sscanf(line, "%8" SCNx32 "%8" SCNx32 "%*8" SCNx32 "%*8" SCNx32 " %hhx %*s "
192                                 "%*s 00000000000000000000000000000000 %*s %*s %*s %" SCNx32 " lo",
193                                 &p.addr.s6_addr32[0], &p.addr.s6_addr32[1], &p.prefix, &rflags) &&
194                                 p.prefix > 0 && (rflags & RTF_NONEXTHOP) && (rflags & RTF_REJECT)) {
195                         // Find source prefixes by scanning through unreachable-routes
196                         p.addr.s6_addr32[0] = htonl(p.addr.s6_addr32[0]);
197                         p.addr.s6_addr32[1] = htonl(p.addr.s6_addr32[1]);
198
199                         for (ssize_t i = 0; i < len; ++i) {
200                                 if (n[i].prefix <= 64 && n[i].prefix >= p.prefix &&
201                                                 !odhcpd_bmemcmp(&p.addr, &n[i].addr, p.prefix)) {
202                                         n[i].dprefix = p.prefix;
203                                         break;
204                                 }
205                         }
206
207                 }
208         }
209
210         return found_default;
211 }
212
213 // Router Advert server mode
214 static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from)
215 {
216         time_t now = odhcpd_time();
217         int mtu = odhcpd_get_interface_config(iface->ifname, "mtu");
218         int hlim = odhcpd_get_interface_config(iface->ifname, "hop_limit");
219
220         if (mtu < 1280)
221                 mtu = 1280;
222
223         struct {
224                 struct nd_router_advert h;
225                 struct icmpv6_opt lladdr;
226                 struct nd_opt_mtu mtu;
227                 struct nd_opt_prefix_info prefix[sizeof(iface->ia_addr) / sizeof(*iface->ia_addr)];
228         } adv = {
229                 .h = {{.icmp6_type = ND_ROUTER_ADVERT, .icmp6_code = 0}, 0, 0},
230                 .lladdr = {ND_OPT_SOURCE_LINKADDR, 1, {0}},
231                 .mtu = {ND_OPT_MTU, 1, 0, htonl(mtu)},
232         };
233
234         if (hlim > 0)
235                 adv.h.nd_ra_curhoplimit = hlim;
236
237         if (iface->dhcpv6)
238                 adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER;
239
240         if (iface->managed >= RELAYD_MANAGED_MFLAG)
241                 adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
242
243         if (iface->route_preference < 0)
244                 adv.h.nd_ra_flags_reserved |= ND_RA_PREF_LOW;
245         else if (iface->route_preference > 0)
246                 adv.h.nd_ra_flags_reserved |= ND_RA_PREF_HIGH;
247         odhcpd_get_mac(iface, adv.lladdr.data);
248
249         // If not currently shutting down
250         struct odhcpd_ipaddr addrs[8];
251         ssize_t ipcnt = 0;
252         int64_t minvalid = INT64_MAX;
253
254         // If not shutdown
255         if (iface->timer_rs.cb) {
256                 ipcnt = iface->ia_addr_len;
257                 memcpy(addrs, iface->ia_addr, ipcnt * sizeof(*addrs));
258
259                 // Check default route
260                 if (parse_routes(addrs, ipcnt))
261                         adv.h.nd_ra_router_lifetime = htons(1);
262                 if (iface->default_router > 1)
263                         adv.h.nd_ra_router_lifetime = htons(iface->default_router);
264         }
265
266         // Construct Prefix Information options
267         size_t cnt = 0;
268
269         struct in6_addr dns_pref, *dns_addr = &dns_pref;
270         size_t dns_cnt = 1;
271
272         odhcpd_get_linklocal_interface_address(iface->ifindex, &dns_pref);
273
274         for (ssize_t i = 0; i < ipcnt; ++i) {
275                 struct odhcpd_ipaddr *addr = &addrs[i];
276                 if (addr->prefix > 96 || addr->valid <= (uint32_t)now)
277                         continue; // Address not suitable
278
279                 struct nd_opt_prefix_info *p = NULL;
280                 for (size_t i = 0; i < cnt; ++i) {
281                         if (addr->prefix == adv.prefix[i].nd_opt_pi_prefix_len &&
282                                         !odhcpd_bmemcmp(&adv.prefix[i].nd_opt_pi_prefix,
283                                         &addr->addr, addr->prefix))
284                                 p = &adv.prefix[i];
285                 }
286
287                 if (!p) {
288                         if (cnt >= ARRAY_SIZE(adv.prefix))
289                                 break;
290
291                         p = &adv.prefix[cnt++];
292                 }
293
294                 if (addr->preferred > (uint32_t)now &&
295                                 minvalid > 1000LL * TIME_LEFT(addr->valid, now))
296                         minvalid = 1000LL * TIME_LEFT(addr->valid, now);
297
298                 uint32_t this_lifetime = TIME_LEFT(addr->valid, now);
299                 if (this_lifetime > UINT16_MAX)
300                         this_lifetime = UINT16_MAX;
301                 if (((addr->addr.s6_addr[0] & 0xfe) != 0xfc || iface->default_router)
302                                 && adv.h.nd_ra_router_lifetime
303                                 && ntohs(adv.h.nd_ra_router_lifetime) < this_lifetime)
304                         adv.h.nd_ra_router_lifetime = htons(this_lifetime);
305
306                 odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr,
307                                 (iface->ra_advrouter) ? 128 : addr->prefix);
308                 p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
309                 p->nd_opt_pi_len = 4;
310                 p->nd_opt_pi_prefix_len = (addr->prefix < 64) ? 64 : addr->prefix;
311                 p->nd_opt_pi_flags_reserved = 0;
312                 if (!iface->ra_not_onlink)
313                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
314                 if (iface->managed < RELAYD_MANAGED_NO_AFLAG && addr->prefix <= 64)
315                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
316                 if (iface->ra_advrouter)
317                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
318                 p->nd_opt_pi_valid_time = htonl(TIME_LEFT(addr->valid, now));
319                 if (addr->preferred > (uint32_t)now)
320                         p->nd_opt_pi_preferred_time = htonl(TIME_LEFT(addr->preferred, now));
321                 else if (addr->valid - now < 7200)
322                         p->nd_opt_pi_valid_time = 0;
323         }
324
325         if (!iface->default_router && adv.h.nd_ra_router_lifetime == htons(1)) {
326                 syslog(LOG_WARNING, "A default route is present but there is no public prefix "
327                                 "on %s thus we don't announce a default route!", iface->ifname);
328                 adv.h.nd_ra_router_lifetime = 0;
329         }
330
331         // DNS Recursive DNS
332         if (iface->dns_cnt > 0) {
333                 dns_addr = iface->dns;
334                 dns_cnt = iface->dns_cnt;
335         }
336
337         if (!dns_addr || IN6_IS_ADDR_UNSPECIFIED(dns_addr))
338                 dns_cnt = 0;
339
340         struct {
341                 uint8_t type;
342                 uint8_t len;
343                 uint8_t pad;
344                 uint8_t pad2;
345                 uint32_t lifetime;
346         } dns = {ND_OPT_RECURSIVE_DNS, (1 + (2 * dns_cnt)), 0, 0, 0};
347
348
349
350         // DNS Search options
351         uint8_t search_buf[256], *search_domain = iface->search;
352         size_t search_len = iface->search_len, search_padded = 0;
353
354         if (!search_domain && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
355                 int len = dn_comp(_res.dnsrch[0], search_buf,
356                                 sizeof(search_buf), NULL, NULL);
357                 if (len > 0) {
358                         search_domain = search_buf;
359                         search_len = len;
360                 }
361         }
362
363         if (search_len > 0)
364                 search_padded = ((search_len + 7) & (~7)) + 8;
365
366         struct {
367                 uint8_t type;
368                 uint8_t len;
369                 uint8_t pad;
370                 uint8_t pad2;
371                 uint32_t lifetime;
372                 uint8_t name[];
373         } *search = alloca(sizeof(*search) + search_padded);
374
375         search->type = ND_OPT_DNS_SEARCH;
376         search->len = search_len ? ((sizeof(*search) + search_padded) / 8) : 0;
377         search->pad = 0;
378         search->pad2 = 0;
379         memcpy(search->name, search_domain, search_len);
380         memset(&search->name[search_len], 0, search_padded - search_len);
381
382
383         size_t routes_cnt = 0;
384         struct {
385                 uint8_t type;
386                 uint8_t len;
387                 uint8_t prefix;
388                 uint8_t flags;
389                 uint32_t lifetime;
390                 uint32_t addr[4];
391         } routes[RELAYD_MAX_PREFIXES];
392
393         for (ssize_t i = 0; i < ipcnt; ++i) {
394                 struct odhcpd_ipaddr *addr = &addrs[i];
395                 if (addr->dprefix > 64 || addr->dprefix == 0 || addr->valid <= (uint32_t)now ||
396                                 (addr->dprefix == 64 && addr->prefix == 64)) {
397                         continue; // Address not suitable
398                 } else if (addr->dprefix > 32) {
399                         addr->addr.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1));
400                 } else if (addr->dprefix <= 32) {
401                         addr->addr.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1));
402                         addr->addr.s6_addr32[1] = 0;
403                 }
404
405                 routes[routes_cnt].type = ND_OPT_ROUTE_INFO;
406                 routes[routes_cnt].len = sizeof(*routes) / 8;
407                 routes[routes_cnt].prefix = addr->dprefix;
408                 routes[routes_cnt].flags = 0;
409                 if (iface->route_preference < 0)
410                         routes[routes_cnt].flags |= ND_RA_PREF_LOW;
411                 else if (iface->route_preference > 0)
412                         routes[routes_cnt].flags |= ND_RA_PREF_HIGH;
413                 routes[routes_cnt].lifetime = htonl(TIME_LEFT(addr->valid, now));
414                 routes[routes_cnt].addr[0] = addr->addr.s6_addr32[0];
415                 routes[routes_cnt].addr[1] = addr->addr.s6_addr32[1];
416                 routes[routes_cnt].addr[2] = 0;
417                 routes[routes_cnt].addr[3] = 0;
418
419                 ++routes_cnt;
420         }
421
422         // Calculate periodic transmit
423         int msecs = 0;
424         uint32_t maxival = iface->ra_maxinterval * 1000;
425         uint32_t minival;
426
427         if (maxival < 4000 || maxival > MaxRtrAdvInterval * 1000)
428                 maxival = MaxRtrAdvInterval * 1000;
429
430         if (maxival > minvalid / 3) {
431                 maxival = minvalid / 3;
432
433                 if (maxival < 4000)
434                         maxival = 4000;
435         }
436
437         minival = (maxival * 3) / 4;
438
439         search->lifetime = htonl(maxival / 100);
440         dns.lifetime = search->lifetime;
441
442         odhcpd_urandom(&msecs, sizeof(msecs));
443         msecs = (labs(msecs) % (maxival - minival)) + minival;
444
445         struct icmpv6_opt adv_interval = {
446                 .type = ND_OPT_RTR_ADV_INTERVAL,
447                 .len = 1,
448                 .data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival}
449         };
450
451         struct iovec iov[RA_IOV_LEN] = {
452                         {&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
453                         {&routes, routes_cnt * sizeof(*routes)},
454                         {&dns, (dns_cnt) ? sizeof(dns) : 0},
455                         {dns_addr, dns_cnt * sizeof(*dns_addr)},
456                         {search, search->len * 8},
457                         {&adv_interval, adv_interval.len * 8}};
458         struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0};
459
460         if (from && !IN6_IS_ADDR_UNSPECIFIED(from))
461                 dest.sin6_addr = *from;
462
463         odhcpd_send(router_event.uloop.fd,
464                         &dest, iov, ARRAY_SIZE(iov), iface);
465
466         return msecs;
467 }
468
469
470 static void trigger_router_advert(struct uloop_timeout *event)
471 {
472         struct interface *iface = container_of(event, struct interface, timer_rs);
473         int msecs = send_router_advert(iface, NULL);
474
475         // Rearm timer if not shut down
476         if (event->cb)
477                 uloop_timeout_set(event, msecs);
478 }
479
480
481 // Event handler for incoming ICMPv6 packets
482 static void handle_icmpv6(void *addr, void *data, size_t len,
483                 struct interface *iface, _unused void *dest)
484 {
485         struct icmp6_hdr *hdr = data;
486         struct sockaddr_in6 *from = addr;
487
488         if (!router_icmpv6_valid(addr, data, len))
489                 return;
490
491         if ((iface->ra == RELAYD_SERVER && !iface->master)) { // Server mode
492                 if (hdr->icmp6_type == ND_ROUTER_SOLICIT)
493                         send_router_advert(iface, &from->sin6_addr);
494         } else if (iface->ra == RELAYD_RELAY) { // Relay mode
495                 if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master)
496                         forward_router_advertisement(data, len);
497                 else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master)
498                         forward_router_solicitation(odhcpd_get_master_interface());
499         }
500 }
501
502
503 // Forward router solicitation
504 static void forward_router_solicitation(const struct interface *iface)
505 {
506         if (!iface)
507                 return;
508
509         struct icmp6_hdr rs = {ND_ROUTER_SOLICIT, 0, 0, {{0}}};
510         struct iovec iov = {&rs, sizeof(rs)};
511         struct sockaddr_in6 all_routers =
512                 {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, iface->ifindex};
513
514         syslog(LOG_NOTICE, "Sending RS to %s", iface->ifname);
515         odhcpd_send(router_event.uloop.fd, &all_routers, &iov, 1, iface);
516 }
517
518
519 // Handler for incoming router solicitations on slave interfaces
520 static void forward_router_advertisement(uint8_t *data, size_t len)
521 {
522         struct nd_router_advert *adv = (struct nd_router_advert *)data;
523
524         // Rewrite options
525         uint8_t *end = data + len;
526         uint8_t *mac_ptr = NULL;
527         struct in6_addr *dns_ptr = NULL;
528         size_t dns_count = 0;
529
530         struct icmpv6_opt *opt;
531         icmpv6_for_each_option(opt, &adv[1], end) {
532                 if (opt->type == ND_OPT_SOURCE_LINKADDR) {
533                         // Store address of source MAC-address
534                         mac_ptr = opt->data;
535                 } else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 1) {
536                         // Check if we have to rewrite DNS
537                         dns_ptr = (struct in6_addr*)&opt->data[6];
538                         dns_count = (opt->len - 1) / 2;
539                 }
540         }
541
542         syslog(LOG_NOTICE, "Got a RA");
543
544         // Indicate a proxy, however we don't follow the rest of RFC 4389 yet
545         adv->nd_ra_flags_reserved |= ND_RA_FLAG_PROXY;
546
547         // Forward advertisement to all slave interfaces
548         struct sockaddr_in6 all_nodes = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0};
549         struct iovec iov = {data, len};
550
551         struct interface *iface;
552         list_for_each_entry(iface, &interfaces, head) {
553                 if (iface->ra != RELAYD_RELAY || iface->master)
554                         continue;
555
556                 // Fixup source hardware address option
557                 if (mac_ptr)
558                         odhcpd_get_mac(iface, mac_ptr);
559
560                 // If we have to rewrite DNS entries
561                 if (iface->always_rewrite_dns && dns_ptr && dns_count > 0) {
562                         const struct in6_addr *rewrite = iface->dns;
563                         struct in6_addr addr;
564                         size_t rewrite_cnt = iface->dns_cnt;
565
566                         if (rewrite_cnt == 0) {
567                                 if (odhcpd_get_linklocal_interface_address(iface->ifindex, &addr))
568                                         continue; // Unable to comply
569
570                                 rewrite = &addr;
571                                 rewrite_cnt = 1;
572                         }
573
574                         // Copy over any other addresses
575                         for (size_t i = 0; i < dns_count; ++i) {
576                                 size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1;
577                                 dns_ptr[i] = rewrite[j];
578                         }
579                 }
580
581                 odhcpd_send(router_event.uloop.fd, &all_nodes, &iov, 1, iface);
582         }
583 }