diff options
-rw-r--r-- | usr.sbin/rtadvd/config.c | 126 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.h | 3 | ||||
-rw-r--r-- | usr.sbin/rtadvd/if.c | 13 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 84 | ||||
-rw-r--r-- | usr.sbin/rtadvd/timer.c | 3 |
5 files changed, 195 insertions, 34 deletions
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index f7a4bbe..ef2680b 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -143,8 +143,68 @@ dname_labelenc(char *dst, const char *src) memset(p, 0, sizeof(*p)); \ } while(0) -void -getconfig(char *intface) +int +rmconfig(int idx) +{ + struct rainfo *rai; + struct prefix *pfx; + struct soliciter *sol; + struct rdnss *rdn; + struct rdnss_addr *rdna; + struct dnssl *dns; + struct rtinfo *rti; + + rai = if_indextorainfo(idx); + if (rai == NULL) { + syslog(LOG_ERR, "<%s>: rainfo not found (idx=%d)", + __func__, idx); + return (-1); + } + + TAILQ_REMOVE(&railist, rai, rai_next); + syslog(LOG_DEBUG, "<%s>: rainfo (idx=%d) removed.", + __func__, idx); + + /* Free all of allocated memories for this entry. */ + rtadvd_remove_timer(rai->rai_timer); + + if (rai->rai_ra_data != NULL) + free(rai->rai_ra_data); + + if (rai->rai_sdl != NULL) + free(rai->rai_sdl); + + while ((pfx = TAILQ_FIRST(&rai->rai_prefix)) != NULL) { + TAILQ_REMOVE(&rai->rai_prefix, pfx, pfx_next); + free(pfx); + } + while ((sol = TAILQ_FIRST(&rai->rai_soliciter)) != NULL) { + TAILQ_REMOVE(&rai->rai_soliciter, sol, sol_next); + free(sol); + } + while ((rdn = TAILQ_FIRST(&rai->rai_rdnss)) != NULL) { + TAILQ_REMOVE(&rai->rai_rdnss, rdn, rd_next); + while ((rdna = TAILQ_FIRST(&rdn->rd_list)) != NULL) { + TAILQ_REMOVE(&rdn->rd_list, rdna, ra_next); + free(rdna); + } + free(rdn); + } + while ((dns = TAILQ_FIRST(&rai->rai_dnssl)) != NULL) { + TAILQ_REMOVE(&rai->rai_dnssl, dns, dn_next); + free(dns); + } + while ((rti = TAILQ_FIRST(&rai->rai_route)) != NULL) { + TAILQ_REMOVE(&rai->rai_route, rti, rti_next); + free(rti); + } + free(rai); + + return (0); +} + +int +getconfig(int idx) { int stat, i; char tbuf[BUFSIZ]; @@ -154,8 +214,15 @@ getconfig(char *intface) char buf[BUFSIZ]; char *bp = buf; char *addr, *flagstr; + char intface[IFNAMSIZ]; static int forwarding = -1; + if (if_indextoname(idx, intface) == NULL) { + syslog(LOG_ERR, "<%s> invalid index number (%d)", + __func__, idx); + return (-1); + } + if ((stat = agetent(tbuf, intface)) <= 0) { memset(tbuf, 0, sizeof(tbuf)); syslog(LOG_INFO, @@ -201,7 +268,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> can't get information of %s", __func__, intface); - exit(1); + return (-1); } rai->rai_ifindex = rai->rai_sdl->sdl_index; } else @@ -227,7 +294,7 @@ getconfig(char *intface) "<%s> maxinterval (%ld) on %s is invalid " "(must be between %u and %u)", __func__, val, intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL); - exit(1); + return (-1); } rai->rai_maxinterval = (u_int)val; @@ -239,7 +306,7 @@ getconfig(char *intface) "(must be between %d and %d)", __func__, val, intface, MIN_MININTERVAL, (rai->rai_maxinterval * 3) / 4); - exit(1); + return (-1); } rai->rai_mininterval = (u_int)val; @@ -258,7 +325,7 @@ getconfig(char *intface) if ((val & ND_RA_FLAG_RTPREF_HIGH)) { syslog(LOG_ERR, "<%s> the \'h\' and \'l\'" " router flags are exclusive", __func__); - exit(1); + return (-1); } val |= ND_RA_FLAG_RTPREF_LOW; } @@ -275,7 +342,7 @@ getconfig(char *intface) if (rai->rai_rtpref == ND_RA_FLAG_RTPREF_RSV) { syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s", __func__, rai->rai_rtpref, intface); - exit(1); + return (-1); } MAYHAVE(val, "rltime", rai->rai_maxinterval * 3); @@ -286,7 +353,7 @@ getconfig(char *intface) "(must be 0 or between %d and %d)", __func__, val, intface, rai->rai_maxinterval, MAXROUTERLIFETIME); - exit(1); + return (-1); } /* * Basically, hosts MUST NOT send Router Advertisement messages at any @@ -302,7 +369,7 @@ getconfig(char *intface) "which must not be allowed for hosts. you must " "change router lifetime or enable IPv6 forwarding.", __func__, intface); - exit(1); + return (-1); } rai->rai_lifetime = val & 0xffff; @@ -312,7 +379,7 @@ getconfig(char *intface) "<%s> reachable time (%ld) on %s is invalid " "(must be no greater than %d)", __func__, val, intface, MAXREACHABLETIME); - exit(1); + return (-1); } rai->rai_reachabletime = (u_int32_t)val; @@ -320,7 +387,7 @@ getconfig(char *intface) if (val64 < 0 || val64 > 0xffffffff) { syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range", __func__, (long long)val64, intface); - exit(1); + return (-1); } rai->rai_retranstimer = (u_int32_t)val64; @@ -328,7 +395,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> mobile-ip6 configuration not supported", __func__); - exit(1); + return (-1); } /* prefix information */ @@ -361,14 +428,14 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> inet_pton failed for %s", __func__, addr); - exit(1); + return (-1); } if (IN6_IS_ADDR_MULTICAST(&pfx->pfx_prefix)) { syslog(LOG_ERR, "<%s> multicast prefix (%s) must " "not be advertised on %s", __func__, addr, intface); - exit(1); + return (-1); } if (IN6_IS_ADDR_LINKLOCAL(&pfx->pfx_prefix)) syslog(LOG_NOTICE, @@ -382,7 +449,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s " "on %s out of range", __func__, val, addr, intface); - exit(1); + return (-1); } pfx->pfx_prefixlen = (int)val; @@ -407,7 +474,7 @@ getconfig(char *intface) "%s/%d on %s is out of range", __func__, (long long)val64, addr, pfx->pfx_prefixlen, intface); - exit(1); + return (-1); } pfx->pfx_validlifetime = (u_int32_t)val64; @@ -427,7 +494,7 @@ getconfig(char *intface) "is out of range", __func__, (long long)val64, addr, pfx->pfx_prefixlen, intface); - exit(1); + return (-1); } pfx->pfx_preflifetime = (u_int32_t)val64; @@ -447,7 +514,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> mtu (%ld) on %s out of range", __func__, val, intface); - exit(1); + return (-1); } rai->rai_linkmtu = (u_int32_t)val; if (rai->rai_linkmtu == 0) { @@ -464,7 +531,7 @@ getconfig(char *intface) "be between least MTU (%d) and physical link MTU (%d)", __func__, (unsigned long)rai->rai_linkmtu, intface, IPV6_MMTU, rai->rai_phymtu); - exit(1); + return (-1); } #ifdef SIOCSIFINFO_IN6 @@ -523,7 +590,7 @@ getconfig(char *intface) if (inet_pton(AF_INET6, addr, &rti->rti_prefix) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed for %s", __func__, addr); - exit(1); + return (-1); } #if 0 /* @@ -538,14 +605,14 @@ getconfig(char *intface) "<%s> multicast route (%s) must " "not be advertised on %s", __func__, addr, intface); - exit(1); + return (-1); } if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { syslog(LOG_NOTICE, "<%s> link-local route (%s) will " "be advertised on %s", __func__, addr, intface); - exit(1); + return (-1); } #endif @@ -565,7 +632,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s " "out of range", __func__, val, addr, intface); - exit(1); + return (-1); } rti->rti_prefixlen = (int)val; @@ -601,7 +668,7 @@ getconfig(char *intface) "for %s/%d on %s", __func__, rti->rti_rtpref, addr, rti->rti_prefixlen, intface); - exit(1); + return (-1); } /* @@ -628,7 +695,7 @@ getconfig(char *intface) syslog(LOG_ERR, "<%s> route lifetime (%lld) for " "%s/%d on %s out of range", __func__, (long long)val64, addr, rti->rti_prefixlen, intface); - exit(1); + return (-1); } rti->rti_ltime = (u_int32_t)val64; } @@ -656,7 +723,8 @@ getconfig(char *intface) if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) { syslog(LOG_ERR, "<%s> inet_pton failed for %s", __func__, abuf); - exit(1); + free(rdna); + return (-1); } TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next); } @@ -669,7 +737,7 @@ getconfig(char *intface) "(must be between %d and %d)", entbuf, val, intface, rai->rai_maxinterval, rai->rai_maxinterval * 2); - exit(1); + return (-1); } rdn->rd_ltime = val; @@ -711,7 +779,7 @@ getconfig(char *intface) "(must be between %d and %d)", entbuf, val, intface, rai->rai_maxinterval, rai->rai_maxinterval * 2); - exit(1); + return (-1); } dns->dn_ltime = val; @@ -727,6 +795,8 @@ getconfig(char *intface) rai, rai); ra_timer_update((void *)rai, &rai->rai_timer->rat_tm); rtadvd_set_timer(&rai->rai_timer->rat_tm, rai->rai_timer); + + return (0); } void diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index 88c31e3..38c19b8 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -30,7 +30,8 @@ * SUCH DAMAGE. */ -extern void getconfig(char *); +extern int getconfig(int); +extern int rmconfig(int); extern void delete_prefix(struct prefix *); extern void invalidate_prefix(struct prefix *); extern void update_prefix(struct prefix *); diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c index f500feb..302c334 100644 --- a/usr.sbin/rtadvd/if.c +++ b/usr.sbin/rtadvd/if.c @@ -271,10 +271,17 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) buf, lim, rtm); break; } - if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { + if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { + syslog(LOG_WARNING, + "<%s> routing message version mismatch " + "(buf=%p lim=%p rtm=%p)", __func__, + buf, lim, rtm); continue; } + if (FILTER_MATCH(rtm->rtm_type, filter) == 0) + continue; + switch (rtm->rtm_type) { case RTM_GET: case RTM_ADD: @@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: + case RTM_IFANNOUNCE: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; @@ -566,6 +574,9 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) void init_iflist(void) { + syslog(LOG_DEBUG, + "<%s> generate iflist.", __func__); + if (ifblock) { free(ifblock); ifblock_size = 0; diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index d76be75..bd31f49 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -90,6 +90,8 @@ int sock; int rtsock = -1; int accept_rr = 0; int dflag = 0, sflag = 0; +static int ifl_len; +static char **ifl_names; struct railist_head_t railist = TAILQ_HEAD_INITIALIZER(railist); @@ -171,6 +173,7 @@ 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); int main(int argc, char *argv[]) @@ -186,6 +189,7 @@ main(int argc, char *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:dDfF:M:p:Rs")) != -1) { @@ -258,9 +262,25 @@ main(int argc, char *argv[]) #endif /* get iflist block from kernel */ init_iflist(); + ifl_names = argv; + ifl_len = argc; + + for (i = 0; i < ifl_len; i++) { + int idx; - while (argc--) - getconfig(*argv++); + 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); if (pfh == NULL) { @@ -376,6 +396,15 @@ main(int argc, char *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(int sig __unused) { @@ -426,12 +455,14 @@ rtmsg_input(void) int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; - u_char ifname[IF_NAMESIZE]; + 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)); syslog(LOG_DEBUG, "<%s> received a routing message " @@ -462,7 +493,8 @@ rtmsg_input(void) RTADV_TYPE2BITMASK(RTM_DELETE) | RTADV_TYPE2BITMASK(RTM_NEWADDR) | RTADV_TYPE2BITMASK(RTM_DELADDR) | - RTADV_TYPE2BITMASK(RTM_IFINFO)); + RTADV_TYPE2BITMASK(RTM_IFINFO) | + RTADV_TYPE2BITMASK(RTM_IFANNOUNCE)); if (len == 0) break; type = rtmsg_type(next); @@ -478,6 +510,50 @@ rtmsg_input(void) case RTM_IFINFO: ifindex = get_ifm_ifindex(next); break; + 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 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, diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c index 954400d..8cad6ad 100644 --- a/usr.sbin/rtadvd/timer.c +++ b/usr.sbin/rtadvd/timer.c @@ -92,6 +92,9 @@ void rtadvd_remove_timer(struct rtadvd_timer *rat) { + if (rat == NULL) + return; + TAILQ_REMOVE(&ra_timer, rat, rat_next); free(rat); } |