17c991abcSHajimu UMEMOTO /* $KAME: if.c,v 1.14 2000/10/25 04:28:34 jinmei Exp $ */ 2b26e03e9SKris Kennaway 39a4365d0SYoshinobu Inoue /* 49a4365d0SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 59a4365d0SYoshinobu Inoue * All rights reserved. 69a4365d0SYoshinobu Inoue * 79a4365d0SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 89a4365d0SYoshinobu Inoue * modification, are permitted provided that the following conditions 99a4365d0SYoshinobu Inoue * are met: 109a4365d0SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 119a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 129a4365d0SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 139a4365d0SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 149a4365d0SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 159a4365d0SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 169a4365d0SYoshinobu Inoue * may be used to endorse or promote products derived from this software 179a4365d0SYoshinobu Inoue * without specific prior written permission. 189a4365d0SYoshinobu Inoue * 199a4365d0SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 209a4365d0SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219a4365d0SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229a4365d0SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 239a4365d0SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249a4365d0SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259a4365d0SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269a4365d0SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279a4365d0SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289a4365d0SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299a4365d0SYoshinobu Inoue * SUCH DAMAGE. 309a4365d0SYoshinobu Inoue * 319a4365d0SYoshinobu Inoue * $FreeBSD$ 329a4365d0SYoshinobu Inoue */ 339a4365d0SYoshinobu Inoue 349a4365d0SYoshinobu Inoue #include <sys/param.h> 359a4365d0SYoshinobu Inoue #include <sys/socket.h> 369a4365d0SYoshinobu Inoue #include <sys/sysctl.h> 379a4365d0SYoshinobu Inoue #include <sys/ioctl.h> 389a4365d0SYoshinobu Inoue #include <net/if.h> 399a4365d0SYoshinobu Inoue #include <net/if_types.h> 40b26e03e9SKris Kennaway #ifdef __FreeBSD__ 419a4365d0SYoshinobu Inoue # include <net/ethernet.h> 42b26e03e9SKris Kennaway #endif 43b26e03e9SKris Kennaway #include <ifaddrs.h> 44b26e03e9SKris Kennaway #ifdef __NetBSD__ 45b26e03e9SKris Kennaway #include <net/if_ether.h> 46b26e03e9SKris Kennaway #endif 479a4365d0SYoshinobu Inoue #include <net/route.h> 489a4365d0SYoshinobu Inoue #include <net/if_dl.h> 499a4365d0SYoshinobu Inoue #include <netinet/in.h> 509a4365d0SYoshinobu Inoue #include <netinet/icmp6.h> 51b26e03e9SKris Kennaway #ifdef __bsdi__ 52b26e03e9SKris Kennaway # include <netinet/if_ether.h> 53b26e03e9SKris Kennaway #endif 54b26e03e9SKris Kennaway #ifdef __OpenBSD__ 55b26e03e9SKris Kennaway #include <netinet/if_ether.h> 56b26e03e9SKris Kennaway #endif 579a4365d0SYoshinobu Inoue #include <unistd.h> 589a4365d0SYoshinobu Inoue #include <errno.h> 599a4365d0SYoshinobu Inoue #include <stdlib.h> 609a4365d0SYoshinobu Inoue #include <string.h> 619a4365d0SYoshinobu Inoue #include <syslog.h> 629a4365d0SYoshinobu Inoue #include "rtadvd.h" 639a4365d0SYoshinobu Inoue #include "if.h" 649a4365d0SYoshinobu Inoue 659a4365d0SYoshinobu Inoue #define ROUNDUP(a, size) \ 669a4365d0SYoshinobu Inoue (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 679a4365d0SYoshinobu Inoue 689a4365d0SYoshinobu Inoue #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 699a4365d0SYoshinobu Inoue ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 709a4365d0SYoshinobu Inoue sizeof(u_long)) :\ 719a4365d0SYoshinobu Inoue sizeof(u_long))) 729a4365d0SYoshinobu Inoue 739a4365d0SYoshinobu Inoue struct if_msghdr **iflist; 749a4365d0SYoshinobu Inoue int iflist_init_ok; 759a4365d0SYoshinobu Inoue size_t ifblock_size; 769a4365d0SYoshinobu Inoue char *ifblock; 779a4365d0SYoshinobu Inoue 789a4365d0SYoshinobu Inoue static void get_iflist __P((char **buf, size_t *size)); 799a4365d0SYoshinobu Inoue static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, 809a4365d0SYoshinobu Inoue size_t bufsize)); 819a4365d0SYoshinobu Inoue 829a4365d0SYoshinobu Inoue static void 839a4365d0SYoshinobu Inoue get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 849a4365d0SYoshinobu Inoue { 859a4365d0SYoshinobu Inoue int i; 869a4365d0SYoshinobu Inoue 879a4365d0SYoshinobu Inoue for (i = 0; i < RTAX_MAX; i++) { 889a4365d0SYoshinobu Inoue if (addrs & (1 << i)) { 899a4365d0SYoshinobu Inoue rti_info[i] = sa; 909a4365d0SYoshinobu Inoue NEXT_SA(sa); 919a4365d0SYoshinobu Inoue } 929a4365d0SYoshinobu Inoue else 939a4365d0SYoshinobu Inoue rti_info[i] = NULL; 949a4365d0SYoshinobu Inoue } 959a4365d0SYoshinobu Inoue } 969a4365d0SYoshinobu Inoue 979a4365d0SYoshinobu Inoue struct sockaddr_dl * 989a4365d0SYoshinobu Inoue if_nametosdl(char *name) 999a4365d0SYoshinobu Inoue { 1009a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 1019a4365d0SYoshinobu Inoue char *buf, *next, *lim; 1029a4365d0SYoshinobu Inoue size_t len; 1039a4365d0SYoshinobu Inoue struct if_msghdr *ifm; 1049a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 1059a4365d0SYoshinobu Inoue struct sockaddr_dl *sdl = NULL, *ret_sdl; 1069a4365d0SYoshinobu Inoue 1079a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 1089a4365d0SYoshinobu Inoue return(NULL); 1099a4365d0SYoshinobu Inoue if ((buf = malloc(len)) == NULL) 1109a4365d0SYoshinobu Inoue return(NULL); 1119a4365d0SYoshinobu Inoue if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { 1129a4365d0SYoshinobu Inoue free(buf); 1139a4365d0SYoshinobu Inoue return(NULL); 1149a4365d0SYoshinobu Inoue } 1159a4365d0SYoshinobu Inoue 1169a4365d0SYoshinobu Inoue lim = buf + len; 1179a4365d0SYoshinobu Inoue for (next = buf; next < lim; next += ifm->ifm_msglen) { 1189a4365d0SYoshinobu Inoue ifm = (struct if_msghdr *)next; 1199a4365d0SYoshinobu Inoue if (ifm->ifm_type == RTM_IFINFO) { 1209a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(ifm + 1); 1219a4365d0SYoshinobu Inoue get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1229a4365d0SYoshinobu Inoue if ((sa = rti_info[RTAX_IFP]) != NULL) { 1239a4365d0SYoshinobu Inoue if (sa->sa_family == AF_LINK) { 1249a4365d0SYoshinobu Inoue sdl = (struct sockaddr_dl *)sa; 125b26e03e9SKris Kennaway if (strlen(name) != sdl->sdl_nlen) 126b26e03e9SKris Kennaway continue; /* not same len */ 1279a4365d0SYoshinobu Inoue if (strncmp(&sdl->sdl_data[0], 1289a4365d0SYoshinobu Inoue name, 1299a4365d0SYoshinobu Inoue sdl->sdl_nlen) == 0) { 1309a4365d0SYoshinobu Inoue break; 1319a4365d0SYoshinobu Inoue } 1329a4365d0SYoshinobu Inoue } 1339a4365d0SYoshinobu Inoue } 1349a4365d0SYoshinobu Inoue } 1359a4365d0SYoshinobu Inoue } 1369a4365d0SYoshinobu Inoue if (next == lim) { 1379a4365d0SYoshinobu Inoue /* search failed */ 1389a4365d0SYoshinobu Inoue free(buf); 1399a4365d0SYoshinobu Inoue return(NULL); 1409a4365d0SYoshinobu Inoue } 1419a4365d0SYoshinobu Inoue 1429a4365d0SYoshinobu Inoue if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) 1439a4365d0SYoshinobu Inoue return(NULL); 1449a4365d0SYoshinobu Inoue memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 1459a4365d0SYoshinobu Inoue return(ret_sdl); 1469a4365d0SYoshinobu Inoue } 1479a4365d0SYoshinobu Inoue 1489a4365d0SYoshinobu Inoue int 1499a4365d0SYoshinobu Inoue if_getmtu(char *name) 1509a4365d0SYoshinobu Inoue { 1517c991abcSHajimu UMEMOTO struct ifaddrs *ifap, *ifa; 1527c991abcSHajimu UMEMOTO struct if_data *ifd; 1537c991abcSHajimu UMEMOTO u_long mtu = 0; 1547c991abcSHajimu UMEMOTO 1557c991abcSHajimu UMEMOTO if (getifaddrs(&ifap) < 0) 1567c991abcSHajimu UMEMOTO return(0); 1577c991abcSHajimu UMEMOTO for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1587c991abcSHajimu UMEMOTO if (strcmp(ifa->ifa_name, name) == 0) { 1597c991abcSHajimu UMEMOTO ifd = ifa->ifa_data; 1607c991abcSHajimu UMEMOTO if (ifd) 1617c991abcSHajimu UMEMOTO mtu = ifd->ifi_mtu; 1627c991abcSHajimu UMEMOTO break; 1637c991abcSHajimu UMEMOTO } 1647c991abcSHajimu UMEMOTO } 1657c991abcSHajimu UMEMOTO freeifaddrs(ifap); 1667c991abcSHajimu UMEMOTO 1677c991abcSHajimu UMEMOTO #ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */ 1687c991abcSHajimu UMEMOTO if (mtu == 0) { 1699a4365d0SYoshinobu Inoue struct ifreq ifr; 1709a4365d0SYoshinobu Inoue int s; 1719a4365d0SYoshinobu Inoue 1729a4365d0SYoshinobu Inoue if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1739a4365d0SYoshinobu Inoue return(0); 1749a4365d0SYoshinobu Inoue 1759a4365d0SYoshinobu Inoue ifr.ifr_addr.sa_family = AF_INET6; 1767c991abcSHajimu UMEMOTO strncpy(ifr.ifr_name, name, 1777c991abcSHajimu UMEMOTO sizeof(ifr.ifr_name)); 1789a4365d0SYoshinobu Inoue if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) { 1799a4365d0SYoshinobu Inoue close(s); 1809a4365d0SYoshinobu Inoue return(0); 1819a4365d0SYoshinobu Inoue } 1829a4365d0SYoshinobu Inoue close(s); 1839a4365d0SYoshinobu Inoue 1847c991abcSHajimu UMEMOTO mtu = ifr.ifr_mtu; 185b26e03e9SKris Kennaway } 186b26e03e9SKris Kennaway #endif 1877c991abcSHajimu UMEMOTO 1887c991abcSHajimu UMEMOTO return(mtu); 1899a4365d0SYoshinobu Inoue } 1909a4365d0SYoshinobu Inoue 1919a4365d0SYoshinobu Inoue /* give interface index and its old flags, then new flags returned */ 1929a4365d0SYoshinobu Inoue int 1939a4365d0SYoshinobu Inoue if_getflags(int ifindex, int oifflags) 1949a4365d0SYoshinobu Inoue { 1959a4365d0SYoshinobu Inoue struct ifreq ifr; 1969a4365d0SYoshinobu Inoue int s; 1979a4365d0SYoshinobu Inoue 1989a4365d0SYoshinobu Inoue if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1999a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, 2009a4365d0SYoshinobu Inoue strerror(errno)); 2019a4365d0SYoshinobu Inoue return (oifflags & ~IFF_UP); 2029a4365d0SYoshinobu Inoue } 2039a4365d0SYoshinobu Inoue 2049a4365d0SYoshinobu Inoue if_indextoname(ifindex, ifr.ifr_name); 2059a4365d0SYoshinobu Inoue if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 2069a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s", 2079a4365d0SYoshinobu Inoue __FUNCTION__, ifr.ifr_name); 2089a4365d0SYoshinobu Inoue close(s); 2099a4365d0SYoshinobu Inoue return (oifflags & ~IFF_UP); 2109a4365d0SYoshinobu Inoue } 2117c991abcSHajimu UMEMOTO close(s); 2129a4365d0SYoshinobu Inoue return (ifr.ifr_flags); 2139a4365d0SYoshinobu Inoue } 2149a4365d0SYoshinobu Inoue 2159a4365d0SYoshinobu Inoue #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 2169a4365d0SYoshinobu Inoue int 2179a4365d0SYoshinobu Inoue lladdropt_length(struct sockaddr_dl *sdl) 2189a4365d0SYoshinobu Inoue { 2199a4365d0SYoshinobu Inoue switch(sdl->sdl_type) { 2209a4365d0SYoshinobu Inoue case IFT_ETHER: 2219a4365d0SYoshinobu Inoue return(ROUNDUP8(ETHER_ADDR_LEN + 2)); 2229a4365d0SYoshinobu Inoue default: 2239a4365d0SYoshinobu Inoue return(0); 2249a4365d0SYoshinobu Inoue } 2259a4365d0SYoshinobu Inoue } 2269a4365d0SYoshinobu Inoue 2279a4365d0SYoshinobu Inoue void 2289a4365d0SYoshinobu Inoue lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 2299a4365d0SYoshinobu Inoue { 2309a4365d0SYoshinobu Inoue char *addr; 2319a4365d0SYoshinobu Inoue 2329a4365d0SYoshinobu Inoue ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 2339a4365d0SYoshinobu Inoue 2349a4365d0SYoshinobu Inoue switch(sdl->sdl_type) { 2359a4365d0SYoshinobu Inoue case IFT_ETHER: 2369a4365d0SYoshinobu Inoue ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 2379a4365d0SYoshinobu Inoue addr = (char *)(ndopt + 1); 2389a4365d0SYoshinobu Inoue memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 2399a4365d0SYoshinobu Inoue break; 2409a4365d0SYoshinobu Inoue default: 2419a4365d0SYoshinobu Inoue syslog(LOG_ERR, 2429a4365d0SYoshinobu Inoue "<%s> unsupported link type(%d)", 2439a4365d0SYoshinobu Inoue __FUNCTION__, sdl->sdl_type); 2449a4365d0SYoshinobu Inoue exit(1); 2459a4365d0SYoshinobu Inoue } 2469a4365d0SYoshinobu Inoue 2479a4365d0SYoshinobu Inoue return; 2489a4365d0SYoshinobu Inoue } 2499a4365d0SYoshinobu Inoue 2509a4365d0SYoshinobu Inoue int 2519a4365d0SYoshinobu Inoue rtbuf_len() 2529a4365d0SYoshinobu Inoue { 2539a4365d0SYoshinobu Inoue size_t len; 2549a4365d0SYoshinobu Inoue 2559a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 2569a4365d0SYoshinobu Inoue 2579a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 2589a4365d0SYoshinobu Inoue return(-1); 2599a4365d0SYoshinobu Inoue 2609a4365d0SYoshinobu Inoue return(len); 2619a4365d0SYoshinobu Inoue } 2629a4365d0SYoshinobu Inoue 2639a4365d0SYoshinobu Inoue int 2649a4365d0SYoshinobu Inoue get_rtinfo(char *buf, size_t *len) 2659a4365d0SYoshinobu Inoue { 2669a4365d0SYoshinobu Inoue int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; 2679a4365d0SYoshinobu Inoue 2689a4365d0SYoshinobu Inoue if (sysctl(mib, 6, buf, len, NULL, 0) < 0) 2699a4365d0SYoshinobu Inoue return(-1); 2709a4365d0SYoshinobu Inoue 2719a4365d0SYoshinobu Inoue return(0); 2729a4365d0SYoshinobu Inoue } 2739a4365d0SYoshinobu Inoue 2749a4365d0SYoshinobu Inoue #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 2759a4365d0SYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)(s)) 2769a4365d0SYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)(s)) 2779a4365d0SYoshinobu Inoue char * 2789a4365d0SYoshinobu Inoue get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) 2799a4365d0SYoshinobu Inoue { 2809a4365d0SYoshinobu Inoue struct rt_msghdr *rtm; 2819a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam; 2829a4365d0SYoshinobu Inoue struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 2839a4365d0SYoshinobu Inoue 2849a4365d0SYoshinobu Inoue *lenp = 0; 2859a4365d0SYoshinobu Inoue for (rtm = (struct rt_msghdr *)buf; 2869a4365d0SYoshinobu Inoue rtm < (struct rt_msghdr *)lim; 2879a4365d0SYoshinobu Inoue rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 2889a4365d0SYoshinobu Inoue /* just for safety */ 2899a4365d0SYoshinobu Inoue if (!rtm->rtm_msglen) { 2909a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " 2919a4365d0SYoshinobu Inoue "(buf=%p lim=%p rtm=%p)", __FUNCTION__, 2929a4365d0SYoshinobu Inoue buf, lim, rtm); 2939a4365d0SYoshinobu Inoue break; 2949a4365d0SYoshinobu Inoue } 2959a4365d0SYoshinobu Inoue if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { 2969a4365d0SYoshinobu Inoue continue; 2979a4365d0SYoshinobu Inoue } 2989a4365d0SYoshinobu Inoue 2999a4365d0SYoshinobu Inoue switch (rtm->rtm_type) { 3009a4365d0SYoshinobu Inoue case RTM_GET: 3019a4365d0SYoshinobu Inoue case RTM_ADD: 3029a4365d0SYoshinobu Inoue case RTM_DELETE: 3039a4365d0SYoshinobu Inoue /* address related checks */ 3049a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 3059a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 3069a4365d0SYoshinobu Inoue if ((dst = rti_info[RTAX_DST]) == NULL || 3079a4365d0SYoshinobu Inoue dst->sa_family != AF_INET6) 3089a4365d0SYoshinobu Inoue continue; 3099a4365d0SYoshinobu Inoue 3109a4365d0SYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 3119a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 3129a4365d0SYoshinobu Inoue continue; 3139a4365d0SYoshinobu Inoue 3149a4365d0SYoshinobu Inoue if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 3159a4365d0SYoshinobu Inoue gw->sa_family != AF_LINK) 3169a4365d0SYoshinobu Inoue continue; 3179a4365d0SYoshinobu Inoue if (ifindex && SDL(gw)->sdl_index != ifindex) 3189a4365d0SYoshinobu Inoue continue; 3199a4365d0SYoshinobu Inoue 3209a4365d0SYoshinobu Inoue if (rti_info[RTAX_NETMASK] == NULL) 3219a4365d0SYoshinobu Inoue continue; 3229a4365d0SYoshinobu Inoue 3239a4365d0SYoshinobu Inoue /* found */ 3249a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 3259a4365d0SYoshinobu Inoue return (char *)rtm; 3269a4365d0SYoshinobu Inoue /* NOTREACHED */ 3279a4365d0SYoshinobu Inoue case RTM_NEWADDR: 3289a4365d0SYoshinobu Inoue case RTM_DELADDR: 3299a4365d0SYoshinobu Inoue ifam = (struct ifa_msghdr *)rtm; 3309a4365d0SYoshinobu Inoue 3319a4365d0SYoshinobu Inoue /* address related checks */ 3329a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(ifam + 1); 3339a4365d0SYoshinobu Inoue get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 3349a4365d0SYoshinobu Inoue if ((ifa = rti_info[RTAX_IFA]) == NULL || 3359a4365d0SYoshinobu Inoue (ifa->sa_family != AF_INET && 3369a4365d0SYoshinobu Inoue ifa->sa_family != AF_INET6)) 3379a4365d0SYoshinobu Inoue continue; 3389a4365d0SYoshinobu Inoue 3399a4365d0SYoshinobu Inoue if (ifa->sa_family == AF_INET6 && 3409a4365d0SYoshinobu Inoue (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 3419a4365d0SYoshinobu Inoue IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 3429a4365d0SYoshinobu Inoue continue; 3439a4365d0SYoshinobu Inoue 3449a4365d0SYoshinobu Inoue if (ifindex && ifam->ifam_index != ifindex) 3459a4365d0SYoshinobu Inoue continue; 3469a4365d0SYoshinobu Inoue 3479a4365d0SYoshinobu Inoue /* found */ 3489a4365d0SYoshinobu Inoue *lenp = ifam->ifam_msglen; 3499a4365d0SYoshinobu Inoue return (char *)rtm; 3509a4365d0SYoshinobu Inoue /* NOTREACHED */ 3519a4365d0SYoshinobu Inoue case RTM_IFINFO: 3529a4365d0SYoshinobu Inoue /* found */ 3539a4365d0SYoshinobu Inoue *lenp = rtm->rtm_msglen; 3549a4365d0SYoshinobu Inoue return (char *)rtm; 3559a4365d0SYoshinobu Inoue /* NOTREACHED */ 3569a4365d0SYoshinobu Inoue } 3579a4365d0SYoshinobu Inoue } 3589a4365d0SYoshinobu Inoue 3599a4365d0SYoshinobu Inoue return (char *)rtm; 3609a4365d0SYoshinobu Inoue } 3619a4365d0SYoshinobu Inoue #undef FILTER_MATCH(type, filter) 3629a4365d0SYoshinobu Inoue 3639a4365d0SYoshinobu Inoue struct in6_addr * 3649a4365d0SYoshinobu Inoue get_addr(char *buf) 3659a4365d0SYoshinobu Inoue { 3669a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 3679a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 3689a4365d0SYoshinobu Inoue 3699a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 3709a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 3719a4365d0SYoshinobu Inoue 3729a4365d0SYoshinobu Inoue return(&SIN6(rti_info[RTAX_DST])->sin6_addr); 3739a4365d0SYoshinobu Inoue } 3749a4365d0SYoshinobu Inoue 3759a4365d0SYoshinobu Inoue int 3769a4365d0SYoshinobu Inoue get_rtm_ifindex(char *buf) 3779a4365d0SYoshinobu Inoue { 3789a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 3799a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 3809a4365d0SYoshinobu Inoue 3819a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 3829a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 3839a4365d0SYoshinobu Inoue 3849a4365d0SYoshinobu Inoue return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); 3859a4365d0SYoshinobu Inoue } 3869a4365d0SYoshinobu Inoue 3879a4365d0SYoshinobu Inoue int 3889a4365d0SYoshinobu Inoue get_ifm_ifindex(char *buf) 3899a4365d0SYoshinobu Inoue { 3909a4365d0SYoshinobu Inoue struct if_msghdr *ifm = (struct if_msghdr *)buf; 3919a4365d0SYoshinobu Inoue 3929a4365d0SYoshinobu Inoue return ((int)ifm->ifm_index); 3939a4365d0SYoshinobu Inoue } 3949a4365d0SYoshinobu Inoue 3959a4365d0SYoshinobu Inoue int 3969a4365d0SYoshinobu Inoue get_ifam_ifindex(char *buf) 3979a4365d0SYoshinobu Inoue { 3989a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf; 3999a4365d0SYoshinobu Inoue 4009a4365d0SYoshinobu Inoue return ((int)ifam->ifam_index); 4019a4365d0SYoshinobu Inoue } 4029a4365d0SYoshinobu Inoue 4039a4365d0SYoshinobu Inoue int 4049a4365d0SYoshinobu Inoue get_ifm_flags(char *buf) 4059a4365d0SYoshinobu Inoue { 4069a4365d0SYoshinobu Inoue struct if_msghdr *ifm = (struct if_msghdr *)buf; 4079a4365d0SYoshinobu Inoue 4089a4365d0SYoshinobu Inoue return (ifm->ifm_flags); 4099a4365d0SYoshinobu Inoue } 4109a4365d0SYoshinobu Inoue 4119a4365d0SYoshinobu Inoue int 4129a4365d0SYoshinobu Inoue get_prefixlen(char *buf) 4139a4365d0SYoshinobu Inoue { 4149a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 4159a4365d0SYoshinobu Inoue struct sockaddr *sa, *rti_info[RTAX_MAX]; 4169a4365d0SYoshinobu Inoue u_char *p, *lim; 4179a4365d0SYoshinobu Inoue 4189a4365d0SYoshinobu Inoue sa = (struct sockaddr *)(rtm + 1); 4199a4365d0SYoshinobu Inoue get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 4209a4365d0SYoshinobu Inoue sa = rti_info[RTAX_NETMASK]; 4219a4365d0SYoshinobu Inoue 4229a4365d0SYoshinobu Inoue p = (u_char *)(&SIN6(sa)->sin6_addr); 4239a4365d0SYoshinobu Inoue lim = (u_char *)sa + sa->sa_len; 4247c991abcSHajimu UMEMOTO return prefixlen(p, lim); 4257c991abcSHajimu UMEMOTO } 4267c991abcSHajimu UMEMOTO 4277c991abcSHajimu UMEMOTO int 4287c991abcSHajimu UMEMOTO prefixlen(u_char *p, u_char *lim) 4297c991abcSHajimu UMEMOTO { 4307c991abcSHajimu UMEMOTO int masklen; 4317c991abcSHajimu UMEMOTO 4329a4365d0SYoshinobu Inoue for (masklen = 0; p < lim; p++) { 4339a4365d0SYoshinobu Inoue switch (*p) { 4349a4365d0SYoshinobu Inoue case 0xff: 4359a4365d0SYoshinobu Inoue masklen += 8; 4369a4365d0SYoshinobu Inoue break; 4379a4365d0SYoshinobu Inoue case 0xfe: 4389a4365d0SYoshinobu Inoue masklen += 7; 4399a4365d0SYoshinobu Inoue break; 4409a4365d0SYoshinobu Inoue case 0xfc: 4419a4365d0SYoshinobu Inoue masklen += 6; 4429a4365d0SYoshinobu Inoue break; 4439a4365d0SYoshinobu Inoue case 0xf8: 4449a4365d0SYoshinobu Inoue masklen += 5; 4459a4365d0SYoshinobu Inoue break; 4469a4365d0SYoshinobu Inoue case 0xf0: 4479a4365d0SYoshinobu Inoue masklen += 4; 4489a4365d0SYoshinobu Inoue break; 4499a4365d0SYoshinobu Inoue case 0xe0: 4509a4365d0SYoshinobu Inoue masklen += 3; 4519a4365d0SYoshinobu Inoue break; 4529a4365d0SYoshinobu Inoue case 0xc0: 4539a4365d0SYoshinobu Inoue masklen += 2; 4549a4365d0SYoshinobu Inoue break; 4559a4365d0SYoshinobu Inoue case 0x80: 4569a4365d0SYoshinobu Inoue masklen += 1; 4579a4365d0SYoshinobu Inoue break; 4589a4365d0SYoshinobu Inoue case 0x00: 4599a4365d0SYoshinobu Inoue break; 4609a4365d0SYoshinobu Inoue default: 4619a4365d0SYoshinobu Inoue return(-1); 4629a4365d0SYoshinobu Inoue } 4639a4365d0SYoshinobu Inoue } 4649a4365d0SYoshinobu Inoue 4659a4365d0SYoshinobu Inoue return(masklen); 4669a4365d0SYoshinobu Inoue } 4679a4365d0SYoshinobu Inoue 4689a4365d0SYoshinobu Inoue int 4699a4365d0SYoshinobu Inoue rtmsg_type(char *buf) 4709a4365d0SYoshinobu Inoue { 4719a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 4729a4365d0SYoshinobu Inoue 4739a4365d0SYoshinobu Inoue return(rtm->rtm_type); 4749a4365d0SYoshinobu Inoue } 4759a4365d0SYoshinobu Inoue 4769a4365d0SYoshinobu Inoue int 4779a4365d0SYoshinobu Inoue rtmsg_len(char *buf) 4789a4365d0SYoshinobu Inoue { 4799a4365d0SYoshinobu Inoue struct rt_msghdr *rtm = (struct rt_msghdr *)buf; 4809a4365d0SYoshinobu Inoue 4819a4365d0SYoshinobu Inoue return(rtm->rtm_msglen); 4829a4365d0SYoshinobu Inoue } 4839a4365d0SYoshinobu Inoue 4849a4365d0SYoshinobu Inoue int 4859a4365d0SYoshinobu Inoue ifmsg_len(char *buf) 4869a4365d0SYoshinobu Inoue { 4879a4365d0SYoshinobu Inoue struct if_msghdr *ifm = (struct if_msghdr *)buf; 4889a4365d0SYoshinobu Inoue 4899a4365d0SYoshinobu Inoue return(ifm->ifm_msglen); 4909a4365d0SYoshinobu Inoue } 4919a4365d0SYoshinobu Inoue 4929a4365d0SYoshinobu Inoue /* 4939a4365d0SYoshinobu Inoue * alloc buffer and get if_msghdrs block from kernel, 4949a4365d0SYoshinobu Inoue * and put them into the buffer 4959a4365d0SYoshinobu Inoue */ 4969a4365d0SYoshinobu Inoue static void 4979a4365d0SYoshinobu Inoue get_iflist(char **buf, size_t *size) 4989a4365d0SYoshinobu Inoue { 4999a4365d0SYoshinobu Inoue int mib[6]; 5009a4365d0SYoshinobu Inoue 5019a4365d0SYoshinobu Inoue mib[0] = CTL_NET; 5029a4365d0SYoshinobu Inoue mib[1] = PF_ROUTE; 5039a4365d0SYoshinobu Inoue mib[2] = 0; 5049a4365d0SYoshinobu Inoue mib[3] = AF_INET6; 5059a4365d0SYoshinobu Inoue mib[4] = NET_RT_IFLIST; 5069a4365d0SYoshinobu Inoue mib[5] = 0; 5079a4365d0SYoshinobu Inoue 5089a4365d0SYoshinobu Inoue if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) { 5099a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> sysctl: iflist size get failed", 5109a4365d0SYoshinobu Inoue __FUNCTION__); 5119a4365d0SYoshinobu Inoue exit(1); 5129a4365d0SYoshinobu Inoue } 5139a4365d0SYoshinobu Inoue if ((*buf = malloc(*size)) == NULL) { 5149a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); 5159a4365d0SYoshinobu Inoue exit(1); 5169a4365d0SYoshinobu Inoue } 5179a4365d0SYoshinobu Inoue if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) { 5189a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> sysctl: iflist get failed", 5199a4365d0SYoshinobu Inoue __FUNCTION__); 5209a4365d0SYoshinobu Inoue exit(1); 5219a4365d0SYoshinobu Inoue } 5229a4365d0SYoshinobu Inoue return; 5239a4365d0SYoshinobu Inoue } 5249a4365d0SYoshinobu Inoue 5259a4365d0SYoshinobu Inoue /* 5269a4365d0SYoshinobu Inoue * alloc buffer and parse if_msghdrs block passed as arg, 5279a4365d0SYoshinobu Inoue * and init the buffer as list of pointers ot each of the if_msghdr. 5289a4365d0SYoshinobu Inoue */ 5299a4365d0SYoshinobu Inoue static void 5309a4365d0SYoshinobu Inoue parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) 5319a4365d0SYoshinobu Inoue { 5329a4365d0SYoshinobu Inoue int iflentry_size, malloc_size; 5339a4365d0SYoshinobu Inoue struct if_msghdr *ifm; 5349a4365d0SYoshinobu Inoue struct ifa_msghdr *ifam; 5359a4365d0SYoshinobu Inoue char *lim; 5369a4365d0SYoshinobu Inoue 5379a4365d0SYoshinobu Inoue /* 5389a4365d0SYoshinobu Inoue * Estimate least size of an iflist entry, to be obtained from kernel. 5399a4365d0SYoshinobu Inoue * Should add sizeof(sockaddr) ?? 5409a4365d0SYoshinobu Inoue */ 5419a4365d0SYoshinobu Inoue iflentry_size = sizeof(struct if_msghdr); 5429a4365d0SYoshinobu Inoue /* roughly estimate max list size of pointers to each if_msghdr */ 5439a4365d0SYoshinobu Inoue malloc_size = (bufsize/iflentry_size) * sizeof(size_t); 5449a4365d0SYoshinobu Inoue if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) { 5459a4365d0SYoshinobu Inoue syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); 5469a4365d0SYoshinobu Inoue exit(1); 5479a4365d0SYoshinobu Inoue } 5489a4365d0SYoshinobu Inoue 5499a4365d0SYoshinobu Inoue lim = buf + bufsize; 5509a4365d0SYoshinobu Inoue for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) { 5519a4365d0SYoshinobu Inoue if (ifm->ifm_msglen == 0) { 5529a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> ifm_msglen is 0 " 5539a4365d0SYoshinobu Inoue "(buf=%p lim=%p ifm=%p)", __FUNCTION__, 5549a4365d0SYoshinobu Inoue buf, lim, ifm); 5559a4365d0SYoshinobu Inoue return; 5569a4365d0SYoshinobu Inoue } 5579a4365d0SYoshinobu Inoue 5589a4365d0SYoshinobu Inoue if (ifm->ifm_type == RTM_IFINFO) { 5599a4365d0SYoshinobu Inoue (*ifmlist_p)[ifm->ifm_index] = ifm; 5609a4365d0SYoshinobu Inoue } else { 5619a4365d0SYoshinobu Inoue syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n" 5629a4365d0SYoshinobu Inoue "expected %d, got %d\n msglen = %d\n" 5639a4365d0SYoshinobu Inoue "buf:%p, ifm:%p, lim:%p\n", 5649a4365d0SYoshinobu Inoue RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, 5659a4365d0SYoshinobu Inoue buf, ifm, lim); 5669a4365d0SYoshinobu Inoue exit (1); 5679a4365d0SYoshinobu Inoue } 5689a4365d0SYoshinobu Inoue for (ifam = (struct ifa_msghdr *) 5699a4365d0SYoshinobu Inoue ((char *)ifm + ifm->ifm_msglen); 5709a4365d0SYoshinobu Inoue ifam < (struct ifa_msghdr *)lim; 5719a4365d0SYoshinobu Inoue ifam = (struct ifa_msghdr *) 5729a4365d0SYoshinobu Inoue ((char *)ifam + ifam->ifam_msglen)) { 5739a4365d0SYoshinobu Inoue /* just for safety */ 5749a4365d0SYoshinobu Inoue if (!ifam->ifam_msglen) { 5759a4365d0SYoshinobu Inoue syslog(LOG_WARNING, "<%s> ifa_msglen is 0 " 5769a4365d0SYoshinobu Inoue "(buf=%p lim=%p ifam=%p)", __FUNCTION__, 5779a4365d0SYoshinobu Inoue buf, lim, ifam); 5789a4365d0SYoshinobu Inoue return; 5799a4365d0SYoshinobu Inoue } 5809a4365d0SYoshinobu Inoue if (ifam->ifam_type != RTM_NEWADDR) 5819a4365d0SYoshinobu Inoue break; 5829a4365d0SYoshinobu Inoue } 5839a4365d0SYoshinobu Inoue ifm = (struct if_msghdr *)ifam; 5849a4365d0SYoshinobu Inoue } 5859a4365d0SYoshinobu Inoue } 5869a4365d0SYoshinobu Inoue 5879a4365d0SYoshinobu Inoue void 5889a4365d0SYoshinobu Inoue init_iflist() 5899a4365d0SYoshinobu Inoue { 5909a4365d0SYoshinobu Inoue if (ifblock) { 5919a4365d0SYoshinobu Inoue free(ifblock); 5929a4365d0SYoshinobu Inoue ifblock_size = 0; 5939a4365d0SYoshinobu Inoue } 5949a4365d0SYoshinobu Inoue if (iflist) 5959a4365d0SYoshinobu Inoue free(iflist); 5969a4365d0SYoshinobu Inoue /* get iflist block from kernel */ 5979a4365d0SYoshinobu Inoue get_iflist(&ifblock, &ifblock_size); 5989a4365d0SYoshinobu Inoue 5999a4365d0SYoshinobu Inoue /* make list of pointers to each if_msghdr */ 6009a4365d0SYoshinobu Inoue parse_iflist(&iflist, ifblock, ifblock_size); 6019a4365d0SYoshinobu Inoue } 602