route.c revision 13389
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 *
2013389Sphk * $Id: route.c,v 1.4 1995/07/08 06:08:52 amurai Exp $
218857Srgrimes *
226059Samurai */
236059Samurai#include <sys/types.h>
246059Samurai#include <machine/endian.h>
256059Samurai#include <sys/param.h>
266059Samurai#include <sys/socket.h>
276059Samurai#include <net/route.h>
286059Samurai#include <sys/ioctl.h>
296059Samurai#include <net/if.h>
306059Samurai#include <errno.h>
316059Samurai#include <netinet/in_systm.h>
326059Samurai#include <netinet/in.h>
336059Samurai#include <arpa/inet.h>
346735Samurai#if (BSD >= 199306)
356059Samurai#include <sys/sysctl.h>
366059Samurai#else
376059Samurai#include <sys/kinfo.h>
386059Samurai#endif
396059Samurai#include <stdlib.h>
406059Samurai#include <stdio.h>
416059Samurai#include <string.h>
426059Samurai#include <unistd.h>
439439Samurai#include "log.h"
446059Samurai
456059Samuraistatic int IfIndex;
466059Samurai
476059Samuraistruct rtmsg {
486059Samurai  struct rt_msghdr m_rtm;
496059Samurai  char m_space[64];
506059Samurai};
516059Samurai
526059Samuraistatic int seqno;
536059Samurai
546059Samuraivoid
556059SamuraiOsSetRoute(cmd, dst, gateway, mask)
566059Samuraiint cmd;
576059Samuraistruct in_addr dst;
586059Samuraistruct in_addr gateway;
596059Samuraistruct in_addr mask;
606059Samurai{
616059Samurai  struct rtmsg rtmes;
626059Samurai  int s, nb, wb;
636059Samurai  char *cp;
646059Samurai  u_long *lp;
656059Samurai  struct sockaddr_in rtdata;
666059Samurai
676059Samurai  s = socket(PF_ROUTE, SOCK_RAW, 0);
686059Samurai  if (s < 0)
696059Samurai    logprintf("socket\n");
706059Samurai
716059Samurai  bzero(&rtmes, sizeof(rtmes));
726059Samurai  rtmes.m_rtm.rtm_version = RTM_VERSION;
736059Samurai  rtmes.m_rtm.rtm_type = cmd;
746059Samurai  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
756059Samurai  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
766059Samurai  rtmes.m_rtm.rtm_seq = ++seqno;
776059Samurai  rtmes.m_rtm.rtm_pid = getpid();
786059Samurai  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
796059Samurai
806059Samurai  bzero(&rtdata, sizeof(rtdata));
816059Samurai  rtdata.sin_len = 16;
826059Samurai  rtdata.sin_family = AF_INET;
836059Samurai  rtdata.sin_port = 0;
846059Samurai  rtdata.sin_addr = dst;
856059Samurai
866059Samurai  cp = rtmes.m_space;
876059Samurai  bcopy(&rtdata, cp, 16);
886059Samurai  cp += 16;
896059Samurai  if (gateway.s_addr) {
906059Samurai    rtdata.sin_addr = gateway;
916059Samurai    bcopy(&rtdata, cp, 16);
926059Samurai    cp += 16;
936059Samurai  }
946059Samurai
956059Samurai  if (dst.s_addr == INADDR_ANY)
966059Samurai    mask.s_addr = INADDR_ANY;
976059Samurai
986059Samurai  lp = (u_long *)cp;
996059Samurai
1006059Samurai  if (mask.s_addr) {
1016059Samurai    *lp++ = 8;
1026059Samurai    cp += sizeof(int);
1036059Samurai    *lp = mask.s_addr;
1046059Samurai  } else
1056059Samurai    *lp = 0;
1066059Samurai  cp += sizeof(u_long);
1076059Samurai
1086059Samurai  nb = cp - (char *)&rtmes;
1096059Samurai  rtmes.m_rtm.rtm_msglen = nb;
1106059Samurai  wb = write(s, &rtmes, nb);
1116059Samurai  if (wb < 0) {
1129439Samurai     LogPrintf(LOG_TCPIP, "Already set route addr dst=%x, gateway=%x\n"
1139439Samurai         ,dst.s_addr, gateway.s_addr);
1146059Samurai  }
1156059Samurai#ifdef DEBUG
1166059Samurai  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
1176059Samurai#endif
1186059Samurai  close(s);
1196059Samurai}
1206059Samurai
1216059Samuraistatic void
1226059Samuraip_sockaddr(sa, width)
1236059Samuraistruct sockaddr *sa;
1246059Samuraiint width;
1256059Samurai{
1266059Samurai  register char *cp;
1276059Samurai  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1286059Samurai
1296059Samurai  cp = (sin->sin_addr.s_addr == 0) ? "default" :
1306059Samurai	   inet_ntoa(sin->sin_addr);
1316059Samurai  printf("%-*.*s ", width, width, cp);
1326059Samurai}
1336059Samurai
1346059Samuraistruct bits {
1356059Samurai  short b_mask;
1366059Samurai  char  b_val;
1376059Samurai} bits[] = {
1386059Samurai  { RTF_UP,	  'U' },
1396059Samurai  { RTF_GATEWAY,  'G' },
1406059Samurai  { RTF_HOST,	  'H' },
1416059Samurai  { RTF_DYNAMIC,  'D' },
1426059Samurai  { RTF_MODIFIED, 'M' },
1436059Samurai  { RTF_CLONING,  'C' },
1446059Samurai  { RTF_XRESOLVE, 'X' },
1456059Samurai  { RTF_LLINFO,   'L' },
1466059Samurai  { RTF_REJECT,   'R' },
1476059Samurai  { 0 }
1486059Samurai};
1496059Samurai
1506059Samuraistatic void
1516059Samuraip_flags(f, format)
1526059Samurairegister int f;
1536059Samuraichar *format;
1546059Samurai{
1556059Samurai  char name[33], *flags;
1566059Samurai  register struct bits *p = bits;
1576059Samurai
1586059Samurai  for (flags = name; p->b_mask; p++)
1596059Samurai    if (p->b_mask & f)
1606059Samurai      *flags++ = p->b_val;
1616059Samurai  *flags = '\0';
1626059Samurai  printf(format, name);
1636059Samurai}
1646059Samurai
1656059Samuraiint
1666059SamuraiShowRoute()
1676059Samurai{
1686059Samurai  struct rt_msghdr *rtm;
1696059Samurai  struct sockaddr *sa;
1706059Samurai  char *sp, *ep, *cp;
1716059Samurai  u_char *wp;
1726059Samurai  int *lp;
1736059Samurai  int needed, nb;
1746059Samurai  u_long mask;
1756735Samurai#if (BSD >= 199306)
1766735Samurai  int mib[6];
1776059Samurai#endif
1786059Samurai
1796735Samurai#if (BSD >= 199306)
1806059Samurai  mib[0] = CTL_NET;
1816059Samurai  mib[1] = PF_ROUTE;
1826735Samurai  mib[2] = 0;
1836735Samurai  mib[3] = 0;
1846059Samurai  mib[4] = NET_RT_DUMP;
1856735Samurai  mib[5] = 0;
1866735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
1876735Samurai    perror("sysctl-estimate");
1886735Samurai    return(1);
1896735Samurai  }
1906059Samurai#else
1916059Samurai  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
1926059Samurai#endif
1936059Samurai  if (needed < 0)
1946059Samurai    return(1);
1956059Samurai  sp = malloc(needed);
1966059Samurai  if (sp == NULL)
1976059Samurai    return(1);
1986735Samurai#if (BSD >= 199306)
1996735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
2006735Samurai    perror("sysctl-getroute");
2016059Samurai    return(1);
2026735Samurai  }
2036059Samurai#else
2046059Samurai  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
2056059Samurai    return(1);
2066059Samurai#endif
2076059Samurai  ep = sp + needed;
2086059Samurai
2096059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
2106059Samurai    rtm = (struct rt_msghdr *)cp;
2116059Samurai    sa = (struct sockaddr *)(rtm + 1);
2126059Samurai    mask = 0xffffffff;
2136059Samurai    if (rtm->rtm_addrs == RTA_DST)
2146059Samurai      p_sockaddr(sa, 36);
2156059Samurai    else {
2166059Samurai      wp = (u_char *)cp + rtm->rtm_msglen;
2176059Samurai      p_sockaddr(sa, 16);
2186059Samurai      if (sa->sa_len == 0)
2196059Samurai	sa->sa_len = sizeof(long);
2206059Samurai      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
2216059Samurai      p_sockaddr(sa, 18);
2226059Samurai      lp = (int *)(sa->sa_len + (char *)sa);
2236059Samurai      if ((char *)lp < (char *)wp && *lp) {
2246059Samurai#ifdef DEBUG
2256059Samurai	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
2266059Samurai#endif
2276059Samurai	wp = (u_char *)(lp + 1);
2286059Samurai	mask = 0;
2296059Samurai	for (nb = *lp; nb > 4; nb--) {
2306059Samurai	  mask <<= 8;
2316059Samurai	  mask |= *wp++;
2326059Samurai	}
2336059Samurai	for (nb = 8 - *lp; nb > 0; nb--)
2346059Samurai	  mask <<= 8;
2356059Samurai      }
2366059Samurai    }
23713389Sphk    printf("%08lx  ", mask);
2386059Samurai    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
2396059Samurai    printf("(%d)\n", rtm->rtm_index);
2406059Samurai  }
2416059Samurai
2426059Samurai  return(1);
2436059Samurai}
2446059Samurai
2456059Samurai/*
2466059Samurai *  Delete routes associated with our interface
2476059Samurai */
2486059Samuraivoid
2496059SamuraiDeleteIfRoutes(all)
2506059Samuraiint all;
2516059Samurai{
2526059Samurai  struct rt_msghdr *rtm;
2536059Samurai  struct sockaddr *sa;
2546059Samurai  struct in_addr dstnet, gateway;
2556059Samurai  int needed;
2566059Samurai  char *sp, *cp, *ep;
2576059Samurai  u_long mask;
2586059Samurai  int *lp, nb;
2596059Samurai  u_char *wp;
2606735Samurai#if (BSD >= 199306)
2616735Samurai  int mib[6];
2626059Samurai#endif
2636059Samurai
2646059Samurai#ifdef DEBUG
2656059Samurai  logprintf("DeleteIfRoutes (%d)\n", IfIndex);
2666059Samurai#endif
2676735Samurai#if (BSD >= 199306)
2686059Samurai  mib[0] = CTL_NET;
2696059Samurai  mib[1] = PF_ROUTE;
2706735Samurai  mib[2] = 0;
2716735Samurai  mib[3] = 0;
2726059Samurai  mib[4] = NET_RT_DUMP;
2736735Samurai  mib[5] = 0;
2746735Samurai  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
2756735Samurai    perror("sysctl-estimate");
2766735Samurai    return;
2776735Samurai  }
2786059Samurai#else
2796059Samurai  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
2806059Samurai#endif
2816735Samurai
2826059Samurai  if (needed < 0)
2836059Samurai    return;
2846059Samurai
2856059Samurai  sp = malloc(needed);
2866059Samurai  if (sp == NULL)
2876059Samurai    return;
2886059Samurai
2896735Samurai#if (BSD >= 199306)
2906735Samurai  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
2916059Samurai    free(sp);
2926735Samurai    perror("sysctl-getroute");
2936059Samurai    return;
2946059Samurai  }
2956059Samurai#else
2966059Samurai  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
2976059Samurai    free(sp);
2986059Samurai    return;
2996059Samurai  }
3006059Samurai#endif
3016059Samurai  ep = sp + needed;
3026059Samurai
3036059Samurai  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
3046059Samurai    rtm = (struct rt_msghdr *)cp;
3056059Samurai    sa = (struct sockaddr *)(rtm + 1);
3066059Samurai#ifdef DEBUG
3076059Samurai    logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
3086059Samurai	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
3096059Samurai	((struct sockaddr_in *)sa)->sin_addr);
3106059Samurai#endif
3116059Samurai    if (rtm->rtm_addrs != RTA_DST &&
3126059Samurai       (rtm->rtm_index == IfIndex) &&
3136059Samurai       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
3146059Samurai      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
3156059Samurai      wp = (u_char *)cp + rtm->rtm_msglen;
3166059Samurai      if (sa->sa_len == 0)
3176059Samurai	sa->sa_len = sizeof(long);
3186059Samurai      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
3196059Samurai      gateway = ((struct sockaddr_in *)sa)->sin_addr;
3206059Samurai      lp = (int *)(sa->sa_len + (char *)sa);
3216059Samurai      mask = 0;
3226059Samurai      if ((char *)lp < (char *)wp && *lp) {
3236059Samurai#ifdef DEBUG
3246059Samurai	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
3256059Samurai#endif
3266059Samurai	wp = (u_char *)(lp + 1);
3276059Samurai	for (nb = *lp; nb > 4; nb--) {
3286059Samurai	  mask <<= 8;
3296059Samurai	  mask |= *wp++;
3306059Samurai	}
3316059Samurai	for (nb = 8 - *lp; nb > 0; nb--)
3326059Samurai	  mask <<= 8;
3336059Samurai      }
3346059Samurai#ifdef DEBUG
3356059Samurai      logprintf("## %s ", inet_ntoa(dstnet));
3366059Samurai      logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
3376059Samurai#endif
3386059Samurai      if (dstnet.s_addr == INADDR_ANY) {
3396059Samurai        gateway.s_addr = INADDR_ANY;
3406059Samurai        mask = INADDR_ANY;
3416059Samurai      }
3426059Samurai      OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask));
3436059Samurai    }
3446059Samurai#ifdef DEBUG
3456059Samurai    else if (rtm->rtm_index == IfIndex) {
3466059Samurai      logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
3476059Samurai    }
3486059Samurai#endif
3496059Samurai  }
3506059Samurai  free(sp);
3516059Samurai}
3526059Samurai
3536059Samuraiint
3546059SamuraiGetIfIndex(name)
3556059Samuraichar *name;
3566059Samurai{
3576059Samurai  struct ifreq *ifrp;
3586059Samurai  int s, len, elen, index;
3596059Samurai  struct ifconf ifconfs;
3606059Samurai  struct ifreq reqbuf[32];
3616059Samurai
3626059Samurai  s = socket(AF_INET, SOCK_DGRAM, 0);
3636059Samurai  if (s < 0) {
3646059Samurai    perror("socket");
3656059Samurai    return(-1);
3666059Samurai  }
3676059Samurai
3686059Samurai  ifconfs.ifc_len = sizeof(reqbuf);
3696059Samurai  ifconfs.ifc_buf = (caddr_t)reqbuf;
3706059Samurai  if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
3716059Samurai    perror("IFCONF");
3726059Samurai    return(-1);
3736059Samurai  }
3746059Samurai
3756059Samurai  ifrp = ifconfs.ifc_req;
3766059Samurai
3776059Samurai  index = 1;
3786059Samurai  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
3796059Samurai    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
3806059Samurai    if (ifrp->ifr_addr.sa_family == AF_LINK) {
3816059Samurai#ifdef DEBUG
3826059Samurai      logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
3836059Samurai	   ifrp->ifr_addr.sa_family, elen);
3846059Samurai#endif
3856059Samurai      if (strcmp(ifrp->ifr_name, name) == 0) {
3866059Samurai        IfIndex = index;
3876059Samurai        return(index);
3886059Samurai      }
3896059Samurai      index++;
3906059Samurai    }
3916059Samurai
3926059Samurai    len -= elen;
3936059Samurai    ifrp = (struct ifreq *)((char *)ifrp + elen);
3946059Samurai    ifrp++;
3956059Samurai  }
3966059Samurai
3976059Samurai  close(s);
3986059Samurai  return(-1);
3996059Samurai}
400