route.c revision 31061
1139749Simp/*
265312Smsmith *	      PPP Routing related Module
365312Smsmith *
465312Smsmith *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
565312Smsmith *
665312Smsmith *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
765312Smsmith *
865312Smsmith * Redistribution and use in source and binary forms are permitted
965312Smsmith * provided that the above copyright notice and this paragraph are
1065312Smsmith * duplicated in all such forms and that any documentation,
1165312Smsmith * advertising materials, and other materials related to such
1265312Smsmith * distribution and use acknowledge that the software was developed
1365312Smsmith * by the Internet Initiative Japan, Inc.  The name of the
1465312Smsmith * IIJ may not be used to endorse or promote products derived
1565312Smsmith * from this software without specific prior written permission.
1665312Smsmith * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1765312Smsmith * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1865312Smsmith * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1965312Smsmith *
2065312Smsmith * $Id: route.c,v 1.22 1997/11/09 03:22:49 brian Exp $
2187826Sobrien *
2265312Smsmith */
2365312Smsmith
2496554Sobrien#include <sys/param.h>
2596554Sobrien#include <sys/time.h>
2665312Smsmith#include <sys/socket.h>
2765312Smsmith#include <net/route.h>
2865312Smsmith#include <net/if.h>
2965312Smsmith#include <netinet/in_systm.h>
3065312Smsmith#include <netinet/in.h>
3165312Smsmith#include <arpa/inet.h>
3296554Sobrien
3365312Smsmith#include <errno.h>
3465312Smsmith#include <machine/endian.h>
3565312Smsmith#include <stdio.h>
3665312Smsmith#include <stdlib.h>
3796554Sobrien#include <string.h>
3896554Sobrien#include <sys/ioctl.h>
3996554Sobrien#include <sys/sysctl.h>
4096554Sobrien#include <unistd.h>
4165312Smsmith
4296554Sobrien#include "mbuf.h"
4396554Sobrien#include "log.h"
4465312Smsmith#include "loadalias.h"
4565312Smsmith#include "command.h"
4665312Smsmith#include "vars.h"
4765312Smsmith#include "id.h"
4865312Smsmith#include "route.h"
4965312Smsmith
5065312Smsmithstatic int IfIndex;
5165312Smsmith
5265312Smsmithstruct rtmsg {
5365312Smsmith  struct rt_msghdr m_rtm;
5465312Smsmith  char m_space[64];
5565312Smsmith};
5665312Smsmith
5765312Smsmithstatic int seqno;
5865312Smsmith
5996554Sobrienvoid
6096554SobrienOsSetRoute(int cmd,
6196554Sobrien	   struct in_addr dst,
6296554Sobrien	   struct in_addr gateway,
6396554Sobrien	   struct in_addr mask)
6496554Sobrien{
6596554Sobrien  struct rtmsg rtmes;
6696554Sobrien  int s, nb, wb;
6796554Sobrien  char *cp, *cmdstr;
6896554Sobrien  u_long *lp;
6996554Sobrien  struct sockaddr_in rtdata;
7065312Smsmith
7165312Smsmith  cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
7265312Smsmith  s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
7365312Smsmith  if (s < 0) {
7465312Smsmith    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
7596551Sobrien    return;
7696551Sobrien  }
7796551Sobrien  memset(&rtmes, '\0', sizeof(rtmes));
7865312Smsmith  rtmes.m_rtm.rtm_version = RTM_VERSION;
7965312Smsmith  rtmes.m_rtm.rtm_type = cmd;
8096554Sobrien  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
8165312Smsmith  rtmes.m_rtm.rtm_seq = ++seqno;
8265312Smsmith  rtmes.m_rtm.rtm_pid = getpid();
8396554Sobrien  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
8465312Smsmith
8596554Sobrien  memset(&rtdata, '\0', sizeof(rtdata));
8665312Smsmith  rtdata.sin_len = 16;
8765312Smsmith  rtdata.sin_family = AF_INET;
8896554Sobrien  rtdata.sin_port = 0;
8965312Smsmith  rtdata.sin_addr = dst;
9065312Smsmith
9165312Smsmith  cp = rtmes.m_space;
9296551Sobrien  memcpy(cp, &rtdata, 16);
9365312Smsmith  cp += 16;
9465312Smsmith  if (gateway.s_addr) {
9565312Smsmith    rtdata.sin_addr = gateway;
9696551Sobrien    memcpy(cp, &rtdata, 16);
9765312Smsmith    cp += 16;
9865312Smsmith    rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
9965312Smsmith  }
10096551Sobrien  if (dst.s_addr == INADDR_ANY)
10165312Smsmith    mask.s_addr = INADDR_ANY;
10265312Smsmith
10365312Smsmith  lp = (u_long *) cp;
10496554Sobrien
10565312Smsmith  if (mask.s_addr) {
10665312Smsmith    *lp++ = 8;
10765312Smsmith    cp += sizeof(int);
10865312Smsmith    *lp = mask.s_addr;
10965312Smsmith  } else
11065312Smsmith    *lp = 0;
11196614Sobrien  cp += sizeof(u_long);
11296551Sobrien
11365312Smsmith  nb = cp - (char *) &rtmes;
11496551Sobrien  rtmes.m_rtm.rtm_msglen = nb;
11565312Smsmith  wb = write(s, &rtmes, nb);
11665312Smsmith  if (wb < 0) {
11796614Sobrien    LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
11896551Sobrien    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
11965312Smsmith    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
12065312Smsmith    switch (rtmes.m_rtm.rtm_errno) {
12196614Sobrien    case EEXIST:
12296614Sobrien      LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
12396551Sobrien      break;
12465312Smsmith    case ESRCH:
12565312Smsmith      LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
12696614Sobrien      break;
12796551Sobrien    case 0:
12865312Smsmith      LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno));
12965312Smsmith      break;
13096614Sobrien    case ENOBUFS:
13196551Sobrien    default:
13265312Smsmith      LogPrintf(LogTCPIP, "%s route failed: %s\n",
13365312Smsmith		cmdstr, strerror(rtmes.m_rtm.rtm_errno));
13496614Sobrien      break;
13596551Sobrien    }
13665312Smsmith  }
13765312Smsmith  LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
13865312Smsmith            wb, cmdstr, dst.s_addr, gateway.s_addr);
13965312Smsmith  close(s);
14096554Sobrien}
14196614Sobrien
14296614Sobrienstatic void
14396614Sobrienp_sockaddr(struct sockaddr * sa, int width)
14496554Sobrien{
14565312Smsmith  if (VarTerm) {
14665312Smsmith    register char *cp;
14765312Smsmith    register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa;
14865312Smsmith
14965312Smsmith    cp = (sock_in->sin_addr.s_addr == 0) ? "default" :
15096554Sobrien      inet_ntoa(sock_in->sin_addr);
15196551Sobrien    fprintf(VarTerm, "%-*.*s ", width, width, cp);
15265312Smsmith  }
15396551Sobrien}
15465312Smsmith
15565312Smsmithstruct bits {
15665312Smsmith  short b_mask;
15796554Sobrien  char b_val;
15896554Sobrien}    bits[] = {
15965312Smsmith
16096554Sobrien  {
16196554Sobrien    RTF_UP, 'U'
16265312Smsmith  },
16396554Sobrien  {
16496554Sobrien    RTF_GATEWAY, 'G'
16596554Sobrien  },
16696554Sobrien  {
16765312Smsmith    RTF_HOST, 'H'
16896554Sobrien  },
16965312Smsmith  {
17096614Sobrien    RTF_DYNAMIC, 'D'
17196614Sobrien  },
17296551Sobrien  {
17396551Sobrien    RTF_MODIFIED, 'M'
17465312Smsmith  },
17596551Sobrien  {
17696551Sobrien    RTF_CLONING, 'C'
17765312Smsmith  },
17896554Sobrien  {
17965312Smsmith    RTF_XRESOLVE, 'X'
18065312Smsmith  },
18165312Smsmith  {
18265312Smsmith    RTF_LLINFO, 'L'
18365312Smsmith  },
18465312Smsmith  {
18596614Sobrien    RTF_REJECT, 'R'
18696551Sobrien  },
18796551Sobrien  {
18865312Smsmith    0
18965312Smsmith  }
19065312Smsmith};
19196551Sobrien
19265312Smsmithstatic void
19365312Smsmithp_flags(int f, char *format)
19496554Sobrien{
19565312Smsmith  if (VarTerm) {
19665312Smsmith    char name[33], *flags;
19765312Smsmith    register struct bits *p = bits;
19896554Sobrien
19996554Sobrien    for (flags = name; p->b_mask; p++)
20096554Sobrien      if (p->b_mask & f)
20165312Smsmith	*flags++ = p->b_val;
20265312Smsmith    *flags = '\0';
20365312Smsmith    fprintf(VarTerm, format, name);
20496614Sobrien  }
20596551Sobrien}
20665312Smsmith
20765312Smsmithint
20865312SmsmithShowRoute()
20965312Smsmith{
21065312Smsmith  struct rt_msghdr *rtm;
21196554Sobrien  struct sockaddr *sa;
21296554Sobrien  char *sp, *ep, *cp;
21365312Smsmith  u_char *wp;
21465312Smsmith  int *lp;
21565312Smsmith  int needed, nb;
21665312Smsmith  u_long mask;
21765312Smsmith  int mib[6];
21865312Smsmith
21965312Smsmith  if (!VarTerm)
22065312Smsmith    return 1;
22196554Sobrien
22296554Sobrien  mib[0] = CTL_NET;
22365312Smsmith  mib[1] = PF_ROUTE;
22465312Smsmith  mib[2] = 0;
22565312Smsmith  mib[3] = 0;
22696554Sobrien  mib[4] = NET_RT_DUMP;
22796554Sobrien  mib[5] = 0;
22865312Smsmith  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
22965312Smsmith    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
23096554Sobrien    return (1);
23165312Smsmith  }
23265312Smsmith  if (needed < 0)
23365312Smsmith    return (1);
23465312Smsmith  sp = malloc(needed);
23565312Smsmith  if (sp == NULL)
23665312Smsmith    return (1);
23765312Smsmith  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
23896551Sobrien    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
23987816Sjhb    free(sp);
24065312Smsmith    return (1);
24165312Smsmith  }
24265312Smsmith  ep = sp + needed;
24396554Sobrien
24496554Sobrien  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
24565312Smsmith    rtm = (struct rt_msghdr *) cp;
24665312Smsmith    sa = (struct sockaddr *) (rtm + 1);
24796554Sobrien    mask = 0xffffffff;
24865312Smsmith    if (rtm->rtm_addrs == RTA_DST)
24996554Sobrien      p_sockaddr(sa, 36);
25096554Sobrien    else {
25165312Smsmith      wp = (u_char *) cp + rtm->rtm_msglen;
25296554Sobrien      p_sockaddr(sa, 16);
25365312Smsmith      if (sa->sa_len == 0)
25465312Smsmith	sa->sa_len = sizeof(long);
25565312Smsmith      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
25696554Sobrien      p_sockaddr(sa, 18);
25796554Sobrien      lp = (int *) (sa->sa_len + (char *) sa);
25865312Smsmith      if ((char *) lp < (char *) wp && *lp) {
25965312Smsmith	LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp);
26096554Sobrien	wp = (u_char *) (lp + 1);
26165312Smsmith	mask = 0;
26265312Smsmith	for (nb = *(char *) lp; nb > 4; nb--) {
26365312Smsmith	  mask <<= 8;
26465312Smsmith	  mask |= *wp++;
26596615Sobrien	}
26696554Sobrien	for (nb = 8 - *(char *) lp; nb > 0; nb--)
26765312Smsmith	  mask <<= 8;
26865312Smsmith      }
26965312Smsmith    }
27096614Sobrien    fprintf(VarTerm, "%08lx  ", mask);
27165312Smsmith    p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
27287816Sjhb    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
27365312Smsmith  }
27465312Smsmith  free(sp);
27596615Sobrien  return 0;
27696554Sobrien}
27765312Smsmith
27865312Smsmith/*
27996615Sobrien *  Delete routes associated with our interface
28096554Sobrien */
28165312Smsmithvoid
28265312SmsmithDeleteIfRoutes(int all)
28365312Smsmith{
28465312Smsmith  struct rt_msghdr *rtm;
28565312Smsmith  struct sockaddr *sa;
28665312Smsmith  struct in_addr dstnet, gateway, maddr;
28796615Sobrien  int needed;
28896554Sobrien  char *sp, *cp, *ep;
28965312Smsmith  u_long mask;
29065312Smsmith  int *lp, nb;
29196615Sobrien  u_char *wp;
29296554Sobrien  int mib[6];
29365312Smsmith
29496554Sobrien  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
29565312Smsmith
29665312Smsmith  mib[0] = CTL_NET;
29765312Smsmith  mib[1] = PF_ROUTE;
29865312Smsmith  mib[2] = 0;
29965312Smsmith  mib[3] = 0;
30065312Smsmith  mib[4] = NET_RT_DUMP;
30165312Smsmith  mib[5] = 0;
30265312Smsmith  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
30396554Sobrien    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
30465312Smsmith	      strerror(errno));
30596554Sobrien    return;
30665312Smsmith  }
30796554Sobrien  if (needed < 0)
30865312Smsmith    return;
30965312Smsmith
31065312Smsmith  sp = malloc(needed);
31165312Smsmith  if (sp == NULL)
31265312Smsmith    return;
31365312Smsmith
31496554Sobrien  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
31565312Smsmith    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
31696554Sobrien	      strerror(errno));
31765312Smsmith    free(sp);
31896554Sobrien    return;
31965312Smsmith  }
32096554Sobrien  ep = sp + needed;
32165312Smsmith
32265312Smsmith  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
32396554Sobrien    rtm = (struct rt_msghdr *) cp;
32465312Smsmith    sa = (struct sockaddr *) (rtm + 1);
32596554Sobrien    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
32665312Smsmith	      " dstnet: %s\n",
32796554Sobrien	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
328108533Sschweikh	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
32996554Sobrien    if (rtm->rtm_addrs != RTA_DST &&
33065312Smsmith	(rtm->rtm_index == IfIndex) &&
33196554Sobrien	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
33265312Smsmith      LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
33396554Sobrien      dstnet = ((struct sockaddr_in *) sa)->sin_addr;
33465312Smsmith      wp = (u_char *) cp + rtm->rtm_msglen;
33565312Smsmith      if (sa->sa_len == 0)
33665312Smsmith	sa->sa_len = sizeof(long);
33765312Smsmith      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
33865312Smsmith      gateway = ((struct sockaddr_in *) sa)->sin_addr;
33965312Smsmith      lp = (int *) (sa->sa_len + (char *) sa);
34065312Smsmith      mask = 0;
34196554Sobrien      if ((char *) lp < (char *) wp && *lp) {
34265312Smsmith	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n",
34365312Smsmith		  rtm->rtm_flags, *lp);
34496554Sobrien	wp = (u_char *) (lp + 1);
34565312Smsmith	for (nb = *lp; nb > 4; nb--) {
34665312Smsmith	  mask <<= 8;
34765312Smsmith	  mask |= *wp++;
34865312Smsmith	}
34965312Smsmith	for (nb = 8 - *lp; nb > 0; nb--)
35065312Smsmith	  mask <<= 8;
35165312Smsmith      }
35265312Smsmith      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
35365312Smsmith      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
35465312Smsmith      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
35596615Sobrien      if (dstnet.s_addr == INADDR_ANY)
35696615Sobrien	mask = INADDR_ANY;
35796615Sobrien      maddr.s_addr = htonl(mask);
35865312Smsmith      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
35965312Smsmith    }
36065312Smsmith  }
36165312Smsmith  free(sp);
36296554Sobrien}
36365312Smsmith
36465312Smsmith /*
36596554Sobrien  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
366  */
367
368int
369GetIfIndex(char *name)
370{
371  char *buffer;
372  struct ifreq *ifrp;
373  int s, len, elen, newIfIndex;
374  struct ifconf ifconfs;
375
376  /* struct ifreq reqbuf[256]; -- obsoleted :) */
377  int oldbufsize, bufsize = sizeof(struct ifreq);
378
379  s = socket(AF_INET, SOCK_DGRAM, 0);
380  if (s < 0) {
381    LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno));
382    return (-1);
383  }
384  buffer = malloc(bufsize);	/* allocate first buffer */
385  ifconfs.ifc_len = bufsize;	/* Initial setting */
386
387  /*
388   * Iterate through here until we don't get many more data
389   */
390
391  do {
392    oldbufsize = ifconfs.ifc_len;
393    bufsize += 1 + sizeof(struct ifreq);
394    buffer = realloc((void *) buffer, bufsize);	/* Make it bigger */
395    LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
396    ifconfs.ifc_len = bufsize;
397    ifconfs.ifc_buf = buffer;
398    if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
399      LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n",
400		strerror(errno));
401      close(s);
402      free(buffer);
403      return (-1);
404    }
405  } while (ifconfs.ifc_len > oldbufsize);
406
407  ifrp = ifconfs.ifc_req;
408
409  newIfIndex = 1;
410  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
411    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
412    if (ifrp->ifr_addr.sa_family == AF_LINK) {
413      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
414		newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
415		ifrp->ifr_addr.sa_family, elen);
416      if (strcmp(ifrp->ifr_name, name) == 0) {
417	IfIndex = newIfIndex;
418	close(s);
419	free(buffer);
420	return (newIfIndex);
421      }
422      newIfIndex++;
423    }
424    len -= elen;
425    ifrp = (struct ifreq *) ((char *) ifrp + elen);
426    ifrp++;
427  }
428
429  close(s);
430  free(buffer);
431  return (-1);
432}
433