diff options
author | hrs <hrs@FreeBSD.org> | 2011-06-06 03:06:43 +0000 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2011-06-06 03:06:43 +0000 |
commit | 10df0af5a54c03a258caf94e9931b16eec080d79 (patch) | |
tree | 7fcbcd5609e82351ec883059d7bfb466d7cb8ef6 /usr.sbin/rtadvd/rtadvd.c | |
parent | acbda2ccc11fcdfe5fa5175c97ac29b4bb729bb5 (diff) | |
download | FreeBSD-src-10df0af5a54c03a258caf94e9931b16eec080d79.zip FreeBSD-src-10df0af5a54c03a258caf94e9931b16eec080d79.tar.gz |
- Implement RDNSS and DNSSL options (RFC 6106, IPv6 Router Advertisement
Options for DNS Configuration) into rtadvd(8) and rtsold(8). DNS
information received by rtsold(8) will go to resolv.conf(5) by
resolvconf(8) script. This is based on work by J.R. Oldroyd (kern/156259)
but revised extensively[1].
- rtadvd(8) now supports "noifprefix" to disable gathering on-link prefixes
from interfaces when no "addr" is specified[2]. An entry in rtadvd.conf
with "noifprefix" + no "addr" generates an RA message with no prefix
information option.
- rtadvd(8) now supports RTM_IFANNOUNCE message to fix crashes when an
interface is added or removed.
- Correct bogus ND_OPT_ROUTE_INFO value to one in RFC 4191.
Reviewed by: bz[1]
PR: kern/156259 [1]
PR: bin/152458 [2]
Diffstat (limited to 'usr.sbin/rtadvd/rtadvd.c')
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 1284 |
1 files changed, 727 insertions, 557 deletions
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index 02e3dc7..614d109 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -4,7 +4,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -16,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -31,12 +31,15 @@ */ #include <sys/param.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/uio.h> #include <sys/time.h> #include <sys/queue.h> +#include <sys/sysctl.h> #include <net/if.h> +#include <net/if_media.h> #include <net/route.h> #include <net/if_dl.h> #include <netinet/in.h> @@ -46,12 +49,17 @@ #include <arpa/inet.h> +#include <net/if_var.h> +#include <netinet/in_var.h> +#include <netinet6/nd6.h> + #include <time.h> #include <unistd.h> #include <stdio.h> #include <err.h> #include <errno.h> #include <libutil.h> +#include <netdb.h> #include <string.h> #include <stdlib.h> #include <syslog.h> @@ -66,6 +74,7 @@ #include "if.h" #include "config.h" #include "dump.h" +#include "pathnames.h" struct msghdr rcvmhdr; static u_char *rcvcmsgbuf; @@ -78,26 +87,27 @@ struct msghdr sndmhdr; struct iovec rcviov[2]; struct iovec sndiov[2]; struct sockaddr_in6 rcvfrom; -struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; -struct in6_addr in6a_site_allrouters; -static char *dumpfilename = "/var/run/rtadvd.dump"; -static char *pidfilename = "/var/run/rtadvd.pid"; +static const char *dumpfilename = _PATH_RTADVDDUMP; +static const char *pidfilename = _PATH_RTADVDPID; +const char *conffile = _PATH_RTADVDCONF; static struct pidfh *pfh; static char *mcastif; int sock; int rtsock = -1; int accept_rr = 0; int dflag = 0, sflag = 0; +static int ifl_len; +static char **ifl_names; -u_char *conffile = NULL; +struct railist_head_t railist = + TAILQ_HEAD_INITIALIZER(railist); -struct rainfo *ralist = NULL; struct nd_optlist { - struct nd_optlist *next; - struct nd_opt_hdr *opt; + TAILQ_ENTRY(nd_optlist) nol_next; + struct nd_opt_hdr *nol_opt; }; -union nd_opts { - struct nd_opt_hdr *nd_opt_array[9]; +union nd_opt { + struct nd_opt_hdr *opt_array[9]; struct { struct nd_opt_hdr *zero; struct nd_opt_hdr *src_lladdr; @@ -105,51 +115,76 @@ union nd_opts { struct nd_opt_prefix_info *pi; struct nd_opt_rd_hdr *rh; struct nd_opt_mtu *mtu; - struct nd_optlist *list; + TAILQ_HEAD(, nd_optlist) opt_list; } nd_opt_each; }; -#define nd_opts_src_lladdr nd_opt_each.src_lladdr -#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr -#define nd_opts_pi nd_opt_each.pi -#define nd_opts_rh nd_opt_each.rh -#define nd_opts_mtu nd_opt_each.mtu -#define nd_opts_list nd_opt_each.list - -#define NDOPT_FLAG_SRCLINKADDR 0x1 -#define NDOPT_FLAG_TGTLINKADDR 0x2 -#define NDOPT_FLAG_PREFIXINFO 0x4 -#define NDOPT_FLAG_RDHDR 0x8 -#define NDOPT_FLAG_MTU 0x10 +#define opt_src_lladdr nd_opt_each.src_lladdr +#define opt_tgt_lladdr nd_opt_each.tgt_lladdr +#define opt_pi nd_opt_each.pi +#define opt_rh nd_opt_each.rh +#define opt_mtu nd_opt_each.mtu +#define opt_list nd_opt_each.opt_list + +#define NDOPT_FLAG_SRCLINKADDR (1 << 0) +#define NDOPT_FLAG_TGTLINKADDR (1 << 1) +#define NDOPT_FLAG_PREFIXINFO (1 << 2) +#define NDOPT_FLAG_RDHDR (1 << 3) +#define NDOPT_FLAG_MTU (1 << 4) +#define NDOPT_FLAG_RDNSS (1 << 5) +#define NDOPT_FLAG_DNSSL (1 << 6) u_int32_t ndopt_flags[] = { - 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, - NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU, + [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR, + [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR, + [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO, + [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR, + [ND_OPT_MTU] = NDOPT_FLAG_MTU, + [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS, + [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL, +}; + +struct sockaddr_in6 sin6_linklocal_allnodes = { + .sin6_len = sizeof(sin6_linklocal_allnodes), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, }; -int main(int, char *[]); -static void set_die(int); -static void die(void); -static void sock_open(void); -static void rtsock_open(void); -static void rtadvd_input(void); -static void rs_input(int, struct nd_router_solicit *, - struct in6_pktinfo *, struct sockaddr_in6 *); -static void ra_input(int, struct nd_router_advert *, - struct in6_pktinfo *, struct sockaddr_in6 *); -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 *, u_int32_t); -static void free_ndopts(union nd_opts *); -static void ra_output(struct rainfo *); -static void rtmsg_input(void); -static void rtadvd_set_dump_file(int); -static void set_short_delay(struct rainfo *); +struct sockaddr_in6 sin6_linklocal_allrouters = { + .sin6_len = sizeof(sin6_linklocal_allrouters), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, +}; + +struct sockaddr_in6 sin6_sitelocal_allrouters = { + .sin6_len = sizeof(sin6_sitelocal_allrouters), + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_SITELOCAL_ALLROUTERS_INIT, +}; + +static void set_die(int); +static void die(void); +static void sock_open(void); +static void rtsock_open(void); +static void rtadvd_input(void); +static void rs_input(int, struct nd_router_solicit *, + struct in6_pktinfo *, struct sockaddr_in6 *); +static void ra_input(int, struct nd_router_advert *, + struct in6_pktinfo *, struct sockaddr_in6 *); +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_opt *, u_int32_t); +static void free_ndopts(union nd_opt *); +static void ra_output(struct rainfo *); +static void rtmsg_input(void); +static void rtadvd_set_dump_file(int); +static void set_short_delay(struct rainfo *); +static int ifl_lookup(char *, char **, int); +static int check_accept_rtadv(int); +static int getinet6sysctl(int); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { #ifdef HAVE_POLL_H struct pollfd set[2]; @@ -162,18 +197,19 @@ main(argc, argv) int i, ch; int fflag = 0, logopt; pid_t pid, otherpid; + int error; /* get command line options and arguments */ - while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) { + while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) { switch (ch) { case 'c': conffile = optarg; break; case 'd': - dflag = 1; + dflag++; break; case 'D': - dflag = 2; + dflag += 2; break; case 'f': fflag = 1; @@ -202,8 +238,9 @@ main(argc, argv) argv += optind; if (argc == 0) { fprintf(stderr, - "usage: rtadvd [-dDfMRs] [-c conffile] " - "[-F dumpfile] [-p pidfile] interfaces...\n"); + "usage: rtadvd [-dDfRs] [-c conffile] " + "[-F dumpfile] [-M ifname] " + "[-p pidfile] interfaces...\n"); exit(1); } @@ -213,10 +250,12 @@ main(argc, argv) openlog("rtadvd", logopt, LOG_DAEMON); /* set log level */ - if (dflag == 0) - (void)setlogmask(LOG_UPTO(LOG_ERR)); - if (dflag == 1) + if (dflag > 1) + (void)setlogmask(LOG_UPTO(LOG_DEBUG)); + else if (dflag > 0) (void)setlogmask(LOG_UPTO(LOG_INFO)); + else + (void)setlogmask(LOG_UPTO(LOG_ERR)); /* timer initialization */ rtadvd_timer_init(); @@ -229,16 +268,26 @@ main(argc, argv) srandom((u_long)time(NULL)); #endif #endif - /* get iflist block from kernel */ init_iflist(); + ifl_names = argv; + ifl_len = argc; - while (argc--) - getconfig(*argv++); + for (i = 0; i < ifl_len; i++) { + int idx; - if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { - fprintf(stderr, "fatal: inet_pton failed\n"); - exit(1); + idx = if_nametoindex(ifl_names[i]); + if (idx == 0) { + syslog(LOG_INFO, + "<%s> interface %s not found." + "Ignored at this moment.", __func__, ifl_names[i]); + continue; + } + error = getconfig(idx); + if (error) + syslog(LOG_INFO, + "<%s> invalid configuration for %s." + "Ignored at this moment.", __func__, ifl_names[i]); } pfh = pidfile_open(pidfilename, 0600, &otherpid); @@ -292,7 +341,6 @@ main(argc, argv) if (rtsock >= 0) FD_SET(rtsock, fdsetp); #endif - signal(SIGTERM, set_die); signal(SIGUSR1, rtadvd_set_dump_file); @@ -300,7 +348,6 @@ main(argc, argv) #ifndef HAVE_POLL_H memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */ #endif - if (do_dump) { /* SIGUSR1 */ do_dump = 0; rtadvd_dump_file(dumpfilename); @@ -325,7 +372,6 @@ main(argc, argv) "<%s> there's no timer. waiting for inputs", __func__); } - #ifdef HAVE_POLL_H if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM)) < 0) @@ -358,75 +404,88 @@ main(argc, argv) exit(0); /* NOTREACHED */ } +static int +ifl_lookup(char *ifn, char **names, int len) +{ + while (len--) + if (strncmp(names[len], ifn, IFNAMSIZ) == 0) + return (0); + return (-1); +} + static void -rtadvd_set_dump_file(sig) - int sig; +rtadvd_set_dump_file(int sig __unused) { + do_dump = 1; } static void -set_die(sig) - int sig; +set_die(int sig __unused) { + do_die = 1; } static void -die() +die(void) { - struct rainfo *ra; + struct rainfo *rai; + struct rdnss *rdn; + struct dnssl *dns; int i; const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; - if (dflag > 1) { - syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", - __func__); - } + syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", + __func__); - for (ra = ralist; ra; ra = ra->next) { - ra->lifetime = 0; - make_packet(ra); + TAILQ_FOREACH(rai, &railist, rai_next) { + rai->rai_lifetime = 0; + TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) + rdn->rd_ltime = 0; + TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) + dns->dn_ltime = 0; + make_packet(rai); } for (i = 0; i < retrans; i++) { - for (ra = ralist; ra; ra = ra->next) - ra_output(ra); + TAILQ_FOREACH(rai, &railist, rai_next) + ra_output(rai); sleep(MIN_DELAY_BETWEEN_RAS); } pidfile_remove(pfh); + exit(0); - /*NOTREACHED*/ } static void -rtmsg_input() +rtmsg_input(void) { int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; - u_char ifname[IF_NAMESIZE]; - struct prefix *prefix; + u_char ifname[IFNAMSIZ]; + struct if_announcemsghdr *ifan; + struct prefix *pfx; struct rainfo *rai; struct in6_addr *addr; char addrbuf[INET6_ADDRSTRLEN]; int prefixchange = 0; + int error; n = read(rtsock, msg, sizeof(msg)); - if (dflag > 1) { - syslog(LOG_DEBUG, "<%s> received a routing message " - "(type = %d, len = %d)", __func__, rtmsg_type(msg), n); - } + syslog(LOG_DEBUG, "<%s> received a routing message " + "(type = %d, len = %d)", __func__, rtmsg_type(msg), n); + if (n > rtmsg_len(msg)) { /* - * This usually won't happen for messages received on + * This usually won't happen for messages received on * a routing socket. */ - if (dflag > 1) - syslog(LOG_DEBUG, - "<%s> received data length is larger than " - "1st routing message len. multiple messages? " - "read %d bytes, but 1st msg len = %d", - __func__, n, rtmsg_len(msg)); + syslog(LOG_DEBUG, + "<%s> received data length is larger than " + "1st routing message len. multiple messages? " + "read %d bytes, but 1st msg len = %d", + __func__, n, rtmsg_len(msg)); #if 0 /* adjust length */ n = rtmsg_len(msg); @@ -438,11 +497,12 @@ rtmsg_input() int oldifflags; next = get_next_msg(next, lim, 0, &len, - RTADV_TYPE2BITMASK(RTM_ADD) | - RTADV_TYPE2BITMASK(RTM_DELETE) | - RTADV_TYPE2BITMASK(RTM_NEWADDR) | - RTADV_TYPE2BITMASK(RTM_DELADDR) | - RTADV_TYPE2BITMASK(RTM_IFINFO)); + RTADV_TYPE2BITMASK(RTM_ADD) | + RTADV_TYPE2BITMASK(RTM_DELETE) | + RTADV_TYPE2BITMASK(RTM_NEWADDR) | + RTADV_TYPE2BITMASK(RTM_DELADDR) | + RTADV_TYPE2BITMASK(RTM_IFINFO) | + RTADV_TYPE2BITMASK(RTM_IFANNOUNCE)); if (len == 0) break; type = rtmsg_type(next); @@ -458,25 +518,65 @@ rtmsg_input() case RTM_IFINFO: ifindex = get_ifm_ifindex(next); break; - default: - /* should not reach here */ - if (dflag > 1) { + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)next; + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + case IFAN_DEPARTURE: + break; + default: syslog(LOG_DEBUG, - "<%s:%d> unknown rtmsg %d on %s", - __func__, __LINE__, type, - if_indextoname(ifindex, ifname)); + "<%s:%d> unknown ifan msg (ifan_what=%d)", + __func__, __LINE__, ifan->ifan_what); + continue; + } + + syslog(LOG_INFO, "<%s>: if_announcemsg (idx=%d:%d)", + __func__, ifan->ifan_index, ifan->ifan_what); + init_iflist(); + error = ifl_lookup(ifan->ifan_name, + ifl_names, ifl_len); + if (error) { + syslog(LOG_INFO, "<%s>: not a target " + "interface (idx=%d)", __func__, + ifan->ifan_index); + continue; } + + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + error = getconfig(ifan->ifan_index); + if (error) + syslog(LOG_ERR, + "<%s>: getconfig failed (idx=%d)" + " Ignored.", __func__, + ifan->ifan_index); + break; + case IFAN_DEPARTURE: + error = rmconfig(ifan->ifan_index); + if (error) + syslog(LOG_ERR, + "<%s>: rmconfig failed (idx=%d)" + " Ignored.", __func__, + ifan->ifan_index); + break; + } + continue; + default: + /* should not reach here */ + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __func__, __LINE__, type, + if_indextoname(ifindex, ifname)); continue; } if ((rai = if_indextorainfo(ifindex)) == NULL) { - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s> route changed on " - "non advertising interface(%s)", - __func__, - if_indextoname(ifindex, ifname)); - } + syslog(LOG_DEBUG, + "<%s> route changed on " + "non advertising interface(%s)", + __func__, + if_indextoname(ifindex, ifname)); continue; } oldifflags = iflist[ifindex]->ifm_flags; @@ -500,25 +600,25 @@ rtmsg_input() __func__, plen); break; } - prefix = find_prefix(rai, addr, plen); - if (prefix) { - if (prefix->timer) { + pfx = find_prefix(rai, addr, plen); + if (pfx) { + if (pfx->pfx_timer) { /* * If the prefix has been invalidated, * make it available again. */ - update_prefix(prefix); + update_prefix(pfx); prefixchange = 1; - } else if (dflag > 1) { + } else syslog(LOG_DEBUG, "<%s> new prefix(%s/%d) " "added on %s, " "but it was already in list", __func__, inet_ntop(AF_INET6, addr, - (char *)addrbuf, INET6_ADDRSTRLEN), - plen, rai->ifname); - } + (char *)addrbuf, + sizeof(addrbuf)), + plen, rai->rai_ifname); break; } make_prefix(rai, ifindex, addr, plen); @@ -543,21 +643,17 @@ rtmsg_input() __func__, plen); break; } - prefix = find_prefix(rai, addr, plen); - if (prefix == NULL) { - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s> prefix(%s/%d) was " - "deleted on %s, " - "but it was not in list", - __func__, - inet_ntop(AF_INET6, addr, - (char *)addrbuf, INET6_ADDRSTRLEN), - plen, rai->ifname); - } + pfx = find_prefix(rai, addr, plen); + if (pfx == NULL) { + syslog(LOG_DEBUG, + "<%s> prefix(%s/%d) was deleted on %s, " + "but it was not in list", + __func__, inet_ntop(AF_INET6, addr, + (char *)addrbuf, sizeof(addrbuf)), + plen, rai->rai_ifname); break; } - invalidate_prefix(prefix); + invalidate_prefix(pfx); prefixchange = 1; break; case RTM_NEWADDR: @@ -571,12 +667,10 @@ rtmsg_input() break; default: /* should not reach here */ - if (dflag > 1) { - syslog(LOG_DEBUG, - "<%s:%d> unknown rtmsg %d on %s", - __func__, __LINE__, type, - if_indextoname(ifindex, ifname)); - } + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __func__, __LINE__, type, + if_indextoname(ifindex, ifname)); return; } @@ -585,27 +679,29 @@ rtmsg_input() !(iflist[ifindex]->ifm_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes down. stop timer.", - __func__, rai->ifname); - rtadvd_remove_timer(&rai->timer); + __func__, rai->rai_ifname); + rtadvd_remove_timer(rai->rai_timer); + rai->rai_timer = NULL; } else if (!(oldifflags & IFF_UP) && /* DOWN to UP */ - (iflist[ifindex]->ifm_flags & IFF_UP)) { + (iflist[ifindex]->ifm_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes up. restart timer.", - __func__, rai->ifname); + __func__, rai->rai_ifname); - rai->initcounter = 0; /* reset the counter */ - rai->waiting = 0; /* XXX */ - rai->timer = rtadvd_add_timer(ra_timeout, + rai->rai_initcounter = 0; /* reset the counter */ + rai->rai_waiting = 0; /* XXX */ + rai->rai_timer = rtadvd_add_timer(ra_timeout, ra_timer_update, rai, rai); - ra_timer_update((void *)rai, &rai->timer->tm); - rtadvd_set_timer(&rai->timer->tm, rai->timer); + ra_timer_update(rai, &rai->rai_timer->rat_tm); + rtadvd_set_timer(&rai->rai_timer->rat_tm, + rai->rai_timer); } else if (prefixchange && (iflist[ifindex]->ifm_flags & IFF_UP)) { /* * An advertised prefix has been added or invalidated. * Will notice the change in a short delay. */ - rai->initcounter = 0; + rai->rai_initcounter = 0; set_short_delay(rai); } } @@ -614,13 +710,13 @@ rtmsg_input() } void -rtadvd_input() +rtadvd_input(void) { - int i; + ssize_t i; int *hlimp = NULL; #ifdef OLDRAWSOCKET struct ip6_hdr *ip; -#endif +#endif struct icmp6_hdr *icp; int ifindex = 0; struct cmsghdr *cm; @@ -655,14 +751,14 @@ rtadvd_input() } if (ifindex == 0) { syslog(LOG_ERR, - "<%s> failed to get receiving interface", - __func__); + "<%s> failed to get receiving interface", + __func__); return; } if (hlimp == NULL) { syslog(LOG_ERR, - "<%s> failed to get receiving hop limit", - __func__); + "<%s> failed to get receiving hop limit", + __func__); return; } @@ -673,28 +769,28 @@ rtadvd_input() if (iflist[pi->ipi6_ifindex] == NULL || (iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_INFO, - "<%s> received data on a disabled interface (%s)", - __func__, - (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" : - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> received data on a disabled interface (%s)", + __func__, + (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" : + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } #ifdef OLDRAWSOCKET - if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { + if ((size_t)i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, - "<%s> packet size(%d) is too short", - __func__, i); + "<%s> packet size(%d) is too short", + __func__, i); return; } ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ #else - if (i < sizeof(struct icmp6_hdr)) { + if ((size_t)i < sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, - "<%s> packet size(%d) is too short", - __func__, i); + "<%s> packet size(%d) is too short", + __func__, i); return; } @@ -704,7 +800,7 @@ rtadvd_input() switch (icp->icmp6_type) { case ND_ROUTER_SOLICIT: /* - * Message verification - RFC-2461 6.1.1 + * Message verification - RFC 4861 6.1.1 * XXX: these checks must be done in the kernel as well, * but we can't completely rely on them. */ @@ -714,7 +810,7 @@ rtadvd_input() "received from %s on %s", __func__, *hlimp, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -724,17 +820,17 @@ rtadvd_input() "received from %s on %s", __func__, icp->icmp6_code, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } - if (i < sizeof(struct nd_router_solicit)) { + if ((size_t)i < sizeof(struct nd_router_solicit)) { syslog(LOG_NOTICE, "<%s> RS from %s on %s does not have enough " "length (len = %d)", __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } @@ -742,16 +838,25 @@ rtadvd_input() break; case ND_ROUTER_ADVERT: /* - * Message verification - RFC-2461 6.1.2 - * XXX: there's a same dilemma as above... + * Message verification - RFC 4861 6.1.2 + * XXX: there's the same dilemma as above... */ + if (!IN6_IS_ADDR_LINKLOCAL(&rcvfrom.sin6_addr)) { + syslog(LOG_NOTICE, + "<%s> RA witn non-linklocal source address " + "received from %s on %s", + __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, + ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } if (*hlimp != 255) { syslog(LOG_NOTICE, "<%s> RA with invalid hop limit(%d) " "received from %s on %s", __func__, *hlimp, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } @@ -761,17 +866,17 @@ rtadvd_input() "received from %s on %s", __func__, icp->icmp6_code, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } - if (i < sizeof(struct nd_router_advert)) { + if ((size_t)i < sizeof(struct nd_router_advert)) { syslog(LOG_NOTICE, "<%s> RA from %s on %s does not have enough " "length (len = %d)", __func__, inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf, - INET6_ADDRSTRLEN), + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); return; } @@ -785,7 +890,7 @@ rtadvd_input() break; } rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom, - &dst); + &dst); break; default: /* @@ -806,17 +911,17 @@ static void rs_input(int len, struct nd_router_solicit *rs, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { - u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; - union nd_opts ndopts; - struct rainfo *ra; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char ifnamebuf[IFNAMSIZ]; + union nd_opt ndopts; + struct rainfo *rai; struct soliciter *sol; syslog(LOG_DEBUG, - "<%s> RS received from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> RS received from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); @@ -824,36 +929,33 @@ rs_input(int len, struct nd_router_solicit *rs, len - sizeof(struct nd_router_solicit), &ndopts, NDOPT_FLAG_SRCLINKADDR)) { syslog(LOG_INFO, - "<%s> ND option check failed for an RS from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> ND option check failed for an RS from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } /* * If the IP source address is the unspecified address, there * must be no source link-layer address option in the message. - * (RFC-2461 6.1.1) + * (RFC 4861 6.1.1) */ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && - ndopts.nd_opts_src_lladdr) { + ndopts.opt_src_lladdr) { syslog(LOG_INFO, - "<%s> RS from unspecified src on %s has a link-layer" - " address option", - __func__, - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> RS from unspecified src on %s has a link-layer" + " address option", + __func__, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } - ra = ralist; - while (ra != NULL) { - if (pi->ipi6_ifindex == ra->ifindex) + TAILQ_FOREACH(rai, &railist, rai_next) + if (pi->ipi6_ifindex == (unsigned int)rai->rai_ifindex) break; - ra = ra->next; - } - if (ra == NULL) { + + if (rai == NULL) { syslog(LOG_INFO, "<%s> RS received on non advertising interface(%s)", __func__, @@ -861,7 +963,7 @@ rs_input(int len, struct nd_router_solicit *rs, goto done; } - ra->rsinput++; /* increment statistics */ + rai->rai_rsinput++; /* increment statistics */ /* * Decide whether to send RA according to the rate-limit @@ -871,21 +973,20 @@ rs_input(int len, struct nd_router_solicit *rs, /* record sockaddr waiting for RA, if possible */ sol = (struct soliciter *)malloc(sizeof(*sol)); if (sol) { - sol->addr = *from; - /* XXX RFC2553 need clarification on flowinfo */ - sol->addr.sin6_flowinfo = 0; - sol->next = ra->soliciter; - ra->soliciter = sol; + sol->sol_addr = *from; + /* XXX RFC 2553 need clarification on flowinfo */ + sol->sol_addr.sin6_flowinfo = 0; + TAILQ_INSERT_TAIL(&rai->rai_soliciter, sol, sol_next); } /* * If there is already a waiting RS packet, don't * update the timer. */ - if (ra->waiting++) + if (rai->rai_waiting++) goto done; - set_short_delay(ra); + set_short_delay(rai); done: free_ndopts(&ndopts); @@ -893,8 +994,7 @@ rs_input(int len, struct nd_router_solicit *rs, } static void -set_short_delay(rai) - struct rainfo *rai; +set_short_delay(struct rainfo *rai) { long delay; /* must not be greater than 1000000 */ struct timeval interval, now, min_delay, tm_tmp, *rest; @@ -904,7 +1004,7 @@ set_short_delay(rai) * corresponds to a time later than the time the next * multicast RA is scheduled to be sent, ignore the random * delay and send the advertisement at the - * already-scheduled time. RFC-2461 6.2.6 + * already-scheduled time. RFC 4861 6.2.6 */ #ifdef HAVE_ARC4RANDOM delay = arc4random_uniform(MAX_RA_DELAY_TIME); @@ -913,8 +1013,8 @@ set_short_delay(rai) #endif interval.tv_sec = 0; interval.tv_usec = delay; - rest = rtadvd_timer_rest(rai->timer); - if (TIMEVAL_LT(*rest, interval)) { + rest = rtadvd_timer_rest(rai->rai_timer); + if (TIMEVAL_LT(rest, &interval)) { syslog(LOG_DEBUG, "<%s> random delay is larger than " "the rest of the current timer", __func__); interval = *rest; @@ -928,170 +1028,217 @@ set_short_delay(rai) * previous advertisement was sent. */ gettimeofday(&now, NULL); - TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp); + TIMEVAL_SUB(&now, &rai->rai_lastsent, &tm_tmp); min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; min_delay.tv_usec = 0; - if (TIMEVAL_LT(tm_tmp, min_delay)) { + if (TIMEVAL_LT(&tm_tmp, &min_delay)) { TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); TIMEVAL_ADD(&min_delay, &interval, &interval); } - rtadvd_set_timer(&interval, rai->timer); + rtadvd_set_timer(&interval, rai->rai_timer); +} + +static int +check_accept_rtadv(int idx) +{ + struct in6_ndireq nd; + u_char ifname[IFNAMSIZ]; + int s6; + int error; + + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, + "<%s> open socket failed for idx=%d.", + __func__, idx); + return (0); + } + if ((if_indextoname(idx, ifname)) == NULL) { + syslog(LOG_ERR, + "<%s> ifindex->ifname failed (idx=%d).", + __func__, idx); + close(s6); + return (0); + } + memset(&nd, 0, sizeof(nd)); + strncpy(nd.ifname, ifname, sizeof(nd.ifname)); + error = ioctl(s6, SIOCGIFINFO_IN6, &nd); + if (error) { + syslog(LOG_ERR, + "<%s> ioctl(SIOCGIFINFO_IN6) failed for idx=%d.", + __func__, idx); + nd.ndi.flags = 0; + } + close(s6); + + return (nd.ndi.flags & ND6_IFF_ACCEPT_RTADV); +} + +static int +getinet6sysctl(int code) +{ + int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; + int value; + size_t size; + + mib[3] = code; + size = sizeof(value); + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) + < 0) { + syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", + __func__, code, + strerror(errno)); + return (-1); + } + else + return (value); } static void -ra_input(int len, struct nd_router_advert *ra, +ra_input(int len, struct nd_router_advert *nra, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { struct rainfo *rai; - u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; - union nd_opts ndopts; - char *on_off[] = {"OFF", "ON"}; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char ifnamebuf[IFNAMSIZ]; + union nd_opt ndopts; + const char *on_off[] = {"OFF", "ON"}; u_int32_t reachabletime, retranstimer, mtu; int inconsistent = 0; + int error; + + syslog(LOG_DEBUG, "<%s> RA received from %s on %s", __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + if (!check_accept_rtadv(pi->ipi6_ifindex)) { + syslog(LOG_INFO, + "<%s> An RA from %s on %s ignored (no ACCEPT_RTADV flag).", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); + return; + } - syslog(LOG_DEBUG, - "<%s> RA received from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); - /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); - if (nd6_options((struct nd_opt_hdr *)(ra + 1), - len - sizeof(struct nd_router_advert), - &ndopts, NDOPT_FLAG_SRCLINKADDR | - NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + error = nd6_options((struct nd_opt_hdr *)(nra + 1), + len - sizeof(struct nd_router_advert), &ndopts, + NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU | + NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL); + if (error) { syslog(LOG_INFO, - "<%s> ND option check failed for an RA from %s on %s", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> ND option check failed for an RA from %s on %s", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); return; } /* - * RA consistency check according to RFC-2461 6.2.7 + * RA consistency check according to RFC 4861 6.2.7 */ - if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { + rai = if_indextorainfo(pi->ipi6_ifindex); + if (rai == NULL) { syslog(LOG_INFO, - "<%s> received RA from %s on non-advertising" - " interface(%s)", - __func__, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + "<%s> received RA from %s on non-advertising" + " interface(%s)", + __func__, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), if_indextoname(pi->ipi6_ifindex, + ifnamebuf)); goto done; } - rai->rainput++; /* increment statistics */ - + rai->rai_rainput++; /* increment statistics */ + /* Cur Hop Limit value */ - if (ra->nd_ra_curhoplimit && rai->hoplimit && - ra->nd_ra_curhoplimit != rai->hoplimit) { + if (nra->nd_ra_curhoplimit && rai->rai_hoplimit && + nra->nd_ra_curhoplimit != rai->rai_hoplimit) { syslog(LOG_INFO, - "<%s> CurHopLimit inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - ra->nd_ra_curhoplimit, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->hoplimit); + "<%s> CurHopLimit inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, nra->nd_ra_curhoplimit, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_hoplimit); inconsistent++; } /* M flag */ - if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != - rai->managedflg) { + if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != + rai->rai_managedflg) { syslog(LOG_INFO, - "<%s> M flag inconsistent on %s:" - " %s from %s, %s from us", - __func__, - rai->ifname, - on_off[!rai->managedflg], - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - on_off[rai->managedflg]); + "<%s> M flag inconsistent on %s:" + " %s from %s, %s from us", + __func__, rai->rai_ifname, on_off[!rai->rai_managedflg], + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), on_off[rai->rai_managedflg]); inconsistent++; } /* O flag */ - if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != - rai->otherflg) { + if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != + rai->rai_otherflg) { syslog(LOG_INFO, - "<%s> O flag inconsistent on %s:" - " %s from %s, %s from us", - __func__, - rai->ifname, - on_off[!rai->otherflg], - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - on_off[rai->otherflg]); + "<%s> O flag inconsistent on %s:" + " %s from %s, %s from us", + __func__, rai->rai_ifname, on_off[!rai->rai_otherflg], + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), on_off[rai->rai_otherflg]); inconsistent++; } /* Reachable Time */ - reachabletime = ntohl(ra->nd_ra_reachable); - if (reachabletime && rai->reachabletime && - reachabletime != rai->reachabletime) { + reachabletime = ntohl(nra->nd_ra_reachable); + if (reachabletime && rai->rai_reachabletime && + reachabletime != rai->rai_reachabletime) { syslog(LOG_INFO, - "<%s> ReachableTime inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - reachabletime, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->reachabletime); + "<%s> ReachableTime inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, reachabletime, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_reachabletime); inconsistent++; } /* Retrans Timer */ - retranstimer = ntohl(ra->nd_ra_retransmit); - if (retranstimer && rai->retranstimer && - retranstimer != rai->retranstimer) { + retranstimer = ntohl(nra->nd_ra_retransmit); + if (retranstimer && rai->rai_retranstimer && + retranstimer != rai->rai_retranstimer) { syslog(LOG_INFO, - "<%s> RetranceTimer inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, - retranstimer, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->retranstimer); + "<%s> RetranceTimer inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, retranstimer, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_retranstimer); inconsistent++; } /* Values in the MTU options */ - if (ndopts.nd_opts_mtu) { - mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); - if (mtu && rai->linkmtu && mtu != rai->linkmtu) { + if (ndopts.opt_mtu) { + mtu = ntohl(ndopts.opt_mtu->nd_opt_mtu_mtu); + if (mtu && rai->rai_linkmtu && mtu != rai->rai_linkmtu) { syslog(LOG_INFO, - "<%s> MTU option value inconsistent on %s:" - " %d from %s, %d from us", - __func__, - rai->ifname, mtu, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->linkmtu); + "<%s> MTU option value inconsistent on %s:" + " %d from %s, %d from us", + __func__, rai->rai_ifname, mtu, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_linkmtu); inconsistent++; } } /* Preferred and Valid Lifetimes for prefixes */ { - struct nd_optlist *optp = ndopts.nd_opts_list; + struct nd_optlist *nol; - if (ndopts.nd_opts_pi) { - if (prefix_check(ndopts.nd_opts_pi, rai, from)) + if (ndopts.opt_pi) + if (prefix_check(ndopts.opt_pi, rai, from)) inconsistent++; - } - while (optp) { - if (prefix_check((struct nd_opt_prefix_info *)optp->opt, - rai, from)) + + TAILQ_FOREACH(nol, &ndopts.opt_list, nol_next) + if (prefix_check((struct nd_opt_prefix_info *)nol->nol_opt, + rai, from)) inconsistent++; - optp = optp->next; - } } if (inconsistent) - rai->rainconsistent++; - + rai->rai_rainconsistent++; + done: free_ndopts(&ndopts); return; @@ -1100,51 +1247,49 @@ ra_input(int len, struct nd_router_advert *ra, /* return a non-zero value if the received prefix is inconsitent with ours */ static int prefix_check(struct nd_opt_prefix_info *pinfo, - struct rainfo *rai, struct sockaddr_in6 *from) + struct rainfo *rai, struct sockaddr_in6 *from) { u_int32_t preferred_time, valid_time; - struct prefix *pp; + struct prefix *pfx; int inconsistent = 0; - u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; + u_char ntopbuf[INET6_ADDRSTRLEN]; + u_char prefixbuf[INET6_ADDRSTRLEN]; struct timeval now; #if 0 /* impossible */ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) - return(0); + return (0); #endif /* * log if the adveritsed prefix has link-local scope(sanity check?) */ - if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { + if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) syslog(LOG_INFO, - "<%s> link-local prefix %s/%d is advertised " - "from %s on %s", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->ifname); - } - - if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, - pinfo->nd_opt_pi_prefix_len)) == NULL) { + "<%s> link-local prefix %s/%d is advertised " + "from %s on %s", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_ifname); + + if ((pfx = find_prefix(rai, &pinfo->nd_opt_pi_prefix, + pinfo->nd_opt_pi_prefix_len)) == NULL) { syslog(LOG_INFO, - "<%s> prefix %s/%d from %s on %s is not in our list", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - rai->ifname); - return(0); + "<%s> prefix %s/%d from %s on %s is not in our list", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), rai->rai_ifname); + return (0); } preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); - if (pp->pltimeexpire) { + if (pfx->pfx_pltimeexpire) { /* * The lifetime is decremented in real time, so we should * compare the expiration time. @@ -1155,134 +1300,135 @@ prefix_check(struct nd_opt_prefix_info *pinfo, gettimeofday(&now, NULL); preferred_time += now.tv_sec; - if (!pp->timer && rai->clockskew && - abs(preferred_time - pp->pltimeexpire) > rai->clockskew) { + if (!pfx->pfx_timer && rai->rai_clockskew && + abs(preferred_time - pfx->pfx_pltimeexpire) > rai->rai_clockskew) { syslog(LOG_INFO, - "<%s> preferred lifetime for %s/%d" - " (decr. in real time) inconsistent on %s:" - " %d from %s, %ld from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->pltimeexpire); + "<%s> preferred lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_pltimeexpire); inconsistent++; } - } else if (!pp->timer && preferred_time != pp->preflifetime) { + } else if (!pfx->pfx_timer && preferred_time != pfx->pfx_preflifetime) syslog(LOG_INFO, - "<%s> preferred lifetime for %s/%d" - " inconsistent on %s:" - " %d from %s, %d from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->preflifetime); - } + "<%s> preferred lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_preflifetime); valid_time = ntohl(pinfo->nd_opt_pi_valid_time); - if (pp->vltimeexpire) { + if (pfx->pfx_vltimeexpire) { gettimeofday(&now, NULL); valid_time += now.tv_sec; - if (!pp->timer && rai->clockskew && - abs(valid_time - pp->vltimeexpire) > rai->clockskew) { + if (!pfx->pfx_timer && rai->rai_clockskew && + abs(valid_time - pfx->pfx_vltimeexpire) > rai->rai_clockskew) { syslog(LOG_INFO, - "<%s> valid lifetime for %s/%d" - " (decr. in real time) inconsistent on %s:" - " %d from %s, %ld from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, preferred_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->vltimeexpire); + "<%s> valid lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_vltimeexpire); inconsistent++; } - } else if (!pp->timer && valid_time != pp->validlifetime) { + } else if (!pfx->pfx_timer && valid_time != pfx->pfx_validlifetime) { syslog(LOG_INFO, - "<%s> valid lifetime for %s/%d" - " inconsistent on %s:" - " %d from %s, %d from us", - __func__, - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - prefixbuf, INET6_ADDRSTRLEN), - pinfo->nd_opt_pi_prefix_len, - rai->ifname, valid_time, - inet_ntop(AF_INET6, &from->sin6_addr, - ntopbuf, INET6_ADDRSTRLEN), - pp->validlifetime); + "<%s> valid lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __func__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, + sizeof(prefixbuf)), + pinfo->nd_opt_pi_prefix_len, + rai->rai_ifname, valid_time, + inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, + sizeof(ntopbuf)), pfx->pfx_validlifetime); inconsistent++; } - return(inconsistent); + return (inconsistent); } struct prefix * find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) { - struct prefix *pp; + struct prefix *pfx; int bytelen, bitlen; u_char bitmask; - for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { - if (plen != pp->prefixlen) + TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) { + if (plen != pfx->pfx_prefixlen) continue; + bytelen = plen / 8; bitlen = plen % 8; bitmask = 0xff << (8 - bitlen); - if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) + + if (memcmp((void *)prefix, (void *)&pfx->pfx_prefix, bytelen)) continue; + if (bitlen == 0 || - ((prefix->s6_addr[bytelen] & bitmask) == - (pp->prefix.s6_addr[bytelen] & bitmask))) { - return(pp); + ((prefix->s6_addr[bytelen] & bitmask) == + (pfx->pfx_prefix.s6_addr[bytelen] & bitmask))) { + return (pfx); } } - return(NULL); + return (NULL); } /* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ int prefix_match(struct in6_addr *p0, int plen0, - struct in6_addr *p1, int plen1) + struct in6_addr *p1, int plen1) { int bytelen, bitlen; u_char bitmask; if (plen0 < plen1) - return(0); + return (0); + bytelen = plen1 / 8; bitlen = plen1 % 8; bitmask = 0xff << (8 - bitlen); + if (memcmp((void *)p0, (void *)p1, bytelen)) - return(0); + return (0); + if (bitlen == 0 || ((p0->s6_addr[bytelen] & bitmask) == (p1->s6_addr[bytelen] & bitmask))) { - return(1); + return (1); } - return(0); + return (0); } static int nd6_options(struct nd_opt_hdr *hdr, int limit, - union nd_opts *ndopts, u_int32_t optflags) + union nd_opt *ndopts, u_int32_t optflags) { int optlen = 0; for (; limit > 0; limit -= optlen) { - if (limit < sizeof(struct nd_opt_hdr)) { + if ((size_t)limit < sizeof(struct nd_opt_hdr)) { syslog(LOG_INFO, "<%s> short option header", __func__); goto bad; } @@ -1300,7 +1446,9 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, goto bad; } - if (hdr->nd_opt_type > ND_OPT_MTU) { + if (hdr->nd_opt_type > ND_OPT_MTU && + hdr->nd_opt_type != ND_OPT_RDNSS && + hdr->nd_opt_type != ND_OPT_DNSSL) { syslog(LOG_INFO, "<%s> unknown ND option(type %d)", __func__, hdr->nd_opt_type); continue; @@ -1316,10 +1464,25 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, * Option length check. Do it here for all fixed-length * options. */ - if ((hdr->nd_opt_type == ND_OPT_MTU && - (optlen != sizeof(struct nd_opt_mtu))) || - ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION && - optlen != sizeof(struct nd_opt_prefix_info)))) { + switch (hdr->nd_opt_type) { + case ND_OPT_MTU: + if (optlen == sizeof(struct nd_opt_mtu)) + break; + goto skip; + case ND_OPT_RDNSS: + if (optlen >= 24 && + (optlen - sizeof(struct nd_opt_rdnss)) % 16 == 0) + break; + goto skip; + case ND_OPT_DNSSL: + if (optlen >= 16 && + (optlen - sizeof(struct nd_opt_dnssl)) % 8 == 0) + break; + goto skip; + case ND_OPT_PREFIX_INFORMATION: + if (optlen == sizeof(struct nd_opt_prefix_info)) + break; +skip: syslog(LOG_INFO, "<%s> invalid option length", __func__); continue; @@ -1328,33 +1491,35 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, switch (hdr->nd_opt_type) { case ND_OPT_TARGET_LINKADDR: case ND_OPT_REDIRECTED_HEADER: + case ND_OPT_RDNSS: + case ND_OPT_DNSSL: break; /* we don't care about these options */ case ND_OPT_SOURCE_LINKADDR: case ND_OPT_MTU: - if (ndopts->nd_opt_array[hdr->nd_opt_type]) { + if (ndopts->opt_array[hdr->nd_opt_type]) { syslog(LOG_INFO, "<%s> duplicated ND option (type = %d)", __func__, hdr->nd_opt_type); } - ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; + ndopts->opt_array[hdr->nd_opt_type] = hdr; break; case ND_OPT_PREFIX_INFORMATION: { - struct nd_optlist *pfxlist; + struct nd_optlist *nol; - if (ndopts->nd_opts_pi == 0) { - ndopts->nd_opts_pi = + if (ndopts->opt_pi == 0) { + ndopts->opt_pi = (struct nd_opt_prefix_info *)hdr; continue; } - if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { + nol = malloc(sizeof(*nol)); + if (nol == NULL) { syslog(LOG_ERR, "<%s> can't allocate memory", __func__); goto bad; } - pfxlist->next = ndopts->nd_opts_list; - pfxlist->opt = hdr; - ndopts->nd_opts_list = pfxlist; + nol->nol_opt = hdr; + TAILQ_INSERT_TAIL(&(ndopts->opt_list), nol, nol_next); break; } @@ -1363,46 +1528,45 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, } } - return(0); + return (0); bad: free_ndopts(ndopts); - return(-1); + return (-1); } static void -free_ndopts(union nd_opts *ndopts) +free_ndopts(union nd_opt *ndopts) { - struct nd_optlist *opt = ndopts->nd_opts_list, *next; + struct nd_optlist *nol; - while (opt) { - next = opt->next; - free(opt); - opt = next; + while ((nol = TAILQ_FIRST(&ndopts->opt_list)) != NULL) { + TAILQ_REMOVE(&ndopts->opt_list, nol, nol_next); + free(nol); } } void -sock_open() +sock_open(void) { struct icmp6_filter filt; struct ipv6_mreq mreq; - struct rainfo *ra = ralist; + struct rainfo *rai; int on; /* XXX: should be max MTU attached to the node */ static u_char answer[1500]; rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); + CMSG_SPACE(sizeof(int)); rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); if (rcvcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __func__); exit(1); } - sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); + sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); if (sndcmsgbuf == NULL) { syslog(LOG_ERR, "<%s> not enough core", __func__); @@ -1410,113 +1574,84 @@ sock_open() } if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { - syslog(LOG_ERR, "<%s> socket: %s", __func__, - strerror(errno)); + syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno)); exit(1); } - /* specify to tell receiving interface */ on = 1; -#ifdef IPV6_RECVPKTINFO if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", - __func__, strerror(errno)); + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__, + strerror(errno)); exit(1); } -#else /* old adv. API */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", - __func__, strerror(errno)); - exit(1); - } -#endif - on = 1; /* specify to tell value of hoplimit field of received IP6 hdr */ -#ifdef IPV6_RECVHOPLIMIT if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", - __func__, strerror(errno)); + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __func__, + strerror(errno)); exit(1); } -#else /* old adv. API */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, - sizeof(on)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", - __func__, strerror(errno)); - exit(1); - } -#endif - ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (accept_rr) ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); + if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) < 0) { + sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", - __func__, strerror(errno)); + __func__, strerror(errno)); exit(1); } /* * join all routers multicast address on each advertising interface. */ - if (inet_pton(AF_INET6, ALLROUTERS_LINK, - &mreq.ipv6mr_multiaddr.s6_addr) - != 1) { - syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", - __func__); - exit(1); - } - while (ra) { - mreq.ipv6mr_interface = ra->ifindex; + memcpy(&mreq.ipv6mr_multiaddr.s6_addr, + &sin6_linklocal_allrouters.sin6_addr, + sizeof(mreq.ipv6mr_multiaddr.s6_addr)); + TAILQ_FOREACH(rai, &railist, rai_next) { + mreq.ipv6mr_interface = rai->rai_ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, - sizeof(mreq)) < 0) { + sizeof(mreq)) < 0) { syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s", - __func__, ra->ifname, strerror(errno)); + __func__, rai->rai_ifname, strerror(errno)); exit(1); } - ra = ra->next; } /* * When attending router renumbering, join all-routers site-local - * multicast group. + * multicast group. */ if (accept_rr) { - if (inet_pton(AF_INET6, ALLROUTERS_SITE, - &in6a_site_allrouters) != 1) { - syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", - __func__); - exit(1); - } - mreq.ipv6mr_multiaddr = in6a_site_allrouters; + memcpy(&mreq.ipv6mr_multiaddr.s6_addr, + &sin6_sitelocal_allrouters.sin6_addr, + sizeof(mreq.ipv6mr_multiaddr.s6_addr)); if (mcastif) { if ((mreq.ipv6mr_interface = if_nametoindex(mcastif)) == 0) { syslog(LOG_ERR, - "<%s> invalid interface: %s", - __func__, mcastif); + "<%s> invalid interface: %s", + __func__, mcastif); exit(1); } } else - mreq.ipv6mr_interface = ralist->ifindex; + mreq.ipv6mr_interface = + TAILQ_FIRST(&railist)->rai_ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, sizeof(mreq)) < 0) { + &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, - "<%s> IPV6_JOIN_GROUP(site) on %s: %s", - __func__, - mcastif ? mcastif : ralist->ifname, - strerror(errno)); + "<%s> IPV6_JOIN_GROUP(site) on %s: %s", __func__, + mcastif ? mcastif : + TAILQ_FIRST(&railist)->rai_ifname, + strerror(errno)); exit(1); } } - + /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; rcviov[0].iov_len = sizeof(answer); @@ -1533,17 +1668,17 @@ sock_open() sndmhdr.msg_iovlen = 1; sndmhdr.msg_control = (caddr_t)sndcmsgbuf; sndmhdr.msg_controllen = sndcmsgbuflen; - + return; } /* open a routing socket to watch the routing table */ static void -rtsock_open() +rtsock_open(void) { if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { syslog(LOG_ERR, - "<%s> socket: %s", __func__, strerror(errno)); + "<%s> socket: %s", __func__, strerror(errno)); exit(1); } } @@ -1551,36 +1686,72 @@ rtsock_open() struct rainfo * if_indextorainfo(int idx) { - struct rainfo *rai = ralist; + struct rainfo *rai; - for (rai = ralist; rai; rai = rai->next) { - if (rai->ifindex == idx) - return(rai); + TAILQ_FOREACH(rai, &railist, rai_next) { + syslog(LOG_DEBUG, "<%s> rai->rai_ifindex %d == idx %d?", + __func__, rai->rai_ifindex, idx); + if (rai->rai_ifindex == idx) + return (rai); } - return(NULL); /* search failed */ + return (NULL); /* search failed */ } static void -ra_output(rainfo) -struct rainfo *rainfo; +ra_output(struct rainfo *rai) { int i; struct cmsghdr *cm; struct in6_pktinfo *pi; - struct soliciter *sol, *nextsol; + struct soliciter *sol; - if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) { + if ((iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) == 0) { syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", - __func__, rainfo->ifname); + __func__, rai->rai_ifname); return; } - make_packet(rainfo); /* XXX: inefficient */ + /* + * Check lifetime, ACCEPT_RTADV flag, and ip6.forwarding. + * + * (lifetime == 0) = output + * (lifetime != 0 && (ACCEPT_RTADV || !ip6.forwarding) = no output + * + * Basically, hosts MUST NOT send Router Advertisement + * messages at any time (RFC 4861, Section 6.2.3). However, it + * would sometimes be useful to allow hosts to advertise some + * parameters such as prefix information and link MTU. Thus, + * we allow hosts to invoke rtadvd only when router lifetime + * (on every advertising interface) is explicitly set + * zero. (see also the above section) + */ + syslog(LOG_DEBUG, + "<%s> check lifetime=%d, ACCEPT_RTADV=%d, ip6.forwarding=%d on %s", + __func__, rai->rai_lifetime, check_accept_rtadv(rai->rai_ifindex), + getinet6sysctl(IPV6CTL_FORWARDING), rai->rai_ifname); + if (rai->rai_lifetime != 0) { + if (check_accept_rtadv(rai->rai_ifindex)) { + syslog(LOG_INFO, + "<%s> non-zero lifetime RA " + "on RA receiving interface %s." + " Ignored.", __func__, rai->rai_ifname); + return; + } + if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { + syslog(LOG_INFO, + "<%s> non-zero lifetime RA " + "but net.inet6.ip6.forwarding=0. " + "Ignored.", __func__); + return; + } + } + + make_packet(rai); /* XXX: inefficient */ - sndmhdr.msg_name = (caddr_t)&sin6_allnodes; - sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; - sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; + sndmhdr.msg_name = (caddr_t)&sin6_linklocal_allnodes; + sndmhdr.msg_iov[0].iov_base = (caddr_t)rai->rai_ra_data; + sndmhdr.msg_iov[0].iov_len = rai->rai_ra_datalen; cm = CMSG_FIRSTHDR(&sndmhdr); /* specify the outgoing interface */ @@ -1589,7 +1760,7 @@ struct rainfo *rainfo; cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pi = (struct in6_pktinfo *)CMSG_DATA(cm); memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ - pi->ipi6_ifindex = rainfo->ifindex; + pi->ipi6_ifindex = rai->rai_ifindex; /* specify the hop limit of the packet */ { @@ -1603,80 +1774,79 @@ struct rainfo *rainfo; } syslog(LOG_DEBUG, - "<%s> send RA on %s, # of waitings = %d", - __func__, rainfo->ifname, rainfo->waiting); + "<%s> send RA on %s, # of waitings = %d", + __func__, rai->rai_ifname, rai->rai_waiting); i = sendmsg(sock, &sndmhdr, 0); - if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0 || (size_t)i != rai->rai_ra_datalen) { if (i < 0) { syslog(LOG_ERR, "<%s> sendmsg on %s: %s", - __func__, rainfo->ifname, - strerror(errno)); + __func__, rai->rai_ifname, + strerror(errno)); } } /* update counter */ - if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) - rainfo->initcounter++; - rainfo->raoutput++; + if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) + rai->rai_initcounter++; + rai->rai_raoutput++; /* * unicast advertisements * XXX commented out. reason: though spec does not forbit it, unicast * advert does not really help */ - for (sol = rainfo->soliciter; sol; sol = nextsol) { - nextsol = sol->next; - - sol->next = NULL; + while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { + TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); free(sol); } - rainfo->soliciter = NULL; /* update timestamp */ - gettimeofday(&rainfo->lastsent, NULL); + gettimeofday(&rai->rai_lastsent, NULL); /* reset waiting conter */ - rainfo->waiting = 0; + rai->rai_waiting = 0; } /* process RA timer */ struct rtadvd_timer * -ra_timeout(void *data) +ra_timeout(void *arg) { - struct rainfo *rai = (struct rainfo *)data; + struct rainfo *rai; #ifdef notyet /* if necessary, reconstruct the packet. */ #endif - - syslog(LOG_DEBUG, - "<%s> RA timer on %s is expired", - __func__, rai->ifname); + rai = (struct rainfo *)arg; + syslog(LOG_DEBUG, "<%s> RA timer on %s is expired", + __func__, rai->rai_ifname); ra_output(rai); - return(rai->timer); + return (rai->rai_timer); } /* update RA timer */ void -ra_timer_update(void *data, struct timeval *tm) +ra_timer_update(void *arg, struct timeval *tm) { - struct rainfo *rai = (struct rainfo *)data; long interval; + struct rainfo *rai; + rai = (struct rainfo *)arg; /* * Whenever a multicast advertisement is sent from an interface, * the timer is reset to a uniformly-distributed random value * between the interface's configured MinRtrAdvInterval and * MaxRtrAdvInterval (RFC2461 6.2.4). */ - interval = rai->mininterval; + interval = rai->rai_mininterval; #ifdef HAVE_ARC4RANDOM - interval += arc4random_uniform(rai->maxinterval - rai->mininterval); + interval += arc4random_uniform(rai->rai_maxinterval - + rai->rai_mininterval); #else - interval += random() % (rai->maxinterval - rai->mininterval); + interval += random() % (rai->rai_maxinterval - + rai->rai_mininterval); #endif /* @@ -1684,9 +1854,9 @@ ra_timer_update(void *data, struct timeval *tm) * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. - * (RFC-2461 6.2.4) + * (RFC 4861 6.2.4) */ - if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && + if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; @@ -1694,9 +1864,9 @@ ra_timer_update(void *data, struct timeval *tm) tm->tv_usec = 0; syslog(LOG_DEBUG, - "<%s> RA timer on %s is set to %ld:%ld", - __func__, rai->ifname, - (long int)tm->tv_sec, (long int)tm->tv_usec); + "<%s> RA timer on %s is set to %ld:%ld", + __func__, rai->rai_ifname, + (long int)tm->tv_sec, (long int)tm->tv_usec); return; } |