route.c revision 6735
137535Sdes/*
263012Sdes *	      PPP Routing related Module
337535Sdes *
437535Sdes *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
537535Sdes *
637535Sdes *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
737535Sdes *
837535Sdes * Redistribution and use in source and binary forms are permitted
937535Sdes * provided that the above copyright notice and this paragraph are
1037535Sdes * duplicated in all such forms and that any documentation,
1137535Sdes * advertising materials, and other materials related to such
1237535Sdes * distribution and use acknowledge that the software was developed
1337535Sdes * by the Internet Initiative Japan, Inc.  The name of the
1437535Sdes * IIJ may not be used to endorse or promote products derived
1563012Sdes * from this software without specific prior written permission.
1637535Sdes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1737535Sdes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1837535Sdes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1937535Sdes *
2037535Sdes * $Id:$
2137535Sdes *
2237535Sdes */
2337535Sdes#include <sys/types.h>
2437535Sdes#include <machine/endian.h>
2537535Sdes#include <sys/param.h>
2637535Sdes#include <sys/socket.h>
2737535Sdes#include <net/route.h>
2837535Sdes#include <sys/ioctl.h>
2984203Sdillon#include <net/if.h>
3084203Sdillon#include <errno.h>
3184203Sdillon#include <netinet/in_systm.h>
3263236Sdes#include <netinet/in.h>
3363236Sdes#include <arpa/inet.h>
3463236Sdes#if (BSD >= 199306)
3563236Sdes#include <sys/sysctl.h>
3663236Sdes#else
3763236Sdes#include <sys/kinfo.h>
3863236Sdes#endif
3963236Sdes#include <stdlib.h>
4063236Sdes#include <stdio.h>
4163236Sdes#include <string.h>
4263236Sdes#include <unistd.h>
4363236Sdes
4463236Sdesstatic int IfIndex;
4563236Sdes
4663236Sdesstruct rtmsg {
4763236Sdes  struct rt_msghdr m_rtm;
4863236Sdes  char m_space[64];
4990267Sdes};
5063236Sdes
5163236Sdesstatic int seqno;
5263236Sdes
5363236Sdesvoid
5463236SdesOsSetRoute(cmd, dst, gateway, mask)
5563236Sdesint cmd;
5663236Sdesstruct in_addr dst;
5763236Sdesstruct in_addr gateway;
5863236Sdesstruct in_addr mask;
5963236Sdes{
6063236Sdes  struct rtmsg rtmes;
6163236Sdes  int s, nb, wb;
6263236Sdes  char *cp;
6363236Sdes  u_long *lp;
6437535Sdes  struct sockaddr_in rtdata;
6560737Sume
6637535Sdes  s = socket(PF_ROUTE, SOCK_RAW, 0);
6763012Sdes  if (s < 0)
6837535Sdes    logprintf("socket\n");
6963012Sdes
7060376Sdes  bzero(&rtmes, sizeof(rtmes));
7160189Sdes  rtmes.m_rtm.rtm_version = RTM_VERSION;
7237608Sdes  rtmes.m_rtm.rtm_type = cmd;
7337535Sdes  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
7437535Sdes  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7537535Sdes  rtmes.m_rtm.rtm_seq = ++seqno;
7660376Sdes  rtmes.m_rtm.rtm_pid = getpid();
7737535Sdes  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
7837535Sdes
7937535Sdes  bzero(&rtdata, sizeof(rtdata));
8040939Sdes  rtdata.sin_len = 16;
8141862Sdes  rtdata.sin_family = AF_INET;
8237535Sdes  rtdata.sin_port = 0;
8363012Sdes  rtdata.sin_addr = dst;
8463012Sdes
8537535Sdes  cp = rtmes.m_space;
8663012Sdes  bcopy(&rtdata, cp, 16);
8763012Sdes  cp += 16;
8863012Sdes  if (gateway.s_addr) {
8963012Sdes    rtdata.sin_addr = gateway;
9063012Sdes    bcopy(&rtdata, cp, 16);
9163012Sdes    cp += 16;
9263012Sdes  }
9387317Sdes
9463012Sdes  if (dst.s_addr == INADDR_ANY)
9560196Sdes    mask.s_addr = INADDR_ANY;
9663012Sdes
9790267Sdes  lp = (u_long *)cp;
9890267Sdes
9963012Sdes  if (mask.s_addr) {
10088771Sdes    *lp++ = 8;
10163012Sdes    cp += sizeof(int);
10290267Sdes    *lp = mask.s_addr;
10363012Sdes  } else
10463012Sdes    *lp = 0;
10563012Sdes  cp += sizeof(u_long);
10663012Sdes
10797859Sdes  nb = cp - (char *)&rtmes;
10837535Sdes  rtmes.m_rtm.rtm_msglen = nb;
10997858Sdes  wb = write(s, &rtmes, nb);
11097866Sdes  if (wb < 0) {
11197858Sdes    perror("write");
11297866Sdes  }
11397866Sdes#ifdef DEBUG
11497866Sdes  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
11597858Sdes#endif
11697858Sdes  close(s);
11797858Sdes}
11863281Sdes
11990267Sdesstatic void
12063012Sdesp_sockaddr(sa, width)
12137535Sdesstruct sockaddr *sa;
12237535Sdesint width;
12337608Sdes{
12463012Sdes  register char *cp;
12537608Sdes  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
12637608Sdes
12797859Sdes  cp = (sin->sin_addr.s_addr == 0) ? "default" :
12837608Sdes	   inet_ntoa(sin->sin_addr);
12990267Sdes  printf("%-*.*s ", width, width, cp);
13090267Sdes}
13197859Sdes
13290267Sdesstruct bits {
13390267Sdes  short b_mask;
13497859Sdes  char  b_val;
13590267Sdes} bits[] = {
13690267Sdes  { RTF_UP,	  'U' },
13797859Sdes  { RTF_GATEWAY,  'G' },
13890267Sdes  { RTF_HOST,	  'H' },
13990267Sdes  { RTF_DYNAMIC,  'D' },
14090267Sdes  { RTF_MODIFIED, 'M' },
14190267Sdes  { RTF_CLONING,  'C' },
14290267Sdes  { RTF_XRESOLVE, 'X' },
14397859Sdes  { RTF_LLINFO,   'L' },
14490267Sdes  { RTF_REJECT,   'R' },
14590267Sdes  { 0 }
14697859Sdes};
14790267Sdes
14890267Sdesstatic void
14990267Sdesp_flags(f, format)
15090267Sdesregister int f;
15163281Sdeschar *format;
15290267Sdes{
15397859Sdes  char name[33], *flags;
15497859Sdes  register struct bits *p = bits;
155106207Sdes
15690267Sdes  for (flags = name; p->b_mask; p++)
157106207Sdes    if (p->b_mask & f)
158106207Sdes      *flags++ = p->b_val;
159106207Sdes  *flags = '\0';
16090267Sdes  printf(format, name);
16163012Sdes}
16290267Sdes
16397859Sdesint
16437608SdesShowRoute()
16537608Sdes{
16637608Sdes  struct rt_msghdr *rtm;
16797866Sdes  struct sockaddr *sa;
16897866Sdes  char *sp, *ep, *cp;
16997866Sdes  u_char *wp;
17097866Sdes  int *lp;
17197866Sdes  int needed, nb;
17297866Sdes  u_long mask;
17397866Sdes#if (BSD >= 199306)
17497866Sdes  int mib[6];
17597866Sdes#endif
17697866Sdes
17797866Sdes#if (BSD >= 199306)
17897866Sdes  mib[0] = CTL_NET;
17997866Sdes  mib[1] = PF_ROUTE;
18097866Sdes  mib[2] = 0;
181106044Sdes  mib[3] = 0;
18297866Sdes  mib[4] = NET_RT_DUMP;
18397866Sdes  mib[5] = 0;
18497866Sdes  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
18537608Sdes    perror("sysctl-estimate");
18637608Sdes    return(1);
18763012Sdes  }
18897866Sdes#else
18937535Sdes  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
19097859Sdes#endif
19190267Sdes  if (needed < 0)
19297859Sdes    return(1);
19390267Sdes  sp = malloc(needed);
19490267Sdes  if (sp == NULL)
19597866Sdes    return(1);
19697866Sdes#if (BSD >= 199306)
19797866Sdes  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
198106185Sdes    perror("sysctl-getroute");
199106185Sdes    return(1);
20097866Sdes  }
201106185Sdes#else
20297866Sdes  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
20397866Sdes    return(1);
20497866Sdes#endif
20597866Sdes  ep = sp + needed;
20697859Sdes
20797859Sdes  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
20890267Sdes    rtm = (struct rt_msghdr *)cp;
20997859Sdes    sa = (struct sockaddr *)(rtm + 1);
21090267Sdes    mask = 0xffffffff;
21190267Sdes    if (rtm->rtm_addrs == RTA_DST)
21297859Sdes      p_sockaddr(sa, 36);
21390267Sdes    else {
21490267Sdes      wp = (u_char *)cp + rtm->rtm_msglen;
21537535Sdes      p_sockaddr(sa, 16);
21663012Sdes      if (sa->sa_len == 0)
21797866Sdes	sa->sa_len = sizeof(long);
21897866Sdes      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
21997866Sdes      p_sockaddr(sa, 18);
22090267Sdes      lp = (int *)(sa->sa_len + (char *)sa);
221106185Sdes      if ((char *)lp < (char *)wp && *lp) {
222106185Sdes#ifdef DEBUG
22397866Sdes	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
224106185Sdes#endif
22597866Sdes	wp = (u_char *)(lp + 1);
22690267Sdes	mask = 0;
22797859Sdes	for (nb = *lp; nb > 4; nb--) {
22897856Sdes	  mask <<= 8;
22997856Sdes	  mask |= *wp++;
23097866Sdes	}
23197856Sdes	for (nb = 8 - *lp; nb > 0; nb--)
23290267Sdes	  mask <<= 8;
23390267Sdes      }
23490267Sdes    }
23597866Sdes    printf("%08x  ", mask);
23690267Sdes    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
23797866Sdes    printf("(%d)\n", rtm->rtm_index);
23837535Sdes  }
23937535Sdes
24037608Sdes  return(1);
24137608Sdes}
24237608Sdes
24337535Sdes/*
24463012Sdes *  Delete routes associated with our interface
24537535Sdes */
24697859Sdesvoid
24790267SdesDeleteIfRoutes(all)
24863012Sdesint all;
24997859Sdes{
25090267Sdes  struct rt_msghdr *rtm;
25197859Sdes  struct sockaddr *sa;
25290267Sdes  struct in_addr dstnet, gateway;
25363012Sdes  int needed;
25490267Sdes  char *sp, *cp, *ep;
25590267Sdes  u_long mask;
25697866Sdes  int *lp, nb;
25797866Sdes  u_char *wp;
25890267Sdes#if (BSD >= 199306)
25997866Sdes  int mib[6];
26090267Sdes#endif
26190267Sdes
26297866Sdes#ifdef DEBUG
26397866Sdes  logprintf("DeleteIfRoutes (%d)\n", IfIndex);
26490267Sdes#endif
26537535Sdes#if (BSD >= 199306)
26697859Sdes  mib[0] = CTL_NET;
26790267Sdes  mib[1] = PF_ROUTE;
26890267Sdes  mib[2] = 0;
26937535Sdes  mib[3] = 0;
27037535Sdes  mib[4] = NET_RT_DUMP;
27137608Sdes  mib[5] = 0;
27237608Sdes  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
27337608Sdes    perror("sysctl-estimate");
27437535Sdes    return;
27563012Sdes  }
27637535Sdes#else
27797859Sdes  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
27890267Sdes#endif
27997866Sdes
28037535Sdes  if (needed < 0)
28137535Sdes    return;
28237608Sdes
28337608Sdes  sp = malloc(needed);
28437608Sdes  if (sp == NULL)
28537535Sdes    return;
28663012Sdes
28737535Sdes#if (BSD >= 199306)
28897859Sdes  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
28990267Sdes    free(sp);
29063012Sdes    perror("sysctl-getroute");
29197859Sdes    return;
29297859Sdes  }
29397859Sdes#else
29497859Sdes  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
29590267Sdes    free(sp);
29637535Sdes    return;
29737535Sdes  }
29837608Sdes#endif
29963012Sdes  ep = sp + needed;
30037608Sdes
30163012Sdes  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
30297866Sdes    rtm = (struct rt_msghdr *)cp;
30337535Sdes    sa = (struct sockaddr *)(rtm + 1);
30497859Sdes#ifdef DEBUG
30590267Sdes    logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
30663012Sdes	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
30797859Sdes	((struct sockaddr_in *)sa)->sin_addr);
30890267Sdes#endif
30990267Sdes    if (rtm->rtm_addrs != RTA_DST &&
31090267Sdes       (rtm->rtm_index == IfIndex) &&
31197859Sdes       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
31297866Sdes      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
31397859Sdes      wp = (u_char *)cp + rtm->rtm_msglen;
31490267Sdes      if (sa->sa_len == 0)
31590267Sdes	sa->sa_len = sizeof(long);
31697859Sdes      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
31790267Sdes      gateway = ((struct sockaddr_in *)sa)->sin_addr;
31890267Sdes      lp = (int *)(sa->sa_len + (char *)sa);
31990267Sdes      mask = 0;
32063012Sdes      if ((char *)lp < (char *)wp && *lp) {
32163012Sdes#ifdef DEBUG
32290267Sdes	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
32363012Sdes#endif
32463012Sdes	wp = (u_char *)(lp + 1);
32563012Sdes	for (nb = *lp; nb > 4; nb--) {
32663012Sdes	  mask <<= 8;
32763012Sdes	  mask |= *wp++;
32863012Sdes	}
32990267Sdes	for (nb = 8 - *lp; nb > 0; nb--)
33090267Sdes	  mask <<= 8;
33190267Sdes      }
33290267Sdes#ifdef DEBUG
33390267Sdes      logprintf("## %s ", inet_ntoa(dstnet));
33490267Sdes      logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
33590267Sdes#endif
33690267Sdes      if (dstnet.s_addr == INADDR_ANY) {
33790267Sdes        gateway.s_addr = INADDR_ANY;
33890267Sdes        mask = INADDR_ANY;
33985093Sdes      }
34063012Sdes      OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask));
34163012Sdes    }
34263012Sdes#ifdef DEBUG
34390267Sdes    else if (rtm->rtm_index == IfIndex) {
34490267Sdes      logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
34563012Sdes    }
34690267Sdes#endif
34790267Sdes  }
34890267Sdes  free(sp);
34990267Sdes}
35090267Sdes
35190267Sdesint
35290267SdesGetIfIndex(name)
35363012Sdeschar *name;
35463012Sdes{
35563012Sdes  struct ifreq *ifrp;
35663012Sdes  int s, len, elen, index;
35763012Sdes  struct ifconf ifconfs;
35863012Sdes  struct ifreq reqbuf[32];
35997856Sdes
36063012Sdes  s = socket(AF_INET, SOCK_DGRAM, 0);
36190267Sdes  if (s < 0) {
36290267Sdes    perror("socket");
36390267Sdes    return(-1);
36490267Sdes  }
36563012Sdes
36690267Sdes  ifconfs.ifc_len = sizeof(reqbuf);
36790267Sdes  ifconfs.ifc_buf = (caddr_t)reqbuf;
36890267Sdes  if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
36990267Sdes    perror("IFCONF");
37090267Sdes    return(-1);
37190267Sdes  }
37290267Sdes
37390267Sdes  ifrp = ifconfs.ifc_req;
37490267Sdes
37590267Sdes  index = 1;
37697856Sdes  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
37790267Sdes    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
37890267Sdes    if (ifrp->ifr_addr.sa_family == AF_LINK) {
37990267Sdes#ifdef DEBUG
38090267Sdes      logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
38190267Sdes	   ifrp->ifr_addr.sa_family, elen);
38290267Sdes#endif
38390267Sdes      if (strcmp(ifrp->ifr_name, name) == 0) {
38490267Sdes        IfIndex = index;
38563012Sdes        return(index);
38663012Sdes      }
38763012Sdes      index++;
38863012Sdes    }
38963012Sdes
39063012Sdes    len -= elen;
39197856Sdes    ifrp = (struct ifreq *)((char *)ifrp + elen);
39263012Sdes    ifrp++;
39390267Sdes  }
39490267Sdes
39597856Sdes  close(s);
39690267Sdes  return(-1);
39790267Sdes}
39890267Sdes