Module Name: src Committed By: roy Date: Fri Apr 20 15:57:23 UTC 2018
Modified Files: src/usr.sbin/rtadvd: config.c rtadvd.c rtadvd.h Log Message: Unicast solicited RA's as per RFC 7772. This is done by having a secondary timer against rainfo so we can delay unicasting by the required randomised amount of time without affecting the unsolicited RA timer. To generate a diff of this commit: cvs rdiff -u -r1.39 -r1.40 src/usr.sbin/rtadvd/config.c cvs rdiff -u -r1.64 -r1.65 src/usr.sbin/rtadvd/rtadvd.c cvs rdiff -u -r1.16 -r1.17 src/usr.sbin/rtadvd/rtadvd.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/rtadvd/config.c diff -u src/usr.sbin/rtadvd/config.c:1.39 src/usr.sbin/rtadvd/config.c:1.40 --- src/usr.sbin/rtadvd/config.c:1.39 Fri Apr 20 15:29:19 2018 +++ src/usr.sbin/rtadvd/config.c Fri Apr 20 15:57:23 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: config.c,v 1.39 2018/04/20 15:29:19 roy Exp $ */ +/* $NetBSD: config.c,v 1.40 2018/04/20 15:57:23 roy Exp $ */ /* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */ /* @@ -113,6 +113,7 @@ free_rainfo(struct rainfo *rai) struct dnssl_domain *dnsd; rtadvd_remove_timer(&rai->timer); + rtadvd_remove_timer(&rai->timer_sol); while ((sol = TAILQ_FIRST(&rai->soliciter))) { TAILQ_REMOVE(&rai->soliciter, sol, next); @@ -791,7 +792,8 @@ getconfig(const char *intface, int exith return; tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, tmp, tmp); - ra_timer_set_short_delay(tmp); + ra_timer_set_short_delay(tmp, tmp->timer); + tmp->timer_sol = rtadvd_add_timer(ra_timeout_sol, NULL, tmp, NULL); return; Index: src/usr.sbin/rtadvd/rtadvd.c diff -u src/usr.sbin/rtadvd/rtadvd.c:1.64 src/usr.sbin/rtadvd/rtadvd.c:1.65 --- src/usr.sbin/rtadvd/rtadvd.c:1.64 Fri Apr 20 11:31:54 2018 +++ src/usr.sbin/rtadvd/rtadvd.c Fri Apr 20 15:57:23 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: rtadvd.c,v 1.64 2018/04/20 11:31:54 roy Exp $ */ +/* $NetBSD: rtadvd.c,v 1.65 2018/04/20 15:57:23 roy Exp $ */ /* $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $ */ /* @@ -166,7 +166,7 @@ static void rs_input(int, struct nd_rout struct in6_pktinfo *, struct sockaddr_in6 *); static void ra_input(int, struct nd_router_advert *, struct in6_pktinfo *, struct sockaddr_in6 *); -static struct rainfo *ra_output(struct rainfo *); +static struct rainfo *ra_output(struct rainfo *, bool); static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, struct sockaddr_in6 *); static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t); @@ -440,7 +440,7 @@ die(void) rai->mininterval = MIN_DELAY_BETWEEN_RAS; rai->maxinterval = MIN_DELAY_BETWEEN_RAS; rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS; - ra_output(rai); + ra_output(rai, false); ra_timer_update(rai, &rai->timer->tm); rtadvd_set_timer(&rai->timer->tm, rai->timer); } @@ -698,13 +698,16 @@ rtmsg_input(void) ra_timer_update, rai, rai); ra_timer_update(rai, &rai->timer->tm); rtadvd_set_timer(&rai->timer->tm, rai->timer); + rtadvd_remove_timer(&rai->timer_sol); + rai->timer_sol = rtadvd_add_timer(ra_timeout_sol, + NULL, rai, NULL); } else if (prefixchange && rai->ifflags & IFF_UP) { /* * An advertised prefix has been added or invalidated. * Will notice the change in a short delay. */ rai->initcounter = 0; - ra_timer_set_short_delay(rai); + ra_timer_set_short_delay(rai, rai->timer); } } @@ -965,12 +968,20 @@ rs_input(int len, struct nd_router_solic */ /* record sockaddr waiting for RA, if possible */ - sol = malloc(sizeof(*sol)); - if (sol) { - sol->addr = *from; - /* XXX RFC2553 need clarification on flowinfo */ - sol->addr.sin6_flowinfo = 0; - TAILQ_INSERT_HEAD(&rai->soliciter, sol, next); + TAILQ_FOREACH(sol, &rai->soliciter, next) { + if (IN6_ARE_ADDR_EQUAL(&sol->addr.sin6_addr, &from->sin6_addr)) + break; + } + if (sol == NULL) { + sol = malloc(sizeof(*sol)); + if (sol == NULL) { + logit(LOG_ERR, "%s: malloc: %m", __func__); + } else { + sol->addr = *from; + /* XXX RFC2553 need clarification on flowinfo */ + sol->addr.sin6_flowinfo = 0; + TAILQ_INSERT_TAIL(&rai->soliciter, sol, next); + } } /* @@ -980,14 +991,14 @@ rs_input(int len, struct nd_router_solic if (rai->waiting++) goto done; - ra_timer_set_short_delay(rai); + ra_timer_set_short_delay(rai, rai->timer_sol); done: free_ndopts(&ndopts); } void -ra_timer_set_short_delay(struct rainfo *rai) +ra_timer_set_short_delay(struct rainfo *rai, struct rtadvd_timer *timer) { long delay; /* must not be greater than 1000000 */ struct timespec interval, now, min_delay, tm_tmp, *rest; @@ -1024,7 +1035,7 @@ ra_timer_set_short_delay(struct rainfo * timespecsub(&min_delay, &tm_tmp, &min_delay); timespecadd(&min_delay, &interval, &interval); } - rtadvd_set_timer(&interval, rai->timer); + rtadvd_set_timer(&interval, timer); } static void @@ -1503,7 +1514,8 @@ sock_open(void) exit(EXIT_FAILURE); } - sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); sndcmsgbuf = malloc(sndcmsgbuflen); if (sndcmsgbuf == NULL) { logit(LOG_ERR, "%s: malloc: %m", __func__); @@ -1522,6 +1534,12 @@ sock_open(void) logit(LOG_ERR, "%s: IPV6_MULTICAST_HOPS: %m", __func__); exit(EXIT_FAILURE); } + on = 255; + if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &on, + sizeof(on)) == -1) { + logit(LOG_ERR, "%s: IPV6_UNICAST_HOPS: %m", __func__); + exit(EXIT_FAILURE); + } /* specify to tell receiving interface */ on = 1; @@ -1661,7 +1679,7 @@ if_indextorainfo(unsigned int idx) } struct rainfo * -ra_output(struct rainfo *rai) +ra_output(struct rainfo *rai, bool solicited) { int i; struct cmsghdr *cm; @@ -1680,8 +1698,8 @@ ra_output(struct rainfo *rai) sndmhdr.msg_iov[0].iov_base = (void *)rai->ra_data; sndmhdr.msg_iov[0].iov_len = rai->ra_datalen; - cm = CMSG_FIRSTHDR(&sndmhdr); /* specify the outgoing interface */ + cm = CMSG_FIRSTHDR(&sndmhdr); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); @@ -1693,8 +1711,32 @@ ra_output(struct rainfo *rai) "%s: send RA on %s, # of waitings = %d", __func__, rai->ifname, rai->waiting); - i = prog_sendmsg(sock, &sndmhdr, 0); + if (solicited) { + /* unicast solicited RA's as per RFC 7772 */ + while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) { + sndmhdr.msg_name = (void *)&sol->addr; + i = prog_sendmsg(sock, &sndmhdr, 0); + if (i < 0 || (size_t)i != rai->ra_datalen) { + if (i < 0) { + logit(LOG_ERR, + "%s: unicast sendmsg on %s: %m", + __func__, rai->ifname); + } + } + TAILQ_REMOVE(&rai->soliciter, sol, next); + free(sol); + } + + /* reset waiting conter */ + rai->waiting = 0; + + /* disable timer */ + rai->timer_sol->enabled = false; + return rai; + } + + i = prog_sendmsg(sock, &sndmhdr, 0); if (i < 0 || (size_t)i != rai->ra_datalen) { if (i < 0) { logit(LOG_ERR, "%s: sendmsg on %s: %m", @@ -1702,27 +1744,6 @@ ra_output(struct rainfo *rai) } } - /* - * unicast advertisements - * XXX commented out. reason: though spec does not forbit it, unicast - * advert does not really help - */ - while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) { -#if 0 - sndmhdr.msg_name = (void *)&sol->addr; - i = sendmsg(sock, &sndmhdr, 0); - if (i < 0 || i != rai->ra_datalen) { - if (i < 0) { - logit(LOG_ERR, - "%s: unicast sendmsg on %s: %m", - __func__, rai->ifname); - } - } -#endif - TAILQ_REMOVE(&rai->soliciter, sol, next); - free(sol); - } - if (rai->leaving_adv > 0) { if (--(rai->leaving_adv) == 0) { /* leaving for ourself means we're shutting down */ @@ -1738,7 +1759,7 @@ ra_output(struct rainfo *rai) rai->leaving_for->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai->leaving_for, rai->leaving_for); - ra_timer_set_short_delay(rai->leaving_for); + ra_timer_set_short_delay(rai->leaving_for, rai->timer); rai->leaving_for->leaving = NULL; free_rainfo(rai); return NULL; @@ -1752,32 +1773,39 @@ ra_output(struct rainfo *rai) /* update timestamp */ prog_clock_gettime(CLOCK_MONOTONIC, &rai->lastsent); - - /* reset waiting conter */ - rai->waiting = 0; - return rai; } -/* process RA timer */ +/* process unsolicited RA timer */ struct rtadvd_timer * ra_timeout(void *data) { struct rainfo *rai = (struct rainfo *)data; -#ifdef notyet - /* if necessary, reconstruct the packet. */ -#endif - logit(LOG_DEBUG, - "%s: RA timer on %s is expired", + "%s: unsolicited RA timer on %s is expired", __func__, rai->ifname); - if (ra_output(rai)) + if (ra_output(rai, false)) return rai->timer; return NULL; } +/* process solicited RA timer */ +struct rtadvd_timer * +ra_timeout_sol(void *data) +{ + struct rainfo *rai = (struct rainfo *)data; + + logit(LOG_DEBUG, + "%s: solicited RA timer on %s is expired", + __func__, rai->ifname); + + if (ra_output(rai, true)) + return rai->timer_sol; + return NULL; +} + /* update RA timer */ void ra_timer_update(void *data, struct timespec *tm) Index: src/usr.sbin/rtadvd/rtadvd.h diff -u src/usr.sbin/rtadvd/rtadvd.h:1.16 src/usr.sbin/rtadvd/rtadvd.h:1.17 --- src/usr.sbin/rtadvd/rtadvd.h:1.16 Fri Apr 20 10:39:37 2018 +++ src/usr.sbin/rtadvd/rtadvd.h Fri Apr 20 15:57:23 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: rtadvd.h,v 1.16 2018/04/20 10:39:37 roy Exp $ */ +/* $NetBSD: rtadvd.h,v 1.17 2018/04/20 15:57:23 roy Exp $ */ /* $KAME: rtadvd.h,v 1.30 2005/10/17 14:40:02 suz Exp $ */ /* @@ -136,7 +136,8 @@ struct rainfo { TAILQ_ENTRY(rainfo) next; /* timer related parameters */ - struct rtadvd_timer *timer; + struct rtadvd_timer *timer; /* unsolicited RA timer */ + struct rtadvd_timer *timer_sol; /* solicited RA timer */ int initcounter; /* counter for the first few advertisements */ struct timespec lastsent; /* timestamp when the latest RA was sent */ int waiting; /* number of RS waiting for RA */ @@ -189,8 +190,9 @@ struct rainfo { extern TAILQ_HEAD(ralist_head_t, rainfo) ralist; struct rtadvd_timer *ra_timeout(void *); +struct rtadvd_timer *ra_timeout_sol(void *); void ra_timer_update(void *, struct timespec *); -void ra_timer_set_short_delay(struct rainfo *); +void ra_timer_set_short_delay(struct rainfo *, struct rtadvd_timer *); int prefix_match(struct in6_addr *, int, struct in6_addr *, int); struct rainfo *if_indextorainfo(unsigned int);