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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt