diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /network_cmds/rtsol.tproj | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'network_cmds/rtsol.tproj')
-rw-r--r-- | network_cmds/rtsol.tproj/dump.c | 172 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/if.c | 501 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/probe.c | 221 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/rtsock.c | 179 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/rtsol.8 | 224 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/rtsol.c | 343 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/rtsold.c | 791 | ||||
-rw-r--r-- | network_cmds/rtsol.tproj/rtsold.h | 96 |
8 files changed, 2527 insertions, 0 deletions
diff --git a/network_cmds/rtsol.tproj/dump.c b/network_cmds/rtsol.tproj/dump.c new file mode 100644 index 0000000..69937f0 --- /dev/null +++ b/network_cmds/rtsol.tproj/dump.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $KAME: dump.c,v 1.8 2000/10/05 22:20:39 itojun Exp $ */ + +/* + * 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: src/usr.sbin/rtsold/dump.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/icmp6.h> + +#include <syslog.h> +#include <time.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "rtsold.h" + +static FILE *fp; + +extern struct ifinfo *iflist; + +static void dump_interface_status __P((void)); +static char *sec2str __P((time_t)); +char *ifstatstr[] = { + "IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE", "OPTIMISTIC" +}; + +static void +dump_interface_status() +{ + struct ifinfo *ifinfo; + struct timeval now; + + gettimeofday(&now, NULL); + + for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { + fprintf(fp, "Interface %s\n", ifinfo->ifname); + fprintf(fp, " probe interval: "); + if (ifinfo->probeinterval) { + fprintf(fp, "%d\n", ifinfo->probeinterval); + fprintf(fp, " probe timer: %d\n", ifinfo->probetimer); + } + else { + fprintf(fp, "infinity\n"); + fprintf(fp, " no probe timer\n"); + } + fprintf(fp, " interface status: %s\n", + ifinfo->active > 0 ? "active" : "inactive"); + fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]); + fprintf(fp, " carrier detection: %s\n", + ifinfo->mediareqok ? "available" : "unavailable"); + fprintf(fp, " probes: %d, dadcount = %d\n", + ifinfo->probes, ifinfo->dadcount); + if (ifinfo->timer.tv_sec == tm_max.tv_sec && + ifinfo->timer.tv_usec == tm_max.tv_usec) + fprintf(fp, " no timer\n"); + else { + fprintf(fp, " timer: interval=%d:%d, expire=%s\n", + (int)ifinfo->timer.tv_sec, + (int)ifinfo->timer.tv_usec, + (ifinfo->expire.tv_sec < now.tv_sec) ? "expired" + : sec2str(ifinfo->expire.tv_sec - now.tv_sec)); + } + fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt); + } +} + +void +rtsold_dump_file(dumpfile) + char *dumpfile; +{ + if ((fp = fopen(dumpfile, "w")) == NULL) { + warnmsg(LOG_WARNING, __FUNCTION__, "open a dump file(%s): %s", + dumpfile, strerror(errno)); + return; + } + + dump_interface_status(); + + fclose(fp); +} + +static char * +sec2str(total) + time_t total; +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += snprintf(p, sizeof(result) - (p - result), "%dd", days); + } + if (!first || hours) { + first = 0; + p += snprintf(p, sizeof(result) - (p - result), "%dh", hours); + } + if (!first || mins) { + first = 0; + p += snprintf(p, sizeof(result) - (p - result), "%dm", mins); + } + snprintf(p, sizeof(result) - (p - result), "%ds", secs); + + return(result); +} diff --git a/network_cmds/rtsol.tproj/if.c b/network_cmds/rtsol.tproj/if.c new file mode 100644 index 0000000..b46c781 --- /dev/null +++ b/network_cmds/rtsol.tproj/if.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $KAME: if.c,v 1.15 2001/05/22 06:04:17 jinmei Exp $ */ + +/* + * 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: src/usr.sbin/rtsold/if.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/ioctl.h> +#include <sys/queue.h> + +#include <net/if.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) +#include <net/if_var.h> +#endif /* __FreeBSD__ >= 3 */ +#include <net/if_types.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#if defined ( __FreeBSD__) || defined (__APPLE__) +# include <net/ethernet.h> +#endif +#ifdef __NetBSD__ +#include <net/if_ether.h> +#endif +#if defined(__bsdi__) || defined(__OpenBSD__) +# include <netinet/in.h> +# include <netinet/if_ether.h> +#endif +#include <netinet/in.h> +#include <netinet/icmp6.h> + +#include <netinet6/in6_var.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <syslog.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#ifdef HAVE_GETIFADDRS +#include <ifaddrs.h> +#endif + +#include "rtsold.h" + +extern int rssock; +static int ifsock; + +static int get_llflag __P((const char *name)); +#ifndef HAVE_GETIFADDRS +static unsigned int if_maxindex __P((void)); +#endif +static void get_rtaddrs __P((int addrs, struct sockaddr *sa, + struct sockaddr **rti_info)); + +int +ifinit() +{ + ifsock = rssock; + + return(0); +} + +int +interface_up(char *name) +{ + struct ifreq ifr; + int llflag; + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warnmsg(LOG_WARNING, __FUNCTION__, "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, __FUNCTION__, + "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); + } + return(-1); + } + + warnmsg(LOG_DEBUG, __FUNCTION__, "checking if %s is ready...", name); + + llflag = get_llflag(name); + if (llflag < 0) { + warnmsg(LOG_WARNING, __FUNCTION__, + "get_llflag() failed, anyway I'll try"); + return 0; + } + + if (!(llflag & (IN6_IFF_NOTREADY | IN6_IFF_DADPROGRESS))) { + warnmsg(LOG_DEBUG, __FUNCTION__, + "%s is ready", name); + return(0); + } else { + if (llflag & IN6_IFF_TENTATIVE) { + warnmsg(LOG_DEBUG, __FUNCTION__, "%s is tentative", + name); + return IFS_TENTATIVE; + } + if (llflag & IN6_IFF_OPTIMISTIC) { + warnmsg(LOG_DEBUG, __FUNCTION__, "%s is optimistic", + name); + return IFS_OPTIMISTIC; + } + if (llflag & IN6_IFF_DUPLICATED) + warnmsg(LOG_DEBUG, __FUNCTION__, "%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, __FUNCTION__, "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, __FUNCTION__, + "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: + 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(uint32_t)) :\ + sizeof(uint32_t))) +#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) + +int +lladdropt_length(struct sockaddr_dl *sdl) +{ + switch(sdl->sdl_type) { + case IFT_ETHER: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif + 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: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif + 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, __FUNCTION__, + "unsupported link type(%d)", sdl->sdl_type); + exit(1); + } + + return; +} + +struct sockaddr_dl * +if_nametosdl(char *name) +{ + int mib[6] = {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, 6, NULL, &len, NULL, 0) < 0) + return(NULL); + if ((buf = malloc(len)) == NULL) + return(NULL); + if (sysctl(mib, 6, 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 *)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 *)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) { + /* search failed */ + free(buf); + return(NULL); + } + + if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) + return(NULL); + memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); + + free(buf); + return(ret_sdl); +} + +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) + return -1; + else + return value; +} + +/*------------------------------------------------------------*/ + +/* get ia6_flags for link-local addr on if. returns -1 on error. */ +static int +get_llflag(const char *name) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifap, *ifa; + struct in6_ifreq ifr6; + struct sockaddr_in6 *sin6; + int s; + + if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s", + strerror(errno)); + exit(1); + } + if (getifaddrs(&ifap) != 0) { + warnmsg(LOG_ERR, __FUNCTION__, "etifaddrs: %s", + strerror(errno)); + exit(1); + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strlen(ifa->ifa_name) != strlen(name) + || strncmp(ifa->ifa_name, name, strlen(name)) != 0) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + + memset(&ifr6, 0, sizeof(ifr6)); + strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); + memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); + exit(1); + } + + freeifaddrs(ifap); + close(s); + return ifr6.ifr_ifru.ifru_flags6; + } + + freeifaddrs(ifap); + close(s); + return -1; +#else + int s; + unsigned int maxif; + struct ifreq *iflist; + struct ifconf ifconf; + struct ifreq *ifr, *ifr_end; + struct sockaddr_in6 *sin6; + struct in6_ifreq ifr6; + + maxif = if_maxindex() + 1; + iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */ + if (iflist == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "not enough core"); + exit(1); + } + + if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s", + strerror(errno)); + exit(1); + } + memset(&ifconf, 0, sizeof(ifconf)); + ifconf.ifc_req = iflist; + ifconf.ifc_len = maxif * BUFSIZ; /* XXX */ + if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFCONF): %s", + strerror(errno)); + exit(1); + } + + /* Look for this interface in the list */ + ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); + for (ifr = ifconf.ifc_req; + ifr < ifr_end; + ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + + ifr->ifr_addr.sa_len)) { + if (strlen(ifr->ifr_name) != strlen(name) + || strncmp(ifr->ifr_name, name, strlen(name)) != 0) + continue; + if (ifr->ifr_addr.sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + + memset(&ifr6, 0, sizeof(ifr6)); + strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); + memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); + exit(1); + } + + free(iflist); + close(s); + return ifr6.ifr_ifru.ifru_flags6; + } + + free(iflist); + close(s); + return -1; +#endif +} + +#ifndef HAVE_GETIFADDRS +static unsigned int +if_maxindex() +{ + struct if_nameindex *p, *p0; + unsigned int max = 0; + + p0 = if_nameindex(); + for (p = p0; p && p->if_index && p->if_name; p++) { + if (max < p->if_index) + max = p->if_index; + } + if_freenameindex(p0); + return max; +} +#endif + +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/network_cmds/rtsol.tproj/probe.c b/network_cmds/rtsol.tproj/probe.c new file mode 100644 index 0000000..305d0a2 --- /dev/null +++ b/network_cmds/rtsol.tproj/probe.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2009 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */ + +/* + * Copyright (C) 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: src/usr.sbin/rtsold/probe.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/queue.h> + +#include <net/if.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <net/if_var.h> +#endif /* __FreeBSD__ >= 3 */ + +#include <netinet/in.h> +#include <netinet6/in6_var.h> +#include <netinet/icmp6.h> +#include <netinet6/nd6.h> + +#include <arpa/inet.h> + +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <stdlib.h> + +#include "rtsold.h" + +static struct msghdr sndmhdr; +static struct iovec sndiov[2]; +static int probesock; +static void sendprobe __P((struct in6_addr *addr, int ifindex)); + + +int +probe_init() +{ + int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + static u_char *sndcmsgbuf = NULL; + + if (sndcmsgbuf == NULL && + (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "malloc failed"); + return(-1); + } + + if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return(-1); + } + +#ifndef __APPLE__ + /* make the socket send-only */ + if (shutdown(probesock, 0)) { + warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno)); + return(-1); + } +#endif /* __APPLE__ */ + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = scmsglen; + + return(0); +} + +/* + * Probe if each router in the default router list is still alive. + */ +void +defrouter_probe(int ifindex) +{ + struct in6_drlist dr; + int s, i; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return; + } + bzero(&dr, sizeof(dr)); + strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy interface */ + if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s", + strerror(errno)); + goto closeandend; + } + + for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { + if (ifindex && dr.defrouter[i].if_index == ifindex) { + /* sanity check */ + if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { + warnmsg(LOG_ERR, __FUNCTION__, + "default router list contains a " + "non-linklocal address(%s)", + inet_ntop(AF_INET6, + &dr.defrouter[i].rtaddr, + (char *)ntopbuf, INET6_ADDRSTRLEN)); + continue; /* ignore the address */ + } + sendprobe(&dr.defrouter[i].rtaddr, + dr.defrouter[i].if_index); + } + } + + closeandend: + close(s); + return; +} + +static void +sendprobe(struct in6_addr *addr, int ifindex) +{ + struct sockaddr_in6 sa6_probe; + struct in6_pktinfo *pi; + struct cmsghdr *cm; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];; + + bzero(&sa6_probe, sizeof(sa6_probe)); + sa6_probe.sin6_family = AF_INET6; + sa6_probe.sin6_len = sizeof(sa6_probe); + sa6_probe.sin6_addr = *addr; + + sndmhdr.msg_name = (caddr_t)&sa6_probe; + sndmhdr.msg_iov[0].iov_base = NULL; + sndmhdr.msg_iov[0].iov_len = 0; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + 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 = ifindex; + + /* specify the hop limit of the packet for safety */ + { + int hoplimit = 1; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s", + inet_ntop(AF_INET6, addr, (char *)ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(ifindex, (char *)ifnamebuf)); + + if (sendmsg(probesock, &sndmhdr, 0)) + warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", + if_indextoname(ifindex, (char *)ifnamebuf), strerror(errno)); + + return; +} diff --git a/network_cmds/rtsol.tproj/rtsock.c b/network_cmds/rtsol.tproj/rtsock.c new file mode 100644 index 0000000..e3f16e4 --- /dev/null +++ b/network_cmds/rtsol.tproj/rtsock.c @@ -0,0 +1,179 @@ +/* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */ +/* $FreeBSD: src/usr.sbin/rtsold/rtsock.c,v 1.1.2.1 2001/07/03 11:02:16 ume Exp $ */ + +/* + * 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 <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/time.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> + +#include <time.h> +#include <unistd.h> +#include <stdio.h> +#include <stddef.h> +#include <err.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> +#include "rtsold.h" + +#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(uint32_t)) \ + : sizeof(uint32_t))) + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int rtsock_input_ifannounce __P((int, struct rt_msghdr *, char *)); +#endif + +static struct { + u_char type; + size_t minlen; + int (*func) __P((int, struct rt_msghdr *, char *)); +} rtsock_dispatch[] = { +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ + { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr), + rtsock_input_ifannounce }, +#endif + { 0, 0UL, NULL }, +}; + +int +rtsock_open() +{ + + return socket(PF_ROUTE, SOCK_RAW, 0); +} + +int +rtsock_input(s) + int s; +{ + ssize_t n; + char msg[2048]; + char *lim, *next; + struct rt_msghdr *rtm; + int idx; + size_t len; + int ret = 0; + const size_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 *)next; + if (lim - next < lenlim) + break; + len = rtm->rtm_msglen; + if (len < lenlim) + break; + + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "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, __FUNCTION__, + "rtmsg type %d too short!", rtm->rtm_type); + continue; + } + + ret = (*rtsock_dispatch[idx].func)(s, rtm, lim); + break; + } + } + + return ret; +} + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int +rtsock_input_ifannounce(s, rtm, lim) + int s; + struct rt_msghdr *rtm; + char *lim; +{ + struct if_announcemsghdr *ifan; + struct ifinfo *ifinfo; + + 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, __FUNCTION__, + "interface %s inserted", ifan->ifan_name); + break; + case IFAN_DEPARTURE: + warnmsg(LOG_WARNING, __FUNCTION__, + "interface %s removed", ifan->ifan_name); + ifinfo = find_ifinfo(ifan->ifan_index); + if (ifinfo) { + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "bring interface %s to DOWN state", + ifan->ifan_name); + } + ifinfo->state = IFS_DOWN; + } + break; + } + + return 0; +} +#endif diff --git a/network_cmds/rtsol.tproj/rtsol.8 b/network_cmds/rtsol.tproj/rtsol.8 new file mode 100644 index 0000000..30c3768 --- /dev/null +++ b/network_cmds/rtsol.tproj/rtsol.8 @@ -0,0 +1,224 @@ +.\" $KAME: rtsold.8,v 1.16 2000/10/15 13:19:05 itojun Exp $ +.\" +.\" 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: src/usr.sbin/rtsold/rtsold.8,v 1.1.2.5 2001/08/16 15:56:30 ru Exp $ +.\" +.Dd May 17, 1998 +.Dt RTSOLD 8 +.Os +.\" +.Sh NAME +.Nm rtsold +.Nd router solicitation daemon +.\" +.Sh SYNOPSIS +.Nm +.Op Fl dDfm1 +.Ar interface ... +.Nm +.Op Fl dDfm1 +.Fl a +.Nm rtsol +.Op Fl dD +.Ar interface ... +.Nm rtsol +.Op Fl dD +.Fl a +.\" +.Sh DESCRIPTION +.Nm +is the daemon program to send ICMPv6 Router Solicitation messages +on the specified interfaces. +If a node (re)attaches to a link, +.Nm +sends some Router Solicitations on the link destined to the link-local scope +all-routers multicast address to discover new routers +and to get non link-local addresses. +.Pp +.Nm +should be used on IPv6 hosts +(non-router nodes) +only. +.Pp +If you invoke the program as +.Nm rtsol , +it will transmit probes from the specified +.Ar interface , +without becoming a daemon. +In other words, +.Nm rtsol +behaves as +.Do +.Nm +.Fl f1 +.Ar interfaces +.Dc . +.Pp +Specifically, +.Nm +sends at most 3 Router Solicitations on an interface +after one of the following events: +.Pp +.Bl -bullet -compact +.It +Just after invocation of +.Nm +daemon. +.It +The interface is up after a temporary interface failure. +.Nm +detects such failures by periodically probing to see if the status +of the interface is active or not. +Note that some network cards and drivers do not allow the extraction +of link state. +In such cases, +.Nm +cannot detect the change of the interface status. +.It +Every 60 seconds if the +.Fl m +option is specified and the +.Nm +daemon cannot get the interface status. +This feature does not conform to the IPv6 neighbor discovery +specification, but is provided for mobile stations. +The default interval for router advertisements, which is on the order of 10 +minutes, is slightly long for mobile stations. +This feature is provided +for such stations so that they can find new routers as soon as possible +when they attach to another link. +.El +.Lp +Once +.Nm +has sent a Router Solicitation, and has received a valid Router Advertisement, +it refrains from sending additional solicitations on that interface, until +the next time one of the above events occurs. +.Lp +When sending a Router Solicitation on an interface, +.Nm +includes a Source Link-layer address option if the interface +has a link-layer address. +.Pp +Upon receipt of signal +.Dv SIGUSR1 , +.Nm +will dump the current internal state into +.Pa /var/run/rtsold.dump . +.\" +.Sh OPTIONS +.Bl -tag -width indent +.It Fl a +Autoprobe outgoing interface. +.Nm +will try to find a non-loopback, non-point-to-point, IPv6-capable interface. +If +.Nm +finds multiple interfaces, +.Nm +will exit with error. +.\" +.It Fl d +Enable debugging. +.It Fl D +Enable more debugging including the printing of internal timer information. +.It Fl f +.Fl f +prevents +.Nm +from becoming a daemon (foreground mode). +Warning messages are generated to standard error +instead of +.Xr syslog 3 . +.It Fl m +Enable mobility support. +If this option is specified, +.Nm +sends probing packets to default routers that have advertised Router +Advertisements +when the node (re)attaches to an interface. +Moreover, if the option is specified, +.Nm +periodically sends Router Solicitation on an interface that does not support +.Dv SIOCGIFMEDIA +ioctl. +.It Fl 1 +Perform only one probe. +Transmit Router Solicitation packets until at least one valid Router +Advertisement packet has arrived on each +.Ar interface , +then exit. +.El +.Sh DIAGNOSTICS +.Ex -std +.\" +.Sh FILES +.Bl -tag -width /var/run/rtsold.dump -compact +.It Pa /var/run/rtsold.pid +the pid of the currently running +.Nm . +.It Pa /var/run/rtsold.dump +dumps internal state on. +.El +.\" +.Sh SEE ALSO +.Xr rtadvd 8 , +.Xr sysctl 8 +.\" +.Sh HISTORY +The +.Nm +command is based on the +.Nm rtsol +command, which first appeared in WIDE/KAME IPv6 protocol stack kit. +.Nm rtsol +is now integrated into +.Xr rtsold 8 . +.\" +.Sh BUGS +In some operating systems, when a PCMCIA network card is removed +and reinserted, the corresponding interface index is changed. +However, +.Nm +assumes such changes will not occur, and always uses the index that +it got at invocation. As a result, +.Nm +may not work if you reinsert a network card. +In such a case, +.Nm +should be killed and restarted. +.Pp +The IPv6 autoconfiguration specification assumes a single-interface host. +You may see kernel error messages if you try to autoconfigure a host with +multiple interfaces. +Also, it seems contradictory for +.Nm +to accept multiple +.Ar interface +arguments. diff --git a/network_cmds/rtsol.tproj/rtsol.c b/network_cmds/rtsol.tproj/rtsol.c new file mode 100644 index 0000000..e1b9bff --- /dev/null +++ b/network_cmds/rtsol.tproj/rtsol.c @@ -0,0 +1,343 @@ +/* $KAME: rtsol.c,v 1.11 2000/08/13 06:14:59 itojun Exp $ */ + +/* + * 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: src/usr.sbin/rtsold/rtsol.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/time.h> +#include <sys/queue.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet/icmp6.h> + +#include <arpa/inet.h> + +#include <time.h> +#include <unistd.h> +#include <stdio.h> +#include <err.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> +#include "rtsold.h" + +#define ALLROUTER "ff02::2" + +static struct msghdr rcvmhdr; +static struct msghdr sndmhdr; +static struct iovec rcviov[2]; +static struct iovec sndiov[2]; +static struct sockaddr_in6 from; + +int rssock; + +static struct sockaddr_in6 sin6_allrouters = {sizeof(sin6_allrouters), AF_INET6}; + +int +sockopen() +{ + int on; + struct icmp6_filter filt; + static u_char answer[1500]; + int rcvcmsglen, sndcmsglen; + static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL; + + sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "malloc for receive msghdr failed"); + return(-1); + } + if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "malloc for send msghdr failed"); + return(-1); + } + memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6)); + if (inet_pton(AF_INET6, ALLROUTER, + &sin6_allrouters.sin6_addr.s6_addr) != 1) { + warnmsg(LOG_ERR, __FUNCTION__, "inet_pton failed for %s", + ALLROUTER); + return(-1); + } + + if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return(-1); + } + + /* specify to tell receiving interface */ + on = 1; +#ifdef IPV6_RECVPKTINFO + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVPKTINFO: %s", + strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_PKTINFO: %s", + strerror(errno)); + exit(1); + } +#endif + + on = 1; + /* specify to tell value of hoplimit field of received IP6 hdr */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVHOPLIMIT: %s", + strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_HOPLIMIT: %s", + strerror(errno)); + exit(1); + } +#endif + + /* specfiy to accept only router advertisements on the socket */ + ICMP6_FILTER_SETBLOCKALL(&filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); + if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) == -1) { + warnmsg(LOG_ERR, __FUNCTION__, "setsockopt(ICMP6_FILTER): %s", + strerror(errno)); + return(-1); + } + + /* initialize msghdr for receiving packets */ + rcviov[0].iov_base = (caddr_t)answer; + rcviov[0].iov_len = sizeof(answer); + rcvmhdr.msg_name = (caddr_t)&from; + rcvmhdr.msg_namelen = sizeof(from); + rcvmhdr.msg_iov = rcviov; + rcvmhdr.msg_iovlen = 1; + rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; + rcvmhdr.msg_controllen = rcvcmsglen; + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = sndcmsglen; + + return(rssock); +} + +void +sendpacket(struct ifinfo *ifinfo) +{ + int i; + struct cmsghdr *cm; + struct in6_pktinfo *pi; + + sndmhdr.msg_name = (caddr_t)&sin6_allrouters; + sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data; + sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + 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 = ifinfo->sdl->sdl_index; + + /* specify the hop limit of the packet */ + { + int hoplimit = 255; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + warnmsg(LOG_DEBUG, + __FUNCTION__, "send RS on %s, whose state is %d", + ifinfo->ifname, ifinfo->state); + + i = sendmsg(rssock, &sndmhdr, 0); + + if (i < 0 || i != ifinfo->rs_datalen) { + /* + * ENETDOWN is not so serious, especially when using several + * network cards on a mobile node. We ignore it. + */ + if (errno != ENETDOWN || dflag > 0) + warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", + ifinfo->ifname, strerror(errno)); + } + + /* update counter */ + ifinfo->probes++; +} + +void +rtsol_input(int s) +{ + int i; + int *hlimp = NULL; + struct icmp6_hdr *icp; + int ifindex = 0; + struct cmsghdr *cm; + struct in6_pktinfo *pi = NULL; + struct ifinfo *ifi = NULL; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + + /* get message */ + if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "recvmsg: %s", strerror(errno)); + return; + } + + /* extract optional information via Advanced API */ + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); + cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + ifindex = pi->ipi6_ifindex; + } + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + hlimp = (int *)CMSG_DATA(cm); + } + + if (ifindex == 0) { + warnmsg(LOG_ERR, + __FUNCTION__, "failed to get receiving interface"); + return; + } + if (hlimp == NULL) { + warnmsg(LOG_ERR, + __FUNCTION__, "failed to get receiving hop limit"); + return; + } + + if (i < sizeof(struct nd_router_advert)) { + warnmsg(LOG_ERR, + __FUNCTION__, "packet size(%d) is too short", i); + return; + } + + icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; + + if (icp->icmp6_type != ND_ROUTER_ADVERT) { + warnmsg(LOG_ERR, __FUNCTION__, + "invalid icmp type(%d) from %s on %s", icp->icmp6_type, + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf)); + return; + } + + if (icp->icmp6_code != 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "invalid icmp code(%d) from %s on %s", icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf)); + return; + } + + if (*hlimp != 255) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "invalid RA with hop limit(%d) from %s on %s", + *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf)); + return; + } + + if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "invalid RA with non link-local source from %s on %s", + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf)); + return; + } + + /* xxx: more validation? */ + + if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "received RA from %s on an unexpeced IF(%s)", + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf)); + return; + } + + warnmsg(LOG_DEBUG, __FUNCTION__, + "received RA from %s on %s, state is %d", + inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf, + INET6_ADDRSTRLEN), + ifi->ifname, ifi->state); + + ifi->racnt++; + + switch(ifi->state) { + case IFS_IDLE: /* should be ignored */ + case IFS_DELAY: /* right? */ + break; + case IFS_PROBE: + ifi->state = IFS_IDLE; + ifi->probes = 0; + rtsol_timer_update(ifi); + break; + } +} diff --git a/network_cmds/rtsol.tproj/rtsold.c b/network_cmds/rtsol.tproj/rtsold.c new file mode 100644 index 0000000..68923ec --- /dev/null +++ b/network_cmds/rtsol.tproj/rtsold.c @@ -0,0 +1,791 @@ +/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei Exp $ */ + +/* + * 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: src/usr.sbin/rtsold/rtsold.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_dl.h> + +#include <netinet/in.h> +#include <netinet/icmp6.h> + +#include <signal.h> +#include <unistd.h> +#include <syslog.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <err.h> +#include <stdarg.h> +#include <ifaddrs.h> +#include "rtsold.h" + +struct ifinfo *iflist; +struct timeval tm_max = {0x7fffffff, 0x7fffffff}; +int aflag = 0; +int dflag = 0; +static int log_upto = 999; +static int fflag = 0; + +/* protocol constatns */ +#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ +#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ +#define MAX_RTR_SOLICITATIONS 3 /* times */ + +/* implementation dependent constants */ +#define PROBE_INTERVAL 60 /* secondes XXX: should be configurable */ + +/* utility macros */ +/* a < b */ +#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) && \ + ((a).tv_usec < (b).tv_usec))) + +/* a <= b */ +#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) &&\ + ((a).tv_usec <= (b).tv_usec))) + +/* a == b */ +#define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec)) + +int main __P((int argc, char *argv[])); + +/* static variables and functions */ +static int mobile_node = 0; +static int do_dump; +static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ +static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ + +static int ifconfig __P((char *ifname)); +#if 0 +static int ifreconfig __P((char *ifname)); +#endif +static int make_packet __P((struct ifinfo *ifinfo)); +static struct timeval *rtsol_check_timer __P((void)); +static void TIMEVAL_ADD __P((struct timeval *a, struct timeval *b, + struct timeval *result)); +static void TIMEVAL_SUB __P((struct timeval *a, struct timeval *b, + struct timeval *result)); + +static void rtsold_set_dump_file __P((void)); +static void usage __P((char *progname)); +static char **autoifprobe __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int s, rtsock, maxfd, ch; + int once = 0; + struct timeval *timeout; + struct fd_set fdset; + char *argv0; + char *opts; + + /* + * Initialization + */ + argv0 = argv[0]; + + /* get option */ + if (argv0 && argv0[strlen(argv0) - 1] != 'd') { + fflag = 1; + once = 1; + opts = "adD"; + } else + opts = "adDfm1"; + + while ((ch = getopt(argc, argv, opts)) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'D': + dflag = 2; + break; + case 'f': + fflag = 1; + break; + case 'm': + mobile_node = 1; + break; + case '1': + once = 1; + break; + default: + usage(argv0); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (aflag) { + int i; + + if (argc != 0) { + usage(argv0); + /*NOTREACHED*/ + } + + argv = autoifprobe(); + if (!argv) { + errx(1, "could not autoprobe interface"); + /*NOTREACHED*/ + } + + for (i = 0; argv[i]; i++) + ; + argc = i; + } + if (argc == 0) { + usage(argv0); + /*NOTREACHED*/ + } + + /* set log level */ + if (dflag == 0) + log_upto = LOG_NOTICE; + if (!fflag) { + char *ident; + ident = strrchr(argv0, '/'); + if (!ident) + ident = argv0; + else + ident++; + openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); + if (log_upto >= 0) + setlogmask(LOG_UPTO(log_upto)); + } + +#ifndef HAVE_ARC4RANDOM + /* random value initilization */ + srandom((u_long)time(NULL)); +#endif + + /* warn if accept_rtadv is down */ + if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) + warnx("kernel is configured not to accept RAs"); + /* warn if forwarding is up */ + if (getinet6sysctl(IPV6CTL_FORWARDING)) + warnx("kernel is configured as a router, not a host"); + + /* initialization to dump internal status to a file */ + if (signal(SIGUSR1, (void *)rtsold_set_dump_file) < 0) { + errx(1, "failed to set signal for dump status"); + /*NOTREACHED*/ + } + + /* + * Open a socket for sending RS and receiving RA. + * This should be done before calling ifinit(), since the function + * uses the socket. + */ + if ((s = sockopen()) < 0) { + errx(1, "failed to open a socket"); + /*NOTREACHED*/ + } + maxfd = s; + if ((rtsock = rtsock_open()) < 0) { + errx(1, "failed to open a socket"); + /*NOTREACHED*/ + } + if (rtsock > maxfd) + maxfd = rtsock; + + /* configuration per interface */ + if (ifinit()) { + errx(1, "failed to initilizatoin interfaces"); + /*NOTREACHED*/ + } + while (argc--) { + if (ifconfig(*argv)) { + errx(1, "failed to initialize %s", *argv); + /*NOTREACHED*/ + } + argv++; + } + + /* setup for probing default routers */ + if (probe_init()) { + errx(1, "failed to setup for probing routers"); + /*NOTREACHED*/ + } + + if (!fflag) + daemon(0, 0); /* act as a daemon */ + + /* dump the current pid */ + if (!once) { + pid_t pid = getpid(); + FILE *fp; + + if ((fp = fopen(pidfilename, "w")) == NULL) + warnmsg(LOG_ERR, __FUNCTION__, + "failed to open a log file(%s): %s", + pidfilename, strerror(errno)); + else { + fprintf(fp, "%d\n", pid); + fclose(fp); + } + } + + FD_ZERO(&fdset); + FD_SET(s, &fdset); + FD_SET(rtsock, &fdset); + while (1) { /* main loop */ + int e; + struct fd_set select_fd = fdset; + + if (do_dump) { /* SIGUSR1 */ + do_dump = 0; + rtsold_dump_file(dumpfilename); + } + + timeout = rtsol_check_timer(); + + if (once) { + struct ifinfo *ifi; + + /* if we have no timeout, we are done (or failed) */ + if (timeout == NULL) + break; + + /* if all interfaces have got RA packet, we are done */ + for (ifi = iflist; ifi; ifi = ifi->next) { + if (ifi->state != IFS_DOWN && ifi->racnt == 0) + break; + } + if (ifi == NULL) + break; + } + e = select(maxfd + 1, &select_fd, NULL, NULL, timeout); + if (e < 1) { + if (e < 0 && errno != EINTR) { + warnmsg(LOG_ERR, __FUNCTION__, "select: %s", + strerror(errno)); + } + continue; + } + + /* packet reception */ + if (FD_ISSET(rtsock, &select_fd)) + rtsock_input(rtsock); + if (FD_ISSET(s, &select_fd)) + rtsol_input(s); + } + /* NOTREACHED */ + + return 0; +} + +static int +ifconfig(char *ifname) +{ + struct ifinfo *ifinfo; + struct sockaddr_dl *sdl; + int flags; + + if ((sdl = if_nametosdl(ifname)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "failed to get link layer information for %s", ifname); + return(-1); + } + if (find_ifinfo(sdl->sdl_index)) { + warnmsg(LOG_ERR, __FUNCTION__, + "interface %s was already cofigured", ifname); + free(sdl); + return(-1); + } + + if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "memory allocation failed"); + free(sdl); + return(-1); + } + memset(ifinfo, 0, sizeof(*ifinfo)); + ifinfo->sdl = sdl; + + strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); + + /* construct a router solicitation message */ + if (make_packet(ifinfo)) + goto bad; + + /* + * check if the interface is available. + * also check if SIOCGIFMEDIA ioctl is OK on the interface. + */ + ifinfo->mediareqok = 1; + ifinfo->active = interface_status(ifinfo); + if (!ifinfo->mediareqok) { + /* + * probe routers periodically even if the link status + * does not change. + */ + ifinfo->probeinterval = PROBE_INTERVAL; + } + + /* activate interface: interface_up returns 0 on success */ + flags = interface_up(ifinfo->ifname); + if (flags == 0) + ifinfo->state = IFS_DELAY; + else if (flags == IFS_TENTATIVE) + ifinfo->state = IFS_TENTATIVE; + else + ifinfo->state = IFS_DOWN; + + rtsol_timer_update(ifinfo); + + /* link into chain */ + if (iflist) + ifinfo->next = iflist; + iflist = ifinfo; + + return(0); + + bad: + free(ifinfo->sdl); + free(ifinfo); + return(-1); +} + +#if 0 +static int +ifreconfig(char *ifname) +{ + struct ifinfo *ifi, *prev; + int rv; + + prev = NULL; + for (ifi = iflist; ifi; ifi = ifi->next) { + if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) + break; + prev = ifi; + } + prev->next = ifi->next; + + rv = ifconfig(ifname); + + /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ + if (ifi->rs_data) + free(ifi->rs_data); + free(ifi->sdl); + free(ifi); + + return rv; +} +#endif + +struct ifinfo * +find_ifinfo(int ifindex) +{ + struct ifinfo *ifi; + + for (ifi = iflist; ifi; ifi = ifi->next) + if (ifi->sdl->sdl_index == ifindex) + return(ifi); + + return(NULL); +} + +static int +make_packet(struct ifinfo *ifinfo) +{ + char *buf; + struct nd_router_solicit *rs; + size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; + + if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { + warnmsg(LOG_INFO, __FUNCTION__, + "link-layer address option has null length" + " on %s. Treat as not included.", ifinfo->ifname); + } + packlen += lladdroptlen; + ifinfo->rs_datalen = packlen; + + /* allocate buffer */ + if ((buf = malloc(packlen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "memory allocation failed for %s", ifinfo->ifname); + return(-1); + } + ifinfo->rs_data = (u_char *)buf; + + /* fill in the message */ + rs = (struct nd_router_solicit *)buf; + rs->nd_rs_type = ND_ROUTER_SOLICIT; + rs->nd_rs_code = 0; + rs->nd_rs_cksum = 0; + rs->nd_rs_reserved = 0; + buf += sizeof(*rs); + + /* fill in source link-layer address option */ + if (lladdroptlen) + lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); + + return(0); +} + +static struct timeval * +rtsol_check_timer() +{ + static struct timeval returnval; + struct timeval now, rtsol_timer; + struct ifinfo *ifinfo; + int flags; + + gettimeofday(&now, NULL); + + rtsol_timer = tm_max; + + for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { + if (TIMEVAL_LEQ(ifinfo->expire, now)) { + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, + "timer expiration on %s, " + "state = %d", ifinfo->ifname, + ifinfo->state); + + switch (ifinfo->state) { + case IFS_DOWN: + case IFS_TENTATIVE: + /* interface_up returns 0 on success */ + flags = interface_up(ifinfo->ifname); + if (flags == 0) + ifinfo->state = IFS_DELAY; + else if (flags == IFS_TENTATIVE) + ifinfo->state = IFS_TENTATIVE; + else + ifinfo->state = IFS_DOWN; + break; + case IFS_IDLE: + { + int oldstatus = ifinfo->active; + int probe = 0; + + ifinfo->active = + interface_status(ifinfo); + + if (oldstatus != ifinfo->active) { + warnmsg(LOG_DEBUG, __FUNCTION__, + "%s status is changed" + " from %d to %d", + ifinfo->ifname, + oldstatus, ifinfo->active); + probe = 1; + ifinfo->state = IFS_DELAY; + } + else if (ifinfo->probeinterval && + (ifinfo->probetimer -= + ifinfo->timer.tv_sec) <= 0) { + /* probe timer expired */ + ifinfo->probetimer = + ifinfo->probeinterval; + probe = 1; + ifinfo->state = IFS_PROBE; + } + + if (probe && mobile_node) + defrouter_probe(ifinfo->sdl->sdl_index); + break; + } + case IFS_DELAY: + ifinfo->state = IFS_PROBE; + sendpacket(ifinfo); + break; + case IFS_PROBE: + if (ifinfo->probes < MAX_RTR_SOLICITATIONS) + sendpacket(ifinfo); + else { + warnmsg(LOG_INFO, __FUNCTION__, + "No answer " + "after sending %d RSs", + ifinfo->probes); + ifinfo->probes = 0; + ifinfo->state = IFS_IDLE; + } + break; + } + rtsol_timer_update(ifinfo); + } + + if (TIMEVAL_LT(ifinfo->expire, rtsol_timer)) + rtsol_timer = ifinfo->expire; + } + + if (TIMEVAL_EQ(rtsol_timer, tm_max)) { + warnmsg(LOG_DEBUG, __FUNCTION__, "there is no timer"); + return(NULL); + } + else if (TIMEVAL_LT(rtsol_timer, now)) + /* this may occur when the interval is too small */ + returnval.tv_sec = returnval.tv_usec = 0; + else + TIMEVAL_SUB(&rtsol_timer, &now, &returnval); + + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, "New timer is %ld:%08ld", + (long)returnval.tv_sec, (long)returnval.tv_usec); + + return(&returnval); +} + +void +rtsol_timer_update(struct ifinfo *ifinfo) +{ +#define MILLION 1000000 +#define DADRETRY 10 /* XXX: adhoc */ + long interval; + struct timeval now; + + bzero(&ifinfo->timer, sizeof(ifinfo->timer)); + + switch (ifinfo->state) { + case IFS_DOWN: + case IFS_TENTATIVE: + if (++ifinfo->dadcount > DADRETRY) { + ifinfo->dadcount = 0; + ifinfo->timer.tv_sec = PROBE_INTERVAL; + } + else + ifinfo->timer.tv_sec = 1; + break; + case IFS_IDLE: + if (mobile_node) { + /* XXX should be configurable */ + ifinfo->timer.tv_sec = 3; + } + else + ifinfo->timer = tm_max; /* stop timer(valid?) */ + break; + case IFS_DELAY: +#ifndef HAVE_ARC4RANDOM + interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); +#else + interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); +#endif + ifinfo->timer.tv_sec = interval / MILLION; + ifinfo->timer.tv_usec = interval % MILLION; + break; + case IFS_PROBE: + if (ifinfo->probes < MAX_RTR_SOLICITATIONS) + ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; + else { + /* + * After sending MAX_RTR_SOLICITATIONS solicitations, + * we're just waiting for possible replies; there + * will be no more solicatation. Thus, we change + * the timer value to MAX_RTR_SOLICITATION_DELAY based + * on RFC 2461, Section 6.3.7. + */ + ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; + } + break; + default: + warnmsg(LOG_ERR, __FUNCTION__, + "illegal interface state(%d) on %s", + ifinfo->state, ifinfo->ifname); + return; + } + + /* reset the timer */ + if (TIMEVAL_EQ(ifinfo->timer, tm_max)) { + ifinfo->expire = tm_max; + warnmsg(LOG_DEBUG, __FUNCTION__, + "stop timer for %s", ifinfo->ifname); + } + else { + gettimeofday(&now, NULL); + TIMEVAL_ADD(&now, &ifinfo->timer, &ifinfo->expire); + + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, + "set timer for %s to %d:%d", ifinfo->ifname, + (int)ifinfo->timer.tv_sec, + (int)ifinfo->timer.tv_usec); + } + +#undef MILLION +} + +/* timer related utility functions */ +#define MILLION 1000000 + +/* result = a + b */ +static void +TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec + b->tv_usec) < MILLION) { + result->tv_usec = l; + result->tv_sec = a->tv_sec + b->tv_sec; + } + else { + result->tv_usec = l - MILLION; + result->tv_sec = a->tv_sec + b->tv_sec + 1; + } +} + +/* + * result = a - b + * XXX: this function assumes that a >= b. + */ +void +TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec - b->tv_usec) >= 0) { + result->tv_usec = l; + result->tv_sec = a->tv_sec - b->tv_sec; + } + else { + result->tv_usec = MILLION + l; + result->tv_sec = a->tv_sec - b->tv_sec - 1; + } +} + +static void +rtsold_set_dump_file() +{ + do_dump = 1; +} + +static void +usage(char *progname) +{ + if (progname && progname[strlen(progname) - 1] != 'd') { + fprintf(stderr, "usage: rtsol [-dD] interfaces...\n"); + fprintf(stderr, "usage: rtsol [-dD] -a\n"); + } else { + fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n"); + fprintf(stderr, "usage: rtsold [-dDfm1] -a\n"); + } + exit(1); +} + +void +#if __STDC__ +warnmsg(int priority, const char *func, const char *msg, ...) +#else +warnmsg(priority, func, msg, va_alist) + int priority; + const char *func; + const char *msg; + va_dcl +#endif +{ + va_list ap; + char buf[BUFSIZ]; + + va_start(ap, msg); + if (fflag) { + if (priority <= log_upto) { + (void)vfprintf(stderr, msg, ap); + (void)fprintf(stderr, "\n"); + } + } else { + snprintf(buf, sizeof(buf), "<%s> %s", func, msg); + msg = buf; + vsyslog(priority, msg, ap); + } + va_end(ap); +} + +static char ** +autoifprobe() +{ +#ifndef HAVE_GETIFADDRS + errx(1, "-a is not available with the configuration"); +#else + static char ifname[IFNAMSIZ + 1]; + static char *argv[2]; + struct ifaddrs *ifap, *ifa, *target; + + if (getifaddrs(&ifap) != 0) + return NULL; + + target = NULL; + /* find an ethernet */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) + continue; + if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) + continue; + if ((ifa->ifa_flags & IFF_MULTICAST) == 0) + continue; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + if (target && strcmp(target->ifa_name, ifa->ifa_name) == 0) + continue; + + if (!target) + target = ifa; + else { + /* if we find multiple candidates, failure. */ + if (dflag > 1) + warnx("multiple interfaces found"); + target = NULL; + break; + } + } + + if (target) { + strlcpy(ifname, target->ifa_name, sizeof(ifname)); + argv[0] = ifname; + argv[1] = NULL; + + if (dflag > 0) + warnx("probing %s", argv[0]); + } + freeifaddrs(ifap); + if (target) + return argv; + else + return (char **)NULL; +#endif +} diff --git a/network_cmds/rtsol.tproj/rtsold.h b/network_cmds/rtsol.tproj/rtsold.h new file mode 100644 index 0000000..fdda539 --- /dev/null +++ b/network_cmds/rtsol.tproj/rtsold.h @@ -0,0 +1,96 @@ +/* $KAME: rtsold.h,v 1.11 2000/10/10 06:18:04 itojun Exp $ */ + +/* + * 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: src/usr.sbin/rtsold/rtsold.h,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +struct ifinfo { + struct ifinfo *next; /* pointer to the next interface */ + + struct sockaddr_dl *sdl; /* link-layer address */ + char ifname[IF_NAMESIZE]; /* interface name */ + int active; /* interface status */ + int probeinterval; /* interval of probe timer(if necessary) */ + int probetimer; /* rest of probe timer */ + int mediareqok; /* wheter the IF supports SIOCGIFMEDIA */ + int state; + int probes; + int dadcount; + struct timeval timer; + struct timeval expire; + int errors; /* # of errors we've got - detect wedge */ + + int racnt; /* total # of valid RAs it have got */ + + size_t rs_datalen; + u_char *rs_data; +}; + +/* per interface status */ +#define IFS_IDLE 0 +#define IFS_DELAY 1 +#define IFS_PROBE 2 +#define IFS_DOWN 3 +#define IFS_TENTATIVE 4 +#define IFS_OPTIMISTIC 5 + +/* rtsold.c */ +extern struct timeval tm_max; +extern int dflag; +struct ifinfo *find_ifinfo __P((int ifindex)); +void rtsol_timer_update __P((struct ifinfo *ifinfo)); +extern void warnmsg __P((int, const char *, const char *, ...)) + __attribute__((__format__(__printf__, 3, 4))); + +/* if.c */ +extern int ifinit __P((void)); +extern int interface_up __P((char *name)); +extern int interface_status __P((struct ifinfo*)); +extern int lladdropt_length __P((struct sockaddr_dl *sdl)); +extern void lladdropt_fill __P((struct sockaddr_dl *sdl, + struct nd_opt_hdr *ndopt)); +extern struct sockaddr_dl *if_nametosdl __P((char *name)); +extern int getinet6sysctl __P((int code)); + +/* rtsol.c */ +extern int sockopen __P((void)); +extern void sendpacket __P((struct ifinfo *ifinfo)); +extern void rtsol_input __P((int s)); + +/* probe.c */ +extern int probe_init __P((void)); +extern void defrouter_probe __P((int ifindex)); + +/* dump.c */ +extern void rtsold_dump_file __P((char *)); + +/* rtsock.c */ +extern int rtsock_open __P((void)); +extern int rtsock_input __P((int)); |