route.c revision 25630
16059Samurai/* 26059Samurai * PPP Routing related Module 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2025630Sbrian * $Id: route.c,v 1.12 1997/02/22 16:10:49 peter Exp $ 218857Srgrimes * 226059Samurai */ 236059Samurai#include <sys/types.h> 246059Samurai#include <machine/endian.h> 2520287Swollman#include <sys/ioctl.h> 266059Samurai#include <sys/param.h> 276059Samurai#include <sys/socket.h> 286735Samurai#if (BSD >= 199306) 296059Samurai#include <sys/sysctl.h> 306059Samurai#else 316059Samurai#include <sys/kinfo.h> 326059Samurai#endif 3320287Swollman#include <sys/time.h> 3420287Swollman 3520287Swollman#include <errno.h> 366059Samurai#include <stdlib.h> 376059Samurai#include <stdio.h> 386059Samurai#include <string.h> 396059Samurai#include <unistd.h> 4020287Swollman 4120287Swollman#include <net/route.h> 4220287Swollman#include <net/if.h> 4320287Swollman#include <netinet/in_systm.h> 4420287Swollman#include <netinet/in.h> 4520287Swollman#include <arpa/inet.h> 4620287Swollman 479439Samurai#include "log.h" 486059Samurai 496059Samuraistatic int IfIndex; 506059Samurai 516059Samuraistruct rtmsg { 526059Samurai struct rt_msghdr m_rtm; 536059Samurai char m_space[64]; 546059Samurai}; 556059Samurai 566059Samuraistatic int seqno; 576059Samurai 586059Samuraivoid 596059SamuraiOsSetRoute(cmd, dst, gateway, mask) 606059Samuraiint cmd; 616059Samuraistruct in_addr dst; 626059Samuraistruct in_addr gateway; 636059Samuraistruct in_addr mask; 646059Samurai{ 656059Samurai struct rtmsg rtmes; 666059Samurai int s, nb, wb; 676059Samurai char *cp; 686059Samurai u_long *lp; 696059Samurai struct sockaddr_in rtdata; 706059Samurai 716059Samurai s = socket(PF_ROUTE, SOCK_RAW, 0); 726059Samurai if (s < 0) 736059Samurai logprintf("socket\n"); 746059Samurai 756059Samurai bzero(&rtmes, sizeof(rtmes)); 766059Samurai rtmes.m_rtm.rtm_version = RTM_VERSION; 776059Samurai rtmes.m_rtm.rtm_type = cmd; 786059Samurai rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 796059Samurai if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 806059Samurai rtmes.m_rtm.rtm_seq = ++seqno; 816059Samurai rtmes.m_rtm.rtm_pid = getpid(); 8217571Speter rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 836059Samurai 846059Samurai bzero(&rtdata, sizeof(rtdata)); 856059Samurai rtdata.sin_len = 16; 866059Samurai rtdata.sin_family = AF_INET; 876059Samurai rtdata.sin_port = 0; 886059Samurai rtdata.sin_addr = dst; 896059Samurai 906059Samurai cp = rtmes.m_space; 916059Samurai bcopy(&rtdata, cp, 16); 926059Samurai cp += 16; 936059Samurai if (gateway.s_addr) { 946059Samurai rtdata.sin_addr = gateway; 956059Samurai bcopy(&rtdata, cp, 16); 966059Samurai cp += 16; 976059Samurai } 986059Samurai 996059Samurai if (dst.s_addr == INADDR_ANY) 1006059Samurai mask.s_addr = INADDR_ANY; 1016059Samurai 1026059Samurai lp = (u_long *)cp; 1036059Samurai 1046059Samurai if (mask.s_addr) { 1056059Samurai *lp++ = 8; 1066059Samurai cp += sizeof(int); 1076059Samurai *lp = mask.s_addr; 1086059Samurai } else 1096059Samurai *lp = 0; 1106059Samurai cp += sizeof(u_long); 1116059Samurai 1126059Samurai nb = cp - (char *)&rtmes; 1136059Samurai rtmes.m_rtm.rtm_msglen = nb; 1146059Samurai wb = write(s, &rtmes, nb); 1156059Samurai if (wb < 0) { 11615738Sphk LogPrintf(LOG_TCPIP_BIT, "Already set route addr dst=%x, gateway=%x\n" 1179439Samurai ,dst.s_addr, gateway.s_addr); 1186059Samurai } 1196059Samurai#ifdef DEBUG 1206059Samurai logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr); 1216059Samurai#endif 1226059Samurai close(s); 1236059Samurai} 1246059Samurai 1256059Samuraistatic void 1266059Samuraip_sockaddr(sa, width) 1276059Samuraistruct sockaddr *sa; 1286059Samuraiint width; 1296059Samurai{ 1306059Samurai register char *cp; 1316059Samurai register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1326059Samurai 1336059Samurai cp = (sin->sin_addr.s_addr == 0) ? "default" : 1346059Samurai inet_ntoa(sin->sin_addr); 1356059Samurai printf("%-*.*s ", width, width, cp); 1366059Samurai} 1376059Samurai 1386059Samuraistruct bits { 1396059Samurai short b_mask; 1406059Samurai char b_val; 1416059Samurai} bits[] = { 1426059Samurai { RTF_UP, 'U' }, 1436059Samurai { RTF_GATEWAY, 'G' }, 1446059Samurai { RTF_HOST, 'H' }, 1456059Samurai { RTF_DYNAMIC, 'D' }, 1466059Samurai { RTF_MODIFIED, 'M' }, 1476059Samurai { RTF_CLONING, 'C' }, 1486059Samurai { RTF_XRESOLVE, 'X' }, 1496059Samurai { RTF_LLINFO, 'L' }, 1506059Samurai { RTF_REJECT, 'R' }, 1516059Samurai { 0 } 1526059Samurai}; 1536059Samurai 1546059Samuraistatic void 1556059Samuraip_flags(f, format) 1566059Samurairegister int f; 1576059Samuraichar *format; 1586059Samurai{ 1596059Samurai char name[33], *flags; 1606059Samurai register struct bits *p = bits; 1616059Samurai 1626059Samurai for (flags = name; p->b_mask; p++) 1636059Samurai if (p->b_mask & f) 1646059Samurai *flags++ = p->b_val; 1656059Samurai *flags = '\0'; 1666059Samurai printf(format, name); 1676059Samurai} 1686059Samurai 1696059Samuraiint 1706059SamuraiShowRoute() 1716059Samurai{ 1726059Samurai struct rt_msghdr *rtm; 1736059Samurai struct sockaddr *sa; 1746059Samurai char *sp, *ep, *cp; 1756059Samurai u_char *wp; 1766059Samurai int *lp; 1776059Samurai int needed, nb; 1786059Samurai u_long mask; 1796735Samurai#if (BSD >= 199306) 1806735Samurai int mib[6]; 1816059Samurai#endif 1826059Samurai 1836735Samurai#if (BSD >= 199306) 1846059Samurai mib[0] = CTL_NET; 1856059Samurai mib[1] = PF_ROUTE; 1866735Samurai mib[2] = 0; 1876735Samurai mib[3] = 0; 1886059Samurai mib[4] = NET_RT_DUMP; 1896735Samurai mib[5] = 0; 1906735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 1916735Samurai perror("sysctl-estimate"); 1926735Samurai return(1); 1936735Samurai } 1946059Samurai#else 1956059Samurai needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0); 1966059Samurai#endif 1976059Samurai if (needed < 0) 1986059Samurai return(1); 1996059Samurai sp = malloc(needed); 2006059Samurai if (sp == NULL) 2016059Samurai return(1); 2026735Samurai#if (BSD >= 199306) 2036735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 2046735Samurai perror("sysctl-getroute"); 20518885Sjkh free(sp); 2066059Samurai return(1); 2076735Samurai } 2086059Samurai#else 2096059Samurai if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) 21018885Sjkh free(sp); 2116059Samurai return(1); 2126059Samurai#endif 2136059Samurai ep = sp + needed; 2146059Samurai 2156059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 2166059Samurai rtm = (struct rt_msghdr *)cp; 2176059Samurai sa = (struct sockaddr *)(rtm + 1); 2186059Samurai mask = 0xffffffff; 2196059Samurai if (rtm->rtm_addrs == RTA_DST) 2206059Samurai p_sockaddr(sa, 36); 2216059Samurai else { 2226059Samurai wp = (u_char *)cp + rtm->rtm_msglen; 2236059Samurai p_sockaddr(sa, 16); 2246059Samurai if (sa->sa_len == 0) 2256059Samurai sa->sa_len = sizeof(long); 2266059Samurai sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 2276059Samurai p_sockaddr(sa, 18); 2286059Samurai lp = (int *)(sa->sa_len + (char *)sa); 2296059Samurai if ((char *)lp < (char *)wp && *lp) { 2306059Samurai#ifdef DEBUG 2316059Samurai logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp); 2326059Samurai#endif 2336059Samurai wp = (u_char *)(lp + 1); 2346059Samurai mask = 0; 23518885Sjkh for (nb = *(char *)lp; nb > 4; nb--) { 2366059Samurai mask <<= 8; 2376059Samurai mask |= *wp++; 2386059Samurai } 23918885Sjkh for (nb = 8 - *(char *)lp; nb > 0; nb--) 2406059Samurai mask <<= 8; 2416059Samurai } 2426059Samurai } 24313389Sphk printf("%08lx ", mask); 2446059Samurai p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s "); 2456059Samurai printf("(%d)\n", rtm->rtm_index); 2466059Samurai } 24718885Sjkh free(sp); 2486059Samurai return(1); 2496059Samurai} 2506059Samurai 2516059Samurai/* 2526059Samurai * Delete routes associated with our interface 2536059Samurai */ 2546059Samuraivoid 2556059SamuraiDeleteIfRoutes(all) 2566059Samuraiint all; 2576059Samurai{ 2586059Samurai struct rt_msghdr *rtm; 2596059Samurai struct sockaddr *sa; 26015738Sphk struct in_addr dstnet, gateway, maddr; 2616059Samurai int needed; 2626059Samurai char *sp, *cp, *ep; 2636059Samurai u_long mask; 2646059Samurai int *lp, nb; 2656059Samurai u_char *wp; 2666735Samurai#if (BSD >= 199306) 2676735Samurai int mib[6]; 2686059Samurai#endif 2696059Samurai 2706059Samurai#ifdef DEBUG 2716059Samurai logprintf("DeleteIfRoutes (%d)\n", IfIndex); 2726059Samurai#endif 2736735Samurai#if (BSD >= 199306) 2746059Samurai mib[0] = CTL_NET; 2756059Samurai mib[1] = PF_ROUTE; 2766735Samurai mib[2] = 0; 2776735Samurai mib[3] = 0; 2786059Samurai mib[4] = NET_RT_DUMP; 2796735Samurai mib[5] = 0; 2806735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 2816735Samurai perror("sysctl-estimate"); 2826735Samurai return; 2836735Samurai } 2846059Samurai#else 2856059Samurai needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0); 2866059Samurai#endif 2876735Samurai 2886059Samurai if (needed < 0) 2896059Samurai return; 2906059Samurai 2916059Samurai sp = malloc(needed); 2926059Samurai if (sp == NULL) 2936059Samurai return; 2946059Samurai 2956735Samurai#if (BSD >= 199306) 2966735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 2976059Samurai free(sp); 2986735Samurai perror("sysctl-getroute"); 2996059Samurai return; 3006059Samurai } 3016059Samurai#else 3026059Samurai if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) { 3036059Samurai free(sp); 3046059Samurai return; 3056059Samurai } 3066059Samurai#endif 3076059Samurai ep = sp + needed; 3086059Samurai 3096059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 3106059Samurai rtm = (struct rt_msghdr *)cp; 3116059Samurai sa = (struct sockaddr *)(rtm + 1); 3126059Samurai#ifdef DEBUG 3136059Samurai logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n", 3146059Samurai rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 3156059Samurai ((struct sockaddr_in *)sa)->sin_addr); 3166059Samurai#endif 3176059Samurai if (rtm->rtm_addrs != RTA_DST && 3186059Samurai (rtm->rtm_index == IfIndex) && 3196059Samurai (all || (rtm->rtm_flags & RTF_GATEWAY))) { 3206059Samurai dstnet = ((struct sockaddr_in *)sa)->sin_addr; 3216059Samurai wp = (u_char *)cp + rtm->rtm_msglen; 3226059Samurai if (sa->sa_len == 0) 3236059Samurai sa->sa_len = sizeof(long); 3246059Samurai sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 3256059Samurai gateway = ((struct sockaddr_in *)sa)->sin_addr; 3266059Samurai lp = (int *)(sa->sa_len + (char *)sa); 3276059Samurai mask = 0; 3286059Samurai if ((char *)lp < (char *)wp && *lp) { 3296059Samurai#ifdef DEBUG 3306059Samurai printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp); 3316059Samurai#endif 3326059Samurai wp = (u_char *)(lp + 1); 3336059Samurai for (nb = *lp; nb > 4; nb--) { 3346059Samurai mask <<= 8; 3356059Samurai mask |= *wp++; 3366059Samurai } 3376059Samurai for (nb = 8 - *lp; nb > 0; nb--) 3386059Samurai mask <<= 8; 3396059Samurai } 3406059Samurai#ifdef DEBUG 3416059Samurai logprintf("## %s ", inet_ntoa(dstnet)); 3426059Samurai logprintf(" %s %d\n", inet_ntoa(gateway), rtm->rtm_index); 3436059Samurai#endif 3446059Samurai if (dstnet.s_addr == INADDR_ANY) { 3456059Samurai gateway.s_addr = INADDR_ANY; 3466059Samurai mask = INADDR_ANY; 3476059Samurai } 34815738Sphk maddr.s_addr = htonl(mask); 34915738Sphk OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 3506059Samurai } 3516059Samurai#ifdef DEBUG 3526059Samurai else if (rtm->rtm_index == IfIndex) { 3536059Samurai logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags); 3546059Samurai } 3556059Samurai#endif 3566059Samurai } 3576059Samurai free(sp); 3586059Samurai} 3596059Samurai 36018752Sjkh /* 36118752Sjkh * 960603 - Modified to use dynamic buffer allocator as in ifconfig 36218752Sjkh */ 36318752Sjkh 3646059Samuraiint 3656059SamuraiGetIfIndex(name) 3666059Samuraichar *name; 3676059Samurai{ 36818752Sjkh char *buffer; 3696059Samurai struct ifreq *ifrp; 3706059Samurai int s, len, elen, index; 3716059Samurai struct ifconf ifconfs; 37218752Sjkh /* struct ifreq reqbuf[256]; -- obsoleted :) */ 37318752Sjkh int oldbufsize, bufsize = sizeof(struct ifreq); 3746059Samurai 3756059Samurai s = socket(AF_INET, SOCK_DGRAM, 0); 3766059Samurai if (s < 0) { 3776059Samurai perror("socket"); 3786059Samurai return(-1); 3796059Samurai } 3806059Samurai 38118752Sjkh buffer = malloc(bufsize); /* allocate first buffer */ 38218752Sjkh ifconfs.ifc_len = bufsize; /* Initial setting */ 38318752Sjkh /* 38418752Sjkh * Iterate through here until we don't get many more data 38518752Sjkh */ 3866059Samurai 38718752Sjkh do { 38818752Sjkh oldbufsize = ifconfs.ifc_len; 38918752Sjkh bufsize += 1+sizeof(struct ifreq); 39018752Sjkh buffer = realloc((void *)buffer, bufsize); /* Make it bigger */ 39118752Sjkh#ifdef DEBUG 39218752Sjkh logprintf ("Growing buffer to %d\n", bufsize); 39318752Sjkh#endif 39418752Sjkh ifconfs.ifc_len = bufsize; 39518752Sjkh ifconfs.ifc_buf = buffer; 39618752Sjkh if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 39718752Sjkh perror("IFCONF"); 39818752Sjkh free(buffer); 39918752Sjkh return(-1); 40018752Sjkh } 40118752Sjkh } while (ifconfs.ifc_len > oldbufsize); 40218752Sjkh 4036059Samurai ifrp = ifconfs.ifc_req; 4046059Samurai 4056059Samurai index = 1; 4066059Samurai for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 4076059Samurai elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 4086059Samurai if (ifrp->ifr_addr.sa_family == AF_LINK) { 4096059Samurai#ifdef DEBUG 4106059Samurai logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 4116059Samurai ifrp->ifr_addr.sa_family, elen); 4126059Samurai#endif 4136059Samurai if (strcmp(ifrp->ifr_name, name) == 0) { 4146059Samurai IfIndex = index; 41525630Sbrian free(buffer); 4166059Samurai return(index); 4176059Samurai } 4186059Samurai index++; 4196059Samurai } 4206059Samurai 4216059Samurai len -= elen; 4226059Samurai ifrp = (struct ifreq *)((char *)ifrp + elen); 4236059Samurai ifrp++; 4246059Samurai } 4256059Samurai 4266059Samurai close(s); 42718752Sjkh free(buffer); 4286059Samurai return(-1); 4296059Samurai} 430