route.c revision 13389
159290Sjlemon/*
259290Sjlemon *	      PPP Routing related Module
359290Sjlemon *
459290Sjlemon *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
559290Sjlemon *
659290Sjlemon *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
759290Sjlemon *
859290Sjlemon * Redistribution and use in source and binary forms are permitted
959290Sjlemon * provided that the above copyright notice and this paragraph are
1059290Sjlemon * duplicated in all such forms and that any documentation,
1159290Sjlemon * advertising materials, and other materials related to such
1259290Sjlemon * distribution and use acknowledge that the software was developed
1359290Sjlemon * by the Internet Initiative Japan, Inc.  The name of the
1459290Sjlemon * IIJ may not be used to endorse or promote products derived
1559290Sjlemon * from this software without specific prior written permission.
1659290Sjlemon * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1759290Sjlemon * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1859290Sjlemon * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1959290Sjlemon *
2059290Sjlemon * $Id: route.c,v 1.4 1995/07/08 06:08:52 amurai Exp $
2159290Sjlemon *
2259290Sjlemon */
2359290Sjlemon#include <sys/types.h>
2459290Sjlemon#include <machine/endian.h>
2559290Sjlemon#include <sys/param.h>
2659290Sjlemon#include <sys/socket.h>
2759290Sjlemon#include <net/route.h>
2859290Sjlemon#include <sys/ioctl.h>
2959290Sjlemon#include <net/if.h>
3059290Sjlemon#include <errno.h>
3159290Sjlemon#include <netinet/in_systm.h>
3259290Sjlemon#include <netinet/in.h>
3359290Sjlemon#include <arpa/inet.h>
3459290Sjlemon#if (BSD >= 199306)
3559290Sjlemon#include <sys/sysctl.h>
3659290Sjlemon#else
3759290Sjlemon#include <sys/kinfo.h>
3859290Sjlemon#endif
3959290Sjlemon#include <stdlib.h>
4059290Sjlemon#include <stdio.h>
4159290Sjlemon#include <string.h>
4259290Sjlemon#include <unistd.h>
4359290Sjlemon#include "log.h"
4459290Sjlemon
4559290Sjlemonstatic int IfIndex;
4659290Sjlemon
4759290Sjlemonstruct rtmsg {
4859290Sjlemon  struct rt_msghdr m_rtm;
4959290Sjlemon  char m_space[64];
5059290Sjlemon};
5159290Sjlemon
5259290Sjlemonstatic int seqno;
5359290Sjlemon
5459290Sjlemonvoid
5559290SjlemonOsSetRoute(cmd, dst, gateway, mask)
5659290Sjlemonint cmd;
5759290Sjlemonstruct in_addr dst;
5859290Sjlemonstruct in_addr gateway;
5959290Sjlemonstruct in_addr mask;
6059290Sjlemon{
6159290Sjlemon  struct rtmsg rtmes;
6259290Sjlemon  int s, nb, wb;
6359290Sjlemon  char *cp;
6459290Sjlemon  u_long *lp;
6559290Sjlemon  struct sockaddr_in rtdata;
6659290Sjlemon
6759290Sjlemon  s = socket(PF_ROUTE, SOCK_RAW, 0);
6859290Sjlemon  if (s < 0)
6959290Sjlemon    logprintf("socket\n");
7059290Sjlemon
7159290Sjlemon  bzero(&rtmes, sizeof(rtmes));
7259290Sjlemon  rtmes.m_rtm.rtm_version = RTM_VERSION;
7359290Sjlemon  rtmes.m_rtm.rtm_type = cmd;
7459290Sjlemon  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
7559290Sjlemon  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7659290Sjlemon  rtmes.m_rtm.rtm_seq = ++seqno;
7759290Sjlemon  rtmes.m_rtm.rtm_pid = getpid();
7859290Sjlemon  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
7959290Sjlemon
8059290Sjlemon  bzero(&rtdata, sizeof(rtdata));
8159290Sjlemon  rtdata.sin_len = 16;
8259290Sjlemon  rtdata.sin_family = AF_INET;
8359290Sjlemon  rtdata.sin_port = 0;
8459290Sjlemon  rtdata.sin_addr = dst;
8559290Sjlemon
8659290Sjlemon  cp = rtmes.m_space;
8759290Sjlemon  bcopy(&rtdata, cp, 16);
8859290Sjlemon  cp += 16;
8959290Sjlemon  if (gateway.s_addr) {
9059290Sjlemon    rtdata.sin_addr = gateway;
9159290Sjlemon    bcopy(&rtdata, cp, 16);
9259290Sjlemon    cp += 16;
9359290Sjlemon  }
9459290Sjlemon
9559290Sjlemon  if (dst.s_addr == INADDR_ANY)
9659290Sjlemon    mask.s_addr = INADDR_ANY;
9759290Sjlemon
9859290Sjlemon  lp = (u_long *)cp;
9959290Sjlemon
10059290Sjlemon  if (mask.s_addr) {
10159290Sjlemon    *lp++ = 8;
10259290Sjlemon    cp += sizeof(int);
10359290Sjlemon    *lp = mask.s_addr;
10459290Sjlemon  } else
10559290Sjlemon    *lp = 0;
10659290Sjlemon  cp += sizeof(u_long);
10759290Sjlemon
10859290Sjlemon  nb = cp - (char *)&rtmes;
10959290Sjlemon  rtmes.m_rtm.rtm_msglen = nb;
11059290Sjlemon  wb = write(s, &rtmes, nb);
11159290Sjlemon  if (wb < 0) {
11259290Sjlemon     LogPrintf(LOG_TCPIP, "Already set route addr dst=%x, gateway=%x\n"
11359290Sjlemon         ,dst.s_addr, gateway.s_addr);
11459290Sjlemon  }
11559290Sjlemon#ifdef DEBUG
11659290Sjlemon  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
11759290Sjlemon#endif
11859290Sjlemon  close(s);
11959290Sjlemon}
12059290Sjlemon
12159290Sjlemonstatic void
12259290Sjlemonp_sockaddr(sa, width)
12359290Sjlemonstruct sockaddr *sa;
12459290Sjlemonint width;
12559290Sjlemon{
12659290Sjlemon  register char *cp;
12759290Sjlemon  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
12859290Sjlemon
12959290Sjlemon  cp = (sin->sin_addr.s_addr == 0) ? "default" :
13059290Sjlemon	   inet_ntoa(sin->sin_addr);
13159290Sjlemon  printf("%-*.*s ", width, width, cp);
13259290Sjlemon}
13359290Sjlemon
13459290Sjlemonstruct bits {
13559290Sjlemon  short b_mask;
13659290Sjlemon  char  b_val;
13759290Sjlemon} bits[] = {
13859290Sjlemon  { RTF_UP,	  'U' },
13959290Sjlemon  { RTF_GATEWAY,  'G' },
14059290Sjlemon  { RTF_HOST,	  'H' },
14159290Sjlemon  { RTF_DYNAMIC,  'D' },
14259290Sjlemon  { RTF_MODIFIED, 'M' },
14359290Sjlemon  { RTF_CLONING,  'C' },
14459290Sjlemon  { RTF_XRESOLVE, 'X' },
14559290Sjlemon  { RTF_LLINFO,   'L' },
14659290Sjlemon  { RTF_REJECT,   'R' },
14759290Sjlemon  { 0 }
14859290Sjlemon};
14959290Sjlemon
15059290Sjlemonstatic void
15159290Sjlemonp_flags(f, format)
15259290Sjlemonregister int f;
15359290Sjlemonchar *format;
15459290Sjlemon{
15559290Sjlemon  char name[33], *flags;
15659290Sjlemon  register struct bits *p = bits;
15759290Sjlemon
15859290Sjlemon  for (flags = name; p->b_mask; p++)
15959290Sjlemon    if (p->b_mask & f)
16059290Sjlemon      *flags++ = p->b_val;
16159290Sjlemon  *flags = '\0';
16259290Sjlemon  printf(format, name);
16359290Sjlemon}
16459290Sjlemon
16559290Sjlemonint
16659290SjlemonShowRoute()
16759290Sjlemon{
16859290Sjlemon  struct rt_msghdr *rtm;
16959290Sjlemon  struct sockaddr *sa;
17059290Sjlemon  char *sp, *ep, *cp;
17159290Sjlemon  u_char *wp;
17259290Sjlemon  int *lp;
17359290Sjlemon  int needed, nb;
17459290Sjlemon  u_long mask;
17559290Sjlemon#if (BSD >= 199306)
17659290Sjlemon  int mib[6];
17759290Sjlemon#endif
17859290Sjlemon
17959290Sjlemon#if (BSD >= 199306)
18059290Sjlemon  mib[0] = CTL_NET;
18159290Sjlemon  mib[1] = PF_ROUTE;
18259290Sjlemon  mib[2] = 0;
18359290Sjlemon  mib[3] = 0;
18459290Sjlemon  mib[4] = NET_RT_DUMP;
18559290Sjlemon  mib[5] = 0;
18659290Sjlemon  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
18759290Sjlemon    perror("sysctl-estimate");
18859290Sjlemon    return(1);
18959290Sjlemon  }
19059290Sjlemon#else
19159290Sjlemon  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
19259290Sjlemon#endif
19359290Sjlemon  if (needed < 0)
19459290Sjlemon    return(1);
19559290Sjlemon  sp = malloc(needed);
19659290Sjlemon  if (sp == NULL)
19759290Sjlemon    return(1);
19859290Sjlemon#if (BSD >= 199306)
19959290Sjlemon  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
20059290Sjlemon    perror("sysctl-getroute");
20159290Sjlemon    return(1);
20259290Sjlemon  }
20359290Sjlemon#else
20459290Sjlemon  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
20559290Sjlemon    return(1);
20659290Sjlemon#endif
20759290Sjlemon  ep = sp + needed;
20859290Sjlemon
20959290Sjlemon  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
21059290Sjlemon    rtm = (struct rt_msghdr *)cp;
21159290Sjlemon    sa = (struct sockaddr *)(rtm + 1);
21259290Sjlemon    mask = 0xffffffff;
21359290Sjlemon    if (rtm->rtm_addrs == RTA_DST)
21459290Sjlemon      p_sockaddr(sa, 36);
21559290Sjlemon    else {
21659290Sjlemon      wp = (u_char *)cp + rtm->rtm_msglen;
21759290Sjlemon      p_sockaddr(sa, 16);
21859290Sjlemon      if (sa->sa_len == 0)
21959290Sjlemon	sa->sa_len = sizeof(long);
22059290Sjlemon      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
22159290Sjlemon      p_sockaddr(sa, 18);
22259290Sjlemon      lp = (int *)(sa->sa_len + (char *)sa);
22359290Sjlemon      if ((char *)lp < (char *)wp && *lp) {
22459290Sjlemon#ifdef DEBUG
22559290Sjlemon	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
22659290Sjlemon#endif
22759290Sjlemon	wp = (u_char *)(lp + 1);
22859290Sjlemon	mask = 0;
22959290Sjlemon	for (nb = *lp; nb > 4; nb--) {
23059290Sjlemon	  mask <<= 8;
23159290Sjlemon	  mask |= *wp++;
23259290Sjlemon	}
23359290Sjlemon	for (nb = 8 - *lp; nb > 0; nb--)
23459290Sjlemon	  mask <<= 8;
23559290Sjlemon      }
23659290Sjlemon    }
23759290Sjlemon    printf("%08lx  ", mask);
23859290Sjlemon    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
23959290Sjlemon    printf("(%d)\n", rtm->rtm_index);
24059290Sjlemon  }
24159290Sjlemon
24259290Sjlemon  return(1);
24359290Sjlemon}
24459290Sjlemon
24559290Sjlemon/*
24659290Sjlemon *  Delete routes associated with our interface
24759290Sjlemon */
24859290Sjlemonvoid
24959290SjlemonDeleteIfRoutes(all)
25059290Sjlemonint all;
25159290Sjlemon{
25259290Sjlemon  struct rt_msghdr *rtm;
25359290Sjlemon  struct sockaddr *sa;
25459290Sjlemon  struct in_addr dstnet, gateway;
25559290Sjlemon  int needed;
25659290Sjlemon  char *sp, *cp, *ep;
25759290Sjlemon  u_long mask;
25859290Sjlemon  int *lp, nb;
25959290Sjlemon  u_char *wp;
26059290Sjlemon#if (BSD >= 199306)
26159290Sjlemon  int mib[6];
26259290Sjlemon#endif
26359290Sjlemon
26459290Sjlemon#ifdef DEBUG
26559290Sjlemon  logprintf("DeleteIfRoutes (%d)\n", IfIndex);
26659290Sjlemon#endif
26759290Sjlemon#if (BSD >= 199306)
26859290Sjlemon  mib[0] = CTL_NET;
26959290Sjlemon  mib[1] = PF_ROUTE;
27059290Sjlemon  mib[2] = 0;
27159290Sjlemon  mib[3] = 0;
27259290Sjlemon  mib[4] = NET_RT_DUMP;
27359290Sjlemon  mib[5] = 0;
27459290Sjlemon  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
27559290Sjlemon    perror("sysctl-estimate");
27659290Sjlemon    return;
27759290Sjlemon  }
27859290Sjlemon#else
27959290Sjlemon  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
28059290Sjlemon#endif
28159290Sjlemon
28259290Sjlemon  if (needed < 0)
28359290Sjlemon    return;
28459290Sjlemon
28559290Sjlemon  sp = malloc(needed);
28659290Sjlemon  if (sp == NULL)
28759290Sjlemon    return;
28859290Sjlemon
28959290Sjlemon#if (BSD >= 199306)
29059290Sjlemon  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
29159290Sjlemon    free(sp);
29259290Sjlemon    perror("sysctl-getroute");
29359290Sjlemon    return;
29459290Sjlemon  }
29559290Sjlemon#else
29659290Sjlemon  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
29759290Sjlemon    free(sp);
29859290Sjlemon    return;
29959290Sjlemon  }
30059290Sjlemon#endif
30159290Sjlemon  ep = sp + needed;
30259290Sjlemon
30359290Sjlemon  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
30459290Sjlemon    rtm = (struct rt_msghdr *)cp;
30559290Sjlemon    sa = (struct sockaddr *)(rtm + 1);
30659290Sjlemon#ifdef DEBUG
30759290Sjlemon    logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
30859290Sjlemon	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
30959290Sjlemon	((struct sockaddr_in *)sa)->sin_addr);
31059290Sjlemon#endif
31159290Sjlemon    if (rtm->rtm_addrs != RTA_DST &&
31259290Sjlemon       (rtm->rtm_index == IfIndex) &&
31359290Sjlemon       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
31459290Sjlemon      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
31559290Sjlemon      wp = (u_char *)cp + rtm->rtm_msglen;
31659290Sjlemon      if (sa->sa_len == 0)
31759290Sjlemon	sa->sa_len = sizeof(long);
31859290Sjlemon      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
31959290Sjlemon      gateway = ((struct sockaddr_in *)sa)->sin_addr;
32059290Sjlemon      lp = (int *)(sa->sa_len + (char *)sa);
32159290Sjlemon      mask = 0;
32259290Sjlemon      if ((char *)lp < (char *)wp && *lp) {
32359290Sjlemon#ifdef DEBUG
32459290Sjlemon	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
32559290Sjlemon#endif
32659290Sjlemon	wp = (u_char *)(lp + 1);
32759290Sjlemon	for (nb = *lp; nb > 4; nb--) {
32859290Sjlemon	  mask <<= 8;
32959290Sjlemon	  mask |= *wp++;
33059290Sjlemon	}
33159290Sjlemon	for (nb = 8 - *lp; nb > 0; nb--)
33259290Sjlemon	  mask <<= 8;
33359290Sjlemon      }
33459290Sjlemon#ifdef DEBUG
33559290Sjlemon      logprintf("## %s ", inet_ntoa(dstnet));
33659290Sjlemon      logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
33759290Sjlemon#endif
33859290Sjlemon      if (dstnet.s_addr == INADDR_ANY) {
33959290Sjlemon        gateway.s_addr = INADDR_ANY;
34059290Sjlemon        mask = INADDR_ANY;
34159290Sjlemon      }
34259290Sjlemon      OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask));
34359290Sjlemon    }
34459290Sjlemon#ifdef DEBUG
34559290Sjlemon    else if (rtm->rtm_index == IfIndex) {
34659290Sjlemon      logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
34759290Sjlemon    }
34859290Sjlemon#endif
34959290Sjlemon  }
35059290Sjlemon  free(sp);
35159290Sjlemon}
35259290Sjlemon
35359290Sjlemonint
35459290SjlemonGetIfIndex(name)
35559290Sjlemonchar *name;
35659290Sjlemon{
35759290Sjlemon  struct ifreq *ifrp;
35859290Sjlemon  int s, len, elen, index;
35959290Sjlemon  struct ifconf ifconfs;
36059290Sjlemon  struct ifreq reqbuf[32];
36159290Sjlemon
36259290Sjlemon  s = socket(AF_INET, SOCK_DGRAM, 0);
36359290Sjlemon  if (s < 0) {
36459290Sjlemon    perror("socket");
36559290Sjlemon    return(-1);
36659290Sjlemon  }
36759290Sjlemon
36859290Sjlemon  ifconfs.ifc_len = sizeof(reqbuf);
36959290Sjlemon  ifconfs.ifc_buf = (caddr_t)reqbuf;
37059290Sjlemon  if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
37159290Sjlemon    perror("IFCONF");
37259290Sjlemon    return(-1);
37359290Sjlemon  }
37459290Sjlemon
37559290Sjlemon  ifrp = ifconfs.ifc_req;
37659290Sjlemon
37759290Sjlemon  index = 1;
37859290Sjlemon  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
37959290Sjlemon    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
38059290Sjlemon    if (ifrp->ifr_addr.sa_family == AF_LINK) {
38159290Sjlemon#ifdef DEBUG
38259290Sjlemon      logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
38359290Sjlemon	   ifrp->ifr_addr.sa_family, elen);
38459290Sjlemon#endif
38559290Sjlemon      if (strcmp(ifrp->ifr_name, name) == 0) {
38659290Sjlemon        IfIndex = index;
38759290Sjlemon        return(index);
38859290Sjlemon      }
38959290Sjlemon      index++;
39059290Sjlemon    }
39159290Sjlemon
39259290Sjlemon    len -= elen;
39359290Sjlemon    ifrp = (struct ifreq *)((char *)ifrp + elen);
39459290Sjlemon    ifrp++;
39559290Sjlemon  }
39659290Sjlemon
39759290Sjlemon  close(s);
39859290Sjlemon  return(-1);
39959290Sjlemon}
40059290Sjlemon