route.c revision 31061
1139749Simp/* 265312Smsmith * PPP Routing related Module 365312Smsmith * 465312Smsmith * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 565312Smsmith * 665312Smsmith * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 765312Smsmith * 865312Smsmith * Redistribution and use in source and binary forms are permitted 965312Smsmith * provided that the above copyright notice and this paragraph are 1065312Smsmith * duplicated in all such forms and that any documentation, 1165312Smsmith * advertising materials, and other materials related to such 1265312Smsmith * distribution and use acknowledge that the software was developed 1365312Smsmith * by the Internet Initiative Japan, Inc. The name of the 1465312Smsmith * IIJ may not be used to endorse or promote products derived 1565312Smsmith * from this software without specific prior written permission. 1665312Smsmith * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1765312Smsmith * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1865312Smsmith * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1965312Smsmith * 2065312Smsmith * $Id: route.c,v 1.22 1997/11/09 03:22:49 brian Exp $ 2187826Sobrien * 2265312Smsmith */ 2365312Smsmith 2496554Sobrien#include <sys/param.h> 2596554Sobrien#include <sys/time.h> 2665312Smsmith#include <sys/socket.h> 2765312Smsmith#include <net/route.h> 2865312Smsmith#include <net/if.h> 2965312Smsmith#include <netinet/in_systm.h> 3065312Smsmith#include <netinet/in.h> 3165312Smsmith#include <arpa/inet.h> 3296554Sobrien 3365312Smsmith#include <errno.h> 3465312Smsmith#include <machine/endian.h> 3565312Smsmith#include <stdio.h> 3665312Smsmith#include <stdlib.h> 3796554Sobrien#include <string.h> 3896554Sobrien#include <sys/ioctl.h> 3996554Sobrien#include <sys/sysctl.h> 4096554Sobrien#include <unistd.h> 4165312Smsmith 4296554Sobrien#include "mbuf.h" 4396554Sobrien#include "log.h" 4465312Smsmith#include "loadalias.h" 4565312Smsmith#include "command.h" 4665312Smsmith#include "vars.h" 4765312Smsmith#include "id.h" 4865312Smsmith#include "route.h" 4965312Smsmith 5065312Smsmithstatic int IfIndex; 5165312Smsmith 5265312Smsmithstruct rtmsg { 5365312Smsmith struct rt_msghdr m_rtm; 5465312Smsmith char m_space[64]; 5565312Smsmith}; 5665312Smsmith 5765312Smsmithstatic int seqno; 5865312Smsmith 5996554Sobrienvoid 6096554SobrienOsSetRoute(int cmd, 6196554Sobrien struct in_addr dst, 6296554Sobrien struct in_addr gateway, 6396554Sobrien struct in_addr mask) 6496554Sobrien{ 6596554Sobrien struct rtmsg rtmes; 6696554Sobrien int s, nb, wb; 6796554Sobrien char *cp, *cmdstr; 6896554Sobrien u_long *lp; 6996554Sobrien struct sockaddr_in rtdata; 7065312Smsmith 7165312Smsmith cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 7265312Smsmith s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 7365312Smsmith if (s < 0) { 7465312Smsmith LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 7596551Sobrien return; 7696551Sobrien } 7796551Sobrien memset(&rtmes, '\0', sizeof(rtmes)); 7865312Smsmith rtmes.m_rtm.rtm_version = RTM_VERSION; 7965312Smsmith rtmes.m_rtm.rtm_type = cmd; 8096554Sobrien rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 8165312Smsmith rtmes.m_rtm.rtm_seq = ++seqno; 8265312Smsmith rtmes.m_rtm.rtm_pid = getpid(); 8396554Sobrien rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 8465312Smsmith 8596554Sobrien memset(&rtdata, '\0', sizeof(rtdata)); 8665312Smsmith rtdata.sin_len = 16; 8765312Smsmith rtdata.sin_family = AF_INET; 8896554Sobrien rtdata.sin_port = 0; 8965312Smsmith rtdata.sin_addr = dst; 9065312Smsmith 9165312Smsmith cp = rtmes.m_space; 9296551Sobrien memcpy(cp, &rtdata, 16); 9365312Smsmith cp += 16; 9465312Smsmith if (gateway.s_addr) { 9565312Smsmith rtdata.sin_addr = gateway; 9696551Sobrien memcpy(cp, &rtdata, 16); 9765312Smsmith cp += 16; 9865312Smsmith rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 9965312Smsmith } 10096551Sobrien if (dst.s_addr == INADDR_ANY) 10165312Smsmith mask.s_addr = INADDR_ANY; 10265312Smsmith 10365312Smsmith lp = (u_long *) cp; 10496554Sobrien 10565312Smsmith if (mask.s_addr) { 10665312Smsmith *lp++ = 8; 10765312Smsmith cp += sizeof(int); 10865312Smsmith *lp = mask.s_addr; 10965312Smsmith } else 11065312Smsmith *lp = 0; 11196614Sobrien cp += sizeof(u_long); 11296551Sobrien 11365312Smsmith nb = cp - (char *) &rtmes; 11496551Sobrien rtmes.m_rtm.rtm_msglen = nb; 11565312Smsmith wb = write(s, &rtmes, nb); 11665312Smsmith if (wb < 0) { 11796614Sobrien LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 11896551Sobrien LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 11965312Smsmith LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 12065312Smsmith switch (rtmes.m_rtm.rtm_errno) { 12196614Sobrien case EEXIST: 12296614Sobrien LogPrintf(LogTCPIP, "Add route failed: Already exists\n"); 12396551Sobrien break; 12465312Smsmith case ESRCH: 12565312Smsmith LogPrintf(LogTCPIP, "Del route failed: Non-existent\n"); 12696614Sobrien break; 12796551Sobrien case 0: 12865312Smsmith LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno)); 12965312Smsmith break; 13096614Sobrien case ENOBUFS: 13196551Sobrien default: 13265312Smsmith LogPrintf(LogTCPIP, "%s route failed: %s\n", 13365312Smsmith cmdstr, strerror(rtmes.m_rtm.rtm_errno)); 13496614Sobrien break; 13596551Sobrien } 13665312Smsmith } 13765312Smsmith LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 13865312Smsmith wb, cmdstr, dst.s_addr, gateway.s_addr); 13965312Smsmith close(s); 14096554Sobrien} 14196614Sobrien 14296614Sobrienstatic void 14396614Sobrienp_sockaddr(struct sockaddr * sa, int width) 14496554Sobrien{ 14565312Smsmith if (VarTerm) { 14665312Smsmith register char *cp; 14765312Smsmith register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa; 14865312Smsmith 14965312Smsmith cp = (sock_in->sin_addr.s_addr == 0) ? "default" : 15096554Sobrien inet_ntoa(sock_in->sin_addr); 15196551Sobrien fprintf(VarTerm, "%-*.*s ", width, width, cp); 15265312Smsmith } 15396551Sobrien} 15465312Smsmith 15565312Smsmithstruct bits { 15665312Smsmith short b_mask; 15796554Sobrien char b_val; 15896554Sobrien} bits[] = { 15965312Smsmith 16096554Sobrien { 16196554Sobrien RTF_UP, 'U' 16265312Smsmith }, 16396554Sobrien { 16496554Sobrien RTF_GATEWAY, 'G' 16596554Sobrien }, 16696554Sobrien { 16765312Smsmith RTF_HOST, 'H' 16896554Sobrien }, 16965312Smsmith { 17096614Sobrien RTF_DYNAMIC, 'D' 17196614Sobrien }, 17296551Sobrien { 17396551Sobrien RTF_MODIFIED, 'M' 17465312Smsmith }, 17596551Sobrien { 17696551Sobrien RTF_CLONING, 'C' 17765312Smsmith }, 17896554Sobrien { 17965312Smsmith RTF_XRESOLVE, 'X' 18065312Smsmith }, 18165312Smsmith { 18265312Smsmith RTF_LLINFO, 'L' 18365312Smsmith }, 18465312Smsmith { 18596614Sobrien RTF_REJECT, 'R' 18696551Sobrien }, 18796551Sobrien { 18865312Smsmith 0 18965312Smsmith } 19065312Smsmith}; 19196551Sobrien 19265312Smsmithstatic void 19365312Smsmithp_flags(int f, char *format) 19496554Sobrien{ 19565312Smsmith if (VarTerm) { 19665312Smsmith char name[33], *flags; 19765312Smsmith register struct bits *p = bits; 19896554Sobrien 19996554Sobrien for (flags = name; p->b_mask; p++) 20096554Sobrien if (p->b_mask & f) 20165312Smsmith *flags++ = p->b_val; 20265312Smsmith *flags = '\0'; 20365312Smsmith fprintf(VarTerm, format, name); 20496614Sobrien } 20596551Sobrien} 20665312Smsmith 20765312Smsmithint 20865312SmsmithShowRoute() 20965312Smsmith{ 21065312Smsmith struct rt_msghdr *rtm; 21196554Sobrien struct sockaddr *sa; 21296554Sobrien char *sp, *ep, *cp; 21365312Smsmith u_char *wp; 21465312Smsmith int *lp; 21565312Smsmith int needed, nb; 21665312Smsmith u_long mask; 21765312Smsmith int mib[6]; 21865312Smsmith 21965312Smsmith if (!VarTerm) 22065312Smsmith return 1; 22196554Sobrien 22296554Sobrien mib[0] = CTL_NET; 22365312Smsmith mib[1] = PF_ROUTE; 22465312Smsmith mib[2] = 0; 22565312Smsmith mib[3] = 0; 22696554Sobrien mib[4] = NET_RT_DUMP; 22796554Sobrien mib[5] = 0; 22865312Smsmith if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 22965312Smsmith LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno)); 23096554Sobrien return (1); 23165312Smsmith } 23265312Smsmith if (needed < 0) 23365312Smsmith return (1); 23465312Smsmith sp = malloc(needed); 23565312Smsmith if (sp == NULL) 23665312Smsmith return (1); 23765312Smsmith if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 23896551Sobrien LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 23987816Sjhb free(sp); 24065312Smsmith return (1); 24165312Smsmith } 24265312Smsmith ep = sp + needed; 24396554Sobrien 24496554Sobrien for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 24565312Smsmith rtm = (struct rt_msghdr *) cp; 24665312Smsmith sa = (struct sockaddr *) (rtm + 1); 24796554Sobrien mask = 0xffffffff; 24865312Smsmith if (rtm->rtm_addrs == RTA_DST) 24996554Sobrien p_sockaddr(sa, 36); 25096554Sobrien else { 25165312Smsmith wp = (u_char *) cp + rtm->rtm_msglen; 25296554Sobrien p_sockaddr(sa, 16); 25365312Smsmith if (sa->sa_len == 0) 25465312Smsmith sa->sa_len = sizeof(long); 25565312Smsmith sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 25696554Sobrien p_sockaddr(sa, 18); 25796554Sobrien lp = (int *) (sa->sa_len + (char *) sa); 25865312Smsmith if ((char *) lp < (char *) wp && *lp) { 25965312Smsmith LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp); 26096554Sobrien wp = (u_char *) (lp + 1); 26165312Smsmith mask = 0; 26265312Smsmith for (nb = *(char *) lp; nb > 4; nb--) { 26365312Smsmith mask <<= 8; 26465312Smsmith mask |= *wp++; 26596615Sobrien } 26696554Sobrien for (nb = 8 - *(char *) lp; nb > 0; nb--) 26765312Smsmith mask <<= 8; 26865312Smsmith } 26965312Smsmith } 27096614Sobrien fprintf(VarTerm, "%08lx ", mask); 27165312Smsmith p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s "); 27287816Sjhb fprintf(VarTerm, "(%d)\n", rtm->rtm_index); 27365312Smsmith } 27465312Smsmith free(sp); 27596615Sobrien return 0; 27696554Sobrien} 27765312Smsmith 27865312Smsmith/* 27996615Sobrien * Delete routes associated with our interface 28096554Sobrien */ 28165312Smsmithvoid 28265312SmsmithDeleteIfRoutes(int all) 28365312Smsmith{ 28465312Smsmith struct rt_msghdr *rtm; 28565312Smsmith struct sockaddr *sa; 28665312Smsmith struct in_addr dstnet, gateway, maddr; 28796615Sobrien int needed; 28896554Sobrien char *sp, *cp, *ep; 28965312Smsmith u_long mask; 29065312Smsmith int *lp, nb; 29196615Sobrien u_char *wp; 29296554Sobrien int mib[6]; 29365312Smsmith 29496554Sobrien LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex); 29565312Smsmith 29665312Smsmith mib[0] = CTL_NET; 29765312Smsmith mib[1] = PF_ROUTE; 29865312Smsmith mib[2] = 0; 29965312Smsmith mib[3] = 0; 30065312Smsmith mib[4] = NET_RT_DUMP; 30165312Smsmith mib[5] = 0; 30265312Smsmith if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 30396554Sobrien LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n", 30465312Smsmith strerror(errno)); 30596554Sobrien return; 30665312Smsmith } 30796554Sobrien if (needed < 0) 30865312Smsmith return; 30965312Smsmith 31065312Smsmith sp = malloc(needed); 31165312Smsmith if (sp == NULL) 31265312Smsmith return; 31365312Smsmith 31496554Sobrien if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 31565312Smsmith LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n", 31696554Sobrien strerror(errno)); 31765312Smsmith free(sp); 31896554Sobrien return; 31965312Smsmith } 32096554Sobrien ep = sp + needed; 32165312Smsmith 32265312Smsmith for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 32396554Sobrien rtm = (struct rt_msghdr *) cp; 32465312Smsmith sa = (struct sockaddr *) (rtm + 1); 32596554Sobrien LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x," 32665312Smsmith " dstnet: %s\n", 32796554Sobrien rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags, 328108533Sschweikh inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); 32996554Sobrien if (rtm->rtm_addrs != RTA_DST && 33065312Smsmith (rtm->rtm_index == IfIndex) && 33196554Sobrien (all || (rtm->rtm_flags & RTF_GATEWAY))) { 33265312Smsmith LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n"); 33396554Sobrien dstnet = ((struct sockaddr_in *) sa)->sin_addr; 33465312Smsmith wp = (u_char *) cp + rtm->rtm_msglen; 33565312Smsmith if (sa->sa_len == 0) 33665312Smsmith sa->sa_len = sizeof(long); 33765312Smsmith sa = (struct sockaddr *) (sa->sa_len + (char *) sa); 33865312Smsmith gateway = ((struct sockaddr_in *) sa)->sin_addr; 33965312Smsmith lp = (int *) (sa->sa_len + (char *) sa); 34065312Smsmith mask = 0; 34196554Sobrien if ((char *) lp < (char *) wp && *lp) { 34265312Smsmith LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n", 34365312Smsmith rtm->rtm_flags, *lp); 34496554Sobrien wp = (u_char *) (lp + 1); 34565312Smsmith for (nb = *lp; nb > 4; nb--) { 34665312Smsmith mask <<= 8; 34765312Smsmith mask |= *wp++; 34865312Smsmith } 34965312Smsmith for (nb = 8 - *lp; nb > 0; nb--) 35065312Smsmith mask <<= 8; 35165312Smsmith } 35265312Smsmith LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet)); 35365312Smsmith LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway)); 35465312Smsmith LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index); 35596615Sobrien if (dstnet.s_addr == INADDR_ANY) 35696615Sobrien mask = INADDR_ANY; 35796615Sobrien maddr.s_addr = htonl(mask); 35865312Smsmith OsSetRoute(RTM_DELETE, dstnet, gateway, maddr); 35965312Smsmith } 36065312Smsmith } 36165312Smsmith free(sp); 36296554Sobrien} 36365312Smsmith 36465312Smsmith /* 36596554Sobrien * 960603 - Modified to use dynamic buffer allocator as in ifconfig 366 */ 367 368int 369GetIfIndex(char *name) 370{ 371 char *buffer; 372 struct ifreq *ifrp; 373 int s, len, elen, newIfIndex; 374 struct ifconf ifconfs; 375 376 /* struct ifreq reqbuf[256]; -- obsoleted :) */ 377 int oldbufsize, bufsize = sizeof(struct ifreq); 378 379 s = socket(AF_INET, SOCK_DGRAM, 0); 380 if (s < 0) { 381 LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno)); 382 return (-1); 383 } 384 buffer = malloc(bufsize); /* allocate first buffer */ 385 ifconfs.ifc_len = bufsize; /* Initial setting */ 386 387 /* 388 * Iterate through here until we don't get many more data 389 */ 390 391 do { 392 oldbufsize = ifconfs.ifc_len; 393 bufsize += 1 + sizeof(struct ifreq); 394 buffer = realloc((void *) buffer, bufsize); /* Make it bigger */ 395 LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize); 396 ifconfs.ifc_len = bufsize; 397 ifconfs.ifc_buf = buffer; 398 if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) { 399 LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n", 400 strerror(errno)); 401 close(s); 402 free(buffer); 403 return (-1); 404 } 405 } while (ifconfs.ifc_len > oldbufsize); 406 407 ifrp = ifconfs.ifc_req; 408 409 newIfIndex = 1; 410 for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) { 411 elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr); 412 if (ifrp->ifr_addr.sa_family == AF_LINK) { 413 LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n", 414 newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name, 415 ifrp->ifr_addr.sa_family, elen); 416 if (strcmp(ifrp->ifr_name, name) == 0) { 417 IfIndex = newIfIndex; 418 close(s); 419 free(buffer); 420 return (newIfIndex); 421 } 422 newIfIndex++; 423 } 424 len -= elen; 425 ifrp = (struct ifreq *) ((char *) ifrp + elen); 426 ifrp++; 427 } 428 429 close(s); 430 free(buffer); 431 return (-1); 432} 433