diff --git a/usr.sbin/rtsold/cap_llflags.c b/usr.sbin/rtsold/cap_llflags.c index b2c07df7379d..195f83893b4d 100644 --- a/usr.sbin/rtsold/cap_llflags.c +++ b/usr.sbin/rtsold/cap_llflags.c @@ -1,158 +1,163 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 The FreeBSD Foundation * * This software was developed by Mark Johnston under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtsold.h" /* * A service to fetch the flags for the link-local IPv6 address on the specified * interface. This cannot easily be done in capability mode because we need to * use the routing socket sysctl API to find the link-local address of a * particular interface. The SIOCGIFCONF ioctl is one other option, but as * currently implemented it is less flexible (it cannot report the required * buffer length), and hard-codes a buffer length limit. */ static int llflags_get(const char *ifname, int *flagsp) { struct in6_ifreq ifr6; struct ifaddrs *ifap, *ifa; struct sockaddr_in6 *sin6; int error, s; s = socket(PF_INET6, SOCK_DGRAM, 0); if (s < 0) return (-1); - if (getifaddrs(&ifap) != 0) - return (-1); - error = -1; + ifap = NULL; + if (getifaddrs(&ifap) != 0) { + error = errno; + goto out; + } + error = ENOENT; for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (strcmp(ifa->ifa_name, ifname) != 0) continue; if (ifa->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr; if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) continue; memset(&ifr6, 0, sizeof(ifr6)); if (strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name)) >= sizeof(ifr6.ifr_name)) { - freeifaddrs(ifap); - errno = EINVAL; - return (-1); + error = errno; + goto out; } memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { error = errno; - freeifaddrs(ifap); - errno = error; - return (-1); + goto out; } *flagsp = ifr6.ifr_ifru.ifru_flags6; error = 0; break; } +out: (void)close(s); - freeifaddrs(ifap); - if (error == -1) - errno = ENOENT; - return (error); + if (ifap != NULL) + freeifaddrs(ifap); + if (error != 0) { + errno = error; + return (-1); + } else { + return (0); + } } int cap_llflags_get(cap_channel_t *cap, const char *ifname, int *flagsp) { #ifdef WITH_CASPER nvlist_t *nvl; int error; nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", "get"); nvlist_add_string(nvl, "ifname", ifname); nvl = cap_xfer_nvlist(cap, nvl); if (nvl == NULL) return (-1); error = (int)dnvlist_get_number(nvl, "error", 0); if (error == 0) *flagsp = (int)nvlist_get_number(nvl, "flags"); nvlist_destroy(nvl); if (error != 0) errno = error; return (error == 0 ? 0 : -1); #else (void)cap; return (llflags_get(ifname, flagsp)); #endif } #ifdef WITH_CASPER static int llflags_command(const char *cmd, const nvlist_t *limits __unused, nvlist_t *nvlin, nvlist_t *nvlout) { const char *ifname; int flags; if (strcmp(cmd, "get") != 0) return (EINVAL); ifname = nvlist_get_string(nvlin, "ifname"); if (llflags_get(ifname, &flags) != 0) return (errno); nvlist_add_number(nvlout, "flags", flags); return (0); } CREATE_SERVICE("rtsold.llflags", NULL, llflags_command, 0); #endif /* WITH_CASPER */ diff --git a/usr.sbin/rtsold/dump.c b/usr.sbin/rtsold/dump.c index 65b4f979bd43..803a6c0d95d3 100644 --- a/usr.sbin/rtsold/dump.c +++ b/usr.sbin/rtsold/dump.c @@ -1,203 +1,204 @@ /* $KAME: dump.c,v 1.13 2003/10/05 00:09:36 itojun Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1999 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtsold.h" static const char * const ifstatstr[] = { "IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE" }; void rtsold_dump(FILE *fp) { struct ifinfo *ifi; struct rainfo *rai; struct ra_opt *rao; struct timespec now; char ntopbuf[INET6_ADDRSTRLEN]; if (fseek(fp, 0, SEEK_SET) != 0) { warnmsg(LOG_ERR, __func__, "fseek(): %s", strerror(errno)); return; } (void)ftruncate(fileno(fp), 0); (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { fprintf(fp, "Interface %s\n", ifi->ifname); fprintf(fp, " probe interval: "); if (ifi->probeinterval) { fprintf(fp, "%d\n", ifi->probeinterval); fprintf(fp, " probe timer: %d\n", ifi->probetimer); } else { fprintf(fp, "infinity\n"); fprintf(fp, " no probe timer\n"); } fprintf(fp, " interface status: %s\n", ifi->active > 0 ? "active" : "inactive"); fprintf(fp, " managed config: %s\n", ifi->managedconfig ? "on" : "off"); fprintf(fp, " other config: %s\n", ifi->otherconfig ? "on" : "off"); fprintf(fp, " rtsold status: %s\n", ifstatstr[ifi->state]); fprintf(fp, " carrier detection: %s\n", ifi->mediareqok ? "available" : "unavailable"); fprintf(fp, " probes: %d, dadcount = %d\n", ifi->probes, ifi->dadcount); if (ifi->timer.tv_sec == tm_max.tv_sec && ifi->timer.tv_nsec == tm_max.tv_nsec) fprintf(fp, " no timer\n"); else { fprintf(fp, " timer: interval=%d:%d, expire=%s\n", (int)ifi->timer.tv_sec, (int)ifi->timer.tv_nsec / 1000, (ifi->expire.tv_sec < now.tv_sec) ? "expired" : sec2str(&ifi->expire)); } fprintf(fp, " number of valid RAs: %d\n", ifi->racnt); TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) { fprintf(fp, " RA from %s\n", inet_ntop(AF_INET6, &rai->rai_saddr.sin6_addr, ntopbuf, sizeof(ntopbuf))); TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) { fprintf(fp, " option: "); switch (rao->rao_type) { case ND_OPT_RDNSS: fprintf(fp, "RDNSS: %s (expire: %s)\n", (char *)rao->rao_msg, sec2str(&rao->rao_expire)); break; case ND_OPT_DNSSL: fprintf(fp, "DNSSL: %s (expire: %s)\n", (char *)rao->rao_msg, sec2str(&rao->rao_expire)); break; default: break; } } fprintf(fp, "\n"); } } fflush(fp); } FILE * rtsold_init_dumpfile(const char *dumpfile) { cap_rights_t rights; FILE *fp; if ((fp = fopen(dumpfile, "w")) == NULL) { warnmsg(LOG_WARNING, __func__, "opening a dump file(%s): %s", dumpfile, strerror(errno)); return (NULL); } cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE); if (caph_rights_limit(fileno(fp), &rights) != 0) { warnmsg(LOG_WARNING, __func__, "caph_rights_limit(%s): %s", dumpfile, strerror(errno)); + (void)fclose(fp); return (NULL); } return (fp); } const char * sec2str(const struct timespec *total) { static char result[256]; int days, hours, mins, secs; int first = 1; char *p = result; char *ep = &result[sizeof(result)]; int n; struct timespec now; time_t tsec; clock_gettime(CLOCK_MONOTONIC_FAST, &now); tsec = total->tv_sec; tsec += total->tv_nsec / 1000 / 1000000; tsec -= now.tv_sec; tsec -= now.tv_nsec / 1000 / 1000000; days = tsec / 3600 / 24; hours = (tsec / 3600) % 24; mins = (tsec / 60) % 60; secs = tsec % 60; if (days) { first = 0; n = snprintf(p, ep - p, "%dd", days); if (n < 0 || n >= ep - p) return "?"; p += n; } if (!first || hours) { first = 0; n = snprintf(p, ep - p, "%dh", hours); if (n < 0 || n >= ep - p) return "?"; p += n; } if (!first || mins) { first = 0; n = snprintf(p, ep - p, "%dm", mins); if (n < 0 || n >= ep - p) return "?"; p += n; } snprintf(p, ep - p, "%ds", secs); return (result); } diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c index 2cc5fa41c29b..b2f2c640b175 100644 --- a/usr.sbin/rtsold/if.c +++ b/usr.sbin/rtsold/if.c @@ -1,358 +1,358 @@ /* $KAME: if.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtsold.h" static int ifsock; static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); int ifinit(void) { cap_rights_t rights; int sock; sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock < 0) { warnmsg(LOG_ERR, __func__, "socket(): %s", strerror(errno)); return (-1); } if (caph_rights_limit(sock, cap_rights_init(&rights, CAP_IOCTL)) < 0) { warnmsg(LOG_ERR, __func__, "caph_rights_limit(): %s", strerror(errno)); (void)close(sock); return (-1); } ifsock = sock; return (0); } int interface_up(char *name) { struct ifreq ifr; struct in6_ndireq nd; int llflag; int s; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); memset(&nd, 0, sizeof(nd)); strlcpy(nd.ifname, name, sizeof(nd.ifname)); if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", strerror(errno)); return (-1); } if (!(ifr.ifr_flags & IFF_UP)) { ifr.ifr_flags |= IFF_UP; if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) warnmsg(LOG_ERR, __func__, "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); return (-1); } if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", strerror(errno)); return (-1); } if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", strerror(errno)); close(s); return (-1); } warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); if (nd.ndi.flags & ND6_IFF_IFDISABLED) { if (Fflag) { nd.ndi.flags &= ~ND6_IFF_IFDISABLED; if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { warnmsg(LOG_WARNING, __func__, "ioctl(SIOCSIFINFO_IN6): %s", strerror(errno)); close(s); return (-1); } } else { warnmsg(LOG_WARNING, __func__, "%s is disabled.", name); close(s); return (-1); } } if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { if (Fflag) { nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { warnmsg(LOG_WARNING, __func__, "ioctl(SIOCSIFINFO_IN6): %s", strerror(errno)); close(s); return (-1); } } else { warnmsg(LOG_WARNING, __func__, "%s does not accept Router Advertisement.", name); close(s); return (-1); } } close(s); if (cap_llflags_get(capllflags, name, &llflag) != 0) { warnmsg(LOG_WARNING, __func__, "cap_llflags_get() failed, anyway I'll try"); return (0); } if (!(llflag & IN6_IFF_NOTREADY)) { warnmsg(LOG_DEBUG, __func__, "%s is ready", name); return (0); } else { if (llflag & IN6_IFF_TENTATIVE) { warnmsg(LOG_DEBUG, __func__, "%s is tentative", name); return (IFS_TENTATIVE); } if (llflag & IN6_IFF_DUPLICATED) warnmsg(LOG_DEBUG, __func__, "%s is duplicated", name); return (-1); } } int interface_status(struct ifinfo *ifinfo) { char *ifname = ifinfo->ifname; struct ifreq ifr; struct ifmediareq ifmr; /* get interface flags */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", ifname, strerror(errno)); return (-1); } /* * if one of UP and RUNNING flags is dropped, * the interface is not active. */ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) goto inactive; /* Next, check carrier on the interface, if possible */ if (!ifinfo->mediareqok) goto active; memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { if (errno != EINVAL) { warnmsg(LOG_DEBUG, __func__, "ioctl(SIOCGIFMEDIA) on %s: %s", ifname, strerror(errno)); return(-1); } /* * EINVAL simply means that the interface does not support * the SIOCGIFMEDIA ioctl. We regard it alive. */ ifinfo->mediareqok = 0; goto active; } if (ifmr.ifm_status & IFM_AVALID) { switch (ifmr.ifm_active & IFM_NMASK) { case IFM_ETHER: case IFM_IEEE80211: if (ifmr.ifm_status & IFM_ACTIVE) goto active; else goto inactive; break; default: goto inactive; } } inactive: return (0); active: return (1); } #define ROUNDUP(a, size) \ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ sizeof(u_long)) : sizeof(u_long))) #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) int lladdropt_length(struct sockaddr_dl *sdl) { switch (sdl->sdl_type) { case IFT_ETHER: return (ROUNDUP8(ETHER_ADDR_LEN + 2)); default: return (0); } } void lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) { char *addr; ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ switch (sdl->sdl_type) { case IFT_ETHER: ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; addr = (char *)(ndopt + 1); memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); break; default: warnmsg(LOG_ERR, __func__, "unsupported link type(%d)", sdl->sdl_type); exit(1); } } struct sockaddr_dl * if_nametosdl(char *name) { int mib[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl = NULL, *ret_sdl; if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) return(NULL); if ((buf = malloc(len)) == NULL) return(NULL); if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) < 0) { free(buf); return (NULL); } lim = buf + len; for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)(void *)next; if (ifm->ifm_type == RTM_IFINFO) { sa = (struct sockaddr *)(ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)(void *)sa; if (strlen(name) != sdl->sdl_nlen) continue; /* not same len */ if (strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { break; } } } } } - if (next == lim) { + if (next >= lim) { /* search failed */ free(buf); return (NULL); } if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { free(buf); return (NULL); } memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); free(buf); return (ret_sdl); } static void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; NEXT_SA(sa); } else rti_info[i] = NULL; } } diff --git a/usr.sbin/rtsold/rtsock.c b/usr.sbin/rtsold/rtsock.c index 37f7df29d0b7..4dfbf61f47db 100644 --- a/usr.sbin/rtsold/rtsock.c +++ b/usr.sbin/rtsold/rtsock.c @@ -1,177 +1,177 @@ /* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */ /* $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 2000 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtsold.h" static int rtsock_input_ifannounce(int, struct rt_msghdr *, char *); static struct { u_char type; size_t minlen; int (*func)(int, struct rt_msghdr *, char *); } rtsock_dispatch[] = { { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr), rtsock_input_ifannounce }, { 0, 0, NULL }, }; int rtsock_open(void) { cap_rights_t rights; int error, s; s = socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) return (s); cap_rights_init(&rights, CAP_EVENT, CAP_READ); if (caph_rights_limit(s, &rights) != 0) { error = errno; (void)close(s); - errno = errno; + errno = error; return (-1); } return (s); } int rtsock_input(int s) { ssize_t n; char msg[2048]; char *lim, *next; struct rt_msghdr *rtm; int idx; ssize_t len; int ret = 0; const ssize_t lenlim = offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen); n = read(s, msg, sizeof(msg)); lim = msg + n; for (next = msg; next < lim; next += len) { rtm = (struct rt_msghdr *)(void *)next; if (lim - next < lenlim) break; len = rtm->rtm_msglen; if (len < lenlim) break; if (dflag > 1) { warnmsg(LOG_INFO, __func__, "rtmsg type %d, len=%lu", rtm->rtm_type, (u_long)len); } for (idx = 0; rtsock_dispatch[idx].func; idx++) { if (rtm->rtm_type != rtsock_dispatch[idx].type) continue; if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) { warnmsg(LOG_INFO, __func__, "rtmsg type %d too short!", rtm->rtm_type); continue; } ret = (*rtsock_dispatch[idx].func)(s, rtm, lim); break; } } return (ret); } static int rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim) { struct if_announcemsghdr *ifan; struct ifinfo *ifi; ifan = (struct if_announcemsghdr *)rtm; if ((char *)(ifan + 1) > lim) return (-1); switch (ifan->ifan_what) { case IFAN_ARRIVAL: /* * XXX for NetBSD 1.5, interface index will monotonically be * increased as new pcmcia card gets inserted. * we may be able to do a name-based interface match, * and call ifreconfig() to enable the interface again. */ warnmsg(LOG_INFO, __func__, "interface %s inserted", ifan->ifan_name); break; case IFAN_DEPARTURE: warnmsg(LOG_WARNING, __func__, "interface %s removed", ifan->ifan_name); ifi = find_ifinfo(ifan->ifan_index); if (ifi) { if (dflag > 1) { warnmsg(LOG_INFO, __func__, "bring interface %s to DOWN state", ifan->ifan_name); } ifi->state = IFS_DOWN; } break; } return (0); }