route.c revision 25630
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 *
2025630Sbrian * $Id: route.c,v 1.12 1997/02/22 16:10:49 peter Exp $
218857Srgrimes *
226059Samurai */
236059Samurai#include <sys/types.h>
246059Samurai#include <machine/endian.h>
2520287Swollman#include <sys/ioctl.h>
266059Samurai#include <sys/param.h>
276059Samurai#include <sys/socket.h>
286735Samurai#if (BSD >= 199306)
296059Samurai#include <sys/sysctl.h>
306059Samurai#else
316059Samurai#include <sys/kinfo.h>
326059Samurai#endif
3320287Swollman#include <sys/time.h>
3420287Swollman
3520287Swollman#include <errno.h>
366059Samurai#include <stdlib.h>
376059Samurai#include <stdio.h>
386059Samurai#include <string.h>
396059Samurai#include <unistd.h>
4020287Swollman
4120287Swollman#include <net/route.h>
4220287Swollman#include <net/if.h>
4320287Swollman#include <netinet/in_systm.h>
4420287Swollman#include <netinet/in.h>
4520287Swollman#include <arpa/inet.h>
4620287Swollman
479439Samurai#include "log.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
596059SamuraiOsSetRoute(cmd, dst, gateway, mask)
606059Samuraiint cmd;
616059Samuraistruct in_addr dst;
626059Samuraistruct in_addr gateway;
636059Samuraistruct in_addr mask;
646059Samurai{
656059Samurai  struct rtmsg rtmes;
666059Samurai  int s, nb, wb;
676059Samurai  char *cp;
686059Samurai  u_long *lp;
696059Samurai  struct sockaddr_in rtdata;
706059Samurai
716059Samurai  s = socket(PF_ROUTE, SOCK_RAW, 0);
726059Samurai  if (s < 0)
736059Samurai    logprintf("socket\n");
746059Samurai
756059Samurai  bzero(&rtmes, sizeof(rtmes));
766059Samurai  rtmes.m_rtm.rtm_version = RTM_VERSION;
776059Samurai  rtmes.m_rtm.rtm_type = cmd;
786059Samurai  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
796059Samurai  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
806059Samurai  rtmes.m_rtm.rtm_seq = ++seqno;
816059Samurai  rtmes.m_rtm.rtm_pid = getpid();
8217571Speter  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
836059Samurai
846059Samurai  bzero(&rtdata, sizeof(rtdata));
856059Samurai  rtdata.sin_len = 16;
866059Samurai  rtdata.sin_family = AF_INET;
876059Samurai  rtdata.sin_port = 0;
886059Samurai  rtdata.sin_addr = dst;
896059Samurai
906059Samurai  cp = rtmes.m_space;
916059Samurai  bcopy(&rtdata, cp, 16);
926059Samurai  cp += 16;
936059Samurai  if (gateway.s_addr) {
946059Samurai    rtdata.sin_addr = gateway;
956059Samurai    bcopy(&rtdata, cp, 16);
966059Samurai    cp += 16;
976059Samurai  }
986059Samurai
996059Samurai  if (dst.s_addr == INADDR_ANY)
1006059Samurai    mask.s_addr = INADDR_ANY;
1016059Samurai
1026059Samurai  lp = (u_long *)cp;
1036059Samurai
1046059Samurai  if (mask.s_addr) {
1056059Samurai    *lp++ = 8;
1066059Samurai    cp += sizeof(int);
1076059Samurai    *lp = mask.s_addr;
1086059Samurai  } else
1096059Samurai    *lp = 0;
1106059Samurai  cp += sizeof(u_long);
1116059Samurai
1126059Samurai  nb = cp - (char *)&rtmes;
1136059Samurai  rtmes.m_rtm.rtm_msglen = nb;
1146059Samurai  wb = write(s, &rtmes, nb);
1156059Samurai  if (wb < 0) {
11615738Sphk     LogPrintf(LOG_TCPIP_BIT, "Already set route addr dst=%x, gateway=%x\n"
1179439Samurai         ,dst.s_addr, gateway.s_addr);
1186059Samurai  }
1196059Samurai#ifdef DEBUG
1206059Samurai  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
1216059Samurai#endif
1226059Samurai  close(s);
1236059Samurai}
1246059Samurai
1256059Samuraistatic void
1266059Samuraip_sockaddr(sa, width)
1276059Samuraistruct sockaddr *sa;
1286059Samuraiint width;
1296059Samurai{
1306059Samurai  register char *cp;
1316059Samurai  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1326059Samurai
1336059Samurai  cp = (sin->sin_addr.s_addr == 0) ? "default" :
1346059Samurai	   inet_ntoa(sin->sin_addr);
1356059Samurai  printf("%-*.*s ", width, width, cp);
1366059Samurai}
1376059Samurai
1386059Samuraistruct bits {
1396059Samurai  short b_mask;
1406059Samurai  char  b_val;
1416059Samurai} bits[] = {
1426059Samurai  { RTF_UP,	  'U' },
1436059Samurai  { RTF_GATEWAY,  'G' },
1446059Samurai  { RTF_HOST,	  'H' },
1456059Samurai  { RTF_DYNAMIC,  'D' },
1466059Samurai  { RTF_MODIFIED, 'M' },
1476059Samurai  { RTF_CLONING,  'C' },
1486059Samurai  { RTF_XRESOLVE, 'X' },
1496059Samurai  { RTF_LLINFO,   'L' },
1506059Samurai  { RTF_REJECT,   'R' },
1516059Samurai  { 0 }
1526059Samurai};
1536059Samurai
1546059Samuraistatic void
1556059Samuraip_flags(f, format)
1566059Samurairegister int f;
1576059Samuraichar *format;
1586059Samurai{
1596059Samurai  char name[33], *flags;
1606059Samurai  register struct bits *p = bits;
1616059Samurai
1626059Samurai  for (flags = name; p->b_mask; p++)
1636059Samurai    if (p->b_mask & f)
1646059Samurai      *flags++ = p->b_val;
1656059Samurai  *flags = '\0';
1666059Samurai  printf(format, name);
1676059Samurai}
1686059Samurai
1696059Samuraiint
1706059SamuraiShowRoute()
1716059Samurai{
1726059Samurai  struct rt_msghdr *rtm;
1736059Samurai  struct sockaddr *sa;
1746059Samurai  char *sp, *ep, *cp;
1756059Samurai  u_char *wp;
1766059Samurai  int *lp;
1776059Samurai  int needed, nb;
1786059Samurai  u_long mask;
1796735Samurai#if (BSD >= 199306)
1806735Samurai  int mib[6];
1816059Samurai#endif
1826059Samurai
1836735Samurai#if (BSD >= 199306)
1846059Samurai  mib[0] = CTL_NET;
1856059Samurai  mib[1] = PF_ROUTE;
1866735Samurai  mib[2] = 0;
1876735Samurai  mib[3] = 0;
1886059Samurai  mib[4] = NET_RT_DUMP;
1896735Samurai  mib[5] = 0;
1906735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
1916735Samurai    perror("sysctl-estimate");
1926735Samurai    return(1);
1936735Samurai  }
1946059Samurai#else
1956059Samurai  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
1966059Samurai#endif
1976059Samurai  if (needed < 0)
1986059Samurai    return(1);
1996059Samurai  sp = malloc(needed);
2006059Samurai  if (sp == NULL)
2016059Samurai    return(1);
2026735Samurai#if (BSD >= 199306)
2036735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
2046735Samurai    perror("sysctl-getroute");
20518885Sjkh    free(sp);
2066059Samurai    return(1);
2076735Samurai  }
2086059Samurai#else
2096059Samurai  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
21018885Sjkh    free(sp);
2116059Samurai    return(1);
2126059Samurai#endif
2136059Samurai  ep = sp + needed;
2146059Samurai
2156059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
2166059Samurai    rtm = (struct rt_msghdr *)cp;
2176059Samurai    sa = (struct sockaddr *)(rtm + 1);
2186059Samurai    mask = 0xffffffff;
2196059Samurai    if (rtm->rtm_addrs == RTA_DST)
2206059Samurai      p_sockaddr(sa, 36);
2216059Samurai    else {
2226059Samurai      wp = (u_char *)cp + rtm->rtm_msglen;
2236059Samurai      p_sockaddr(sa, 16);
2246059Samurai      if (sa->sa_len == 0)
2256059Samurai	sa->sa_len = sizeof(long);
2266059Samurai      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
2276059Samurai      p_sockaddr(sa, 18);
2286059Samurai      lp = (int *)(sa->sa_len + (char *)sa);
2296059Samurai      if ((char *)lp < (char *)wp && *lp) {
2306059Samurai#ifdef DEBUG
2316059Samurai	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
2326059Samurai#endif
2336059Samurai	wp = (u_char *)(lp + 1);
2346059Samurai	mask = 0;
23518885Sjkh	for (nb = *(char *)lp; nb > 4; nb--) {
2366059Samurai	  mask <<= 8;
2376059Samurai	  mask |= *wp++;
2386059Samurai	}
23918885Sjkh	for (nb = 8 - *(char *)lp; nb > 0; nb--)
2406059Samurai	  mask <<= 8;
2416059Samurai      }
2426059Samurai    }
24313389Sphk    printf("%08lx  ", mask);
2446059Samurai    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
2456059Samurai    printf("(%d)\n", rtm->rtm_index);
2466059Samurai  }
24718885Sjkh  free(sp);
2486059Samurai  return(1);
2496059Samurai}
2506059Samurai
2516059Samurai/*
2526059Samurai *  Delete routes associated with our interface
2536059Samurai */
2546059Samuraivoid
2556059SamuraiDeleteIfRoutes(all)
2566059Samuraiint all;
2576059Samurai{
2586059Samurai  struct rt_msghdr *rtm;
2596059Samurai  struct sockaddr *sa;
26015738Sphk  struct in_addr dstnet, gateway, maddr;
2616059Samurai  int needed;
2626059Samurai  char *sp, *cp, *ep;
2636059Samurai  u_long mask;
2646059Samurai  int *lp, nb;
2656059Samurai  u_char *wp;
2666735Samurai#if (BSD >= 199306)
2676735Samurai  int mib[6];
2686059Samurai#endif
2696059Samurai
2706059Samurai#ifdef DEBUG
2716059Samurai  logprintf("DeleteIfRoutes (%d)\n", IfIndex);
2726059Samurai#endif
2736735Samurai#if (BSD >= 199306)
2746059Samurai  mib[0] = CTL_NET;
2756059Samurai  mib[1] = PF_ROUTE;
2766735Samurai  mib[2] = 0;
2776735Samurai  mib[3] = 0;
2786059Samurai  mib[4] = NET_RT_DUMP;
2796735Samurai  mib[5] = 0;
2806735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
2816735Samurai    perror("sysctl-estimate");
2826735Samurai    return;
2836735Samurai  }
2846059Samurai#else
2856059Samurai  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
2866059Samurai#endif
2876735Samurai
2886059Samurai  if (needed < 0)
2896059Samurai    return;
2906059Samurai
2916059Samurai  sp = malloc(needed);
2926059Samurai  if (sp == NULL)
2936059Samurai    return;
2946059Samurai
2956735Samurai#if (BSD >= 199306)
2966735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
2976059Samurai    free(sp);
2986735Samurai    perror("sysctl-getroute");
2996059Samurai    return;
3006059Samurai  }
3016059Samurai#else
3026059Samurai  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
3036059Samurai    free(sp);
3046059Samurai    return;
3056059Samurai  }
3066059Samurai#endif
3076059Samurai  ep = sp + needed;
3086059Samurai
3096059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
3106059Samurai    rtm = (struct rt_msghdr *)cp;
3116059Samurai    sa = (struct sockaddr *)(rtm + 1);
3126059Samurai#ifdef DEBUG
3136059Samurai    logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
3146059Samurai	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
3156059Samurai	((struct sockaddr_in *)sa)->sin_addr);
3166059Samurai#endif
3176059Samurai    if (rtm->rtm_addrs != RTA_DST &&
3186059Samurai       (rtm->rtm_index == IfIndex) &&
3196059Samurai       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
3206059Samurai      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
3216059Samurai      wp = (u_char *)cp + rtm->rtm_msglen;
3226059Samurai      if (sa->sa_len == 0)
3236059Samurai	sa->sa_len = sizeof(long);
3246059Samurai      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
3256059Samurai      gateway = ((struct sockaddr_in *)sa)->sin_addr;
3266059Samurai      lp = (int *)(sa->sa_len + (char *)sa);
3276059Samurai      mask = 0;
3286059Samurai      if ((char *)lp < (char *)wp && *lp) {
3296059Samurai#ifdef DEBUG
3306059Samurai	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
3316059Samurai#endif
3326059Samurai	wp = (u_char *)(lp + 1);
3336059Samurai	for (nb = *lp; nb > 4; nb--) {
3346059Samurai	  mask <<= 8;
3356059Samurai	  mask |= *wp++;
3366059Samurai	}
3376059Samurai	for (nb = 8 - *lp; nb > 0; nb--)
3386059Samurai	  mask <<= 8;
3396059Samurai      }
3406059Samurai#ifdef DEBUG
3416059Samurai      logprintf("## %s ", inet_ntoa(dstnet));
3426059Samurai      logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
3436059Samurai#endif
3446059Samurai      if (dstnet.s_addr == INADDR_ANY) {
3456059Samurai        gateway.s_addr = INADDR_ANY;
3466059Samurai        mask = INADDR_ANY;
3476059Samurai      }
34815738Sphk      maddr.s_addr = htonl(mask);
34915738Sphk      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
3506059Samurai    }
3516059Samurai#ifdef DEBUG
3526059Samurai    else if (rtm->rtm_index == IfIndex) {
3536059Samurai      logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
3546059Samurai    }
3556059Samurai#endif
3566059Samurai  }
3576059Samurai  free(sp);
3586059Samurai}
3596059Samurai
36018752Sjkh /*
36118752Sjkh  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
36218752Sjkh  */
36318752Sjkh
3646059Samuraiint
3656059SamuraiGetIfIndex(name)
3666059Samuraichar *name;
3676059Samurai{
36818752Sjkh  char *buffer;
3696059Samurai  struct ifreq *ifrp;
3706059Samurai  int s, len, elen, index;
3716059Samurai  struct ifconf ifconfs;
37218752Sjkh  /* struct ifreq reqbuf[256]; -- obsoleted :) */
37318752Sjkh  int oldbufsize, bufsize = sizeof(struct ifreq);
3746059Samurai
3756059Samurai  s = socket(AF_INET, SOCK_DGRAM, 0);
3766059Samurai  if (s < 0) {
3776059Samurai    perror("socket");
3786059Samurai    return(-1);
3796059Samurai  }
3806059Samurai
38118752Sjkh  buffer = malloc(bufsize);   /* allocate first buffer */
38218752Sjkh  ifconfs.ifc_len = bufsize;  /* Initial setting */
38318752Sjkh  /*
38418752Sjkh   * Iterate through here until we don't get many more data
38518752Sjkh   */
3866059Samurai
38718752Sjkh  do {
38818752Sjkh      oldbufsize = ifconfs.ifc_len;
38918752Sjkh      bufsize += 1+sizeof(struct ifreq);
39018752Sjkh      buffer = realloc((void *)buffer, bufsize);      /* Make it bigger */
39118752Sjkh#ifdef DEBUG
39218752Sjkh      logprintf ("Growing buffer to %d\n", bufsize);
39318752Sjkh#endif
39418752Sjkh      ifconfs.ifc_len = bufsize;
39518752Sjkh      ifconfs.ifc_buf = buffer;
39618752Sjkh      if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
39718752Sjkh          perror("IFCONF");
39818752Sjkh          free(buffer);
39918752Sjkh          return(-1);
40018752Sjkh      }
40118752Sjkh  } while (ifconfs.ifc_len > oldbufsize);
40218752Sjkh
4036059Samurai  ifrp = ifconfs.ifc_req;
4046059Samurai
4056059Samurai  index = 1;
4066059Samurai  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
4076059Samurai    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
4086059Samurai    if (ifrp->ifr_addr.sa_family == AF_LINK) {
4096059Samurai#ifdef DEBUG
4106059Samurai      logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
4116059Samurai	   ifrp->ifr_addr.sa_family, elen);
4126059Samurai#endif
4136059Samurai      if (strcmp(ifrp->ifr_name, name) == 0) {
4146059Samurai        IfIndex = index;
41525630Sbrian	free(buffer);
4166059Samurai        return(index);
4176059Samurai      }
4186059Samurai      index++;
4196059Samurai    }
4206059Samurai
4216059Samurai    len -= elen;
4226059Samurai    ifrp = (struct ifreq *)((char *)ifrp + elen);
4236059Samurai    ifrp++;
4246059Samurai  }
4256059Samurai
4266059Samurai  close(s);
42718752Sjkh  free(buffer);
4286059Samurai  return(-1);
4296059Samurai}
430