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