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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt