route.c revision 30715
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 * 2030715Sbrian * $Id: route.c,v 1.19 1997/08/31 22:59:47 brian Exp $ 218857Srgrimes * 226059Samurai */ 2330715Sbrian 246059Samurai#include <sys/param.h> 2530715Sbrian#include <sys/time.h> 266059Samurai#include <sys/socket.h> 2730715Sbrian#include <net/route.h> 2830715Sbrian#include <net/if.h> 2930715Sbrian#include <netinet/in_systm.h> 3030715Sbrian#include <netinet/in.h> 3130715Sbrian#include <arpa/inet.h> 3220287Swollman 3320287Swollman#include <errno.h> 3430715Sbrian#include <machine/endian.h> 3530715Sbrian#include <stdio.h> 366059Samurai#include <stdlib.h> 376059Samurai#include <string.h> 3830715Sbrian#include <sys/ioctl.h> 3930715Sbrian#include <sys/sysctl.h> 406059Samurai#include <unistd.h> 4120287Swollman 4230715Sbrian#include "mbuf.h" 439439Samurai#include "log.h" 4426516Sbrian#include "loadalias.h" 4530715Sbrian#include "command.h" 4626516Sbrian#include "vars.h" 4730715Sbrian#include "route.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 5928679SbrianOsSetRoute(int cmd, 6028679Sbrian struct in_addr dst, 6128679Sbrian struct in_addr gateway, 6228679Sbrian struct in_addr mask) 636059Samurai{ 646059Samurai struct rtmsg rtmes; 656059Samurai int s, nb, wb; 666059Samurai char *cp; 676059Samurai u_long *lp; 686059Samurai struct sockaddr_in rtdata; 696059Samurai 706059Samurai s = socket(PF_ROUTE, SOCK_RAW, 0); 7127725Sbrian if (s < 0) { 7228974Sbrian LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 7327725Sbrian return; 7427725Sbrian } 7530715Sbrian memset(&rtmes, '\0', sizeof(rtmes)); 766059Samurai rtmes.m_rtm.rtm_version = RTM_VERSION; 776059Samurai rtmes.m_rtm.rtm_type = cmd; 7826591Sbrian rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 796059Samurai rtmes.m_rtm.rtm_seq = ++seqno; 806059Samurai rtmes.m_rtm.rtm_pid = getpid(); 8117571Speter rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 826059Samurai 8330715Sbrian memset(&rtdata, '\0', sizeof(rtdata)); 846059Samurai rtdata.sin_len = 16; 856059Samurai rtdata.sin_family = AF_INET; 866059Samurai rtdata.sin_port = 0; 876059Samurai rtdata.sin_addr = dst; 886059Samurai 896059Samurai cp = rtmes.m_space; 9030715Sbrian memcpy(cp, &rtdata, 16); 916059Samurai cp += 16; 926059Samurai if (gateway.s_addr) { 936059Samurai rtdata.sin_addr = gateway; 9430715Sbrian memcpy(cp, &rtdata, 16); 956059Samurai cp += 16; 966059Samurai } 976059Samurai if (dst.s_addr == INADDR_ANY) 986059Samurai mask.s_addr = INADDR_ANY; 996059Samurai 10028679Sbrian lp = (u_long *) cp; 1016059Samurai 1026059Samurai if (mask.s_addr) { 1036059Samurai *lp++ = 8; 1046059Samurai cp += sizeof(int); 1056059Samurai *lp = mask.s_addr; 1066059Samurai } else 1076059Samurai *lp = 0; 1086059Samurai cp += sizeof(u_long); 1096059Samurai 11028679Sbrian nb = cp - (char *) &rtmes; 1116059Samurai rtmes.m_rtm.rtm_msglen = nb; 1126059Samurai wb = write(s, &rtmes, nb); 1136059Samurai if (wb < 0) { 11426591Sbrian LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 11526591Sbrian LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 11626591Sbrian LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 11728679Sbrian switch (rtmes.m_rtm.rtm_errno) { 11828679Sbrian case EEXIST: 11928679Sbrian LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 12028679Sbrian break; 12128679Sbrian case ESRCH: 12228679Sbrian LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 12328679Sbrian break; 12428679Sbrian case ENOBUFS: 12528679Sbrian default: 12628679Sbrian LogPrintf(LogTCPIP, "Add/Del route failed: %s\n", 12728679Sbrian strerror(rtmes.m_rtm.rtm_errno)); 12828679Sbrian break; 12926591Sbrian } 1306059Samurai } 13126516Sbrian LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb, 13228679Sbrian dst.s_addr, gateway.s_addr); 1336059Samurai close(s); 1346059Samurai} 1356059Samurai 1366059Samuraistatic void 13728679Sbrianp_sockaddr(struct sockaddr * sa, int width) 1386059Samurai{ 13926516Sbrian if (VarTerm) { 14026516Sbrian register char *cp; 14128679Sbrian register struct sockaddr_in *sin = (struct sockaddr_in *) sa; 1426059Samurai 14326516Sbrian cp = (sin->sin_addr.s_addr == 0) ? "default" : 14428679Sbrian inet_ntoa(sin->sin_addr); 14526516Sbrian fprintf(VarTerm, "%-*.*s ", width, width, cp); 14626516Sbrian } 1476059Samurai} 1486059Samurai 1496059Samuraistruct bits { 1506059Samurai short b_mask; 15128679Sbrian char b_val; 15228679Sbrian} bits[] = { 15328679Sbrian 15428679Sbrian { 15528679Sbrian RTF_UP, 'U' 15628679Sbrian }, 15728679Sbrian { 15828679Sbrian RTF_GATEWAY, 'G' 15928679Sbrian }, 16028679Sbrian { 16128679Sbrian RTF_HOST, 'H' 16228679Sbrian }, 16328679Sbrian { 16428679Sbrian RTF_DYNAMIC, 'D' 16528679Sbrian }, 16628679Sbrian { 16728679Sbrian RTF_MODIFIED, 'M' 16828679Sbrian }, 16928679Sbrian { 17028679Sbrian RTF_CLONING, 'C' 17128679Sbrian }, 17228679Sbrian { 17328679Sbrian RTF_XRESOLVE, 'X' 17428679Sbrian }, 17528679Sbrian { 17628679Sbrian RTF_LLINFO, 'L' 17728679Sbrian }, 17828679Sbrian { 17928679Sbrian RTF_REJECT, 'R' 18028679Sbrian }, 18128679Sbrian { 18228679Sbrian 0 18328679Sbrian } 1846059Samurai}; 1856059Samurai 1866059Samuraistatic void 18728679Sbrianp_flags(int f, char *format) 1886059Samurai{ 18926516Sbrian if (VarTerm) { 19026516Sbrian char name[33], *flags; 19126516Sbrian register struct bits *p = bits; 1926059Samurai 19326516Sbrian for (flags = name; p->b_mask; p++) 19426516Sbrian if (p->b_mask & f) 19528679Sbrian *flags++ = p->b_val; 19626516Sbrian *flags = '\0'; 19726516Sbrian fprintf(VarTerm, format, name); 19826516Sbrian } 1996059Samurai} 2006059Samurai 2016059Samuraiint 2026059SamuraiShowRoute() 2036059Samurai{ 2046059Samurai struct rt_msghdr *rtm; 2056059Samurai struct sockaddr *sa; 2066059Samurai char *sp, *ep, *cp; 2076059Samurai u_char *wp; 2086059Samurai int *lp; 2096059Samurai int needed, nb; 2106059Samurai u_long mask; 2116735Samurai int mib[6]; 2126059Samurai 21326516Sbrian if (!VarTerm) 21426516Sbrian return 1; 21526516Sbrian 2166059Samurai mib[0] = CTL_NET; 2176059Samurai mib[1] = PF_ROUTE; 2186735Samurai mib[2] = 0; 2196735Samurai mib[3] = 0; 2206059Samurai mib[4] = NET_RT_DUMP; 2216735Samurai mib[5] = 0; 2226735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 22328974Sbrian LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 22428679Sbrian return (1); 2256735Samurai } 2266059Samurai if (needed < 0) 22728679Sbrian return (1); 2286059Samurai sp = malloc(needed); 2296059Samurai if (sp == NULL) 23028679Sbrian return (1); 2316735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 23228974Sbrian LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 23318885Sjkh free(sp); 23428679Sbrian return (1); 2356735Samurai } 2366059Samurai ep = sp + needed; 2376059Samurai 2386059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 23928679Sbrian rtm = (struct rt_msghdr *) cp; 24028679Sbrian sa = (struct sockaddr *) (rtm + 1); 2416059Samurai mask = 0xffffffff; 2426059Samurai if (rtm->rtm_addrs == RTA_DST) 2436059Samurai p_sockaddr(sa, 36); 2446059Samurai else { 24528679Sbrian wp = (u_char *) cp + rtm->rtm_msglen; 2466059Samurai p_sockaddr(sa, 16); 2476059Samurai if (sa->sa_len == 0) 2486059Samurai sa->sa_len = sizeof(long); 24928679Sbrian sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 2506059Samurai p_sockaddr(sa, 18); 25128679Sbrian lp = (int *) (sa->sa_len + (char *) sa); 25228679Sbrian if ((char *) lp < (char *) wp && *lp) { 25328974Sbrian LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp); 25428679Sbrian wp = (u_char *) (lp + 1); 2556059Samurai mask = 0; 25628679Sbrian for (nb = *(char *) lp; nb > 4; nb--) { 2576059Samurai mask <<= 8; 2586059Samurai mask |= *wp++; 2596059Samurai } 26028679Sbrian for (nb = 8 - *(char *) lp; nb > 0; nb--) 2616059Samurai mask <<= 8; 2626059Samurai } 2636059Samurai } 26426516Sbrian fprintf(VarTerm, "%08lx ", mask); 26528679Sbrian p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s "); 26626516Sbrian fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 2676059Samurai } 26818885Sjkh free(sp); 26926516Sbrian return 0; 2706059Samurai} 2716059Samurai 2726059Samurai/* 2736059Samurai * Delete routes associated with our interface 2746059Samurai */ 2756059Samuraivoid 27628679SbrianDeleteIfRoutes(int all) 2776059Samurai{ 2786059Samurai struct rt_msghdr *rtm; 2796059Samurai struct sockaddr *sa; 28015738Sphk struct in_addr dstnet, gateway, maddr; 2816059Samurai int needed; 2826059Samurai char *sp, *cp, *ep; 2836059Samurai u_long mask; 2846059Samurai int *lp, nb; 2856059Samurai u_char *wp; 2866735Samurai int mib[6]; 2876059Samurai 28826516Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 28926516Sbrian 2906059Samurai mib[0] = CTL_NET; 2916059Samurai mib[1] = PF_ROUTE; 2926735Samurai mib[2] = 0; 2936735Samurai mib[3] = 0; 2946059Samurai mib[4] = NET_RT_DUMP; 2956735Samurai mib[5] = 0; 2966735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 29728974Sbrian LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 29828974Sbrian strerror(errno)); 2996735Samurai return; 3006735Samurai } 3016059Samurai if (needed < 0) 3026059Samurai return; 3036059Samurai 3046059Samurai sp = malloc(needed); 3056059Samurai if (sp == NULL) 3066059Samurai return; 3076059Samurai 3086735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 30928974Sbrian LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 31028974Sbrian strerror(errno)); 3116059Samurai free(sp); 3126059Samurai return; 3136059Samurai } 3146059Samurai ep = sp + needed; 3156059Samurai 3166059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 31728679Sbrian rtm = (struct rt_msghdr *) cp; 31828679Sbrian sa = (struct sockaddr *) (rtm + 1); 31926516Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 32028679Sbrian " dstnet: %s\n", 32128679Sbrian rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 32228679Sbrian inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 3236059Samurai if (rtm->rtm_addrs != RTA_DST && 32428679Sbrian (rtm->rtm_index == IfIndex) && 32528679Sbrian (all || (rtm->rtm_flags & RTF_GATEWAY))) { 32626754Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 32728679Sbrian dstnet = ((struct sockaddr_in *) sa)->sin_addr; 32828679Sbrian wp = (u_char *) cp + rtm->rtm_msglen; 3296059Samurai if (sa->sa_len == 0) 3306059Samurai sa->sa_len = sizeof(long); 33128679Sbrian sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 33228679Sbrian gateway = ((struct sockaddr_in *) sa)->sin_addr; 33328679Sbrian lp = (int *) (sa->sa_len + (char *) sa); 3346059Samurai mask = 0; 33528679Sbrian if ((char *) lp < (char *) wp && *lp) { 33628974Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n", 33726516Sbrian rtm->rtm_flags, *lp); 33828679Sbrian wp = (u_char *) (lp + 1); 3396059Samurai for (nb = *lp; nb > 4; nb--) { 3406059Samurai mask <<= 8; 3416059Samurai mask |= *wp++; 3426059Samurai } 3436059Samurai for (nb = 8 - *lp; nb > 0; nb--) 3446059Samurai mask <<= 8; 3456059Samurai } 34626754Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet)); 34726516Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 34826516Sbrian LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 34926754Sbrian if (dstnet.s_addr == INADDR_ANY) 35028679Sbrian mask = INADDR_ANY; 35115738Sphk maddr.s_addr = htonl(mask); 35215738Sphk OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 3536059Samurai } 3546059Samurai } 3556059Samurai free(sp); 3566059Samurai} 3576059Samurai 35818752Sjkh /* 35918752Sjkh * 960603 - Modified to use dynamic buffer allocator as in ifconfig 36018752Sjkh */ 36118752Sjkh 3626059Samuraiint 36328679SbrianGetIfIndex(char *name) 3646059Samurai{ 36518752Sjkh char *buffer; 3666059Samurai struct ifreq *ifrp; 3676059Samurai int s, len, elen, index; 3686059Samurai struct ifconf ifconfs; 36928679Sbrian 37018752Sjkh /* struct ifreq reqbuf[256]; -- obsoleted :) */ 37118752Sjkh int oldbufsize, bufsize = sizeof(struct ifreq); 3726059Samurai 3736059Samurai s = socket(AF_INET, SOCK_DGRAM, 0); 3746059Samurai if (s < 0) { 37528974Sbrian LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno)); 37628679Sbrian return (-1); 3776059Samurai } 37828679Sbrian buffer = malloc(bufsize); /* allocate first buffer */ 37928679Sbrian ifconfs.ifc_len = bufsize; /* Initial setting */ 3806059Samurai 38118752Sjkh /* 38228679Sbrian * Iterate through here until we don't get many more data 38318752Sjkh */ 3846059Samurai 38518752Sjkh do { 38628679Sbrian oldbufsize = ifconfs.ifc_len; 38728679Sbrian bufsize += 1 + sizeof(struct ifreq); 38828679Sbrian buffer = realloc((void *) buffer, bufsize); /* Make it bigger */ 38928679Sbrian LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 39028679Sbrian ifconfs.ifc_len = bufsize; 39128679Sbrian ifconfs.ifc_buf = buffer; 39228679Sbrian if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 39328974Sbrian LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n", 39428974Sbrian strerror(errno)); 39528679Sbrian close(s); 39628679Sbrian free(buffer); 39728679Sbrian return (-1); 39828679Sbrian } 39918752Sjkh } while (ifconfs.ifc_len > oldbufsize); 40018752Sjkh 4016059Samurai ifrp = ifconfs.ifc_req; 4026059Samurai 4036059Samurai index = 1; 4046059Samurai for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 4056059Samurai elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 4066059Samurai if (ifrp->ifr_addr.sa_family == AF_LINK) { 40726516Sbrian LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 40826516Sbrian index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 40926516Sbrian ifrp->ifr_addr.sa_family, elen); 4106059Samurai if (strcmp(ifrp->ifr_name, name) == 0) { 41128679Sbrian IfIndex = index; 41227725Sbrian close(s); 41325630Sbrian free(buffer); 41428679Sbrian return (index); 4156059Samurai } 4166059Samurai index++; 4176059Samurai } 4186059Samurai len -= elen; 41928679Sbrian ifrp = (struct ifreq *) ((char *) ifrp + elen); 4206059Samurai ifrp++; 4216059Samurai } 4226059Samurai 4236059Samurai close(s); 42418752Sjkh free(buffer); 42528679Sbrian return (-1); 4266059Samurai} 427