route.c revision 6735
137535Sdes/* 263012Sdes * PPP Routing related Module 337535Sdes * 437535Sdes * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 537535Sdes * 637535Sdes * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 737535Sdes * 837535Sdes * Redistribution and use in source and binary forms are permitted 937535Sdes * provided that the above copyright notice and this paragraph are 1037535Sdes * duplicated in all such forms and that any documentation, 1137535Sdes * advertising materials, and other materials related to such 1237535Sdes * distribution and use acknowledge that the software was developed 1337535Sdes * by the Internet Initiative Japan, Inc. The name of the 1437535Sdes * IIJ may not be used to endorse or promote products derived 1563012Sdes * from this software without specific prior written permission. 1637535Sdes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1737535Sdes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1837535Sdes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1937535Sdes * 2037535Sdes * $Id:$ 2137535Sdes * 2237535Sdes */ 2337535Sdes#include <sys/types.h> 2437535Sdes#include <machine/endian.h> 2537535Sdes#include <sys/param.h> 2637535Sdes#include <sys/socket.h> 2737535Sdes#include <net/route.h> 2837535Sdes#include <sys/ioctl.h> 2984203Sdillon#include <net/if.h> 3084203Sdillon#include <errno.h> 3184203Sdillon#include <netinet/in_systm.h> 3263236Sdes#include <netinet/in.h> 3363236Sdes#include <arpa/inet.h> 3463236Sdes#if (BSD >= 199306) 3563236Sdes#include <sys/sysctl.h> 3663236Sdes#else 3763236Sdes#include <sys/kinfo.h> 3863236Sdes#endif 3963236Sdes#include <stdlib.h> 4063236Sdes#include <stdio.h> 4163236Sdes#include <string.h> 4263236Sdes#include <unistd.h> 4363236Sdes 4463236Sdesstatic int IfIndex; 4563236Sdes 4663236Sdesstruct rtmsg { 4763236Sdes struct rt_msghdr m_rtm; 4863236Sdes char m_space[64]; 4990267Sdes}; 5063236Sdes 5163236Sdesstatic int seqno; 5263236Sdes 5363236Sdesvoid 5463236SdesOsSetRoute(cmd, dst, gateway, mask) 5563236Sdesint cmd; 5663236Sdesstruct in_addr dst; 5763236Sdesstruct in_addr gateway; 5863236Sdesstruct in_addr mask; 5963236Sdes{ 6063236Sdes struct rtmsg rtmes; 6163236Sdes int s, nb, wb; 6263236Sdes char *cp; 6363236Sdes u_long *lp; 6437535Sdes struct sockaddr_in rtdata; 6560737Sume 6637535Sdes s = socket(PF_ROUTE, SOCK_RAW, 0); 6763012Sdes if (s < 0) 6837535Sdes logprintf("socket\n"); 6963012Sdes 7060376Sdes bzero(&rtmes, sizeof(rtmes)); 7160189Sdes rtmes.m_rtm.rtm_version = RTM_VERSION; 7237608Sdes rtmes.m_rtm.rtm_type = cmd; 7337535Sdes rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 7437535Sdes if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 7537535Sdes rtmes.m_rtm.rtm_seq = ++seqno; 7660376Sdes rtmes.m_rtm.rtm_pid = getpid(); 7737535Sdes rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY; 7837535Sdes 7937535Sdes bzero(&rtdata, sizeof(rtdata)); 8040939Sdes rtdata.sin_len = 16; 8141862Sdes rtdata.sin_family = AF_INET; 8237535Sdes rtdata.sin_port = 0; 8363012Sdes rtdata.sin_addr = dst; 8463012Sdes 8537535Sdes cp = rtmes.m_space; 8663012Sdes bcopy(&rtdata, cp, 16); 8763012Sdes cp += 16; 8863012Sdes if (gateway.s_addr) { 8963012Sdes rtdata.sin_addr = gateway; 9063012Sdes bcopy(&rtdata, cp, 16); 9163012Sdes cp += 16; 9263012Sdes } 9387317Sdes 9463012Sdes if (dst.s_addr == INADDR_ANY) 9560196Sdes mask.s_addr = INADDR_ANY; 9663012Sdes 9790267Sdes lp = (u_long *)cp; 9890267Sdes 9963012Sdes if (mask.s_addr) { 10088771Sdes *lp++ = 8; 10163012Sdes cp += sizeof(int); 10290267Sdes *lp = mask.s_addr; 10363012Sdes } else 10463012Sdes *lp = 0; 10563012Sdes cp += sizeof(u_long); 10663012Sdes 10797859Sdes nb = cp - (char *)&rtmes; 10837535Sdes rtmes.m_rtm.rtm_msglen = nb; 10997858Sdes wb = write(s, &rtmes, nb); 11097866Sdes if (wb < 0) { 11197858Sdes perror("write"); 11297866Sdes } 11397866Sdes#ifdef DEBUG 11497866Sdes logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr); 11597858Sdes#endif 11697858Sdes close(s); 11797858Sdes} 11863281Sdes 11990267Sdesstatic void 12063012Sdesp_sockaddr(sa, width) 12137535Sdesstruct sockaddr *sa; 12237535Sdesint width; 12337608Sdes{ 12463012Sdes register char *cp; 12537608Sdes register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 12637608Sdes 12797859Sdes cp = (sin->sin_addr.s_addr == 0) ? "default" : 12837608Sdes inet_ntoa(sin->sin_addr); 12990267Sdes printf("%-*.*s ", width, width, cp); 13090267Sdes} 13197859Sdes 13290267Sdesstruct bits { 13390267Sdes short b_mask; 13497859Sdes char b_val; 13590267Sdes} bits[] = { 13690267Sdes { RTF_UP, 'U' }, 13797859Sdes { RTF_GATEWAY, 'G' }, 13890267Sdes { RTF_HOST, 'H' }, 13990267Sdes { RTF_DYNAMIC, 'D' }, 14090267Sdes { RTF_MODIFIED, 'M' }, 14190267Sdes { RTF_CLONING, 'C' }, 14290267Sdes { RTF_XRESOLVE, 'X' }, 14397859Sdes { RTF_LLINFO, 'L' }, 14490267Sdes { RTF_REJECT, 'R' }, 14590267Sdes { 0 } 14697859Sdes}; 14790267Sdes 14890267Sdesstatic void 14990267Sdesp_flags(f, format) 15090267Sdesregister int f; 15163281Sdeschar *format; 15290267Sdes{ 15397859Sdes char name[33], *flags; 15497859Sdes register struct bits *p = bits; 155106207Sdes 15690267Sdes for (flags = name; p->b_mask; p++) 157106207Sdes if (p->b_mask & f) 158106207Sdes *flags++ = p->b_val; 159106207Sdes *flags = '\0'; 16090267Sdes printf(format, name); 16163012Sdes} 16290267Sdes 16397859Sdesint 16437608SdesShowRoute() 16537608Sdes{ 16637608Sdes struct rt_msghdr *rtm; 16797866Sdes struct sockaddr *sa; 16897866Sdes char *sp, *ep, *cp; 16997866Sdes u_char *wp; 17097866Sdes int *lp; 17197866Sdes int needed, nb; 17297866Sdes u_long mask; 17397866Sdes#if (BSD >= 199306) 17497866Sdes int mib[6]; 17597866Sdes#endif 17697866Sdes 17797866Sdes#if (BSD >= 199306) 17897866Sdes mib[0] = CTL_NET; 17997866Sdes mib[1] = PF_ROUTE; 18097866Sdes mib[2] = 0; 181106044Sdes mib[3] = 0; 18297866Sdes mib[4] = NET_RT_DUMP; 18397866Sdes mib[5] = 0; 18497866Sdes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 18537608Sdes perror("sysctl-estimate"); 18637608Sdes return(1); 18763012Sdes } 18897866Sdes#else 18937535Sdes needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0); 19097859Sdes#endif 19190267Sdes if (needed < 0) 19297859Sdes return(1); 19390267Sdes sp = malloc(needed); 19490267Sdes if (sp == NULL) 19597866Sdes return(1); 19697866Sdes#if (BSD >= 199306) 19797866Sdes if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 198106185Sdes perror("sysctl-getroute"); 199106185Sdes return(1); 20097866Sdes } 201106185Sdes#else 20297866Sdes if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) 20397866Sdes return(1); 20497866Sdes#endif 20597866Sdes ep = sp + needed; 20697859Sdes 20797859Sdes for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 20890267Sdes rtm = (struct rt_msghdr *)cp; 20997859Sdes sa = (struct sockaddr *)(rtm + 1); 21090267Sdes mask = 0xffffffff; 21190267Sdes if (rtm->rtm_addrs == RTA_DST) 21297859Sdes p_sockaddr(sa, 36); 21390267Sdes else { 21490267Sdes wp = (u_char *)cp + rtm->rtm_msglen; 21537535Sdes p_sockaddr(sa, 16); 21663012Sdes if (sa->sa_len == 0) 21797866Sdes sa->sa_len = sizeof(long); 21897866Sdes sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 21997866Sdes p_sockaddr(sa, 18); 22090267Sdes lp = (int *)(sa->sa_len + (char *)sa); 221106185Sdes if ((char *)lp < (char *)wp && *lp) { 222106185Sdes#ifdef DEBUG 22397866Sdes logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp); 224106185Sdes#endif 22597866Sdes wp = (u_char *)(lp + 1); 22690267Sdes mask = 0; 22797859Sdes for (nb = *lp; nb > 4; nb--) { 22897856Sdes mask <<= 8; 22997856Sdes mask |= *wp++; 23097866Sdes } 23197856Sdes for (nb = 8 - *lp; nb > 0; nb--) 23290267Sdes mask <<= 8; 23390267Sdes } 23490267Sdes } 23597866Sdes printf("%08x ", mask); 23690267Sdes p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s "); 23797866Sdes printf("(%d)\n", rtm->rtm_index); 23837535Sdes } 23937535Sdes 24037608Sdes return(1); 24137608Sdes} 24237608Sdes 24337535Sdes/* 24463012Sdes * Delete routes associated with our interface 24537535Sdes */ 24697859Sdesvoid 24790267SdesDeleteIfRoutes(all) 24863012Sdesint all; 24997859Sdes{ 25090267Sdes struct rt_msghdr *rtm; 25197859Sdes struct sockaddr *sa; 25290267Sdes struct in_addr dstnet, gateway; 25363012Sdes int needed; 25490267Sdes char *sp, *cp, *ep; 25590267Sdes u_long mask; 25697866Sdes int *lp, nb; 25797866Sdes u_char *wp; 25890267Sdes#if (BSD >= 199306) 25997866Sdes int mib[6]; 26090267Sdes#endif 26190267Sdes 26297866Sdes#ifdef DEBUG 26397866Sdes logprintf("DeleteIfRoutes (%d)\n", IfIndex); 26490267Sdes#endif 26537535Sdes#if (BSD >= 199306) 26697859Sdes mib[0] = CTL_NET; 26790267Sdes mib[1] = PF_ROUTE; 26890267Sdes mib[2] = 0; 26937535Sdes mib[3] = 0; 27037535Sdes mib[4] = NET_RT_DUMP; 27137608Sdes mib[5] = 0; 27237608Sdes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 27337608Sdes perror("sysctl-estimate"); 27437535Sdes return; 27563012Sdes } 27637535Sdes#else 27797859Sdes needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0); 27890267Sdes#endif 27997866Sdes 28037535Sdes if (needed < 0) 28137535Sdes return; 28237608Sdes 28337608Sdes sp = malloc(needed); 28437608Sdes if (sp == NULL) 28537535Sdes return; 28663012Sdes 28737535Sdes#if (BSD >= 199306) 28897859Sdes if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 28990267Sdes free(sp); 29063012Sdes perror("sysctl-getroute"); 29197859Sdes return; 29297859Sdes } 29397859Sdes#else 29497859Sdes if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) { 29590267Sdes free(sp); 29637535Sdes return; 29737535Sdes } 29837608Sdes#endif 29963012Sdes ep = sp + needed; 30037608Sdes 30163012Sdes for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 30297866Sdes rtm = (struct rt_msghdr *)cp; 30337535Sdes sa = (struct sockaddr *)(rtm + 1); 30497859Sdes#ifdef DEBUG 30590267Sdes logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n", 30663012Sdes rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 30797859Sdes ((struct sockaddr_in *)sa)->sin_addr); 30890267Sdes#endif 30990267Sdes if (rtm->rtm_addrs != RTA_DST && 31090267Sdes (rtm->rtm_index == IfIndex) && 31197859Sdes (all || (rtm->rtm_flags & RTF_GATEWAY))) { 31297866Sdes dstnet = ((struct sockaddr_in *)sa)->sin_addr; 31397859Sdes wp = (u_char *)cp + rtm->rtm_msglen; 31490267Sdes if (sa->sa_len == 0) 31590267Sdes sa->sa_len = sizeof(long); 31697859Sdes sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 31790267Sdes gateway = ((struct sockaddr_in *)sa)->sin_addr; 31890267Sdes lp = (int *)(sa->sa_len + (char *)sa); 31990267Sdes mask = 0; 32063012Sdes if ((char *)lp < (char *)wp && *lp) { 32163012Sdes#ifdef DEBUG 32290267Sdes printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp); 32363012Sdes#endif 32463012Sdes wp = (u_char *)(lp + 1); 32563012Sdes for (nb = *lp; nb > 4; nb--) { 32663012Sdes mask <<= 8; 32763012Sdes mask |= *wp++; 32863012Sdes } 32990267Sdes for (nb = 8 - *lp; nb > 0; nb--) 33090267Sdes mask <<= 8; 33190267Sdes } 33290267Sdes#ifdef DEBUG 33390267Sdes logprintf("## %s ", inet_ntoa(dstnet)); 33490267Sdes logprintf(" %s %d\n", inet_ntoa(gateway), rtm->rtm_index); 33590267Sdes#endif 33690267Sdes if (dstnet.s_addr == INADDR_ANY) { 33790267Sdes gateway.s_addr = INADDR_ANY; 33890267Sdes mask = INADDR_ANY; 33985093Sdes } 34063012Sdes OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask)); 34163012Sdes } 34263012Sdes#ifdef DEBUG 34390267Sdes else if (rtm->rtm_index == IfIndex) { 34490267Sdes logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags); 34563012Sdes } 34690267Sdes#endif 34790267Sdes } 34890267Sdes free(sp); 34990267Sdes} 35090267Sdes 35190267Sdesint 35290267SdesGetIfIndex(name) 35363012Sdeschar *name; 35463012Sdes{ 35563012Sdes struct ifreq *ifrp; 35663012Sdes int s, len, elen, index; 35763012Sdes struct ifconf ifconfs; 35863012Sdes struct ifreq reqbuf[32]; 35997856Sdes 36063012Sdes s = socket(AF_INET, SOCK_DGRAM, 0); 36190267Sdes if (s < 0) { 36290267Sdes perror("socket"); 36390267Sdes return(-1); 36490267Sdes } 36563012Sdes 36690267Sdes ifconfs.ifc_len = sizeof(reqbuf); 36790267Sdes ifconfs.ifc_buf = (caddr_t)reqbuf; 36890267Sdes if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 36990267Sdes perror("IFCONF"); 37090267Sdes return(-1); 37190267Sdes } 37290267Sdes 37390267Sdes ifrp = ifconfs.ifc_req; 37490267Sdes 37590267Sdes index = 1; 37697856Sdes for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 37790267Sdes elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 37890267Sdes if (ifrp->ifr_addr.sa_family == AF_LINK) { 37990267Sdes#ifdef DEBUG 38090267Sdes logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 38190267Sdes ifrp->ifr_addr.sa_family, elen); 38290267Sdes#endif 38390267Sdes if (strcmp(ifrp->ifr_name, name) == 0) { 38490267Sdes IfIndex = index; 38563012Sdes return(index); 38663012Sdes } 38763012Sdes index++; 38863012Sdes } 38963012Sdes 39063012Sdes len -= elen; 39197856Sdes ifrp = (struct ifreq *)((char *)ifrp + elen); 39263012Sdes ifrp++; 39390267Sdes } 39490267Sdes 39597856Sdes close(s); 39690267Sdes return(-1); 39790267Sdes} 39890267Sdes