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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt