diff options
author | hrs <hrs@FreeBSD.org> | 2011-07-14 10:09:58 +0000 |
---|---|---|
committer | hrs <hrs@FreeBSD.org> | 2011-07-14 10:09:58 +0000 |
commit | cdcbea6ad239dd44f37a01b119599e17dac4a5a8 (patch) | |
tree | c97e2a5f6ba4790dc756b51374a4d00de9f4ecae /usr.sbin/rtadvd/rtadvd.c | |
parent | 90aa2cef03ff2efa8e9af771632eb3d02d0df168 (diff) | |
download | FreeBSD-src-cdcbea6ad239dd44f37a01b119599e17dac4a5a8.zip FreeBSD-src-cdcbea6ad239dd44f37a01b119599e17dac4a5a8.tar.gz |
- Refactoring the interface list. It now supports dynamically
added/removed interfaces in a more consistent manner and reloading
the configuration file.
- Add initial support for control socket. RA information in the
daemon can be obtained by rtadvctl(8) instead of SIGUSR1 in a similar
manner to ifconfig(8). The information dump has been removed in favor of it.
(reload the configuration file)
# rtadvctl reload
(show RA messages being sent on each interfaces)
# rtadvctl show
em0: flags=<UP,CONFIGURED,PERSIST> status=<RA_SEND> mtu 1280
DefaultLifetime: 30m
MinAdvInterval/MaxAdvInterval: 3m20s/3m20s
AdvLinkMTU: <none>, Flags: O, Preference: medium
ReachableTime: 0s, RetransTimer: 0s, CurHopLimit: 64
AdvIfPrefixes: yes
(show RA messages being sent only on em0)
# rtadvctl show em0
(rtadvctl -v show provides additional information)
# rtadvctl -v show em0
em0: flags=<UP,CONFIGURED,PERSIST> status=<RA_SEND> mtu 1280
DefaultLifetime: 30m
MinAdvInterval/MaxAdvInterval: 3m20s/3m20s
AdvLinkMTU: <none>, Flags: O, Preference: medium
ReachableTime: 0s, RetransTimer: 0s, CurHopLimit: 64
AdvIfPrefixes: yes
Prefixes (1):
2001:db8:1::/64 (CONFIG, vltime=30d, pltime=7d, flags=LA)
RDNSS entries:
2001:db8:1::128 (ltime=2m40s)
(stop rtadvd)
# rtadvctl shutdown
A remaining issue when reloading the configuration file is that
during that period rtadvd cannot communicate with rtadvctl due to some
additional RA sending for graceful shutdown. This will be fixed later.
Diffstat (limited to 'usr.sbin/rtadvd/rtadvd.c')
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 635 |
1 files changed, 283 insertions, 352 deletions
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index 72fb46e..d67280a 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -3,6 +3,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,12 +37,14 @@ #include <sys/uio.h> #include <sys/time.h> #include <sys/queue.h> +#include <sys/stat.h> #include <sys/sysctl.h> #include <net/if.h> +#include <net/if_types.h> #include <net/if_media.h> -#include <net/route.h> #include <net/if_dl.h> +#include <net/route.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> @@ -60,6 +63,7 @@ #include <errno.h> #include <libutil.h> #include <netdb.h> +#include <signal.h> #include <string.h> #include <stdlib.h> #include <syslog.h> @@ -67,41 +71,44 @@ #include <poll.h> #endif +#include "pathnames.h" #include "rtadvd.h" +#include "if.h" #include "rrenum.h" #include "advcap.h" +#include "timer_subr.h" #include "timer.h" -#include "if.h" #include "config.h" -#include "dump.h" -#include "pathnames.h" +#include "control.h" +#include "control_server.h" + +#define RTADV_TYPE2BITMASK(type) (0x1 << type) struct msghdr rcvmhdr; static u_char *rcvcmsgbuf; static size_t rcvcmsgbuflen; static u_char *sndcmsgbuf = NULL; static size_t sndcmsgbuflen; -volatile sig_atomic_t do_dump; -volatile sig_atomic_t do_die; -volatile sig_atomic_t do_reload; struct msghdr sndmhdr; struct iovec rcviov[2]; struct iovec sndiov[2]; struct sockaddr_in6 rcvfrom; -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; + +#ifdef HAVE_POLL_H +#define PFD_RAWSOCK 0 +#define PFD_RTSOCK 1 +#define PFD_CSOCK 2 +#define PFD_MAX 3 +#endif struct railist_head_t railist = TAILQ_HEAD_INITIALIZER(railist); +struct ifilist_head_t ifilist = + TAILQ_HEAD_INITIALIZER(ifilist); struct nd_optlist { TAILQ_ENTRY(nd_optlist) nol_next; @@ -144,30 +151,10 @@ u_int32_t ndopt_flags[] = { [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, -}; - -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_reload(int); -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 sock_open(struct sockinfo *); +static void rtsock_open(struct sockinfo *); +static void rtadvd_input(struct sockinfo *); static void rs_input(int, struct nd_router_solicit *, struct in6_pktinfo *, struct sockaddr_in6 *); static void ra_input(int, struct nd_router_advert *, @@ -177,18 +164,15 @@ static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *, static int nd6_options(struct nd_opt_hdr *, int, union nd_opt *, u_int32_t); static void free_ndopts(union nd_opt *); -static void rtmsg_input(void); -static void rtadvd_set_dump_file(int); +static void rtmsg_input(struct sockinfo *); 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(int argc, char *argv[]) { #ifdef HAVE_POLL_H - struct pollfd set[2]; + struct pollfd set[PFD_MAX]; #else fd_set *fdsetp, *selectfdp; int fdmasks; @@ -197,14 +181,18 @@ main(int argc, char *argv[]) struct timeval *timeout; int i, ch; int fflag = 0, logopt; + int error; pid_t pid, otherpid; /* get command line options and arguments */ - while ((ch = getopt(argc, argv, "c:dDfF:M:p:Rs")) != -1) { + while ((ch = getopt(argc, argv, "c:C:dDfM:p:Rs")) != -1) { switch (ch) { case 'c': conffile = optarg; break; + case 'C': + ctrlsock.si_name = optarg; + break; case 'd': dflag++; break; @@ -229,9 +217,6 @@ main(int argc, char *argv[]) case 'p': pidfilename = optarg; break; - case 'F': - dumpfilename = optarg; - break; } } argc -= optind; @@ -239,7 +224,7 @@ main(int argc, char *argv[]) if (argc == 0) { fprintf(stderr, "usage: rtadvd [-dDfRs] [-c conffile] " - "[-F dumpfile] [-M ifname] " + "[-C ctrlsockname] [-M ifname] " "[-p pidfile] interfaces...\n"); exit(1); } @@ -268,13 +253,6 @@ main(int argc, char *argv[]) srandom((u_long)time(NULL)); #endif #endif - /* get iflist block from kernel */ - init_iflist(); - ifl_names = argv; - ifl_len = argc; - - loadconfig(argv, argc); - pfh = pidfile_open(pidfilename, 0600, &otherpid); if (pfh == NULL) { if (errno == EEXIST) @@ -284,33 +262,46 @@ main(int argc, char *argv[]) "<%s> failed to open the pid log file, run anyway.", __func__); } - if (!fflag) daemon(1, 0); - sock_open(); + sock_open(&sock); + + update_ifinfo(&ifilist, UPDATE_IFINFO_ALL); + for (i = 0; i < argc; i++) + update_persist_ifinfo(&ifilist, argv[i]); + + csock_open(&ctrlsock, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (ctrlsock.si_fd == -1) { + syslog(LOG_ERR, "<%s> cannot open control socket", __func__); + exit(1); + } /* record the current PID */ pid = getpid(); pidfile_write(pfh); #ifdef HAVE_POLL_H - set[0].fd = sock; - set[0].events = POLLIN; + set[PFD_RAWSOCK].fd = sock.si_fd; + set[PFD_RAWSOCK].events = POLLIN; if (sflag == 0) { - rtsock_open(); - set[1].fd = rtsock; - set[1].events = POLLIN; + rtsock_open(&rtsock); + set[PFD_RTSOCK].fd = rtsock.si_fd; + set[PFD_RTSOCK].events = POLLIN; } else - set[1].fd = -1; + set[PFD_RTSOCK].fd = -1; + set[PFD_CSOCK].fd = ctrlsock.si_fd; + set[PFD_CSOCK].events = POLLIN; #else - maxfd = sock; + maxfd = sock.si_fd; if (sflag == 0) { rtsock_open(); - if (rtsock > sock) - maxfd = rtsock; + if (rtsock.si_fd > sock.si_fd) + maxfd = rtsock.si_fd; } else - rtsock = -1; + rtsock.si_fd = -1; + if (maxfd < ctrlsock.si_fd) + maxfd = ctrlsock.si_fd; fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); if ((fdsetp = malloc(fdmasks)) == NULL) { @@ -322,33 +313,41 @@ main(int argc, char *argv[]) /*NOTREACHED*/ } memset(fdsetp, 0, fdmasks); - FD_SET(sock, fdsetp); - if (rtsock >= 0) - FD_SET(rtsock, fdsetp); + FD_SET(sock.si_fd, fdsetp); + if (rtsock.si_fd >= 0) + FD_SET(rtsock.si_fd, fdsetp); + FD_SET(ctrlsock.si_fd, fdsetp); #endif - signal(SIGTERM, set_die); - signal(SIGUSR1, rtadvd_set_dump_file); - signal(SIGHUP, set_reload); + signal(SIGTERM, set_do_die); + signal(SIGINT, set_do_die); + signal(SIGHUP, set_do_reload); + + error = csock_listen(&ctrlsock); + if (error) { + syslog(LOG_ERR, "<%s> listen failed", __func__); + exit(1); + } + + /* load configuration file */ + set_do_reload(0); while (1) { #ifndef HAVE_POLL_H memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */ #endif - if (do_dump) { /* SIGUSR1 */ - do_dump = 0; - rtadvd_dump_file(dumpfilename); - } - - if (do_die) { + if (do_die()) die(); - /*NOTREACHED*/ - } - if (do_reload) { - loadconfig(argv, argc); - do_reload = 0; + if (do_reload()) { + reset_do_reload(); + loadconfig_ifname(NULL); + syslog(LOG_INFO, + "configuration file reloaded."); } + /* timeout handler update for active interfaces */ + rtadvd_update_timeout_handler(); + /* timer expiration check and reset the timer */ timeout = rtadvd_check_timer(); @@ -364,8 +363,9 @@ main(int argc, char *argv[]) __func__); } #ifdef HAVE_POLL_H - if ((i = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + - timeout->tv_usec / 1000) : INFTIM)) < 0) + if ((i = poll(set, sizeof(set)/sizeof(set[0]), + timeout ? (timeout->tv_sec * 1000 + + timeout->tv_usec / 1000) : INFTIM)) < 0) #else if ((i = select(maxfd + 1, selectfdp, NULL, NULL, timeout)) < 0) @@ -380,51 +380,35 @@ main(int argc, char *argv[]) if (i == 0) /* timeout */ continue; #ifdef HAVE_POLL_H - if (rtsock != -1 && set[1].revents & POLLIN) + if (rtsock.si_fd != -1 && set[PFD_RTSOCK].revents & POLLIN) +#else + if (rtsock.si_fd != -1 && FD_ISSET(rtsock.si_fd, selectfdp)) +#endif + rtmsg_input(&rtsock); +#ifdef HAVE_POLL_H + if (set[PFD_RAWSOCK].revents & POLLIN) #else - if (rtsock != -1 && FD_ISSET(rtsock, selectfdp)) + if (FD_ISSET(sock.si_fd, selectfdp)) #endif - rtmsg_input(); + rtadvd_input(&sock); #ifdef HAVE_POLL_H - if (set[0].revents & POLLIN) + if (set[PFD_CSOCK].revents & POLLIN) #else - if (FD_ISSET(sock, selectfdp)) + if (FD_ISSET(ctrlsock.si_fd, selectfdp)) #endif - rtadvd_input(); + { + int fd; + + fd = csock_accept(&ctrlsock); + if (fd == -1) + syslog(LOG_ERR, "<%s> accept", __func__); + else + cmsg_handler_server(fd); + } } 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(int sig __unused) -{ - - do_dump = 1; -} - -static void -set_reload(int sig __unused) -{ - - do_reload = 1; -} - -static void -set_die(int sig __unused) -{ - - do_die = 1; -} - static void die(void) { @@ -446,35 +430,48 @@ die(void) make_packet(rai); } for (i = 0; i < retrans; i++) { + syslog(LOG_INFO, "<%s> final RA transmission #%d/%d\n", + __func__, i, retrans - i); TAILQ_FOREACH(rai, &railist, rai_next) - ra_output(rai); + if (rai->rai_ifinfo->ifi_state + == IFI_STATE_CONFIGURED) + ra_output(rai); + syslog(LOG_INFO, "<%s> waiting for %d sec.\n", + __func__, MIN_DELAY_BETWEEN_RAS); sleep(MIN_DELAY_BETWEEN_RAS); } pidfile_remove(pfh); - + csock_close(&ctrlsock); + exit(0); } static void -rtmsg_input(void) +rtmsg_input(struct sockinfo *s) { int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; u_char ifname[IFNAMSIZ]; struct if_announcemsghdr *ifan; + struct rt_msghdr *rtm; struct prefix *pfx; struct rainfo *rai; struct in6_addr *addr; + struct ifinfo *ifi; char addrbuf[INET6_ADDRSTRLEN]; int prefixchange = 0; - int error; - n = read(rtsock, msg, sizeof(msg)); + if (s == NULL) { + syslog(LOG_ERR, "<%s> internal error", __func__); + exit(1); + } + n = read(s->si_fd, msg, sizeof(msg)); + rtm = (struct rt_msghdr *)msg; syslog(LOG_DEBUG, "<%s> received a routing message " - "(type = %d, len = %d)", __func__, rtmsg_type(msg), n); + "(type = %d, len = %d)", __func__, rtm->rtm_type, n); - if (n > rtmsg_len(msg)) { + if (n > rtm->rtm_msglen) { /* * This usually won't happen for messages received on * a routing socket. @@ -483,10 +480,10 @@ rtmsg_input(void) "<%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)); + __func__, n, rtm->rtm_msglen); #if 0 /* adjust length */ - n = rtmsg_len(msg); + n = rtm->rtm_msglen; #endif } @@ -503,14 +500,7 @@ rtmsg_input(void) RTADV_TYPE2BITMASK(RTM_IFANNOUNCE)); if (len == 0) break; - if (((struct rt_msghdr *)next)->rtm_version != RTM_VERSION) { - syslog(LOG_ERR, - "<%s> RTM_VERSION mismatch (%d != %d).", - __func__, ((struct rt_msghdr *)next)->rtm_version, - RTM_VERSION); - continue; - } - type = rtmsg_type(next); + type = ((struct rt_msghdr *)next)->rtm_type; switch (type) { case RTM_ADD: case RTM_DELETE: @@ -518,10 +508,10 @@ rtmsg_input(void) break; case RTM_NEWADDR: case RTM_DELADDR: - ifindex = get_ifam_ifindex(next); + ifindex = (int)((struct ifa_msghdr *)next)->ifam_index; break; case RTM_IFINFO: - ifindex = get_ifm_ifindex(next); + ifindex = (int)((struct if_msghdr *)next)->ifm_index; break; case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *)next; @@ -538,32 +528,20 @@ rtmsg_input(void) 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); + syslog(LOG_INFO, + "<%s>: interface added (idx=%d)", + __func__, ifan->ifan_index); + update_ifinfo(&ifilist, ifan->ifan_index); + loadconfig_index(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); + syslog(LOG_INFO, + "<%s>: interface removed (idx=%d)", + __func__, ifan->ifan_index); + rmconfig(ifan->ifan_index); + update_ifinfo(&ifilist, ifan->ifan_index); break; } continue; @@ -575,26 +553,31 @@ rtmsg_input(void) if_indextoname(ifindex, ifname)); continue; } - - if ((rai = if_indextorainfo(ifindex)) == NULL) { + ifi = if_indextoifinfo(ifindex); + if (ifi == NULL) { syslog(LOG_DEBUG, - "<%s> route changed on " - "non advertising interface(%s)", - __func__, - if_indextoname(ifindex, ifname)); + "<%s> ifinfo not found for idx=%d. Why?", + __func__, ifindex); + continue; + } + rai = ifi->ifi_rainfo; + if (rai == NULL) { + syslog(LOG_DEBUG, + "<%s> route changed on " + "non advertising interface(%s)", + __func__, ifi->ifi_ifname); continue; } - oldifflags = iflist[ifindex]->ifm_flags; + + oldifflags = ifi->ifi_flags; + /* init ifflags because it may have changed */ + update_ifinfo(&ifilist, ifindex); switch (type) { case RTM_ADD: - /* init ifflags because it may have changed */ - iflist[ifindex]->ifm_flags = - if_getflags(ifindex, iflist[ifindex]->ifm_flags); - if (sflag) break; /* we aren't interested in prefixes */ - + addr = get_addr(msg); plen = get_prefixlen(msg); /* sanity check for plen */ @@ -623,17 +606,13 @@ rtmsg_input(void) inet_ntop(AF_INET6, addr, (char *)addrbuf, sizeof(addrbuf)), - plen, rai->rai_ifname); + plen, ifi->ifi_ifname); break; } make_prefix(rai, ifindex, addr, plen); prefixchange = 1; break; case RTM_DELETE: - /* init ifflags because it may have changed */ - iflist[ifindex]->ifm_flags = - if_getflags(ifindex, iflist[ifindex]->ifm_flags); - if (sflag) break; @@ -655,7 +634,7 @@ rtmsg_input(void) "but it was not in list", __func__, inet_ntop(AF_INET6, addr, (char *)addrbuf, sizeof(addrbuf)), - plen, rai->rai_ifname); + plen, ifi->ifi_ifname); break; } invalidate_prefix(pfx); @@ -663,12 +642,7 @@ rtmsg_input(void) break; case RTM_NEWADDR: case RTM_DELADDR: - /* init ifflags because it may have changed */ - iflist[ifindex]->ifm_flags = - if_getflags(ifindex, iflist[ifindex]->ifm_flags); - break; case RTM_IFINFO: - iflist[ifindex]->ifm_flags = get_ifm_flags(next); break; default: /* should not reach here */ @@ -681,17 +655,17 @@ rtmsg_input(void) /* check if an interface flag is changed */ if ((oldifflags & IFF_UP) && /* UP to DOWN */ - !(iflist[ifindex]->ifm_flags & IFF_UP)) { + !(ifi->ifi_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes down. stop timer.", - __func__, rai->rai_ifname); + __func__, ifi->ifi_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)) { + (ifi->ifi_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> interface %s becomes up. restart timer.", - __func__, rai->rai_ifname); + __func__, ifi->ifi_ifname); rai->rai_initcounter = 0; /* reset the counter */ rai->rai_waiting = 0; /* XXX */ @@ -701,7 +675,7 @@ rtmsg_input(void) rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer); } else if (prefixchange && - (iflist[ifindex]->ifm_flags & IFF_UP)) { + (ifi->ifi_flags & IFF_UP)) { /* * An advertised prefix has been added or invalidated. * Will notice the change in a short delay. @@ -715,7 +689,7 @@ rtmsg_input(void) } void -rtadvd_input(void) +rtadvd_input(struct sockinfo *s) { ssize_t i; int *hlimp = NULL; @@ -728,14 +702,21 @@ rtadvd_input(void) struct in6_pktinfo *pi = NULL; u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; struct in6_addr dst = in6addr_any; + struct ifinfo *ifi; + syslog(LOG_DEBUG, "<%s> enter", __func__); + + if (s == NULL) { + syslog(LOG_ERR, "<%s> internal error", __func__); + exit(1); + } /* * Get message. We reset msg_controllen since the field could * be modified if we had received a message before setting * receive options. */ rcvmhdr.msg_controllen = rcvcmsgbuflen; - if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0) + if ((i = recvmsg(s->si_fd, &rcvmhdr, 0)) < 0) return; /* extract optional information via Advanced API */ @@ -771,13 +752,12 @@ rtadvd_input(void) * If we happen to receive data on an interface which is now gone * or down, just discard the data. */ - if (iflist[pi->ipi6_ifindex] == NULL || - (iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) { + ifi = if_indextoifinfo(pi->ipi6_ifindex); + if (ifi == NULL || !(ifi->ifi_flags & IFF_UP)) { syslog(LOG_INFO, "<%s> received data on a disabled interface (%s)", __func__, - (iflist[pi->ipi6_ifindex] == NULL) ? "[gone]" : - if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + (ifi == NULL) ? "[gone]" : ifi->ifi_ifname); return; } @@ -888,7 +868,7 @@ rtadvd_input(void) ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom); break; case ICMP6_ROUTER_RENUMBERING: - if (accept_rr == 0) { + if (mcastif == NULL) { syslog(LOG_ERR, "<%s> received a router renumbering " "message, but not allowed to be accepted", __func__); @@ -920,6 +900,7 @@ rs_input(int len, struct nd_router_solicit *rs, u_char ifnamebuf[IFNAMSIZ]; union nd_opt ndopts; struct rainfo *rai; + struct ifinfo *ifi; struct soliciter *sol; syslog(LOG_DEBUG, @@ -956,10 +937,14 @@ rs_input(int len, struct nd_router_solicit *rs, goto done; } - TAILQ_FOREACH(rai, &railist, rai_next) - if (pi->ipi6_ifindex == (unsigned int)rai->rai_ifindex) - break; - + ifi = if_indextoifinfo(pi->ipi6_ifindex); + if (ifi == NULL) { + syslog(LOG_INFO, + "<%s> if (idx=%d) not found. Why?", + __func__, pi->ipi6_ifindex); + goto done; + } + rai = ifi->ifi_rainfo; if (rai == NULL) { syslog(LOG_INFO, "<%s> RS received on non advertising interface(%s)", @@ -968,7 +953,7 @@ rs_input(int len, struct nd_router_solicit *rs, goto done; } - rai->rai_rsinput++; /* increment statistics */ + rai->rai_ifinfo->ifi_rsinput++; /* * Decide whether to send RA according to the rate-limit @@ -1046,56 +1031,28 @@ set_short_delay(struct rainfo *rai) static int check_accept_rtadv(int idx) { - struct in6_ndireq nd; - u_char ifname[IFNAMSIZ]; - int s6; + struct ifinfo *ifi; 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); + + TAILQ_FOREACH(ifi, &ifilist, ifi_next) { + if (ifi->ifi_ifindex == idx) + break; } - if ((if_indextoname(idx, ifname)) == NULL) { + if (ifi == NULL) { syslog(LOG_ERR, - "<%s> ifindex->ifname failed (idx=%d).", + "<%s> if (idx=%d) not found. Why?", __func__, idx); - close(s6); return (0); } - memset(&nd, 0, sizeof(nd)); - strncpy(nd.ifname, ifname, sizeof(nd.ifname)); - error = ioctl(s6, SIOCGIFINFO_IN6, &nd); + error =update_ifinfo_nd_flags(ifi); if (error) { syslog(LOG_ERR, - "<%s> ioctl(SIOCGIFINFO_IN6) failed for idx=%d.", + "<%s> nd6 flags failed (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); + return (0); } - else - return (value); + + return (ifi->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV); } static void @@ -1103,6 +1060,7 @@ ra_input(int len, struct nd_router_advert *nra, struct in6_pktinfo *pi, struct sockaddr_in6 *from) { struct rainfo *rai; + struct ifinfo *ifi; u_char ntopbuf[INET6_ADDRSTRLEN]; u_char ifnamebuf[IFNAMSIZ]; union nd_opt ndopts; @@ -1115,16 +1073,6 @@ ra_input(int len, struct nd_router_advert *nra, 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; - } - /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); error = nd6_options((struct nd_opt_hdr *)(nra + 1), @@ -1144,8 +1092,8 @@ ra_input(int len, struct nd_router_advert *nra, /* * RA consistency check according to RFC 4861 6.2.7 */ - rai = if_indextorainfo(pi->ipi6_ifindex); - if (rai == NULL) { + ifi = if_indextoifinfo(pi->ipi6_ifindex); + if (ifi->ifi_rainfo == NULL) { syslog(LOG_INFO, "<%s> received RA from %s on non-advertising" " interface(%s)", @@ -1155,15 +1103,18 @@ ra_input(int len, struct nd_router_advert *nra, ifnamebuf)); goto done; } - rai->rai_rainput++; /* increment statistics */ - + rai = ifi->ifi_rainfo; + ifi->ifi_rainput++; + syslog(LOG_DEBUG, "<%s> ifi->ifi_rainput = %llu\n", __func__, + ifi->ifi_rainput); + /* Cur Hop Limit value */ 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->rai_ifname, nra->nd_ra_curhoplimit, + __func__, ifi->ifi_ifname, nra->nd_ra_curhoplimit, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), rai->rai_hoplimit); inconsistent++; @@ -1174,7 +1125,7 @@ ra_input(int len, struct nd_router_advert *nra, syslog(LOG_INFO, "<%s> M flag inconsistent on %s:" " %s from %s, %s from us", - __func__, rai->rai_ifname, on_off[!rai->rai_managedflg], + __func__, ifi->ifi_ifname, on_off[!rai->rai_managedflg], inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), on_off[rai->rai_managedflg]); inconsistent++; @@ -1185,7 +1136,7 @@ ra_input(int len, struct nd_router_advert *nra, syslog(LOG_INFO, "<%s> O flag inconsistent on %s:" " %s from %s, %s from us", - __func__, rai->rai_ifname, on_off[!rai->rai_otherflg], + __func__, ifi->ifi_ifname, on_off[!rai->rai_otherflg], inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), on_off[rai->rai_otherflg]); inconsistent++; @@ -1197,7 +1148,7 @@ ra_input(int len, struct nd_router_advert *nra, syslog(LOG_INFO, "<%s> ReachableTime inconsistent on %s:" " %d from %s, %d from us", - __func__, rai->rai_ifname, reachabletime, + __func__, ifi->ifi_ifname, reachabletime, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), rai->rai_reachabletime); inconsistent++; @@ -1209,7 +1160,7 @@ ra_input(int len, struct nd_router_advert *nra, syslog(LOG_INFO, "<%s> RetranceTimer inconsistent on %s:" " %d from %s, %d from us", - __func__, rai->rai_ifname, retranstimer, + __func__, ifi->ifi_ifname, retranstimer, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), rai->rai_retranstimer); inconsistent++; @@ -1221,7 +1172,7 @@ ra_input(int len, struct nd_router_advert *nra, syslog(LOG_INFO, "<%s> MTU option value inconsistent on %s:" " %d from %s, %d from us", - __func__, rai->rai_ifname, mtu, + __func__, ifi->ifi_ifname, mtu, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), rai->rai_linkmtu); inconsistent++; @@ -1242,7 +1193,7 @@ ra_input(int len, struct nd_router_advert *nra, } if (inconsistent) - rai->rai_rainconsistent++; + ifi->ifi_rainconsistent++; done: free_ndopts(&ndopts); @@ -1254,6 +1205,7 @@ static int prefix_check(struct nd_opt_prefix_info *pinfo, struct rainfo *rai, struct sockaddr_in6 *from) { + struct ifinfo *ifi; u_int32_t preferred_time, valid_time; struct prefix *pfx; int inconsistent = 0; @@ -1265,7 +1217,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) return (0); #endif - + ifi = rai->rai_ifinfo; /* * log if the adveritsed prefix has link-local scope(sanity check?) */ @@ -1278,7 +1230,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, - sizeof(ntopbuf)), rai->rai_ifname); + sizeof(ntopbuf)), ifi->ifi_ifname); if ((pfx = find_prefix(rai, &pinfo->nd_opt_pi_prefix, pinfo->nd_opt_pi_prefix_len)) == NULL) { @@ -1289,7 +1241,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, - sizeof(ntopbuf)), rai->rai_ifname); + sizeof(ntopbuf)), ifi->ifi_ifname); return (0); } @@ -1315,7 +1267,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, - rai->rai_ifname, preferred_time, + ifi->ifi_ifname, preferred_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), pfx->pfx_pltimeexpire); inconsistent++; @@ -1329,7 +1281,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, - rai->rai_ifname, preferred_time, + ifi->ifi_ifname, preferred_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), pfx->pfx_preflifetime); @@ -1348,7 +1300,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, - rai->rai_ifname, preferred_time, + ifi->ifi_ifname, preferred_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), pfx->pfx_vltimeexpire); inconsistent++; @@ -1362,7 +1314,7 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, prefixbuf, sizeof(prefixbuf)), pinfo->nd_opt_pi_prefix_len, - rai->rai_ifname, valid_time, + ifi->ifi_ifname, valid_time, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, sizeof(ntopbuf)), pfx->pfx_validlifetime); inconsistent++; @@ -1553,15 +1505,19 @@ free_ndopts(union nd_opt *ndopts) } void -sock_open(void) +sock_open(struct sockinfo *s) { struct icmp6_filter filt; - struct ipv6_mreq mreq; - struct rainfo *rai; int on; /* XXX: should be max MTU attached to the node */ static u_char answer[1500]; + syslog(LOG_DEBUG, "<%s> enter", __func__); + + if (s == NULL) { + syslog(LOG_ERR, "<%s> internal error", __func__); + exit(1); + } rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); @@ -1578,13 +1534,13 @@ sock_open(void) exit(1); } - if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + if ((s->si_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno)); exit(1); } /* specify to tell receiving interface */ on = 1; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", __func__, strerror(errno)); @@ -1592,7 +1548,7 @@ sock_open(void) } on = 1; /* specify to tell value of hoplimit field of received IP6 hdr */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", __func__, strerror(errno)); @@ -1601,62 +1557,16 @@ sock_open(void) ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - if (accept_rr) + if (mcastif != NULL) ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); - if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + if (setsockopt(s->si_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", __func__, strerror(errno)); exit(1); } - /* - * join all routers multicast address on each advertising interface. - */ - 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) { - syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s", - __func__, rai->rai_ifname, strerror(errno)); - exit(1); - } - } - - /* - * When attending router renumbering, join all-routers site-local - * multicast group. - */ - if (accept_rr) { - 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); - exit(1); - } - } else - mreq.ipv6mr_interface = - TAILQ_FIRST(&railist)->rai_ifindex; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, sizeof(mreq)) < 0) { - syslog(LOG_ERR, - "<%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); @@ -1679,27 +1589,36 @@ sock_open(void) /* open a routing socket to watch the routing table */ static void -rtsock_open(void) +rtsock_open(struct sockinfo *s) { - if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { + if (s == NULL) { + syslog(LOG_ERR, "<%s> internal error", __func__); + exit(1); + } + if ((s->si_fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __func__, strerror(errno)); exit(1); } } -struct rainfo * -if_indextorainfo(int idx) +struct ifinfo * +if_indextoifinfo(int idx) { - struct rainfo *rai; + struct ifinfo *ifi; - 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); + TAILQ_FOREACH(ifi, &ifilist, ifi_next) { + if (ifi->ifi_ifindex == idx) + return (ifi); } + if (ifi != NULL) + syslog(LOG_DEBUG, "<%s> ifi found (idx=%d)", + __func__, idx); + else + syslog(LOG_DEBUG, "<%s> ifi not found (idx=%d)", + __func__, idx); + return (NULL); /* search failed */ } @@ -1710,13 +1629,22 @@ ra_output(struct rainfo *rai) struct cmsghdr *cm; struct in6_pktinfo *pi; struct soliciter *sol; - - if ((iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) == 0) { - syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", - __func__, rai->rai_ifname); + struct ifinfo *ifi; + + ifi = rai->rai_ifinfo; + + if (ifi->ifi_state != IFI_STATE_CONFIGURED) { + syslog(LOG_DEBUG, "<%s> %s is unconfigured. " + "Skip sending RAs.", + __func__, ifi->ifi_ifname); + return; + } + if (!(ifi->ifi_flags & IFF_UP)) { + syslog(LOG_DEBUG, "<%s> %s is not up. " + "Skip sending RAs.", + __func__, ifi->ifi_ifname); return; } - /* * Check lifetime, ACCEPT_RTADV flag, and ip6.forwarding. * @@ -1733,14 +1661,14 @@ ra_output(struct rainfo *rai) */ 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); + __func__, rai->rai_lifetime, check_accept_rtadv(ifi->ifi_ifindex), + getinet6sysctl(IPV6CTL_FORWARDING), ifi->ifi_ifname); if (rai->rai_lifetime != 0) { - if (check_accept_rtadv(rai->rai_ifindex)) { + if (check_accept_rtadv(ifi->ifi_ifindex)) { syslog(LOG_INFO, "<%s> non-zero lifetime RA " "on RA receiving interface %s." - " Ignored.", __func__, rai->rai_ifname); + " Ignored.", __func__, ifi->ifi_ifname); return; } if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { @@ -1765,7 +1693,7 @@ ra_output(struct rainfo *rai) 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 = rai->rai_ifindex; + pi->ipi6_ifindex = ifi->ifi_ifindex; /* specify the hop limit of the packet */ { @@ -1780,21 +1708,21 @@ ra_output(struct rainfo *rai) syslog(LOG_DEBUG, "<%s> send RA on %s, # of waitings = %d", - __func__, rai->rai_ifname, rai->rai_waiting); + __func__, ifi->ifi_ifname, rai->rai_waiting); - i = sendmsg(sock, &sndmhdr, 0); + i = sendmsg(sock.si_fd, &sndmhdr, 0); if (i < 0 || (size_t)i != rai->rai_ra_datalen) { if (i < 0) { syslog(LOG_ERR, "<%s> sendmsg on %s: %s", - __func__, rai->rai_ifname, + __func__, ifi->ifi_ifname, strerror(errno)); } } /* update counter */ if (rai->rai_initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) rai->rai_initcounter++; - rai->rai_raoutput++; + ifi->ifi_raoutput++; /* * unicast advertisements @@ -1818,13 +1746,14 @@ struct rtadvd_timer * ra_timeout(void *arg) { struct rainfo *rai; - + struct ifinfo *ifi; #ifdef notyet /* if necessary, reconstruct the packet. */ #endif rai = (struct rainfo *)arg; + ifi = rai->rai_ifinfo; syslog(LOG_DEBUG, "<%s> RA timer on %s is expired", - __func__, rai->rai_ifname); + __func__, ifi->ifi_ifname); ra_output(rai); @@ -1837,8 +1766,10 @@ ra_timer_update(void *arg, struct timeval *tm) { long interval; struct rainfo *rai; - + struct ifinfo *ifi; + rai = (struct rainfo *)arg; + ifi = rai->rai_ifinfo; /* * Whenever a multicast advertisement is sent from an interface, * the timer is reset to a uniformly-distributed random value @@ -1870,7 +1801,7 @@ ra_timer_update(void *arg, struct timeval *tm) syslog(LOG_DEBUG, "<%s> RA timer on %s is set to %ld:%ld", - __func__, rai->rai_ifname, + __func__, ifi->ifi_ifname, (long int)tm->tv_sec, (long int)tm->tv_usec); return; |