• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/router.c

  1 /**
  2  * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2018 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12  * GNU General Public License for more details.
 13  *
 14  */
 15 
 16 #include <errno.h>
 17 #include <fcntl.h>
 18 #include <signal.h>
 19 #include <resolv.h>
 20 #include <stdio.h>
 21 #include <stdlib.h>
 22 #include <unistd.h>
 23 #include <stdbool.h>
 24 #include <arpa/inet.h>
 25 #include <net/route.h>
 26 
 27 #include <libubox/utils.h>
 28 
 29 #include "router.h"
 30 #include "odhcpd.h"
 31 #include "statefiles.h"
 32 
 33 
 34 static void forward_router_solicitation(const struct interface *iface);
 35 static void forward_router_advertisement(const struct interface *iface, uint8_t *data, size_t len);
 36 
 37 static void handle_icmpv6(void *addr, void *data, size_t len,
 38                 struct interface *iface, void *dest);
 39 static void trigger_router_advert(struct uloop_timeout *event);
 40 static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info);
 41 
 42 static struct netevent_handler router_netevent_handler = { .cb = router_netevent_cb, };
 43 
 44 static FILE *fp_route = NULL;
 45 
 46 
 47 #define TIME_LEFT(t1, now) ((t1) != UINT32_MAX ? (t1) - (now) : UINT32_MAX)
 48 
 49 int router_init(void)
 50 {
 51         int ret = 0;
 52 
 53         if (!(fp_route = fopen("/proc/net/ipv6_route", "r"))) {
 54                 error("fopen(/proc/net/ipv6_route): %m");
 55                 ret = -1;
 56                 goto out;
 57         }
 58 
 59         if (netlink_add_netevent_handler(&router_netevent_handler) < 0) {
 60                 error("Failed to add netevent handler");
 61                 ret = -1;
 62         }
 63 
 64 out:
 65         if (ret < 0 && fp_route) {
 66                 fclose(fp_route);
 67                 fp_route = NULL;
 68         }
 69 
 70         return ret;
 71 }
 72 
 73 
 74 int router_setup_interface(struct interface *iface, bool enable)
 75 {
 76         int ret = 0;
 77 
 78         enable = enable && (iface->ra != MODE_DISABLED);
 79 
 80         if (!fp_route) {
 81                 ret = -1;
 82                 goto out;
 83         }
 84 
 85 
 86         if (!enable && iface->router_event.uloop.fd >= 0) {
 87                 if (!iface->master) {
 88                         uloop_timeout_cancel(&iface->timer_rs);
 89                         iface->timer_rs.cb = NULL;
 90 
 91                         trigger_router_advert(&iface->timer_rs);
 92                 }
 93 
 94                 uloop_fd_delete(&iface->router_event.uloop);
 95                 close(iface->router_event.uloop.fd);
 96                 iface->router_event.uloop.fd = -1;
 97         } else if (enable) {
 98                 struct icmp6_filter filt;
 99                 struct ipv6_mreq mreq;
100                 int val = 2;
101 
102                 if (iface->router_event.uloop.fd < 0) {
103                         /* Open ICMPv6 socket */
104                         iface->router_event.uloop.fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC,
105                                                                 IPPROTO_ICMPV6);
106                         if (iface->router_event.uloop.fd < 0) {
107                                 error("socket(AF_INET6): %m");
108                                 ret = -1;
109                                 goto out;
110                         }
111 
112                         if (setsockopt(iface->router_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE,
113                                                 iface->ifname, strlen(iface->ifname)) < 0) {
114                                 error("setsockopt(SO_BINDTODEVICE): %m");
115                                 ret = -1;
116                                 goto out;
117                         }
118 
119                         /* Let the kernel compute our checksums */
120                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_RAW, IPV6_CHECKSUM,
121                                                 &val, sizeof(val)) < 0) {
122                                 error("setsockopt(IPV6_CHECKSUM): %m");
123                                 ret = -1;
124                                 goto out;
125                         }
126 
127                         /* This is required by RFC 4861 */
128                         val = 255;
129                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
130                                                 &val, sizeof(val)) < 0) {
131                                 error("setsockopt(IPV6_MULTICAST_HOPS): %m");
132                                 ret = -1;
133                                 goto out;
134                         }
135 
136                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
137                                                 &val, sizeof(val)) < 0) {
138                                 error("setsockopt(IPV6_UNICAST_HOPS): %m");
139                                 ret = -1;
140                                 goto out;
141                         }
142 
143                         /* We need to know the source interface */
144                         val = 1;
145                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
146                                                 &val, sizeof(val)) < 0) {
147                                 error("setsockopt(IPV6_RECVPKTINFO): %m");
148                                 ret = -1;
149                                 goto out;
150                         }
151 
152                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
153                                                 &val, sizeof(val)) < 0) {
154                                 error("setsockopt(IPV6_RECVHOPLIMIT): %m");
155                                 ret = -1;
156                                 goto out;
157                         }
158 
159                         /* Don't loop back */
160                         val = 0;
161                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
162                                                 &val, sizeof(val)) < 0) {
163                                 error("setsockopt(IPV6_MULTICAST_LOOP): %m");
164                                 ret = -1;
165                                 goto out;
166                         }
167 
168                         /* Filter ICMPv6 package types */
169                         ICMP6_FILTER_SETBLOCKALL(&filt);
170                         ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
171                         ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
172                         if (setsockopt(iface->router_event.uloop.fd, IPPROTO_ICMPV6, ICMP6_FILTER,
173                                                 &filt, sizeof(filt)) < 0) {
174                                 error("setsockopt(ICMP6_FILTER): %m");
175                                 ret = -1;
176                                 goto out;
177                         }
178 
179                         iface->router_event.handle_dgram = handle_icmpv6;
180                         iface->ra_sent = 0;
181                         odhcpd_register(&iface->router_event);
182                 } else {
183                         uloop_timeout_cancel(&iface->timer_rs);
184                         iface->timer_rs.cb = NULL;
185 
186                         memset(&mreq, 0, sizeof(mreq));
187                         mreq.ipv6mr_interface = iface->ifindex;
188                         inet_pton(AF_INET6, ALL_IPV6_NODES, &mreq.ipv6mr_multiaddr);
189                         setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
190                                    &mreq, sizeof(mreq));
191 
192                         inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &mreq.ipv6mr_multiaddr);
193                         setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
194                                    &mreq, sizeof(mreq));
195                 }
196 
197                 memset(&mreq, 0, sizeof(mreq));
198                 mreq.ipv6mr_interface = iface->ifindex;
199                 inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &mreq.ipv6mr_multiaddr);
200 
201                 if (iface->ra == MODE_RELAY && iface->master) {
202                         inet_pton(AF_INET6, ALL_IPV6_NODES, &mreq.ipv6mr_multiaddr);
203                         forward_router_solicitation(iface);
204                 } else if (iface->ra == MODE_SERVER) {
205                         iface->timer_rs.cb = trigger_router_advert;
206                         uloop_timeout_set(&iface->timer_rs, 1000);
207                 }
208 
209                 if (setsockopt(iface->router_event.uloop.fd, IPPROTO_IPV6,
210                                         IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
211                         ret = -1;
212                         error("setsockopt(IPV6_ADD_MEMBERSHIP): %m");
213                         goto out;
214                 }
215         }
216 out:
217         if (ret < 0 && iface->router_event.uloop.fd >= 0) {
218                 if (iface->router_event.uloop.registered)
219                         uloop_fd_delete(&iface->router_event.uloop);
220 
221                 close(iface->router_event.uloop.fd);
222                 iface->router_event.uloop.fd = -1;
223         }
224 
225         return ret;
226 }
227 
228 
229 static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info)
230 {
231         struct interface *iface;
232 
233         switch (event) {
234         case NETEV_IFINDEX_CHANGE:
235                 iface = info->iface;
236                 if (iface && iface->router_event.uloop.fd >= 0) {
237                         if (iface->router_event.uloop.registered)
238                                 uloop_fd_delete(&iface->router_event.uloop);
239 
240                         close(iface->router_event.uloop.fd);
241                         iface->router_event.uloop.fd = -1;
242                 }
243                 break;
244         case NETEV_ROUTE6_ADD:
245         case NETEV_ROUTE6_DEL:
246                 if (info->rt.dst_len)
247                         break;
248 
249                 avl_for_each_element(&interfaces, iface, avl) {
250                         if (iface->ra == MODE_SERVER && !iface->master)
251                                 uloop_timeout_set(&iface->timer_rs, 1000);
252                 }
253                 break;
254         case NETEV_ADDR6LIST_CHANGE:
255                 iface = info->iface;
256                 if (iface && iface->ra == MODE_SERVER && !iface->master)
257                         uloop_timeout_set(&iface->timer_rs, 1000);
258                 break;
259         default:
260                 break;
261         }
262 }
263 
264 
265 static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len)
266 {
267         struct icmp6_hdr *hdr = (struct icmp6_hdr *)data;
268         struct icmpv6_opt *opt, *end = (struct icmpv6_opt*)&data[len];
269 
270         /* Hoplimit is already checked in odhcpd_receive_packets */
271         if (len < sizeof(*hdr) || hdr->icmp6_code)
272                 return false;
273 
274         switch (hdr->icmp6_type) {
275         case ND_ROUTER_ADVERT:
276                 if (!IN6_IS_ADDR_LINKLOCAL(&source->sin6_addr))
277                         return false;
278 
279                 opt = (struct icmpv6_opt *)((struct nd_router_advert *)data + 1);
280                 break;
281 
282         case ND_ROUTER_SOLICIT:
283                 opt = (struct icmpv6_opt *)((struct nd_router_solicit *)data + 1);
284                 break;
285 
286         default:
287                 return false;
288         }
289 
290         icmpv6_for_each_option(opt, opt, end)
291                 if (opt->type == ND_OPT_SOURCE_LINKADDR &&
292                                 IN6_IS_ADDR_UNSPECIFIED(&source->sin6_addr) &&
293                                 hdr->icmp6_type == ND_ROUTER_SOLICIT)
294                         return false;
295 
296         /* Check all options parsed successfully */
297         return opt == end;
298 }
299 
300 
301 /* Detect whether a default route exists, also find the source prefixes */
302 static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
303 {
304         struct odhcpd_ipaddr p = {
305                 .addr.in6 = IN6ADDR_ANY_INIT,
306                 .prefix_len = 0,
307                 .dprefix_len = 0,
308                 .preferred_lt = 0,
309                 .valid_lt = 0
310         };
311         bool found_default = false;
312         char line[512], ifname[16];
313 
314         rewind(fp_route);
315 
316         while (fgets(line, sizeof(line), fp_route)) {
317                 uint32_t rflags;
318                 if (sscanf(line, "00000000000000000000000000000000 00 "
319                                 "%*s %*s %*s %*s %*s %*s %*s %15s", ifname) &&
320                                 strcmp(ifname, "lo")) {
321                         found_default = true;
322                 } else if (sscanf(line, "%8" SCNx32 "%8" SCNx32 "%*8" SCNx32 "%*8" SCNx32 " %hhx %*s "
323                                 "%*s 00000000000000000000000000000000 %*s %*s %*s %" SCNx32 " lo",
324                                 &p.addr.in6.s6_addr32[0], &p.addr.in6.s6_addr32[1], &p.prefix_len, &rflags) &&
325                                 p.prefix_len > 0 && (rflags & RTF_NONEXTHOP) && (rflags & RTF_REJECT)) {
326                         // Find source prefixes by scanning through unreachable-routes
327                         p.addr.in6.s6_addr32[0] = htonl(p.addr.in6.s6_addr32[0]);
328                         p.addr.in6.s6_addr32[1] = htonl(p.addr.in6.s6_addr32[1]);
329 
330                         for (ssize_t i = 0; i < len; ++i) {
331                                 if (n[i].prefix_len <= 64 && n[i].prefix_len >= p.prefix_len &&
332                                     !odhcpd_bmemcmp(&p.addr.in6, &n[i].addr.in6, p.prefix_len)) {
333                                         n[i].dprefix_len = p.prefix_len;
334                                         break;
335                                 }
336                         }
337                 }
338         }
339 
340         return found_default;
341 }
342 
343 static int calc_adv_interval(struct interface *iface, uint32_t lowest_found_lifetime,
344                                 uint32_t *maxival)
345 {
346         uint32_t minival = iface->ra_mininterval;
347         int msecs;
348 
349         *maxival = iface->ra_maxinterval;
350 
351         if (*maxival > lowest_found_lifetime)
352                 *maxival = lowest_found_lifetime;
353 
354         odhcpd_urandom(&msecs, sizeof(msecs));
355         msecs = (labs(msecs) % ((*maxival != minival) ? (*maxival - minival)*1000 : 500)) +
356                         minival*1000;
357 
358         /* RFC 2461 6.2.4 For the first MAX_INITIAL_RTR_ADVERTISEMENTS advertisements
359          * if the timer is bigger than MAX_INITIAL_RTR_ADVERT_INTERVAL it should be
360          * set to MAX_INITIAL_RTR_ADVERT_INTERVAL
361          * Off by one as an initial interval timer has already expired
362          */
363         if ((iface->ra_sent + 1) < MaxInitialRtAdvs && msecs > MaxInitialRtrAdvInterval*1000)
364                 msecs = MaxInitialRtrAdvInterval*1000;
365 
366         return msecs;
367 }
368 
369 static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival)
370 {
371         uint32_t lifetime = iface->max_preferred_lifetime;
372 
373         if (iface->ra_lifetime > 0) {
374                 lifetime = iface->ra_lifetime;
375         }
376 
377         if (lifetime > 0 && lifetime < maxival)
378                 lifetime = maxival;
379         else if (lifetime > RouterLifetime)
380                 lifetime = RouterLifetime;
381 
382         return lifetime;
383 }
384 
385 enum {
386         IOV_RA_ADV=0,
387         IOV_RA_PFXS,
388         IOV_RA_ROUTES,
389         IOV_RA_DNS,
390         IOV_RA_SEARCH,
391         IOV_RA_PREF64,
392         IOV_RA_DNR,
393         IOV_RA_ADV_INTERVAL,
394         IOV_RA_CAPT_PORTAL,
395         IOV_RA_TOTAL,
396 };
397 
398 struct adv_msg {
399         struct nd_router_advert h;
400         struct icmpv6_opt lladdr;
401         struct nd_opt_mtu mtu;
402 };
403 
404 struct nd_opt_dns_server {
405         uint8_t type;
406         uint8_t len;
407         uint8_t pad;
408         uint8_t pad2;
409         uint32_t lifetime;
410         struct in6_addr addr[];
411 };
412 
413 struct nd_opt_search_list {
414         uint8_t type;
415         uint8_t len;
416         uint16_t reserved;
417         uint32_t lifetime;
418         uint8_t name[];
419 } _o_packed;
420 
421 struct nd_opt_route_info {
422         uint8_t type;
423         uint8_t len;
424         uint8_t prefix_len;
425         uint8_t flags;
426         uint32_t lifetime;
427         uint32_t addr[4];
428 };
429 
430 struct nd_opt_pref64_info {
431         uint8_t type;
432         uint8_t len;
433         uint16_t lifetime_plc;
434         uint32_t prefix[3];
435 };
436 
437 struct nd_opt_dnr_info {
438         uint8_t type;
439         uint8_t len;
440         uint16_t priority;
441         uint32_t lifetime;
442         uint16_t adn_len;
443         uint8_t body[];
444 };
445 
446 struct nd_opt_capt_portal {
447         uint8_t type;
448         uint8_t len;
449         uint8_t data[];
450 };
451 
452 /* IPv6 RA PIOs */
453 inline static int router_compare_pio_addr(const struct ra_pio *pio, const struct odhcpd_ipaddr *addr)
454 {
455         uint8_t cmp_len = max(64, max(pio->length, addr->prefix_len));
456 
457         return odhcpd_bmemcmp(&pio->prefix, &addr->addr.in6, cmp_len);
458 }
459 
460 static struct ra_pio *router_find_ra_pio(struct interface *iface,
461         struct odhcpd_ipaddr *addr)
462 {
463         for (size_t i = 0; i < iface->pio_cnt; i++) {
464                 struct ra_pio *cur_pio = &iface->pios[i];
465 
466                 if (!router_compare_pio_addr(cur_pio, addr))
467                         return cur_pio;
468         }
469 
470         return NULL;
471 }
472 
473 static void router_add_ra_pio(struct interface *iface,
474         struct odhcpd_ipaddr *addr)
475 {
476         char ipv6_str[INET6_ADDRSTRLEN];
477         struct ra_pio *new_pios, *pio;
478 
479         pio = router_find_ra_pio(iface, addr);
480         if (pio) {
481                 if (memcmp(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr)) != 0 ||
482                     pio->length != addr->prefix_len)
483                 {
484                         char new_ipv6_str[INET6_ADDRSTRLEN];
485 
486                         iface->pio_update = true;
487                         warn("rfc9096: %s: changed %s/%u -> %s/%u",
488                              iface->ifname,
489                              inet_ntop(AF_INET6, &pio->prefix, ipv6_str, sizeof(ipv6_str)),
490                              pio->length,
491                              inet_ntop(AF_INET6, &addr->addr.in6, new_ipv6_str, sizeof(new_ipv6_str)),
492                              addr->prefix_len);
493 
494                         memcpy(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr));
495                         pio->length = addr->prefix_len;
496                 }
497 
498                 if (pio->lifetime) {
499                         pio->lifetime = 0;
500 
501                         iface->pio_update = true;
502                         warn("rfc9096: %s: renew %s/%u",
503                              iface->ifname,
504                              inet_ntop(AF_INET6, &pio->prefix, ipv6_str, sizeof(ipv6_str)),
505                              pio->length);
506                 }
507 
508                 return;
509         }
510 
511         new_pios = realloc(iface->pios, sizeof(struct ra_pio) * (iface->pio_cnt + 1));
512         if (!new_pios)
513                 return;
514 
515         iface->pios = new_pios;
516         pio = &iface->pios[iface->pio_cnt];
517         iface->pio_cnt++;
518 
519         memcpy(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr));
520         pio->length = addr->prefix_len;
521         pio->lifetime = 0;
522 
523         iface->pio_update = true;
524         info("rfc9096: %s: add %s/%u",
525              iface->ifname,
526              inet_ntop(AF_INET6, &pio->prefix, ipv6_str, sizeof(ipv6_str)),
527              pio->length);
528 }
529 
530 static void router_clear_duplicated_ra_pio(struct interface *iface)
531 {
532         size_t pio_cnt = iface->pio_cnt;
533         char ipv6_str[INET6_ADDRSTRLEN];
534 
535         for (size_t i = 0; i < iface->pio_cnt; i++) {
536                 struct ra_pio *pio_a = &iface->pios[i];
537                 size_t j = i + 1;
538 
539                 while (j < iface->pio_cnt) {
540                         struct ra_pio *pio_b = &iface->pios[j];
541 
542                         if (!memcmp(pio_a, pio_b, ra_pio_cmp_len)) {
543                                 warn("rfc9096: %s: clear duplicated %s/%u",
544                                      iface->ifname,
545                                      inet_ntop(AF_INET6, &pio_a->prefix, ipv6_str, sizeof(ipv6_str)),
546                                      pio_a->length);
547 
548                                 iface->pios[j] = iface->pios[iface->pio_cnt - 1];
549                                 iface->pio_cnt--;
550                         } else {
551                                 j++;
552                         }
553                 }
554         }
555 
556         if (iface->pio_cnt != pio_cnt) {
557                 struct ra_pio *new_pios = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
558 
559                 if (new_pios)
560                         iface->pios = new_pios;
561         }
562 }
563 
564 static void router_clear_expired_ra_pio(time_t now,
565         struct interface *iface)
566 {
567         size_t i = 0, pio_cnt = iface->pio_cnt;
568         char ipv6_str[INET6_ADDRSTRLEN];
569 
570         while (i < iface->pio_cnt) {
571                 struct ra_pio *cur_pio = &iface->pios[i];
572 
573                 if (ra_pio_expired(cur_pio, now)) {
574                         info("rfc9096: %s: clear expired %s/%u",
575                              iface->ifname,
576                              inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str)),
577                              cur_pio->length);
578 
579                         iface->pios[i] = iface->pios[iface->pio_cnt - 1];
580                         iface->pio_cnt--;
581                 } else {
582                         i++;
583                 }
584         }
585 
586         if (!iface->pio_cnt) {
587                 free(iface->pios);
588                 iface->pios = NULL;
589         } else if (iface->pio_cnt != pio_cnt) {
590                 struct ra_pio *new_pios = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
591 
592                 if (new_pios)
593                         iface->pios = new_pios;
594         }
595 }
596 
597 static void router_stale_ra_pio(struct interface *iface,
598         struct odhcpd_ipaddr *addr,
599         time_t now)
600 {
601         struct ra_pio *pio = router_find_ra_pio(iface, addr);
602         char ipv6_str[INET6_ADDRSTRLEN];
603 
604         if (!pio || pio->lifetime)
605                 return;
606 
607         pio->lifetime = now + iface->max_valid_lifetime;
608 
609         iface->pio_update = true;
610         warn("rfc9096: %s: stale %s/%u",
611              iface->ifname,
612              inet_ntop(AF_INET6, &pio->prefix, ipv6_str, sizeof(ipv6_str)),
613              pio->length);
614 }
615 
616 /* Router Advert server mode */
617 static int send_router_advert(struct interface *iface, const struct in6_addr *from)
618 {
619         time_t now = odhcpd_time();
620         struct odhcpd_ipaddr *addrs = NULL;
621         struct adv_msg adv;
622         struct nd_opt_prefix_info *pfxs = NULL;
623         struct nd_opt_dns_server *dns = NULL;
624         struct nd_opt_search_list *search = NULL;
625         struct nd_opt_route_info *routes = NULL;
626         struct nd_opt_pref64_info *pref64 = NULL;
627         struct nd_opt_dnr_info *dnrs = NULL;
628         struct nd_opt_adv_interval adv_interval;
629         struct nd_opt_capt_portal *capt_portal = NULL;
630         struct iovec iov[IOV_RA_TOTAL];
631         struct sockaddr_in6 dest;
632         size_t dns_sz = 0, search_sz = 0, pref64_sz = 0, dnrs_sz = 0;
633         size_t pfxs_cnt = 0, routes_cnt = 0;
634         size_t total_addr_cnt = 0, valid_addr_cnt = 0;
635         size_t capt_portal_sz = 0;
636         /*
637          * lowest_found_lifetime stores the lowest lifetime of all prefixes;
638          * necessary to find longest adv interval necessary
639          * for shortest lived prefix
640          */
641         uint32_t lowest_found_lifetime = UINT32_MAX, highest_found_lifetime = 0, maxival, ra_lifetime;
642         int msecs, hlim = iface->ra_hoplimit;
643         bool default_route = false;
644         bool valid_prefix = false;
645         char buf[INET6_ADDRSTRLEN];
646 
647         router_clear_expired_ra_pio(now, iface);
648 
649         memset(&adv, 0, sizeof(adv));
650         adv.h.nd_ra_type = ND_ROUTER_ADVERT;
651 
652         if (hlim == 0)
653                 hlim = odhcpd_get_interface_config(iface->ifname, "hop_limit");
654 
655         if (hlim > 0)
656                 adv.h.nd_ra_curhoplimit = hlim;
657 
658         adv.h.nd_ra_flags_reserved = iface->ra_flags;
659 
660         if (iface->route_preference < 0)
661                 adv.h.nd_ra_flags_reserved |= ND_RA_PREF_LOW;
662         else if (iface->route_preference > 0)
663                 adv.h.nd_ra_flags_reserved |= ND_RA_PREF_HIGH;
664 
665         if (iface->dhcpv6 != MODE_DISABLED && iface->dhcpv6_pd && iface->dhcpv6_pd_preferred) {
666                 /* RFC9762 § 5
667                  * If the network desires to delegate prefixes to devices that support
668                  * DHCPv6 prefix delegation but do not support the P flag, it SHOULD
669                  * also set the M or O bits in the RA to 1
670                  */
671                 adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
672         }
673 
674         adv.h.nd_ra_reachable = htonl(iface->ra_reachabletime);
675         adv.h.nd_ra_retransmit = htonl(iface->ra_retranstime);
676 
677         adv.lladdr.type = ND_OPT_SOURCE_LINKADDR;
678         adv.lladdr.len = 1;
679         odhcpd_get_mac(iface, adv.lladdr.data);
680 
681         adv.mtu.nd_opt_mtu_type = ND_OPT_MTU;
682         adv.mtu.nd_opt_mtu_len = 1;
683 
684         adv.mtu.nd_opt_mtu_mtu = htonl(iface->ra_mtu);
685 
686         iov[IOV_RA_ADV].iov_base = (char *)&adv;
687         iov[IOV_RA_ADV].iov_len = sizeof(adv);
688 
689         valid_addr_cnt = (iface->timer_rs.cb /* if not shutdown */ ? iface->addr6_len : 0);
690 
691         // check ra_default
692         if (iface->default_router) {
693                 default_route = true;
694 
695                 if (iface->default_router > 1)
696                         valid_prefix = true;
697         }
698 
699         if (valid_addr_cnt + iface->pio_cnt) {
700                 addrs = alloca(sizeof(*addrs) * (valid_addr_cnt + iface->pio_cnt));
701 
702                 if (valid_addr_cnt) {
703                         memcpy(addrs, iface->addr6, sizeof(*addrs) * valid_addr_cnt);
704                         total_addr_cnt = valid_addr_cnt;
705 
706                         /* Check default route */
707                         if (!default_route && parse_routes(addrs, valid_addr_cnt))
708                                 default_route = true;
709                 }
710 
711                 for (size_t i = 0; i < iface->pio_cnt; i++) {
712                         struct ra_pio *cur_pio = &iface->pios[i];
713                         bool pio_found = false;
714 
715                         for (size_t j = 0; j < valid_addr_cnt; j++) {
716                                 struct odhcpd_ipaddr *cur_addr = &addrs[j];
717 
718                                 if (!router_compare_pio_addr(cur_pio, cur_addr)) {
719                                         pio_found = true;
720                                         break;
721                                 }
722                         }
723 
724                         if (!pio_found) {
725                                 struct odhcpd_ipaddr *addr = &addrs[total_addr_cnt];
726 
727                                 memcpy(&addr->addr.in6, &cur_pio->prefix, sizeof(addr->addr.in6));
728                                 addr->prefix_len = cur_pio->length;
729                                 addr->preferred_lt = 0;
730                                 addr->valid_lt = (uint32_t) (now + ND_VALID_LIMIT);
731                                 total_addr_cnt++;
732                         }
733                 }
734         }
735 
736         /* Construct Prefix Information options */
737         for (size_t i = 0; i < total_addr_cnt; ++i) {
738                 struct odhcpd_ipaddr *addr = &addrs[i];
739                 struct nd_opt_prefix_info *p = NULL;
740                 uint32_t preferred_lt = 0;
741                 uint32_t valid_lt = 0;
742 
743                 if (addr->prefix_len > 96 || (i < valid_addr_cnt && addr->valid_lt <= (uint32_t)now)) {
744                         info("Address %s (prefix %d, valid-lifetime %u) not suitable as RA prefix on %s",
745                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)), addr->prefix_len,
746                              addr->valid_lt, iface->name);
747                         continue;
748                 }
749 
750                 if (ADDR_MATCH_PIO_FILTER(addr, iface)) {
751                         info("Address %s filtered out as RA prefix on %s",
752                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)),
753                              iface->name);
754                         continue; /* PIO filtered out of this RA */
755                 }
756 
757                 for (size_t j = 0; j < pfxs_cnt; ++j) {
758                         if (addr->prefix_len == pfxs[j].nd_opt_pi_prefix_len &&
759                             !odhcpd_bmemcmp(&pfxs[j].nd_opt_pi_prefix,
760                                             &addr->addr.in6, addr->prefix_len))
761                                 p = &pfxs[j];
762                 }
763 
764                 if (!p) {
765                         struct nd_opt_prefix_info *tmp;
766 
767                         tmp = realloc(pfxs, sizeof(*pfxs) * (pfxs_cnt + 1));
768                         if (!tmp) {
769                                 error("Realloc failed for RA prefix option on %s", iface->name);
770                                 continue;
771                         }
772 
773                         pfxs = tmp;
774                         p = &pfxs[pfxs_cnt++];
775                         memset(p, 0, sizeof(*p));
776                 }
777 
778                 if (addr->preferred_lt > (uint32_t)now) {
779                         preferred_lt = TIME_LEFT(addr->preferred_lt, now);
780 
781                         if (iface->max_preferred_lifetime && preferred_lt > iface->max_preferred_lifetime) {
782                                 preferred_lt = iface->max_preferred_lifetime;
783                         }
784                 }
785 
786                 if (addr->valid_lt > (uint32_t)now) {
787                         valid_lt = TIME_LEFT(addr->valid_lt, now);
788 
789                         if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime)
790                                 valid_lt = iface->max_valid_lifetime;
791                 }
792 
793                 if (preferred_lt > valid_lt) {
794                         /*
795                          * RFC4861 § 6.2.1
796                          * This value [AdvPreferredLifetime] MUST NOT be larger than
797                          * AdvValidLifetime.
798                          */
799                         preferred_lt = valid_lt;
800                 }
801 
802                 if (lowest_found_lifetime > valid_lt)
803                         lowest_found_lifetime = valid_lt;
804 
805                 if ((!IN6_IS_ADDR_ULA(&addr->addr.in6) || iface->default_router) && valid_lt)
806                         valid_prefix = true;
807 
808                 if (!IN6_IS_ADDR_ULA(&addr->addr.in6) && valid_lt) {
809                         if (highest_found_lifetime < valid_lt)
810                                 highest_found_lifetime = valid_lt;
811                 }
812 
813                 odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr.in6,
814                                 (iface->ra_advrouter) ? 128 : addr->prefix_len);
815                 p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
816                 p->nd_opt_pi_len = 4;
817                 p->nd_opt_pi_prefix_len = (addr->prefix_len < 64) ? 64 : addr->prefix_len;
818                 /* RFC9762 DHCPv6-PD Preferred Flag § 6:
819                  * Routers SHOULD set the P flag to zero by default...
820                  */
821                 p->nd_opt_pi_flags_reserved = 0;
822                 if (!iface->ra_not_onlink)
823                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
824                 if (iface->ra_slaac && addr->prefix_len <= 64)
825                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
826                 if (iface->dhcpv6 != MODE_DISABLED && iface->dhcpv6_pd && iface->dhcpv6_pd_preferred)
827                         /* RFC9762 DHCPv6-PD Preferred Flag
828                          * We can run both SLAAC and DHCPv6-PD.
829                          * §6:
830                          * "Routers MUST allow the P flag to be configured separately from the A flag.
831                          * ...en/disabling the P flag MUST NOT trigger automatic changes in the A flag
832                          * value set by the router."
833                          */
834                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_PD_PREFERRED;
835                 if (iface->ra_advrouter)
836                         // RFC6275, §7.2
837                         p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
838                 if (i >= valid_addr_cnt || !preferred_lt) {
839                         /*
840                          * RFC9096 § 3.5
841                          *
842                          * - Any prefixes that were previously advertised by the CE router
843                          *   via PIOs in RA messages, but that have now become stale, MUST
844                          *   be advertised with PIOs that have the "Valid Lifetime" and the
845                          *   "Preferred Lifetime" set to 0 and the "A" and "L" bits
846                          *   unchanged.
847                          */
848                         p->nd_opt_pi_preferred_time = 0;
849                         p->nd_opt_pi_valid_time = 0;
850 
851                         router_stale_ra_pio(iface, addr, now);
852                 } else {
853                         p->nd_opt_pi_preferred_time = htonl(preferred_lt);
854                         p->nd_opt_pi_valid_time = htonl(valid_lt);
855 
856                         router_add_ra_pio(iface, addr);
857                 }
858         }
859 
860         router_clear_duplicated_ra_pio(iface);
861 
862         iov[IOV_RA_PFXS].iov_base = (char *)pfxs;
863         iov[IOV_RA_PFXS].iov_len = pfxs_cnt * sizeof(*pfxs);
864 
865         /* Calculate periodic transmit */
866         msecs = calc_adv_interval(iface, lowest_found_lifetime, &maxival);
867         ra_lifetime = calc_ra_lifetime(iface, maxival);
868         if (!highest_found_lifetime)
869                 highest_found_lifetime = ra_lifetime;
870 
871         if (!iface->have_link_local) {
872                 notice("Skip sending a RA on %s as no link local address is available", iface->name);
873                 goto out;
874         }
875 
876         if (default_route && valid_prefix) {
877                 adv.h.nd_ra_router_lifetime = htons(ra_lifetime < UINT16_MAX ? ra_lifetime : UINT16_MAX);
878         } else {
879                 adv.h.nd_ra_router_lifetime = 0;
880 
881                 if (default_route)
882                         warn("A default route is present but there is no public prefix "
883                              "on %s thus we announce no default route by setting ra_lifetime to 0!", iface->name);
884                 else
885                         warn("No default route present, setting ra_lifetime to 0!");
886         }
887 
888         debug("Using a RA lifetime of %d seconds on %s", ntohs(adv.h.nd_ra_router_lifetime), iface->name);
889 
890         /* DNS options */
891         if (iface->ra_dns) {
892                 struct in6_addr *dns_addrs6 = NULL, dns_addr6;
893                 size_t dns_addrs6_cnt = 0, dns_search_len = iface->dns_search_len;
894                 uint8_t *dns_search = iface->dns_search;
895                 uint8_t dns_search_buf[DNS_MAX_NAME_LEN];
896 
897                 /* DNS Recursive DNS aka RDNSS Type 25; RFC8106 */
898                 if (iface->dns_addrs6_cnt > 0) {
899                         dns_addrs6 = iface->dns_addrs6;
900                         dns_addrs6_cnt = iface->dns_addrs6_cnt;
901                 } else if (!odhcpd_get_interface_dns_addr6(iface, &dns_addr6)) {
902                         dns_addrs6 = &dns_addr6;
903                         dns_addrs6_cnt = 1;
904                 }
905 
906                 if (dns_addrs6_cnt) {
907                         dns_sz = sizeof(*dns) + dns_addrs6_cnt * sizeof(*dns_addrs6);
908 
909                         dns = alloca(dns_sz);
910                         memset(dns, 0, dns_sz);
911                         dns->type = ND_OPT_RECURSIVE_DNS;
912                         dns->len = 1 + (2 * dns_addrs6_cnt);
913                         dns->lifetime = htonl(highest_found_lifetime);
914                         memcpy(dns->addr, dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6));
915                 }
916 
917                 /* DNS Search List option aka DNSSL Type 31; RFC8106, §5.2 */
918                 if (!dns_search && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
919                         int len = dn_comp(_res.dnsrch[0], dns_search_buf,
920                                         sizeof(dns_search_buf), NULL, NULL);
921                         if (len > 0) {
922                                 dns_search = dns_search_buf;
923                                 dns_search_len = len;
924                         }
925                 }
926 
927                 if (dns_search_len > 0) {
928                         search_sz = sizeof(*search) + ((dns_search_len + 7) & (~7));
929                         search = alloca(search_sz);
930                         *search = (struct nd_opt_search_list) {
931                                 .type = ND_OPT_DNS_SEARCH,
932                                 .len = search_sz / 8,
933                                 .reserved = 0,
934                                 .lifetime = htonl(highest_found_lifetime),
935                         };
936                         memcpy(search->name, dns_search, dns_search_len);
937                 }
938         }
939 
940         iov[IOV_RA_DNS].iov_base = (char *)dns;
941         iov[IOV_RA_DNS].iov_len = dns_sz;
942         iov[IOV_RA_SEARCH].iov_base = (char *)search;
943         iov[IOV_RA_SEARCH].iov_len = search_sz;
944 
945         if (iface->pref64_length) {
946                 /* RFC 8781 § 4.1 rounding up lifetime to multiple of 8 */
947                 uint16_t pref64_lifetime = ra_lifetime < (UINT16_MAX - 7) ? ra_lifetime + 7 : (UINT16_MAX - 7);
948 
949                 pref64_sz = sizeof(*pref64);
950                 pref64 = alloca(pref64_sz);
951                 pref64->type = ND_OPT_PREF64;
952                 pref64->len = 2;
953                 pref64->lifetime_plc = htons((0xfff8 & pref64_lifetime) |
954                                              (0x7 & iface->pref64_plc));
955                 memcpy(pref64->prefix, iface->pref64_prefix, sizeof(pref64->prefix));
956         }
957         iov[IOV_RA_PREF64].iov_base = (char *)pref64;
958         iov[IOV_RA_PREF64].iov_len = pref64_sz;
959 
960         if (iface->dnr_cnt) {
961                 size_t dnr_sz[iface->dnr_cnt];
962 
963                 for (unsigned i = 0; i < iface->dnr_cnt; i++) {
964                         dnr_sz[i] = sizeof(struct nd_opt_dnr_info) + iface->dnr[i].adn_len;
965                         if (iface->dnr[i].addr6_cnt > 0 || iface->dnr[i].svc_len > 0) {
966                                 dnr_sz[i] += 2 + iface->dnr[i].addr6_cnt * sizeof(struct in6_addr);
967                                 dnr_sz[i] += 2 + iface->dnr[i].svc_len;
968                         }
969                         dnr_sz[i] = (dnr_sz[i] + 7) & ~7;
970                         dnrs_sz += dnr_sz[i];
971                 }
972 
973                 /* dnrs are sized in multiples of 8, so each dnr should be aligned */
974                 dnrs = alloca(dnrs_sz);
975                 memset(dnrs, 0, dnrs_sz);
976 
977                 uint8_t *pos = (uint8_t *)dnrs;
978                 for (unsigned i = 0; i < iface->dnr_cnt; pos += dnr_sz[i], i++) {
979                         struct nd_opt_dnr_info *dnr = (struct nd_opt_dnr_info *)pos;
980                         size_t dnr_addr6_sz = iface->dnr[i].addr6_cnt * sizeof(struct in6_addr);
981                         uint8_t *tmp = dnr->body;
982 
983                         dnr->type = ND_OPT_DNR;
984                         dnr->len = dnr_sz[i] / 8;
985                         dnr->priority = htons(iface->dnr[i].priority);
986                         if (iface->dnr[i].lifetime_set)
987                                 dnr->lifetime = htonl(iface->dnr[i].lifetime);
988                         else
989                                 dnr->lifetime = htonl(highest_found_lifetime);
990 
991                         dnr->adn_len = htons(iface->dnr[i].adn_len);
992                         memcpy(tmp, iface->dnr[i].adn, iface->dnr[i].adn_len);
993                         tmp += iface->dnr[i].adn_len;
994 
995                         *(tmp++) = dnr_addr6_sz >> 8;
996                         *(tmp++) = dnr_addr6_sz & 0xff;
997                         memcpy(tmp, iface->dnr[i].addr6, dnr_addr6_sz);
998                         tmp += dnr_addr6_sz;
999 
1000                         *(tmp++) = iface->dnr[i].svc_len >> 8;
1001                         *(tmp++) = iface->dnr[i].svc_len & 0xff;
1002                         memcpy(tmp, iface->dnr[i].svc, iface->dnr[i].svc_len);
1003                 }
1004         }
1005         iov[IOV_RA_DNR].iov_base = (char *)dnrs;
1006         iov[IOV_RA_DNR].iov_len = dnrs_sz;
1007 
1008         /*
1009          * RFC7084 § 4.3 :
1010          *    L-3:   An IPv6 CE router MUST advertise itself as a router for the
1011          *           delegated prefix(es) (and ULA prefix if configured to provide
1012          *           ULA addressing) using the "Route Information Option" specified
1013          *           in Section 2.3 of [RFC4191]. This advertisement is
1014          *           independent of having or not having IPv6 connectivity on the
1015          *           WAN interface.
1016          */
1017 
1018         for (size_t i = 0; i < valid_addr_cnt; ++i) {
1019                 struct odhcpd_ipaddr *addr = &addrs[i];
1020                 struct nd_opt_route_info *tmp;
1021                 uint32_t valid_lt;
1022 
1023                 if (addr->dprefix_len >= 64 || addr->dprefix_len == 0 || addr->valid_lt <= (uint32_t)now) {
1024                         info("Address %s (dprefix %d, valid-lifetime %u) not suitable as RA route on %s",
1025                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)),
1026                              addr->dprefix_len, addr->valid_lt, iface->name);
1027 
1028                         continue; /* Address not suitable */
1029                 }
1030 
1031                 if (ADDR_MATCH_PIO_FILTER(addr, iface)) {
1032                         info("Address %s filtered out as RA route on %s",
1033                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)),
1034                              iface->name);
1035                         continue; /* PIO filtered out of this RA */
1036                 }
1037 
1038                 if (addr->dprefix_len > 32) {
1039                         addr->addr.in6.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix_len)) - 1));
1040                 } else if (addr->dprefix_len <= 32) {
1041                         addr->addr.in6.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix_len)) - 1));
1042                         addr->addr.in6.s6_addr32[1] = 0;
1043                 }
1044 
1045                 tmp = realloc(routes, sizeof(*routes) * (routes_cnt + 1));
1046                 if (!tmp) {
1047                         error("Realloc failed for RA route option on %s", iface->name);
1048                         continue;
1049                 }
1050 
1051                 routes = tmp;
1052 
1053                 memset(&routes[routes_cnt], 0, sizeof(*routes));
1054                 routes[routes_cnt].type = ND_OPT_ROUTE_INFO;
1055                 routes[routes_cnt].len = sizeof(*routes) / 8;
1056                 routes[routes_cnt].prefix_len = addr->dprefix_len;
1057                 routes[routes_cnt].flags = 0;
1058                 if (iface->route_preference < 0)
1059                         routes[routes_cnt].flags |= ND_RA_PREF_LOW;
1060                 else if (iface->route_preference > 0)
1061                         routes[routes_cnt].flags |= ND_RA_PREF_HIGH;
1062 
1063                 valid_lt = TIME_LEFT(addr->valid_lt, now);
1064                 if (iface->max_valid_lifetime && valid_lt > iface->max_valid_lifetime)
1065                         valid_lt = iface->max_valid_lifetime;
1066                 routes[routes_cnt].lifetime = htonl(valid_lt);
1067                 routes[routes_cnt].addr[0] = addr->addr.in6.s6_addr32[0];
1068                 routes[routes_cnt].addr[1] = addr->addr.in6.s6_addr32[1];
1069                 routes[routes_cnt].addr[2] = 0;
1070                 routes[routes_cnt].addr[3] = 0;
1071 
1072                 ++routes_cnt;
1073         }
1074 
1075         iov[IOV_RA_ROUTES].iov_base = (char *)routes;
1076         iov[IOV_RA_ROUTES].iov_len = routes_cnt * sizeof(*routes);
1077 
1078         memset(&adv_interval, 0, sizeof(adv_interval));
1079         adv_interval.nd_opt_adv_interval_type = ND_OPT_RTR_ADV_INTERVAL;
1080         adv_interval.nd_opt_adv_interval_len = 1;
1081         adv_interval.nd_opt_adv_interval_ival = htonl(maxival*1000);
1082 
1083         iov[IOV_RA_ADV_INTERVAL].iov_base = (char *)&adv_interval;
1084         iov[IOV_RA_ADV_INTERVAL].iov_len = adv_interval.nd_opt_adv_interval_len * 8;
1085 
1086         /* RFC 8910 Captive Portal */
1087         uint8_t *captive_portal_uri = (uint8_t *)iface->captive_portal_uri;
1088         if (iface->captive_portal_uri_len > 0) {
1089                 /* compute pad so that (header + data + pad) is a multiple of 8 */
1090                 capt_portal_sz = (sizeof(struct nd_opt_capt_portal) + iface->captive_portal_uri_len + 7) & ~7;
1091 
1092                 capt_portal = alloca(capt_portal_sz);
1093                 memset(capt_portal, 0, capt_portal_sz);
1094 
1095                 capt_portal->type = ND_OPT_CAPTIVE_PORTAL;
1096                 capt_portal->len = capt_portal_sz / 8;
1097 
1098                 memcpy(capt_portal->data, captive_portal_uri, iface->captive_portal_uri_len);
1099                 /* remaining padding bytes already set to 0x00 */
1100         }
1101 
1102         iov[IOV_RA_CAPT_PORTAL].iov_base = capt_portal;
1103         iov[IOV_RA_CAPT_PORTAL].iov_len = capt_portal_sz;
1104 
1105         memset(&dest, 0, sizeof(dest));
1106         dest.sin6_family = AF_INET6;
1107 
1108         if (from && !IN6_IS_ADDR_UNSPECIFIED(from))
1109                 dest.sin6_addr = *from;
1110         else
1111                 inet_pton(AF_INET6, ALL_IPV6_NODES, &dest.sin6_addr);
1112 
1113         debug("Sending a RA on %s", iface->name);
1114 
1115         if (odhcpd_try_send_with_src(iface->router_event.uloop.fd, &dest, iov, ARRAY_SIZE(iov), iface) > 0) {
1116                 iface->ra_sent++;
1117 
1118                 statefiles_write_prefix_information(iface);
1119         }
1120 
1121 out:
1122         free(pfxs);
1123         free(routes);
1124 
1125         return msecs;
1126 }
1127 
1128 
1129 static void trigger_router_advert(struct uloop_timeout *event)
1130 {
1131         struct interface *iface = container_of(event, struct interface, timer_rs);
1132         int msecs = send_router_advert(iface, NULL);
1133 
1134         /* Rearm timer if not shut down */
1135         if (event->cb)
1136                 uloop_timeout_set(event, msecs);
1137 }
1138 
1139 
1140 /* Event handler for incoming ICMPv6 packets */
1141 static void handle_icmpv6(void *addr, void *data, size_t len,
1142                 struct interface *iface, _o_unused void *dest)
1143 {
1144         struct icmp6_hdr *hdr = data;
1145         struct sockaddr_in6 *from = addr;
1146 
1147         if (!router_icmpv6_valid(addr, data, len))
1148                 return;
1149 
1150         if ((iface->ra == MODE_SERVER && !iface->master)) { /* Server mode */
1151                 if (hdr->icmp6_type == ND_ROUTER_SOLICIT)
1152                         send_router_advert(iface, &from->sin6_addr);
1153         } else if (iface->ra == MODE_RELAY) { /* Relay mode */
1154                 if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) {
1155                         struct interface *c;
1156 
1157                         avl_for_each_element(&interfaces, c, avl) {
1158                                 if (!c->master || c->ra != MODE_RELAY)
1159                                         continue;
1160 
1161                                 forward_router_solicitation(c);
1162                         }
1163                 } else if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master)
1164                         forward_router_advertisement(iface, data, len);
1165         }
1166 }
1167 
1168 
1169 /* Forward a router solicitation from slave to master interface */
1170 static void forward_router_solicitation(const struct interface *iface)
1171 {
1172         struct icmp6_hdr rs = {ND_ROUTER_SOLICIT, 0, 0, {{0}}};
1173         struct iovec iov = {&rs, sizeof(rs)};
1174         struct sockaddr_in6 all_routers;
1175 
1176         if (!iface)
1177                 return;
1178 
1179         memset(&all_routers, 0, sizeof(all_routers));
1180         all_routers.sin6_family = AF_INET6;
1181         inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &all_routers.sin6_addr);
1182         all_routers.sin6_scope_id = iface->ifindex;
1183 
1184         notice("Sending RS to %s", iface->name);
1185         odhcpd_send(iface->router_event.uloop.fd, &all_routers, &iov, 1, iface);
1186 }
1187 
1188 
1189 /* Forward a router advertisement from master to slave interfaces */
1190 static void forward_router_advertisement(const struct interface *iface, uint8_t *data, size_t len)
1191 {
1192         struct nd_router_advert *adv = (struct nd_router_advert *)data;
1193         struct sockaddr_in6 all_nodes;
1194         struct icmpv6_opt *opt;
1195         struct interface *c;
1196         struct iovec iov = { .iov_base = data, .iov_len = len };
1197         /* Rewrite options */
1198         uint8_t *end = data + len;
1199         uint8_t *mac_ptr = NULL;
1200         struct in6_addr *dns_addrs6 = NULL;
1201         size_t dns_addrs6_cnt = 0;
1202         // MTU option
1203         struct nd_opt_mtu *mtu_opt = NULL;
1204         uint32_t ingress_mtu_val = 0;
1205         /* PIO L flag and RA M/O Flags */
1206         uint8_t ra_flags;
1207         size_t pio_count = 0;
1208         struct fwd_pio_flags {
1209                 uint8_t *ptr;
1210                 uint8_t flags;
1211         } *pio_flags = NULL;
1212 
1213         icmpv6_for_each_option(opt, &adv[1], end) {
1214                 /* check our packet content is not truncated */
1215                 if (opt->len == 0 || (uint8_t *)opt + opt->len * 8 > end) {
1216                         error("Ingress RA packet option for relaying has incorrect length");
1217                         return;
1218                 }
1219 
1220                 switch(opt->type) {
1221                 case ND_OPT_PREFIX_INFORMATION:
1222                         pio_count++;
1223                         break;
1224                 }
1225         }
1226 
1227         if (pio_count > 0) {
1228                 pio_flags = alloca(sizeof(*pio_flags) * pio_count);
1229                 pio_count = 0;
1230         }
1231 
1232         /* Parse existing options */
1233         icmpv6_for_each_option(opt, &adv[1], end) {
1234                 switch (opt->type) {
1235                 case ND_OPT_SOURCE_LINKADDR:
1236                         mac_ptr = opt->data;
1237                         break;
1238 
1239                 case ND_OPT_RECURSIVE_DNS:
1240                         if (opt->len > 1) {
1241                                 dns_addrs6 = (struct in6_addr *)&opt->data[6];
1242                                 dns_addrs6_cnt = (opt->len - 1) / 2;
1243                         }
1244                         break;
1245 
1246                 case ND_OPT_MTU:
1247                         if (opt->len == 1 && (uint8_t *)opt + sizeof(struct nd_opt_mtu) <= end) {
1248                                 mtu_opt = (struct nd_opt_mtu *)opt;
1249                                 ingress_mtu_val = ntohl(mtu_opt->nd_opt_mtu_mtu);
1250                         }
1251                         break;
1252                 case ND_OPT_PREFIX_INFORMATION:
1253                         /* Store options for each PIO */
1254                         pio_flags[pio_count].ptr = &opt->data[1];
1255                         pio_flags[pio_count].flags = opt->data[1];
1256                         pio_count++;
1257                         break;
1258                 }
1259         }
1260 
1261         info("Got a RA on %s", iface->name);
1262 
1263         /*      Indicate a proxy, however we don't follow the rest of RFC 4389 yet
1264          *      store original upstream RA state 
1265          */
1266         ra_flags = adv->nd_ra_flags_reserved | ND_RA_FLAG_PROXY;
1267 
1268         /* Forward advertisement to all slave interfaces */
1269         memset(&all_nodes, 0, sizeof(all_nodes));
1270         all_nodes.sin6_family = AF_INET6;
1271         inet_pton(AF_INET6, ALL_IPV6_NODES, &all_nodes.sin6_addr);
1272 
1273         avl_for_each_element(&interfaces, c, avl) {
1274                 if (c->ra != MODE_RELAY || c->master)
1275                         continue;
1276 
1277                 /* Fixup source hardware address option */
1278                 if (mac_ptr)
1279                         odhcpd_get_mac(c, mac_ptr);
1280 
1281                 if (pio_count > 0)
1282                         debug("RA forward: Rewriting RA PIO flags");
1283 
1284                 for (size_t i = 0; i < pio_count; i++) {
1285                         /* restore the flags byte to its upstream state before applying per-interface policy */
1286                         *pio_flags[i].ptr = pio_flags[i].flags;
1287                         /* ensure L flag (on-link) cleared; relayed == not on-link */
1288                         *pio_flags[i].ptr &= ~ND_OPT_PI_FLAG_ONLINK;
1289                 }
1290 
1291                 /* Apply per-interface modifications of upstream RA state */
1292                 adv->nd_ra_flags_reserved = ra_flags;
1293                 /* Rewrite M/O flags unless we relay DHCPv6 */
1294                 if (c->dhcpv6 != MODE_RELAY) {
1295                         /* Clear the relayed M/O bits */
1296                         adv->nd_ra_flags_reserved &= ~(ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER);
1297                         /* Apply the locally configured ra_flags for M and O */
1298                         adv->nd_ra_flags_reserved |= c->ra_flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER);
1299                 }
1300 
1301                 /* If we have to rewrite DNS entries */
1302                 if (c->always_rewrite_dns && dns_addrs6 && dns_addrs6_cnt > 0) {
1303                         const struct in6_addr *rewrite = c->dns_addrs6;
1304                         struct in6_addr addr;
1305                         size_t rewrite_cnt = c->dns_addrs6_cnt;
1306 
1307                         if (rewrite_cnt == 0) {
1308                                 if (odhcpd_get_interface_dns_addr6(c, &addr))
1309                                         continue; /* Unable to comply */
1310 
1311                                 rewrite = &addr;
1312                                 rewrite_cnt = 1;
1313                         }
1314 
1315                         /* Copy over any other addresses */
1316                         for (size_t i = 0; i < dns_addrs6_cnt; ++i) {
1317                                 size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1;
1318                                 dns_addrs6[i] = rewrite[j];
1319                         }
1320                 }
1321 
1322                 /* Rewrite MTU option if local RA MTU is configured */
1323                 if (c->ra_mtu && mtu_opt) {
1324                         if (ingress_mtu_val != c->ra_mtu) {
1325                                 debug("Rewriting RA MTU from %u to %u on %s",
1326                                       ingress_mtu_val, c->ra_mtu, c->name);
1327                                 mtu_opt->nd_opt_mtu_mtu = htonl(c->ra_mtu);
1328                         }
1329                 }
1330 
1331                 info("Forward a RA on %s", c->name);
1332                 odhcpd_send(c->router_event.uloop.fd, &all_nodes, &iov, 1, c);
1333         }
1334 }
1335 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt