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

Sources/odhcpd/src/router.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt