route.c revision 28974
159290Sjlemon/* 272969Sjlemon * PPP Routing related Module 3133741Sjmg * 4197240Ssson * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 559290Sjlemon * 659290Sjlemon * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 759290Sjlemon * 859290Sjlemon * Redistribution and use in source and binary forms are permitted 959290Sjlemon * provided that the above copyright notice and this paragraph are 1059290Sjlemon * duplicated in all such forms and that any documentation, 1159290Sjlemon * advertising materials, and other materials related to such 1259290Sjlemon * distribution and use acknowledge that the software was developed 1359290Sjlemon * by the Internet Initiative Japan, Inc. The name of the 1459290Sjlemon * IIJ may not be used to endorse or promote products derived 1559290Sjlemon * from this software without specific prior written permission. 1659290Sjlemon * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1759290Sjlemon * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1859290Sjlemon * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1959290Sjlemon * 2059290Sjlemon * $Id: route.c,v 1.18 1997/08/25 00:29:26 brian Exp $ 2159290Sjlemon * 2259290Sjlemon */ 2359290Sjlemon#include <sys/types.h> 2459290Sjlemon#include <machine/endian.h> 2559290Sjlemon#include <sys/ioctl.h> 2659290Sjlemon#include <sys/param.h> 2759290Sjlemon#include <sys/socket.h> 2859290Sjlemon#include <sys/sysctl.h> 29116182Sobrien#include <sys/time.h> 30116182Sobrien 31116182Sobrien#include <errno.h> 32162592Sjmg#include <stdlib.h> 33162592Sjmg#include <stdio.h> 3459290Sjlemon#include <string.h> 3559290Sjlemon#include <unistd.h> 36224778Srwatson 3759290Sjlemon#include <net/route.h> 3876166Smarkm#include <net/if.h> 3976166Smarkm#include <netinet/in_systm.h> 40233505Smelifaro#include <netinet/in.h> 4159290Sjlemon#include <arpa/inet.h> 42132138Salfred 4359290Sjlemon#include "log.h" 4459290Sjlemon#include "loadalias.h" 45108524Salfred#include "vars.h" 46132138Salfred 4759290Sjlemonstatic int IfIndex; 48133741Sjmg 4970834Swollmanstruct rtmsg { 5059290Sjlemon struct rt_msghdr m_rtm; 5159290Sjlemon char m_space[64]; 5259290Sjlemon}; 5359290Sjlemon 5459290Sjlemonstatic int seqno; 55132138Salfred 56132138Salfredvoid 5759290SjlemonOsSetRoute(int cmd, 5859290Sjlemon struct in_addr dst, 5959290Sjlemon struct in_addr gateway, 6084138Sjlemon struct in_addr mask) 6159290Sjlemon{ 62142934Sps struct rtmsg rtmes; 63133741Sjmg int s, nb, wb; 6459290Sjlemon char *cp; 65162592Sjmg u_long *lp; 66162592Sjmg struct sockaddr_in rtdata; 67162592Sjmg 6859290Sjlemon s = socket(PF_ROUTE, SOCK_RAW, 0); 6992751Sjeff if (s < 0) { 7059290Sjlemon LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 71141616Sphk return; 72141616Sphk } 73133741Sjmg bzero(&rtmes, sizeof(rtmes)); 74133741Sjmg rtmes.m_rtm.rtm_version = RTM_VERSION; 75133741Sjmg rtmes.m_rtm.rtm_type = cmd; 76133741Sjmg rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY; 77133741Sjmg rtmes.m_rtm.rtm_seq = ++seqno; 78133741Sjmg rtmes.m_rtm.rtm_pid = getpid(); 79133741Sjmg rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 80133741Sjmg 81133741Sjmg bzero(&rtdata, sizeof(rtdata)); 82133741Sjmg rtdata.sin_len = 16; 83133741Sjmg rtdata.sin_family = AF_INET; 84133741Sjmg rtdata.sin_port = 0; 85133741Sjmg rtdata.sin_addr = dst; 86133741Sjmg 87133741Sjmg cp = rtmes.m_space; 88133741Sjmg bcopy(&rtdata, cp, 16); 8984138Sjlemon cp += 16; 90133741Sjmg if (gateway.s_addr) { 91133741Sjmg rtdata.sin_addr = gateway; 92146950Sps bcopy(&rtdata, cp, 16); 93146950Sps cp += 16; 94162594Sjmg } 95162594Sjmg if (dst.s_addr == INADDR_ANY) 96170029Srwatson mask.s_addr = INADDR_ANY; 97133741Sjmg 98133741Sjmg lp = (u_long *) cp; 99133741Sjmg 100133741Sjmg if (mask.s_addr) { 101133741Sjmg *lp++ = 8; 102146950Sps cp += sizeof(int); 103146950Sps *lp = mask.s_addr; 104146950Sps } else 10559290Sjlemon *lp = 0; 106133741Sjmg cp += sizeof(u_long); 107133741Sjmg 10859290Sjlemon nb = cp - (char *) &rtmes; 109108255Sphk rtmes.m_rtm.rtm_msglen = nb; 110108255Sphk wb = write(s, &rtmes, nb); 111175140Sjhb if (wb < 0) { 112108255Sphk LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 113108255Sphk LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 114108255Sphk LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 115108255Sphk switch (rtmes.m_rtm.rtm_errno) { 116108255Sphk case EEXIST: 117108238Sphk LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 11872521Sjlemon break; 119116546Sphk case ESRCH: 120116546Sphk LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 121175140Sjhb break; 122116546Sphk case ENOBUFS: 123116546Sphk default: 124116546Sphk LogPrintf(LogTCPIP, "Add/Del route failed: %s\n", 125116546Sphk strerror(rtmes.m_rtm.rtm_errno)); 126116546Sphk break; 127224914Skib } 128224914Skib } 12972521Sjlemon LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb, 13072521Sjlemon dst.s_addr, gateway.s_addr); 131133741Sjmg close(s); 13283366Sjulian} 13359290Sjlemon 13459290Sjlemonstatic void 13559290Sjlemonp_sockaddr(struct sockaddr * sa, int width) 136133741Sjmg{ 13759290Sjlemon if (VarTerm) { 13859290Sjlemon register char *cp; 13972521Sjlemon register struct sockaddr_in *sin = (struct sockaddr_in *) sa; 14072521Sjlemon 14172521Sjlemon cp = (sin->sin_addr.s_addr == 0) ? "default" : 14272521Sjlemon inet_ntoa(sin->sin_addr); 14372521Sjlemon fprintf(VarTerm, "%-*.*s ", width, width, cp); 14472521Sjlemon } 14579989Sjlemon} 14679989Sjlemon 14779989Sjlemonstruct bits { 14879989Sjlemon short b_mask; 149197241Ssson char b_val; 150197241Ssson} bits[] = { 151197241Ssson 152197294Srdivacky { 153197407Srdivacky RTF_UP, 'U' 15472521Sjlemon }, 155197134Srwatson { 156197134Srwatson RTF_GATEWAY, 'G' 157197134Srwatson }, 158197134Srwatson { 159197134Srwatson RTF_HOST, 'H' 160197134Srwatson }, 161197134Srwatson { 162197134Srwatson RTF_DYNAMIC, 'D' 163197134Srwatson }, 164133741Sjmg { 165197134Srwatson RTF_MODIFIED, 'M' 166197134Srwatson }, 167197134Srwatson { 168197134Srwatson RTF_CLONING, 'C' 169197134Srwatson }, 170197134Srwatson { 171197134Srwatson RTF_XRESOLVE, 'X' 172197134Srwatson }, 173197134Srwatson { 174197134Srwatson RTF_LLINFO, 'L' 175197134Srwatson }, 176197134Srwatson { 177197241Ssson RTF_REJECT, 'R' 178197241Ssson }, 179197241Ssson { 180197241Ssson 0 181197241Ssson } 182197241Ssson}; 18372521Sjlemon 18492751Sjeffstatic void 18584138Sjlemonp_flags(int f, char *format) 18684138Sjlemon{ 18784138Sjlemon if (VarTerm) { 18884138Sjlemon char name[33], *flags; 18959290Sjlemon register struct bits *p = bits; 190133741Sjmg 191133741Sjmg for (flags = name; p->b_mask; p++) 192133741Sjmg if (p->b_mask & f) 193133741Sjmg *flags++ = p->b_val; 194133741Sjmg *flags = '\0'; 195133741Sjmg fprintf(VarTerm, format, name); 196133741Sjmg } 197133741Sjmg} 198133741Sjmg 199133741Sjmgint 200133741SjmgShowRoute() 20159290Sjlemon{ 202133741Sjmg struct rt_msghdr *rtm; 203133741Sjmg struct sockaddr *sa; 204133741Sjmg char *sp, *ep, *cp; 205133741Sjmg u_char *wp; 206133741Sjmg int *lp; 207133741Sjmg int needed, nb; 208133741Sjmg u_long mask; 209133741Sjmg int mib[6]; 210133741Sjmg 211133741Sjmg if (!VarTerm) 212133741Sjmg return 1; 213133741Sjmg 214133741Sjmg mib[0] = CTL_NET; 215133741Sjmg mib[1] = PF_ROUTE; 216133741Sjmg mib[2] = 0; 217133741Sjmg mib[3] = 0; 218133741Sjmg mib[4] = NET_RT_DUMP; 219133741Sjmg mib[5] = 0; 220133741Sjmg if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 221133741Sjmg LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 222133741Sjmg return (1); 223133741Sjmg } 224133741Sjmg if (needed < 0) 225133741Sjmg return (1); 226147730Sssouhlal sp = malloc(needed); 227133741Sjmg if (sp == NULL) 228133741Sjmg return (1); 229147730Sssouhlal if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 230147730Sssouhlal LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 231133741Sjmg free(sp); 232147730Sssouhlal return (1); 233147730Sssouhlal } 234147730Sssouhlal ep = sp + needed; 235147730Sssouhlal 236147730Sssouhlal for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 237147730Sssouhlal rtm = (struct rt_msghdr *) cp; 238147730Sssouhlal sa = (struct sockaddr *) (rtm + 1); 239147730Sssouhlal mask = 0xffffffff; 240193951Skib if (rtm->rtm_addrs == RTA_DST) 241147730Sssouhlal p_sockaddr(sa, 36); 242193951Skib else { 243193951Skib wp = (u_char *) cp + rtm->rtm_msglen; 244147730Sssouhlal p_sockaddr(sa, 16); 245147730Sssouhlal if (sa->sa_len == 0) 246147730Sssouhlal sa->sa_len = sizeof(long); 247147730Sssouhlal sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 248147730Sssouhlal p_sockaddr(sa, 18); 24959290Sjlemon lp = (int *) (sa->sa_len + (char *) sa); 25059290Sjlemon if ((char *) lp < (char *) wp && *lp) { 25159290Sjlemon LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp); 25259290Sjlemon wp = (u_char *) (lp + 1); 25388633Salfred mask = 0; 25488633Salfred for (nb = *(char *) lp; nb > 4; nb--) { 25588633Salfred mask <<= 8; 25688633Salfred mask |= *wp++; 25788633Salfred } 25888633Salfred for (nb = 8 - *(char *) lp; nb > 0; nb--) 25988633Salfred mask <<= 8; 260197134Srwatson } 261197134Srwatson } 262197134Srwatson fprintf(VarTerm, "%08lx ", mask); 263197134Srwatson p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s "); 26488633Salfred fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 265133741Sjmg } 26659290Sjlemon free(sp); 267131562Salfred return 0; 26859290Sjlemon} 26959290Sjlemon 27072521Sjlemon/* 27159290Sjlemon * Delete routes associated with our interface 272133741Sjmg */ 273133741Sjmgvoid 274133741SjmgDeleteIfRoutes(int all) 275133741Sjmg{ 276133741Sjmg struct rt_msghdr *rtm; 277133741Sjmg struct sockaddr *sa; 278133741Sjmg struct in_addr dstnet, gateway, maddr; 279133741Sjmg int needed; 280133741Sjmg char *sp, *cp, *ep; 281133741Sjmg u_long mask; 282133741Sjmg int *lp, nb; 283133741Sjmg u_char *wp; 284133741Sjmg int mib[6]; 285133741Sjmg 286201350Sbrooks LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 287133741Sjmg 288151260Sambrisko mib[0] = CTL_NET; 289197241Ssson mib[1] = PF_ROUTE; 29059290Sjlemon mib[2] = 0; 29159290Sjlemon mib[3] = 0; 292133741Sjmg mib[4] = NET_RT_DUMP; 293133741Sjmg mib[5] = 0; 294133741Sjmg if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 295133741Sjmg LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 29659290Sjlemon strerror(errno)); 29772521Sjlemon return; 29859290Sjlemon } 299133635Sjmg if (needed < 0) 30072521Sjlemon return; 30159290Sjlemon 30259290Sjlemon sp = malloc(needed); 30372521Sjlemon if (sp == NULL) 30459290Sjlemon return; 30572521Sjlemon 30659290Sjlemon if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 307109153Sdillon LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 30859290Sjlemon strerror(errno)); 30972521Sjlemon free(sp); 310133741Sjmg return; 31159290Sjlemon } 312133741Sjmg ep = sp + needed; 31372521Sjlemon 314133741Sjmg for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 315133741Sjmg rtm = (struct rt_msghdr *) cp; 31659290Sjlemon sa = (struct sockaddr *) (rtm + 1); 31759290Sjlemon LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 31859290Sjlemon " dstnet: %s\n", 31959290Sjlemon rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 32059290Sjlemon inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 32159290Sjlemon if (rtm->rtm_addrs != RTA_DST && 322109153Sdillon (rtm->rtm_index == IfIndex) && 32359290Sjlemon (all || (rtm->rtm_flags & RTF_GATEWAY))) { 324133741Sjmg LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 32559290Sjlemon dstnet = ((struct sockaddr_in *) sa)->sin_addr; 32659290Sjlemon wp = (u_char *) cp + rtm->rtm_msglen; 32759290Sjlemon if (sa->sa_len == 0) 32859290Sjlemon sa->sa_len = sizeof(long); 32959290Sjlemon sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 33059290Sjlemon gateway = ((struct sockaddr_in *) sa)->sin_addr; 331109153Sdillon lp = (int *) (sa->sa_len + (char *) sa); 33259290Sjlemon mask = 0; 33359290Sjlemon if ((char *) lp < (char *) wp && *lp) { 33459290Sjlemon LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n", 33559290Sjlemon rtm->rtm_flags, *lp); 33659290Sjlemon wp = (u_char *) (lp + 1); 337133741Sjmg for (nb = *lp; nb > 4; nb--) { 33859290Sjlemon mask <<= 8; 33959290Sjlemon mask |= *wp++; 34059290Sjlemon } 34159290Sjlemon for (nb = 8 - *lp; nb > 0; nb--) 342113377Skbyanc mask <<= 8; 34375451Srwatson } 34459290Sjlemon LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet)); 345113377Skbyanc LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 34659290Sjlemon LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 347113377Skbyanc if (dstnet.s_addr == INADDR_ANY) 348113377Skbyanc mask = INADDR_ANY; 349113377Skbyanc maddr.s_addr = htonl(mask); 350133741Sjmg OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 351133741Sjmg } 352113377Skbyanc } 353133741Sjmg free(sp); 354122019Scognet} 355122019Scognet 356203875Skib /* 357203875Skib * 960603 - Modified to use dynamic buffer allocator as in ifconfig 35875451Srwatson */ 359203875Skib 36059290Sjlemonint 36159290SjlemonGetIfIndex(char *name) 36259290Sjlemon{ 36359290Sjlemon char *buffer; 36459290Sjlemon struct ifreq *ifrp; 36559290Sjlemon int s, len, elen, index; 36659290Sjlemon struct ifconf ifconfs; 36759290Sjlemon 36859290Sjlemon /* struct ifreq reqbuf[256]; -- obsoleted :) */ 36959290Sjlemon int oldbufsize, bufsize = sizeof(struct ifreq); 37059290Sjlemon 37159290Sjlemon s = socket(AF_INET, SOCK_DGRAM, 0); 37259290Sjlemon if (s < 0) { 373122686Scognet LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno)); 374133741Sjmg return (-1); 375113377Skbyanc } 376113377Skbyanc buffer = malloc(bufsize); /* allocate first buffer */ 377113377Skbyanc ifconfs.ifc_len = bufsize; /* Initial setting */ 378113377Skbyanc 379113377Skbyanc /* 380113377Skbyanc * Iterate through here until we don't get many more data 381113377Skbyanc */ 382133741Sjmg 383113377Skbyanc do { 38471500Sjhb oldbufsize = ifconfs.ifc_len; 38559290Sjlemon bufsize += 1 + sizeof(struct ifreq); 38659290Sjlemon buffer = realloc((void *) buffer, bufsize); /* Make it bigger */ 38759290Sjlemon LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 38859290Sjlemon ifconfs.ifc_len = bufsize; 38959290Sjlemon ifconfs.ifc_buf = buffer; 39059290Sjlemon if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 39159290Sjlemon LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n", 39259290Sjlemon strerror(errno)); 39359290Sjlemon close(s); 39459290Sjlemon free(buffer); 39559290Sjlemon return (-1); 39659290Sjlemon } 397133741Sjmg } while (ifconfs.ifc_len > oldbufsize); 39859290Sjlemon 39959290Sjlemon ifrp = ifconfs.ifc_req; 40059290Sjlemon 401133741Sjmg index = 1; 40259290Sjlemon for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 403133741Sjmg elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 404133741Sjmg if (ifrp->ifr_addr.sa_family == AF_LINK) { 405133741Sjmg LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 40659290Sjlemon index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 40759290Sjlemon ifrp->ifr_addr.sa_family, elen); 408133741Sjmg if (strcmp(ifrp->ifr_name, name) == 0) { 40959290Sjlemon IfIndex = index; 41059290Sjlemon close(s); 41159290Sjlemon free(buffer); 412133741Sjmg return (index); 41359290Sjlemon } 41459290Sjlemon index++; 41559290Sjlemon } 41659290Sjlemon len -= elen; 41759290Sjlemon ifrp = (struct ifreq *) ((char *) ifrp + elen); 41859290Sjlemon ifrp++; 41959290Sjlemon } 42059290Sjlemon 42159290Sjlemon close(s); 42259290Sjlemon free(buffer); 42359290Sjlemon return (-1); 42459290Sjlemon} 42559290Sjlemon