route.c revision 28679
1230557Sjimharris/*
2230557Sjimharris *	      PPP Routing related Module
3230557Sjimharris *
4230557Sjimharris *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5230557Sjimharris *
6230557Sjimharris *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7230557Sjimharris *
8230557Sjimharris * Redistribution and use in source and binary forms are permitted
9230557Sjimharris * provided that the above copyright notice and this paragraph are
10230557Sjimharris * duplicated in all such forms and that any documentation,
11230557Sjimharris * advertising materials, and other materials related to such
12230557Sjimharris * distribution and use acknowledge that the software was developed
13230557Sjimharris * by the Internet Initiative Japan, Inc.  The name of the
14230557Sjimharris * IIJ may not be used to endorse or promote products derived
15230557Sjimharris * from this software without specific prior written permission.
16230557Sjimharris * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17230557Sjimharris * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18230557Sjimharris * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19230557Sjimharris *
20230557Sjimharris * $Id: route.c,v 1.17 1997/07/28 01:02:27 brian Exp $
21230557Sjimharris *
22230557Sjimharris */
23230557Sjimharris#include <sys/types.h>
24230557Sjimharris#include <machine/endian.h>
25230557Sjimharris#include <sys/ioctl.h>
26230557Sjimharris#include <sys/param.h>
27230557Sjimharris#include <sys/socket.h>
28230557Sjimharris#include <sys/sysctl.h>
29230557Sjimharris#include <sys/time.h>
30230557Sjimharris
31230557Sjimharris#include <errno.h>
32230557Sjimharris#include <stdlib.h>
33230557Sjimharris#include <stdio.h>
34230557Sjimharris#include <string.h>
35230557Sjimharris#include <unistd.h>
36230557Sjimharris
37230557Sjimharris#include <net/route.h>
38230557Sjimharris#include <net/if.h>
39230557Sjimharris#include <netinet/in_systm.h>
40230557Sjimharris#include <netinet/in.h>
41230557Sjimharris#include <arpa/inet.h>
42230557Sjimharris
43230557Sjimharris#include "log.h"
44230557Sjimharris#include "loadalias.h"
45230557Sjimharris#include "vars.h"
46230557Sjimharris
47230557Sjimharrisstatic int IfIndex;
48230557Sjimharris
49230557Sjimharrisstruct rtmsg {
50230557Sjimharris  struct rt_msghdr m_rtm;
51230557Sjimharris  char m_space[64];
52230557Sjimharris};
53230557Sjimharris
54230557Sjimharrisstatic int seqno;
55230557Sjimharris
56230557Sjimharrisvoid
57230557SjimharrisOsSetRoute(int cmd,
58230557Sjimharris	   struct in_addr dst,
59230557Sjimharris	   struct in_addr gateway,
60230557Sjimharris	   struct in_addr mask)
61230557Sjimharris{
62230557Sjimharris  struct rtmsg rtmes;
63230557Sjimharris  int s, nb, wb;
64230557Sjimharris  char *cp;
65230557Sjimharris  u_long *lp;
66230557Sjimharris  struct sockaddr_in rtdata;
67230557Sjimharris
68230557Sjimharris  s = socket(PF_ROUTE, SOCK_RAW, 0);
69230557Sjimharris  if (s < 0) {
70230557Sjimharris    LogPrintf(LogERROR, "OsSetRoute: socket: %s", strerror(errno));
71230557Sjimharris    return;
72230557Sjimharris  }
73230557Sjimharris  bzero(&rtmes, sizeof(rtmes));
74230557Sjimharris  rtmes.m_rtm.rtm_version = RTM_VERSION;
75230557Sjimharris  rtmes.m_rtm.rtm_type = cmd;
76230557Sjimharris  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
77230557Sjimharris  rtmes.m_rtm.rtm_seq = ++seqno;
78230557Sjimharris  rtmes.m_rtm.rtm_pid = getpid();
79230557Sjimharris  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
80230557Sjimharris
81230557Sjimharris  bzero(&rtdata, sizeof(rtdata));
82230557Sjimharris  rtdata.sin_len = 16;
83230557Sjimharris  rtdata.sin_family = AF_INET;
84230557Sjimharris  rtdata.sin_port = 0;
85230557Sjimharris  rtdata.sin_addr = dst;
86230557Sjimharris
87230557Sjimharris  cp = rtmes.m_space;
88230557Sjimharris  bcopy(&rtdata, cp, 16);
89230557Sjimharris  cp += 16;
90230557Sjimharris  if (gateway.s_addr) {
91230557Sjimharris    rtdata.sin_addr = gateway;
92230557Sjimharris    bcopy(&rtdata, cp, 16);
93230557Sjimharris    cp += 16;
94230557Sjimharris  }
95230557Sjimharris  if (dst.s_addr == INADDR_ANY)
96230557Sjimharris    mask.s_addr = INADDR_ANY;
97230557Sjimharris
98230557Sjimharris  lp = (u_long *) cp;
99230557Sjimharris
100230557Sjimharris  if (mask.s_addr) {
101230557Sjimharris    *lp++ = 8;
102230557Sjimharris    cp += sizeof(int);
103230557Sjimharris    *lp = mask.s_addr;
104230557Sjimharris  } else
105230557Sjimharris    *lp = 0;
106230557Sjimharris  cp += sizeof(u_long);
107230557Sjimharris
108230557Sjimharris  nb = cp - (char *) &rtmes;
109230557Sjimharris  rtmes.m_rtm.rtm_msglen = nb;
110230557Sjimharris  wb = write(s, &rtmes, nb);
111230557Sjimharris  if (wb < 0) {
112230557Sjimharris    LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
113230557Sjimharris    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
114230557Sjimharris    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
115230557Sjimharris    switch (rtmes.m_rtm.rtm_errno) {
116230557Sjimharris    case EEXIST:
117230557Sjimharris      LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
118230557Sjimharris      break;
119230557Sjimharris    case ESRCH:
120230557Sjimharris      LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
121230557Sjimharris      break;
122230557Sjimharris    case ENOBUFS:
123230557Sjimharris    default:
124230557Sjimharris      LogPrintf(LogTCPIP, "Add/Del route failed: %s\n",
125230557Sjimharris		strerror(rtmes.m_rtm.rtm_errno));
126230557Sjimharris      break;
127230557Sjimharris    }
128230557Sjimharris  }
129230557Sjimharris  LogPrintf(LogDEBUG, "wrote %d: dst = %x, gateway = %x\n", nb,
130230557Sjimharris	    dst.s_addr, gateway.s_addr);
131230557Sjimharris  close(s);
132230557Sjimharris}
133230557Sjimharris
134230557Sjimharrisstatic void
135230557Sjimharrisp_sockaddr(struct sockaddr * sa, int width)
136230557Sjimharris{
137230557Sjimharris  if (VarTerm) {
138230557Sjimharris    register char *cp;
139230557Sjimharris    register struct sockaddr_in *sin = (struct sockaddr_in *) sa;
140230557Sjimharris
141230557Sjimharris    cp = (sin->sin_addr.s_addr == 0) ? "default" :
142230557Sjimharris      inet_ntoa(sin->sin_addr);
143230557Sjimharris    fprintf(VarTerm, "%-*.*s ", width, width, cp);
144230557Sjimharris  }
145230557Sjimharris}
146230557Sjimharris
147230557Sjimharrisstruct bits {
148230557Sjimharris  short b_mask;
149230557Sjimharris  char b_val;
150230557Sjimharris}    bits[] = {
151230557Sjimharris
152230557Sjimharris  {
153230557Sjimharris    RTF_UP, 'U'
154230557Sjimharris  },
155230557Sjimharris  {
156240518Seadler    RTF_GATEWAY, 'G'
157230557Sjimharris  },
158230557Sjimharris  {
159230557Sjimharris    RTF_HOST, 'H'
160230557Sjimharris  },
161230557Sjimharris  {
162230557Sjimharris    RTF_DYNAMIC, 'D'
163230557Sjimharris  },
164230557Sjimharris  {
165230557Sjimharris    RTF_MODIFIED, 'M'
166230557Sjimharris  },
167230557Sjimharris  {
168230557Sjimharris    RTF_CLONING, 'C'
169230557Sjimharris  },
170230557Sjimharris  {
171230557Sjimharris    RTF_XRESOLVE, 'X'
172230557Sjimharris  },
173230557Sjimharris  {
174230557Sjimharris    RTF_LLINFO, 'L'
175230557Sjimharris  },
176230557Sjimharris  {
177230557Sjimharris    RTF_REJECT, 'R'
178230557Sjimharris  },
179230557Sjimharris  {
180230557Sjimharris    0
181230557Sjimharris  }
182230557Sjimharris};
183230557Sjimharris
184230557Sjimharrisstatic void
185230557Sjimharrisp_flags(int f, char *format)
186230557Sjimharris{
187230557Sjimharris  if (VarTerm) {
188230557Sjimharris    char name[33], *flags;
189230557Sjimharris    register struct bits *p = bits;
190230557Sjimharris
191230557Sjimharris    for (flags = name; p->b_mask; p++)
192230557Sjimharris      if (p->b_mask & f)
193230557Sjimharris	*flags++ = p->b_val;
194230557Sjimharris    *flags = '\0';
195230557Sjimharris    fprintf(VarTerm, format, name);
196230557Sjimharris  }
197230557Sjimharris}
198230557Sjimharris
199230557Sjimharrisint
200230557SjimharrisShowRoute()
201230557Sjimharris{
202230557Sjimharris  struct rt_msghdr *rtm;
203230557Sjimharris  struct sockaddr *sa;
204230557Sjimharris  char *sp, *ep, *cp;
205230557Sjimharris  u_char *wp;
206230557Sjimharris  int *lp;
207230557Sjimharris  int needed, nb;
208230557Sjimharris  u_long mask;
209230557Sjimharris  int mib[6];
210230557Sjimharris
211230557Sjimharris  if (!VarTerm)
212230557Sjimharris    return 1;
213230557Sjimharris
214230557Sjimharris  mib[0] = CTL_NET;
215230557Sjimharris  mib[1] = PF_ROUTE;
216230557Sjimharris  mib[2] = 0;
217230557Sjimharris  mib[3] = 0;
218230557Sjimharris  mib[4] = NET_RT_DUMP;
219230557Sjimharris  mib[5] = 0;
220230557Sjimharris  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
221230557Sjimharris    LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
222230557Sjimharris    return (1);
223230557Sjimharris  }
224230557Sjimharris  if (needed < 0)
225230557Sjimharris    return (1);
226230557Sjimharris  sp = malloc(needed);
227230557Sjimharris  if (sp == NULL)
228230557Sjimharris    return (1);
229230557Sjimharris  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
230230557Sjimharris    LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
231230557Sjimharris    free(sp);
232230557Sjimharris    return (1);
233230557Sjimharris  }
234230557Sjimharris  ep = sp + needed;
235230557Sjimharris
236230557Sjimharris  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
237230557Sjimharris    rtm = (struct rt_msghdr *) cp;
238230557Sjimharris    sa = (struct sockaddr *) (rtm + 1);
239230557Sjimharris    mask = 0xffffffff;
240230557Sjimharris    if (rtm->rtm_addrs == RTA_DST)
241230557Sjimharris      p_sockaddr(sa, 36);
242230557Sjimharris    else {
243230557Sjimharris      wp = (u_char *) cp + rtm->rtm_msglen;
244230557Sjimharris      p_sockaddr(sa, 16);
245230557Sjimharris      if (sa->sa_len == 0)
246230557Sjimharris	sa->sa_len = sizeof(long);
247230557Sjimharris      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
248230557Sjimharris      p_sockaddr(sa, 18);
249230557Sjimharris      lp = (int *) (sa->sa_len + (char *) sa);
250230557Sjimharris      if ((char *) lp < (char *) wp && *lp) {
251230557Sjimharris	LogPrintf(LogDEBUG, " flag = %x, rest = %d", rtm->rtm_flags, *lp);
252230557Sjimharris	wp = (u_char *) (lp + 1);
253230557Sjimharris	mask = 0;
254230557Sjimharris	for (nb = *(char *) lp; nb > 4; nb--) {
255230557Sjimharris	  mask <<= 8;
256230557Sjimharris	  mask |= *wp++;
257230557Sjimharris	}
258230557Sjimharris	for (nb = 8 - *(char *) lp; nb > 0; nb--)
259230557Sjimharris	  mask <<= 8;
260230557Sjimharris      }
261230557Sjimharris    }
262230557Sjimharris    fprintf(VarTerm, "%08lx  ", mask);
263230557Sjimharris    p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
264230557Sjimharris    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
265230557Sjimharris  }
266230557Sjimharris  free(sp);
267230557Sjimharris  return 0;
268230557Sjimharris}
269230557Sjimharris
270230557Sjimharris/*
271230557Sjimharris *  Delete routes associated with our interface
272230557Sjimharris */
273230557Sjimharrisvoid
274230557SjimharrisDeleteIfRoutes(int all)
275230557Sjimharris{
276230557Sjimharris  struct rt_msghdr *rtm;
277230557Sjimharris  struct sockaddr *sa;
278230557Sjimharris  struct in_addr dstnet, gateway, maddr;
279230557Sjimharris  int needed;
280230557Sjimharris  char *sp, *cp, *ep;
281230557Sjimharris  u_long mask;
282230557Sjimharris  int *lp, nb;
283230557Sjimharris  u_char *wp;
284230557Sjimharris  int mib[6];
285230557Sjimharris
286230557Sjimharris  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
287230557Sjimharris
288230557Sjimharris  mib[0] = CTL_NET;
289230557Sjimharris  mib[1] = PF_ROUTE;
290230557Sjimharris  mib[2] = 0;
291230557Sjimharris  mib[3] = 0;
292230557Sjimharris  mib[4] = NET_RT_DUMP;
293230557Sjimharris  mib[5] = 0;
294230557Sjimharris  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
295230557Sjimharris    LogPrintf(LogERROR, "sysctl: estimate: %s", strerror(errno));
296230557Sjimharris    return;
297230557Sjimharris  }
298230557Sjimharris  if (needed < 0)
299230557Sjimharris    return;
300230557Sjimharris
301230557Sjimharris  sp = malloc(needed);
302230557Sjimharris  if (sp == NULL)
303230557Sjimharris    return;
304230557Sjimharris
305230557Sjimharris  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
306230557Sjimharris    LogPrintf(LogERROR, "sysctl: getroute: %s", strerror(errno));
307230557Sjimharris    free(sp);
308230557Sjimharris    return;
309230557Sjimharris  }
310230557Sjimharris  ep = sp + needed;
311230557Sjimharris
312230557Sjimharris  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
313230557Sjimharris    rtm = (struct rt_msghdr *) cp;
314230557Sjimharris    sa = (struct sockaddr *) (rtm + 1);
315230557Sjimharris    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
316230557Sjimharris	      " dstnet: %s\n",
317230557Sjimharris	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
318230557Sjimharris	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
319230557Sjimharris    if (rtm->rtm_addrs != RTA_DST &&
320230557Sjimharris	(rtm->rtm_index == IfIndex) &&
321230557Sjimharris	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
322230557Sjimharris      LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
323230557Sjimharris      dstnet = ((struct sockaddr_in *) sa)->sin_addr;
324230557Sjimharris      wp = (u_char *) cp + rtm->rtm_msglen;
325230557Sjimharris      if (sa->sa_len == 0)
326230557Sjimharris	sa->sa_len = sizeof(long);
327230557Sjimharris      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
328230557Sjimharris      gateway = ((struct sockaddr_in *) sa)->sin_addr;
329230557Sjimharris      lp = (int *) (sa->sa_len + (char *) sa);
330230557Sjimharris      mask = 0;
331230557Sjimharris      if ((char *) lp < (char *) wp && *lp) {
332230557Sjimharris	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d",
333230557Sjimharris		  rtm->rtm_flags, *lp);
334230557Sjimharris	wp = (u_char *) (lp + 1);
335230557Sjimharris	for (nb = *lp; nb > 4; nb--) {
336230557Sjimharris	  mask <<= 8;
337230557Sjimharris	  mask |= *wp++;
338230557Sjimharris	}
339230557Sjimharris	for (nb = 8 - *lp; nb > 0; nb--)
340230557Sjimharris	  mask <<= 8;
341230557Sjimharris      }
342230557Sjimharris      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
343230557Sjimharris      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
344230557Sjimharris      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
345230557Sjimharris      if (dstnet.s_addr == INADDR_ANY)
346230557Sjimharris	mask = INADDR_ANY;
347230557Sjimharris      maddr.s_addr = htonl(mask);
348230557Sjimharris      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
349230557Sjimharris    }
350230557Sjimharris  }
351230557Sjimharris  free(sp);
352230557Sjimharris}
353230557Sjimharris
354230557Sjimharris /*
355230557Sjimharris  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
356230557Sjimharris  */
357230557Sjimharris
358230557Sjimharrisint
359230557SjimharrisGetIfIndex(char *name)
360230557Sjimharris{
361230557Sjimharris  char *buffer;
362230557Sjimharris  struct ifreq *ifrp;
363230557Sjimharris  int s, len, elen, index;
364230557Sjimharris  struct ifconf ifconfs;
365230557Sjimharris
366230557Sjimharris  /* struct ifreq reqbuf[256]; -- obsoleted :) */
367230557Sjimharris  int oldbufsize, bufsize = sizeof(struct ifreq);
368230557Sjimharris
369230557Sjimharris  s = socket(AF_INET, SOCK_DGRAM, 0);
370230557Sjimharris  if (s < 0) {
371230557Sjimharris    LogPrintf(LogERROR, "GetIfIndex: socket: %s", strerror(errno));
372230557Sjimharris    return (-1);
373230557Sjimharris  }
374230557Sjimharris  buffer = malloc(bufsize);	/* allocate first buffer */
375230557Sjimharris  ifconfs.ifc_len = bufsize;	/* Initial setting */
376230557Sjimharris
377230557Sjimharris  /*
378230557Sjimharris   * Iterate through here until we don't get many more data
379230557Sjimharris   */
380230557Sjimharris
381230557Sjimharris  do {
382230557Sjimharris    oldbufsize = ifconfs.ifc_len;
383230557Sjimharris    bufsize += 1 + sizeof(struct ifreq);
384230557Sjimharris    buffer = realloc((void *) buffer, bufsize);	/* Make it bigger */
385230557Sjimharris    LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
386230557Sjimharris    ifconfs.ifc_len = bufsize;
387230557Sjimharris    ifconfs.ifc_buf = buffer;
388230557Sjimharris    if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
389230557Sjimharris      LogPrintf(LogERROR, "ioctl(SIOCGIFCONF): %s", strerror(errno));
390230557Sjimharris      close(s);
391230557Sjimharris      free(buffer);
392230557Sjimharris      return (-1);
393230557Sjimharris    }
394230557Sjimharris  } while (ifconfs.ifc_len > oldbufsize);
395230557Sjimharris
396230557Sjimharris  ifrp = ifconfs.ifc_req;
397230557Sjimharris
398230557Sjimharris  index = 1;
399230557Sjimharris  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
400230557Sjimharris    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
401230557Sjimharris    if (ifrp->ifr_addr.sa_family == AF_LINK) {
402230557Sjimharris      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
403230557Sjimharris		index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
404230557Sjimharris		ifrp->ifr_addr.sa_family, elen);
405230557Sjimharris      if (strcmp(ifrp->ifr_name, name) == 0) {
406230557Sjimharris	IfIndex = index;
407230557Sjimharris	close(s);
408230557Sjimharris	free(buffer);
409230557Sjimharris	return (index);
410230557Sjimharris      }
411230557Sjimharris      index++;
412230557Sjimharris    }
413230557Sjimharris    len -= elen;
414230557Sjimharris    ifrp = (struct ifreq *) ((char *) ifrp + elen);
415230557Sjimharris    ifrp++;
416230557Sjimharris  }
417230557Sjimharris
418230557Sjimharris  close(s);
419230557Sjimharris  free(buffer);
420230557Sjimharris  return (-1);
421230557Sjimharris}
422230557Sjimharris