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);