route.c revision 26591
12258Scsgr/* 22258Scsgr * PPP Routing related Module 32258Scsgr * 42258Scsgr * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 52258Scsgr * 62258Scsgr * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 72258Scsgr * 82258Scsgr * Redistribution and use in source and binary forms are permitted 916519Snate * provided that the above copyright notice and this paragraph are 102258Scsgr * duplicated in all such forms and that any documentation, 112258Scsgr * advertising materials, and other materials related to such 122258Scsgr * distribution and use acknowledge that the software was developed 132258Scsgr * by the Internet Initiative Japan, Inc. The name of the 142258Scsgr * IIJ may not be used to endorse or promote products derived 152258Scsgr * from this software without specific prior written permission. 162258Scsgr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 172258Scsgr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 182258Scsgr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 192258Scsgr * 202258Scsgr * $Id: route.c,v 1.14 1997/06/09 03:27:36 brian Exp $ 212258Scsgr * 222258Scsgr */ 232258Scsgr#include <sys/types.h> 242258Scsgr#include <machine/endian.h> 252258Scsgr#include <sys/ioctl.h> 262258Scsgr#include <sys/param.h> 272258Scsgr#include <sys/socket.h> 282258Scsgr#include <sys/sysctl.h> 2952555Sobrien#include <sys/time.h> 3050488Speter 312258Scsgr#include <errno.h> 322258Scsgr#include <stdlib.h> 332258Scsgr#include <stdio.h> 342258Scsgr#include <string.h> 352258Scsgr#include <unistd.h> 362258Scsgr 372258Scsgr#include <net/route.h> 382258Scsgr#include <net/if.h> 392258Scsgr#include <netinet/in_systm.h> 402258Scsgr#include <netinet/in.h> 412258Scsgr#include <arpa/inet.h> 422258Scsgr 432258Scsgr#include "log.h" 442258Scsgr#include "loadalias.h" 452258Scsgr#include "vars.h" 462258Scsgr 472258Scsgrstatic int IfIndex; 482258Scsgr 492258Scsgrstruct rtmsg { 502258Scsgr struct rt_msghdr m_rtm; 512258Scsgr char m_space[64]; 522258Scsgr}; 532258Scsgr 542258Scsgrstatic int seqno; 552258Scsgr 562258Scsgrvoid 572258ScsgrOsSetRoute(cmd, dst, gateway, mask) 582258Scsgrint cmd; 592258Scsgrstruct in_addr dst; 602258Scsgrstruct in_addr gateway; 612258Scsgrstruct in_addr mask; 622258Scsgr{ 632258Scsgr struct rtmsg rtmes; 642258Scsgr int s, nb, wb; 652258Scsgr char *cp; 662258Scsgr u_long *lp; 672258Scsgr struct sockaddr_in rtdata; 682258Scsgr 692258Scsgr s = socket(PF_ROUTE, SOCK_RAW, 0); 702258Scsgr if (s < 0) 712258Scsgr LogPrintf(LogERROR, "socket: %s", strerror(errno)); 722258Scsgr 732258Scsgr bzero(&rtmes, sizeof(rtmes)); 742258Scsgr rtmes.m_rtm.rtm_version = RTM_VERSION; 752258Scsgr rtmes.m_rtm.rtm_type = cmd; 762258Scsgr rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 772258Scsgr rtmes.m_rtm.rtm_seq = ++seqno; 782258Scsgr rtmes.m_rtm.rtm_pid = getpid(); 792258Scsgr rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 802258Scsgr 812258Scsgr bzero(&rtdata, sizeof(rtdata)); 822258Scsgr rtdata.sin_len = 16; 832258Scsgr rtdata.sin_family = AF_INET; 842258Scsgr rtdata.sin_port = 0; 852258Scsgr rtdata.sin_addr = dst; 862258Scsgr 872258Scsgr cp = rtmes.m_space; 882258Scsgr bcopy(&rtdata, cp, 16); 892258Scsgr cp += 16; 902258Scsgr if (gateway.s_addr) { 912258Scsgr rtdata.sin_addr = gateway; 922258Scsgr bcopy(&rtdata, cp, 16); 932258Scsgr cp += 16; 942258Scsgr } 952258Scsgr 962258Scsgr if (dst.s_addr == INADDR_ANY) 972258Scsgr mask.s_addr = INADDR_ANY; 982258Scsgr 992258Scsgr lp = (u_long *)cp; 1002258Scsgr 1012258Scsgr if (mask.s_addr) { 1022258Scsgr *lp++ = 8; 1032258Scsgr cp += sizeof(int); 1042258Scsgr *lp = mask.s_addr; 1052258Scsgr } else 1062258Scsgr *lp = 0; 1072258Scsgr cp += sizeof(u_long); 1082258Scsgr 1092258Scsgr nb = cp - (char *)&rtmes; 1102258Scsgr rtmes.m_rtm.rtm_msglen = nb; 1112258Scsgr wb = write(s, &rtmes, nb); 1122258Scsgr if (wb < 0) { 1132258Scsgr LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 1142258Scsgr LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 1152258Scsgr LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 1162258Scsgr switch(rtmes.m_rtm.rtm_errno) { 1172258Scsgr case EEXIST: 1182258Scsgr LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 1192258Scsgr break; 1202258Scsgr case ESRCH: 1212258Scsgr LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 1222258Scsgr break; 1232258Scsgr case ENOBUFS: 1242258Scsgr default: 1252258Scsgr LogPrintf(LogTCPIP, "Add/Del route failed: %s\n", 1262258Scsgr strerror(rtmes.m_rtm.rtm_errno)); 1272258Scsgr break; 1282258Scsgr } 1292258Scsgr } 1302258Scsgr 1312258Scsgr LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb, 1322258Scsgr dst.s_addr, gateway.s_addr); 1332258Scsgr close(s); 1342258Scsgr} 1352258Scsgr 1362258Scsgrstatic void 1372258Scsgrp_sockaddr(sa, width) 1382258Scsgrstruct sockaddr *sa; 1392258Scsgrint width; 1402258Scsgr{ 1412258Scsgr if (VarTerm) { 1422258Scsgr register char *cp; 1432258Scsgr register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1442258Scsgr 1452258Scsgr cp = (sin->sin_addr.s_addr == 0) ? "default" : 1462258Scsgr inet_ntoa(sin->sin_addr); 1472258Scsgr fprintf(VarTerm, "%-*.*s ", width, width, cp); 1482258Scsgr } 1492258Scsgr} 1502258Scsgr 1512258Scsgrstruct bits { 1522258Scsgr short b_mask; 1532258Scsgr char b_val; 1542258Scsgr} bits[] = { 1552258Scsgr { RTF_UP, 'U' }, 1562258Scsgr { RTF_GATEWAY, 'G' }, 1572258Scsgr { RTF_HOST, 'H' }, 1582258Scsgr { RTF_DYNAMIC, 'D' }, 1592258Scsgr { RTF_MODIFIED, 'M' }, 1602258Scsgr { RTF_CLONING, 'C' }, 1612258Scsgr { RTF_XRESOLVE, 'X' }, 1622258Scsgr { RTF_LLINFO, 'L' }, 1632258Scsgr { RTF_REJECT, 'R' }, 1642258Scsgr { 0 } 1652258Scsgr}; 1662258Scsgr 1672258Scsgrstatic void 1682258Scsgrp_flags(f, format) 1692258Scsgrregister int f; 1702258Scsgrchar *format; 1712258Scsgr{ 1722258Scsgr if (VarTerm) { 1732258Scsgr char name[33], *flags; 1742258Scsgr register struct bits *p = bits; 1752258Scsgr 1762258Scsgr for (flags = name; p->b_mask; p++) 1772258Scsgr if (p->b_mask & f) 1782258Scsgr *flags++ = p->b_val; 1792258Scsgr *flags = '\0'; 1802258Scsgr fprintf(VarTerm, format, name); 1812258Scsgr } 1822258Scsgr} 1832258Scsgr 1842258Scsgrint 1852258ScsgrShowRoute() 1862258Scsgr{ 1872258Scsgr struct rt_msghdr *rtm; 1882258Scsgr struct sockaddr *sa; 1892258Scsgr char *sp, *ep, *cp; 1902258Scsgr u_char *wp; 1912258Scsgr int *lp; 1922258Scsgr int needed, nb; 1932258Scsgr u_long mask; 1942258Scsgr int mib[6]; 1952258Scsgr 1962258Scsgr if (!VarTerm) 1972258Scsgr return 1; 1982258Scsgr 1992258Scsgr mib[0] = CTL_NET; 2002258Scsgr mib[1] = PF_ROUTE; 2012258Scsgr mib[2] = 0; 2022258Scsgr mib[3] = 0; 2032258Scsgr mib[4] = NET_RT_DUMP; 2042258Scsgr mib[5] = 0; 2052258Scsgr if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 2062258Scsgr LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno)); 2072258Scsgr return(1); 2082258Scsgr } 2092258Scsgr 2102258Scsgr if (needed < 0) 2112258Scsgr return(1); 2122258Scsgr sp = malloc(needed); 2132258Scsgr if (sp == NULL) 2142258Scsgr return(1); 2152258Scsgr if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 2162258Scsgr LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno)); 2172258Scsgr free(sp); 2182258Scsgr return(1); 2192258Scsgr } 2202258Scsgr 2212258Scsgr ep = sp + needed; 2222258Scsgr 2232258Scsgr for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 2242258Scsgr rtm = (struct rt_msghdr *)cp; 2252258Scsgr sa = (struct sockaddr *)(rtm + 1); 2262258Scsgr mask = 0xffffffff; 2272258Scsgr if (rtm->rtm_addrs == RTA_DST) 2282258Scsgr p_sockaddr(sa, 36); 2292258Scsgr else { 2302258Scsgr wp = (u_char *)cp + rtm->rtm_msglen; 2312258Scsgr p_sockaddr(sa, 16); 2322258Scsgr if (sa->sa_len == 0) 2332258Scsgr sa->sa_len = sizeof(long); 2342258Scsgr sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 2352258Scsgr p_sockaddr(sa, 18); 2362258Scsgr lp = (int *)(sa->sa_len + (char *)sa); 2372258Scsgr if ((char *)lp < (char *)wp && *lp) { 2382258Scsgr LogPrintf(LogDEBUG, " flag = %x, rest = %d", rtm->rtm_flags, *lp); 2392258Scsgr wp = (u_char *)(lp + 1); 2402258Scsgr mask = 0; 2412258Scsgr for (nb = *(char *)lp; nb > 4; nb--) { 2422258Scsgr mask <<= 8; 2432258Scsgr mask |= *wp++; 2442258Scsgr } 2452258Scsgr for (nb = 8 - *(char *)lp; nb > 0; nb--) 2462258Scsgr mask <<= 8; 2472258Scsgr } 2482258Scsgr } 2492258Scsgr fprintf(VarTerm, "%08lx ", mask); 2502258Scsgr p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s "); 2512258Scsgr fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 2522258Scsgr } 2532258Scsgr free(sp); 2542258Scsgr return 0; 2552258Scsgr} 2562258Scsgr 2572258Scsgr/* 2582258Scsgr * Delete routes associated with our interface 2592258Scsgr */ 2602258Scsgrvoid 2612258ScsgrDeleteIfRoutes(all) 2622258Scsgrint all; 2632258Scsgr{ 2642258Scsgr struct rt_msghdr *rtm; 2652258Scsgr struct sockaddr *sa; 2662258Scsgr struct in_addr dstnet, gateway, maddr; 2672258Scsgr int needed; 2682258Scsgr char *sp, *cp, *ep; 2692258Scsgr u_long mask; 2702258Scsgr int *lp, nb; 2712258Scsgr u_char *wp; 2722258Scsgr int mib[6]; 2732258Scsgr 2742258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 2752258Scsgr 2762258Scsgr mib[0] = CTL_NET; 2772258Scsgr mib[1] = PF_ROUTE; 2782258Scsgr mib[2] = 0; 2792258Scsgr mib[3] = 0; 2802258Scsgr mib[4] = NET_RT_DUMP; 2812258Scsgr mib[5] = 0; 2822258Scsgr if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 2832258Scsgr LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno)); 2842258Scsgr return; 2852258Scsgr } 2862258Scsgr 2872258Scsgr if (needed < 0) 2882258Scsgr return; 2892258Scsgr 2902258Scsgr sp = malloc(needed); 2912258Scsgr if (sp == NULL) 2922258Scsgr return; 2932258Scsgr 2942258Scsgr if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 2952258Scsgr LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno)); 2962258Scsgr free(sp); 2972258Scsgr return; 2982258Scsgr } 2992258Scsgr ep = sp + needed; 3002258Scsgr 3012258Scsgr for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 3022258Scsgr rtm = (struct rt_msghdr *)cp; 3032258Scsgr sa = (struct sockaddr *)(rtm + 1); 3042258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 3052258Scsgr " dstnet: %x\n", 3062258Scsgr rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 3072258Scsgr ((struct sockaddr_in *)sa)->sin_addr); 3082258Scsgr if (rtm->rtm_addrs != RTA_DST && 3092258Scsgr (rtm->rtm_index == IfIndex) && 3102258Scsgr (all || (rtm->rtm_flags & RTF_GATEWAY))) { 3112258Scsgr dstnet = ((struct sockaddr_in *)sa)->sin_addr; 3122258Scsgr wp = (u_char *)cp + rtm->rtm_msglen; 3132258Scsgr if (sa->sa_len == 0) 31416519Snate sa->sa_len = sizeof(long); 3152258Scsgr sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 3162258Scsgr gateway = ((struct sockaddr_in *)sa)->sin_addr; 3172258Scsgr lp = (int *)(sa->sa_len + (char *)sa); 3182258Scsgr mask = 0; 3192258Scsgr if ((char *)lp < (char *)wp && *lp) { 3202258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d", 3212258Scsgr rtm->rtm_flags, *lp); 3222258Scsgr wp = (u_char *)(lp + 1); 3232258Scsgr for (nb = *lp; nb > 4; nb--) { 3242258Scsgr mask <<= 8; 3252258Scsgr mask |= *wp++; 3262258Scsgr } 3272258Scsgr for (nb = 8 - *lp; nb > 0; nb--) 3282258Scsgr mask <<= 8; 3292258Scsgr } 3302258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: Dest: %s\n", inet_ntoa(dstnet)); 3312258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 3322258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 3332258Scsgr if (dstnet.s_addr == INADDR_ANY) { 3342258Scsgr gateway.s_addr = INADDR_ANY; 3352258Scsgr mask = INADDR_ANY; 3362258Scsgr } 3372258Scsgr maddr.s_addr = htonl(mask); 3382258Scsgr OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 3392258Scsgr } 3402258Scsgr else if(rtm->rtm_index == IfIndex) 3412258Scsgr LogPrintf(LogDEBUG, "DeleteIfRoutes: Ignoring (looking for index %d)\n", 3422258Scsgr IfIndex); 3432258Scsgr } 3442258Scsgr free(sp); 3452258Scsgr} 3462258Scsgr 3472258Scsgr /* 3482258Scsgr * 960603 - Modified to use dynamic buffer allocator as in ifconfig 3492258Scsgr */ 3502258Scsgr 3512258Scsgrint 3522258ScsgrGetIfIndex(name) 3532258Scsgrchar *name; 3542258Scsgr{ 3552258Scsgr char *buffer; 3562258Scsgr struct ifreq *ifrp; 3572258Scsgr int s, len, elen, index; 3582258Scsgr struct ifconf ifconfs; 3592258Scsgr /* struct ifreq reqbuf[256]; -- obsoleted :) */ 3602258Scsgr int oldbufsize, bufsize = sizeof(struct ifreq); 3612258Scsgr 3622258Scsgr s = socket(AF_INET, SOCK_DGRAM, 0); 3632258Scsgr if (s < 0) { 3642258Scsgr LogPrintf(LogERROR, "socket: %s", strerror(errno)); 3652258Scsgr return(-1); 3662258Scsgr } 3672258Scsgr 3682258Scsgr buffer = malloc(bufsize); /* allocate first buffer */ 3692258Scsgr ifconfs.ifc_len = bufsize; /* Initial setting */ 3702258Scsgr /* 3712258Scsgr * Iterate through here until we don't get many more data 3722258Scsgr */ 3732258Scsgr 3742258Scsgr do { 3752258Scsgr oldbufsize = ifconfs.ifc_len; 3762258Scsgr bufsize += 1+sizeof(struct ifreq); 3772258Scsgr buffer = realloc((void *)buffer, bufsize); /* Make it bigger */ 3782258Scsgr LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 3792258Scsgr ifconfs.ifc_len = bufsize; 3802258Scsgr ifconfs.ifc_buf = buffer; 3812258Scsgr if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 3822258Scsgr LogPrintf(LogERROR, "ioctl(SIOCGIFCONF): %s", strerror(errno)); 3832258Scsgr free(buffer); 3842258Scsgr return(-1); 3852258Scsgr } 3862258Scsgr } while (ifconfs.ifc_len > oldbufsize); 3872258Scsgr 3882258Scsgr ifrp = ifconfs.ifc_req; 3892258Scsgr 3902258Scsgr index = 1; 3912258Scsgr for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 3922258Scsgr elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 3932258Scsgr if (ifrp->ifr_addr.sa_family == AF_LINK) { 3942258Scsgr LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 3952258Scsgr index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 3962258Scsgr ifrp->ifr_addr.sa_family, elen); 3972258Scsgr if (strcmp(ifrp->ifr_name, name) == 0) { 3982258Scsgr IfIndex = index; 3992258Scsgr free(buffer); 4002258Scsgr return(index); 4012258Scsgr } 4022258Scsgr index++; 4032258Scsgr } 4042258Scsgr 4052258Scsgr len -= elen; 4062258Scsgr ifrp = (struct ifreq *)((char *)ifrp + elen); 4072258Scsgr ifrp++; 4082258Scsgr } 4092258Scsgr 4102258Scsgr close(s); 4112258Scsgr free(buffer); 4122258Scsgr return(-1); 4132258Scsgr} 4142258Scsgr