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