route.c revision 28974
159290Sjlemon/*
272969Sjlemon *	      PPP Routing related Module
3133741Sjmg *
4197240Ssson *	    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.18 1997/08/25 00:29:26 brian Exp $
2159290Sjlemon *
2259290Sjlemon */
2359290Sjlemon#include <sys/types.h>
2459290Sjlemon#include <machine/endian.h>
2559290Sjlemon#include <sys/ioctl.h>
2659290Sjlemon#include <sys/param.h>
2759290Sjlemon#include <sys/socket.h>
2859290Sjlemon#include <sys/sysctl.h>
29116182Sobrien#include <sys/time.h>
30116182Sobrien
31116182Sobrien#include <errno.h>
32162592Sjmg#include <stdlib.h>
33162592Sjmg#include <stdio.h>
3459290Sjlemon#include <string.h>
3559290Sjlemon#include <unistd.h>
36224778Srwatson
3759290Sjlemon#include <net/route.h>
3876166Smarkm#include <net/if.h>
3976166Smarkm#include <netinet/in_systm.h>
40233505Smelifaro#include <netinet/in.h>
4159290Sjlemon#include <arpa/inet.h>
42132138Salfred
4359290Sjlemon#include "log.h"
4459290Sjlemon#include "loadalias.h"
45108524Salfred#include "vars.h"
46132138Salfred
4759290Sjlemonstatic int IfIndex;
48133741Sjmg
4970834Swollmanstruct rtmsg {
5059290Sjlemon  struct rt_msghdr m_rtm;
5159290Sjlemon  char m_space[64];
5259290Sjlemon};
5359290Sjlemon
5459290Sjlemonstatic int seqno;
55132138Salfred
56132138Salfredvoid
5759290SjlemonOsSetRoute(int cmd,
5859290Sjlemon	   struct in_addr dst,
5959290Sjlemon	   struct in_addr gateway,
6084138Sjlemon	   struct in_addr mask)
6159290Sjlemon{
62142934Sps  struct rtmsg rtmes;
63133741Sjmg  int s, nb, wb;
6459290Sjlemon  char *cp;
65162592Sjmg  u_long *lp;
66162592Sjmg  struct sockaddr_in rtdata;
67162592Sjmg
6859290Sjlemon  s = socket(PF_ROUTE, SOCK_RAW, 0);
6992751Sjeff  if (s < 0) {
7059290Sjlemon    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
71141616Sphk    return;
72141616Sphk  }
73133741Sjmg  bzero(&rtmes, sizeof(rtmes));
74133741Sjmg  rtmes.m_rtm.rtm_version = RTM_VERSION;
75133741Sjmg  rtmes.m_rtm.rtm_type = cmd;
76133741Sjmg  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
77133741Sjmg  rtmes.m_rtm.rtm_seq = ++seqno;
78133741Sjmg  rtmes.m_rtm.rtm_pid = getpid();
79133741Sjmg  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
80133741Sjmg
81133741Sjmg  bzero(&rtdata, sizeof(rtdata));
82133741Sjmg  rtdata.sin_len = 16;
83133741Sjmg  rtdata.sin_family = AF_INET;
84133741Sjmg  rtdata.sin_port = 0;
85133741Sjmg  rtdata.sin_addr = dst;
86133741Sjmg
87133741Sjmg  cp = rtmes.m_space;
88133741Sjmg  bcopy(&rtdata, cp, 16);
8984138Sjlemon  cp += 16;
90133741Sjmg  if (gateway.s_addr) {
91133741Sjmg    rtdata.sin_addr = gateway;
92146950Sps    bcopy(&rtdata, cp, 16);
93146950Sps    cp += 16;
94162594Sjmg  }
95162594Sjmg  if (dst.s_addr == INADDR_ANY)
96170029Srwatson    mask.s_addr = INADDR_ANY;
97133741Sjmg
98133741Sjmg  lp = (u_long *) cp;
99133741Sjmg
100133741Sjmg  if (mask.s_addr) {
101133741Sjmg    *lp++ = 8;
102146950Sps    cp += sizeof(int);
103146950Sps    *lp = mask.s_addr;
104146950Sps  } else
10559290Sjlemon    *lp = 0;
106133741Sjmg  cp += sizeof(u_long);
107133741Sjmg
10859290Sjlemon  nb = cp - (char *) &rtmes;
109108255Sphk  rtmes.m_rtm.rtm_msglen = nb;
110108255Sphk  wb = write(s, &rtmes, nb);
111175140Sjhb  if (wb < 0) {
112108255Sphk    LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
113108255Sphk    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
114108255Sphk    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
115108255Sphk    switch (rtmes.m_rtm.rtm_errno) {
116108255Sphk    case EEXIST:
117108238Sphk      LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
11872521Sjlemon      break;
119116546Sphk    case ESRCH:
120116546Sphk      LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
121175140Sjhb      break;
122116546Sphk    case ENOBUFS:
123116546Sphk    default:
124116546Sphk      LogPrintf(LogTCPIP, "Add/Del route failed: %s\n",
125116546Sphk		strerror(rtmes.m_rtm.rtm_errno));
126116546Sphk      break;
127224914Skib    }
128224914Skib  }
12972521Sjlemon  LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
13072521Sjlemon	    dst.s_addr, gateway.s_addr);
131133741Sjmg  close(s);
13283366Sjulian}
13359290Sjlemon
13459290Sjlemonstatic void
13559290Sjlemonp_sockaddr(struct sockaddr * sa, int width)
136133741Sjmg{
13759290Sjlemon  if (VarTerm) {
13859290Sjlemon    register char *cp;
13972521Sjlemon    register struct sockaddr_in *sin = (struct sockaddr_in *) sa;
14072521Sjlemon
14172521Sjlemon    cp = (sin->sin_addr.s_addr == 0) ? "default" :
14272521Sjlemon      inet_ntoa(sin->sin_addr);
14372521Sjlemon    fprintf(VarTerm, "%-*.*s ", width, width, cp);
14472521Sjlemon  }
14579989Sjlemon}
14679989Sjlemon
14779989Sjlemonstruct bits {
14879989Sjlemon  short b_mask;
149197241Ssson  char b_val;
150197241Ssson}    bits[] = {
151197241Ssson
152197294Srdivacky  {
153197407Srdivacky    RTF_UP, 'U'
15472521Sjlemon  },
155197134Srwatson  {
156197134Srwatson    RTF_GATEWAY, 'G'
157197134Srwatson  },
158197134Srwatson  {
159197134Srwatson    RTF_HOST, 'H'
160197134Srwatson  },
161197134Srwatson  {
162197134Srwatson    RTF_DYNAMIC, 'D'
163197134Srwatson  },
164133741Sjmg  {
165197134Srwatson    RTF_MODIFIED, 'M'
166197134Srwatson  },
167197134Srwatson  {
168197134Srwatson    RTF_CLONING, 'C'
169197134Srwatson  },
170197134Srwatson  {
171197134Srwatson    RTF_XRESOLVE, 'X'
172197134Srwatson  },
173197134Srwatson  {
174197134Srwatson    RTF_LLINFO, 'L'
175197134Srwatson  },
176197134Srwatson  {
177197241Ssson    RTF_REJECT, 'R'
178197241Ssson  },
179197241Ssson  {
180197241Ssson    0
181197241Ssson  }
182197241Ssson};
18372521Sjlemon
18492751Sjeffstatic void
18584138Sjlemonp_flags(int f, char *format)
18684138Sjlemon{
18784138Sjlemon  if (VarTerm) {
18884138Sjlemon    char name[33], *flags;
18959290Sjlemon    register struct bits *p = bits;
190133741Sjmg
191133741Sjmg    for (flags = name; p->b_mask; p++)
192133741Sjmg      if (p->b_mask & f)
193133741Sjmg	*flags++ = p->b_val;
194133741Sjmg    *flags = '\0';
195133741Sjmg    fprintf(VarTerm, format, name);
196133741Sjmg  }
197133741Sjmg}
198133741Sjmg
199133741Sjmgint
200133741SjmgShowRoute()
20159290Sjlemon{
202133741Sjmg  struct rt_msghdr *rtm;
203133741Sjmg  struct sockaddr *sa;
204133741Sjmg  char *sp, *ep, *cp;
205133741Sjmg  u_char *wp;
206133741Sjmg  int *lp;
207133741Sjmg  int needed, nb;
208133741Sjmg  u_long mask;
209133741Sjmg  int mib[6];
210133741Sjmg
211133741Sjmg  if (!VarTerm)
212133741Sjmg    return 1;
213133741Sjmg
214133741Sjmg  mib[0] = CTL_NET;
215133741Sjmg  mib[1] = PF_ROUTE;
216133741Sjmg  mib[2] = 0;
217133741Sjmg  mib[3] = 0;
218133741Sjmg  mib[4] = NET_RT_DUMP;
219133741Sjmg  mib[5] = 0;
220133741Sjmg  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
221133741Sjmg    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
222133741Sjmg    return (1);
223133741Sjmg  }
224133741Sjmg  if (needed < 0)
225133741Sjmg    return (1);
226147730Sssouhlal  sp = malloc(needed);
227133741Sjmg  if (sp == NULL)
228133741Sjmg    return (1);
229147730Sssouhlal  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
230147730Sssouhlal    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
231133741Sjmg    free(sp);
232147730Sssouhlal    return (1);
233147730Sssouhlal  }
234147730Sssouhlal  ep = sp + needed;
235147730Sssouhlal
236147730Sssouhlal  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
237147730Sssouhlal    rtm = (struct rt_msghdr *) cp;
238147730Sssouhlal    sa = (struct sockaddr *) (rtm + 1);
239147730Sssouhlal    mask = 0xffffffff;
240193951Skib    if (rtm->rtm_addrs == RTA_DST)
241147730Sssouhlal      p_sockaddr(sa, 36);
242193951Skib    else {
243193951Skib      wp = (u_char *) cp + rtm->rtm_msglen;
244147730Sssouhlal      p_sockaddr(sa, 16);
245147730Sssouhlal      if (sa->sa_len == 0)
246147730Sssouhlal	sa->sa_len = sizeof(long);
247147730Sssouhlal      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
248147730Sssouhlal      p_sockaddr(sa, 18);
24959290Sjlemon      lp = (int *) (sa->sa_len + (char *) sa);
25059290Sjlemon      if ((char *) lp < (char *) wp && *lp) {
25159290Sjlemon	LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp);
25259290Sjlemon	wp = (u_char *) (lp + 1);
25388633Salfred	mask = 0;
25488633Salfred	for (nb = *(char *) lp; nb > 4; nb--) {
25588633Salfred	  mask <<= 8;
25688633Salfred	  mask |= *wp++;
25788633Salfred	}
25888633Salfred	for (nb = 8 - *(char *) lp; nb > 0; nb--)
25988633Salfred	  mask <<= 8;
260197134Srwatson      }
261197134Srwatson    }
262197134Srwatson    fprintf(VarTerm, "%08lx  ", mask);
263197134Srwatson    p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
26488633Salfred    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
265133741Sjmg  }
26659290Sjlemon  free(sp);
267131562Salfred  return 0;
26859290Sjlemon}
26959290Sjlemon
27072521Sjlemon/*
27159290Sjlemon *  Delete routes associated with our interface
272133741Sjmg */
273133741Sjmgvoid
274133741SjmgDeleteIfRoutes(int all)
275133741Sjmg{
276133741Sjmg  struct rt_msghdr *rtm;
277133741Sjmg  struct sockaddr *sa;
278133741Sjmg  struct in_addr dstnet, gateway, maddr;
279133741Sjmg  int needed;
280133741Sjmg  char *sp, *cp, *ep;
281133741Sjmg  u_long mask;
282133741Sjmg  int *lp, nb;
283133741Sjmg  u_char *wp;
284133741Sjmg  int mib[6];
285133741Sjmg
286201350Sbrooks  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
287133741Sjmg
288151260Sambrisko  mib[0] = CTL_NET;
289197241Ssson  mib[1] = PF_ROUTE;
29059290Sjlemon  mib[2] = 0;
29159290Sjlemon  mib[3] = 0;
292133741Sjmg  mib[4] = NET_RT_DUMP;
293133741Sjmg  mib[5] = 0;
294133741Sjmg  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
295133741Sjmg    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
29659290Sjlemon	      strerror(errno));
29772521Sjlemon    return;
29859290Sjlemon  }
299133635Sjmg  if (needed < 0)
30072521Sjlemon    return;
30159290Sjlemon
30259290Sjlemon  sp = malloc(needed);
30372521Sjlemon  if (sp == NULL)
30459290Sjlemon    return;
30572521Sjlemon
30659290Sjlemon  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
307109153Sdillon    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
30859290Sjlemon	      strerror(errno));
30972521Sjlemon    free(sp);
310133741Sjmg    return;
31159290Sjlemon  }
312133741Sjmg  ep = sp + needed;
31372521Sjlemon
314133741Sjmg  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
315133741Sjmg    rtm = (struct rt_msghdr *) cp;
31659290Sjlemon    sa = (struct sockaddr *) (rtm + 1);
31759290Sjlemon    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
31859290Sjlemon	      " dstnet: %s\n",
31959290Sjlemon	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
32059290Sjlemon	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
32159290Sjlemon    if (rtm->rtm_addrs != RTA_DST &&
322109153Sdillon	(rtm->rtm_index == IfIndex) &&
32359290Sjlemon	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
324133741Sjmg      LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
32559290Sjlemon      dstnet = ((struct sockaddr_in *) sa)->sin_addr;
32659290Sjlemon      wp = (u_char *) cp + rtm->rtm_msglen;
32759290Sjlemon      if (sa->sa_len == 0)
32859290Sjlemon	sa->sa_len = sizeof(long);
32959290Sjlemon      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
33059290Sjlemon      gateway = ((struct sockaddr_in *) sa)->sin_addr;
331109153Sdillon      lp = (int *) (sa->sa_len + (char *) sa);
33259290Sjlemon      mask = 0;
33359290Sjlemon      if ((char *) lp < (char *) wp && *lp) {
33459290Sjlemon	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n",
33559290Sjlemon		  rtm->rtm_flags, *lp);
33659290Sjlemon	wp = (u_char *) (lp + 1);
337133741Sjmg	for (nb = *lp; nb > 4; nb--) {
33859290Sjlemon	  mask <<= 8;
33959290Sjlemon	  mask |= *wp++;
34059290Sjlemon	}
34159290Sjlemon	for (nb = 8 - *lp; nb > 0; nb--)
342113377Skbyanc	  mask <<= 8;
34375451Srwatson      }
34459290Sjlemon      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
345113377Skbyanc      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
34659290Sjlemon      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
347113377Skbyanc      if (dstnet.s_addr == INADDR_ANY)
348113377Skbyanc	mask = INADDR_ANY;
349113377Skbyanc      maddr.s_addr = htonl(mask);
350133741Sjmg      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
351133741Sjmg    }
352113377Skbyanc  }
353133741Sjmg  free(sp);
354122019Scognet}
355122019Scognet
356203875Skib /*
357203875Skib  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
35875451Srwatson  */
359203875Skib
36059290Sjlemonint
36159290SjlemonGetIfIndex(char *name)
36259290Sjlemon{
36359290Sjlemon  char *buffer;
36459290Sjlemon  struct ifreq *ifrp;
36559290Sjlemon  int s, len, elen, index;
36659290Sjlemon  struct ifconf ifconfs;
36759290Sjlemon
36859290Sjlemon  /* struct ifreq reqbuf[256]; -- obsoleted :) */
36959290Sjlemon  int oldbufsize, bufsize = sizeof(struct ifreq);
37059290Sjlemon
37159290Sjlemon  s = socket(AF_INET, SOCK_DGRAM, 0);
37259290Sjlemon  if (s < 0) {
373122686Scognet    LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno));
374133741Sjmg    return (-1);
375113377Skbyanc  }
376113377Skbyanc  buffer = malloc(bufsize);	/* allocate first buffer */
377113377Skbyanc  ifconfs.ifc_len = bufsize;	/* Initial setting */
378113377Skbyanc
379113377Skbyanc  /*
380113377Skbyanc   * Iterate through here until we don't get many more data
381113377Skbyanc   */
382133741Sjmg
383113377Skbyanc  do {
38471500Sjhb    oldbufsize = ifconfs.ifc_len;
38559290Sjlemon    bufsize += 1 + sizeof(struct ifreq);
38659290Sjlemon    buffer = realloc((void *) buffer, bufsize);	/* Make it bigger */
38759290Sjlemon    LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
38859290Sjlemon    ifconfs.ifc_len = bufsize;
38959290Sjlemon    ifconfs.ifc_buf = buffer;
39059290Sjlemon    if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
39159290Sjlemon      LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n",
39259290Sjlemon		strerror(errno));
39359290Sjlemon      close(s);
39459290Sjlemon      free(buffer);
39559290Sjlemon      return (-1);
39659290Sjlemon    }
397133741Sjmg  } while (ifconfs.ifc_len > oldbufsize);
39859290Sjlemon
39959290Sjlemon  ifrp = ifconfs.ifc_req;
40059290Sjlemon
401133741Sjmg  index = 1;
40259290Sjlemon  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
403133741Sjmg    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
404133741Sjmg    if (ifrp->ifr_addr.sa_family == AF_LINK) {
405133741Sjmg      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
40659290Sjlemon		index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
40759290Sjlemon		ifrp->ifr_addr.sa_family, elen);
408133741Sjmg      if (strcmp(ifrp->ifr_name, name) == 0) {
40959290Sjlemon	IfIndex = index;
41059290Sjlemon	close(s);
41159290Sjlemon	free(buffer);
412133741Sjmg	return (index);
41359290Sjlemon      }
41459290Sjlemon      index++;
41559290Sjlemon    }
41659290Sjlemon    len -= elen;
41759290Sjlemon    ifrp = (struct ifreq *) ((char *) ifrp + elen);
41859290Sjlemon    ifrp++;
41959290Sjlemon  }
42059290Sjlemon
42159290Sjlemon  close(s);
42259290Sjlemon  free(buffer);
42359290Sjlemon  return (-1);
42459290Sjlemon}
42559290Sjlemon