route.c revision 31121
1/*
2 *	      PPP Routing related Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: route.c,v 1.24 1997/11/09 14:18:50 brian Exp $
21 *
22 */
23
24#include <sys/param.h>
25#include <sys/time.h>
26#include <sys/socket.h>
27#include <net/route.h>
28#include <net/if.h>
29#include <netinet/in_systm.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32
33#include <errno.h>
34#include <machine/endian.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <sys/ioctl.h>
39#include <sys/sysctl.h>
40#include <unistd.h>
41
42#include "mbuf.h"
43#include "log.h"
44#include "loadalias.h"
45#include "command.h"
46#include "defs.h"
47#include "vars.h"
48#include "id.h"
49#include "route.h"
50
51static int IfIndex;
52
53struct rtmsg {
54  struct rt_msghdr m_rtm;
55  char m_space[64];
56};
57
58static int seqno;
59
60void
61OsSetRoute(int cmd,
62	   struct in_addr dst,
63	   struct in_addr gateway,
64	   struct in_addr mask)
65{
66  struct rtmsg rtmes;
67  int s, nb, wb;
68  char *cp, *cmdstr;
69  u_long *lp;
70  struct sockaddr_in rtdata;
71
72  cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
73  s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
74  if (s < 0) {
75    LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno));
76    return;
77  }
78  memset(&rtmes, '\0', sizeof(rtmes));
79  rtmes.m_rtm.rtm_version = RTM_VERSION;
80  rtmes.m_rtm.rtm_type = cmd;
81  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
82  rtmes.m_rtm.rtm_seq = ++seqno;
83  rtmes.m_rtm.rtm_pid = getpid();
84  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
85
86  memset(&rtdata, '\0', sizeof(rtdata));
87  rtdata.sin_len = 16;
88  rtdata.sin_family = AF_INET;
89  rtdata.sin_port = 0;
90  rtdata.sin_addr = dst;
91
92  cp = rtmes.m_space;
93  memcpy(cp, &rtdata, 16);
94  cp += 16;
95  if (gateway.s_addr) {
96    rtdata.sin_addr = gateway;
97    memcpy(cp, &rtdata, 16);
98    cp += 16;
99    rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
100  }
101  if (dst.s_addr == INADDR_ANY)
102    mask.s_addr = INADDR_ANY;
103
104  lp = (u_long *) cp;
105
106  if (mask.s_addr) {
107    *lp++ = 8;
108    cp += sizeof(int);
109    *lp = mask.s_addr;
110  } else
111    *lp = 0;
112  cp += sizeof(u_long);
113
114  nb = cp - (char *) &rtmes;
115  rtmes.m_rtm.rtm_msglen = nb;
116  wb = write(s, &rtmes, nb);
117  if (wb < 0) {
118    LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst));
119    LogPrintf(LogTCPIP, "OsSetRoute:  Gateway = %s\n", inet_ntoa(gateway));
120    LogPrintf(LogTCPIP, "OsSetRoute:  Mask = %s\n", inet_ntoa(mask));
121    switch (rtmes.m_rtm.rtm_errno) {
122    case EEXIST:
123      LogPrintf(LogTCPIP, "Add route failed: Already exists\n");
124      break;
125    case ESRCH:
126      LogPrintf(LogTCPIP, "Del route failed: Non-existent\n");
127      break;
128    case 0:
129      LogPrintf(LogTCPIP, "%s route failed: %s\n", cmdstr, strerror(errno));
130      break;
131    case ENOBUFS:
132    default:
133      LogPrintf(LogTCPIP, "%s route failed: %s\n",
134		cmdstr, strerror(rtmes.m_rtm.rtm_errno));
135      break;
136    }
137  }
138  LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
139            wb, cmdstr, dst.s_addr, gateway.s_addr);
140  close(s);
141}
142
143static void
144p_sockaddr(struct sockaddr * sa, int width)
145{
146  if (VarTerm) {
147    register char *cp;
148    register struct sockaddr_in *sock_in = (struct sockaddr_in *) sa;
149
150    cp = (sock_in->sin_addr.s_addr == 0) ? "default" :
151      inet_ntoa(sock_in->sin_addr);
152    fprintf(VarTerm, "%-*.*s ", width, width, cp);
153  }
154}
155
156struct bits {
157  short b_mask;
158  char b_val;
159}    bits[] = {
160
161  {
162    RTF_UP, 'U'
163  },
164  {
165    RTF_GATEWAY, 'G'
166  },
167  {
168    RTF_HOST, 'H'
169  },
170  {
171    RTF_DYNAMIC, 'D'
172  },
173  {
174    RTF_MODIFIED, 'M'
175  },
176  {
177    RTF_CLONING, 'C'
178  },
179  {
180    RTF_XRESOLVE, 'X'
181  },
182  {
183    RTF_LLINFO, 'L'
184  },
185  {
186    RTF_REJECT, 'R'
187  },
188  {
189    0
190  }
191};
192
193static void
194p_flags(int f, char *format)
195{
196  if (VarTerm) {
197    char name[33], *flags;
198    register struct bits *p = bits;
199
200    for (flags = name; p->b_mask; p++)
201      if (p->b_mask & f)
202	*flags++ = p->b_val;
203    *flags = '\0';
204    fprintf(VarTerm, format, name);
205  }
206}
207
208int
209ShowRoute()
210{
211  struct rt_msghdr *rtm;
212  struct sockaddr *sa;
213  char *sp, *ep, *cp;
214  u_char *wp;
215  int *lp;
216  int needed, nb;
217  u_long mask;
218  int mib[6];
219
220  if (!VarTerm)
221    return 1;
222
223  mib[0] = CTL_NET;
224  mib[1] = PF_ROUTE;
225  mib[2] = 0;
226  mib[3] = 0;
227  mib[4] = NET_RT_DUMP;
228  mib[5] = 0;
229  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
230    LogPrintf(LogERROR, "ShowRoute: sysctl: estimate: %s\n", strerror(errno));
231    return (1);
232  }
233  if (needed < 0)
234    return (1);
235  sp = malloc(needed);
236  if (sp == NULL)
237    return (1);
238  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
239    LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
240    free(sp);
241    return (1);
242  }
243  ep = sp + needed;
244
245  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
246    rtm = (struct rt_msghdr *) cp;
247    sa = (struct sockaddr *) (rtm + 1);
248    mask = 0xffffffff;
249    if (rtm->rtm_addrs == RTA_DST)
250      p_sockaddr(sa, 36);
251    else {
252      wp = (u_char *) cp + rtm->rtm_msglen;
253      p_sockaddr(sa, 16);
254      if (sa->sa_len == 0)
255	sa->sa_len = sizeof(long);
256      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
257      p_sockaddr(sa, 18);
258      lp = (int *) (sa->sa_len + (char *) sa);
259      if ((char *) lp < (char *) wp && *lp) {
260	LogPrintf(LogDEBUG, " flag = %x, rest = %d\n", rtm->rtm_flags, *lp);
261	wp = (u_char *) (lp + 1);
262	mask = 0;
263	for (nb = *(char *) lp; nb > 4; nb--) {
264	  mask <<= 8;
265	  mask |= *wp++;
266	}
267	for (nb = 8 - *(char *) lp; nb > 0; nb--)
268	  mask <<= 8;
269      }
270    }
271    fprintf(VarTerm, "0x%08lx  ", mask);
272    p_flags(rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST), "%-6.6s ");
273    fprintf(VarTerm, "(%d)\n", rtm->rtm_index);
274  }
275  free(sp);
276  return 0;
277}
278
279/*
280 *  Delete routes associated with our interface
281 */
282void
283DeleteIfRoutes(int all)
284{
285  struct rt_msghdr *rtm;
286  struct sockaddr *sa;
287  struct in_addr dstnet, gateway, maddr;
288  int needed;
289  char *sp, *cp, *ep;
290  u_long mask;
291  int *lp, nb;
292  u_char *wp;
293  int mib[6];
294
295  LogPrintf(LogDEBUG, "DeleteIfRoutes (%d)\n", IfIndex);
296
297  mib[0] = CTL_NET;
298  mib[1] = PF_ROUTE;
299  mib[2] = 0;
300  mib[3] = 0;
301  mib[4] = NET_RT_DUMP;
302  mib[5] = 0;
303  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
304    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: estimate: %s\n",
305	      strerror(errno));
306    return;
307  }
308  if (needed < 0)
309    return;
310
311  sp = malloc(needed);
312  if (sp == NULL)
313    return;
314
315  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
316    LogPrintf(LogERROR, "DeleteIfRoutes: sysctl: getroute: %s\n",
317	      strerror(errno));
318    free(sp);
319    return;
320  }
321  ep = sp + needed;
322
323  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
324    rtm = (struct rt_msghdr *) cp;
325    sa = (struct sockaddr *) (rtm + 1);
326    LogPrintf(LogDEBUG, "DeleteIfRoutes: addrs: %x, index: %d, flags: %x,"
327	      " dstnet: %s\n",
328	      rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
329	      inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
330    if (rtm->rtm_addrs != RTA_DST &&
331	(rtm->rtm_index == IfIndex) &&
332	(all || (rtm->rtm_flags & RTF_GATEWAY))) {
333      LogPrintf(LogDEBUG, "DeleteIfRoutes: Remove it\n");
334      dstnet = ((struct sockaddr_in *) sa)->sin_addr;
335      wp = (u_char *) cp + rtm->rtm_msglen;
336      if (sa->sa_len == 0)
337	sa->sa_len = sizeof(long);
338      sa = (struct sockaddr *) (sa->sa_len + (char *) sa);
339      gateway = ((struct sockaddr_in *) sa)->sin_addr;
340      lp = (int *) (sa->sa_len + (char *) sa);
341      mask = 0;
342      if ((char *) lp < (char *) wp && *lp) {
343	LogPrintf(LogDEBUG, "DeleteIfRoutes: flag = %x, rest = %d\n",
344		  rtm->rtm_flags, *lp);
345	wp = (u_char *) (lp + 1);
346	for (nb = *lp; nb > 4; nb--) {
347	  mask <<= 8;
348	  mask |= *wp++;
349	}
350	for (nb = 8 - *lp; nb > 0; nb--)
351	  mask <<= 8;
352      }
353      LogPrintf(LogDEBUG, "DeleteIfRoutes: Dst: %s\n", inet_ntoa(dstnet));
354      LogPrintf(LogDEBUG, "DeleteIfRoutes: Gw: %s\n", inet_ntoa(gateway));
355      LogPrintf(LogDEBUG, "DeleteIfRoutes: Index: %d\n", rtm->rtm_index);
356      if (dstnet.s_addr == INADDR_ANY)
357	mask = INADDR_ANY;
358      maddr.s_addr = htonl(mask);
359      OsSetRoute(RTM_DELETE, dstnet, gateway, maddr);
360    }
361  }
362  free(sp);
363}
364
365 /*
366  * 960603 - Modified to use dynamic buffer allocator as in ifconfig
367  */
368
369int
370GetIfIndex(char *name)
371{
372  char *buffer;
373  struct ifreq *ifrp;
374  int s, len, elen, newIfIndex;
375  struct ifconf ifconfs;
376
377  /* struct ifreq reqbuf[256]; -- obsoleted :) */
378  int oldbufsize, bufsize = sizeof(struct ifreq);
379
380  s = socket(AF_INET, SOCK_DGRAM, 0);
381  if (s < 0) {
382    LogPrintf(LogERROR, "GetIfIndex: socket(): %s\n", strerror(errno));
383    return (-1);
384  }
385  buffer = malloc(bufsize);	/* allocate first buffer */
386  ifconfs.ifc_len = bufsize;	/* Initial setting */
387
388  /*
389   * Iterate through here until we don't get many more data
390   */
391
392  do {
393    oldbufsize = ifconfs.ifc_len;
394    bufsize += 1 + sizeof(struct ifreq);
395    buffer = realloc((void *) buffer, bufsize);	/* Make it bigger */
396    LogPrintf(LogDEBUG, "GetIfIndex: Growing buffer to %d\n", bufsize);
397    ifconfs.ifc_len = bufsize;
398    ifconfs.ifc_buf = buffer;
399    if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
400      LogPrintf(LogERROR, "GetIfIndex: ioctl(SIOCGIFCONF): %s\n",
401		strerror(errno));
402      close(s);
403      free(buffer);
404      return (-1);
405    }
406  } while (ifconfs.ifc_len > oldbufsize);
407
408  ifrp = ifconfs.ifc_req;
409
410  newIfIndex = 1;
411  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
412    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
413    if (ifrp->ifr_addr.sa_family == AF_LINK) {
414      LogPrintf(LogDEBUG, "GetIfIndex: %d: %-*.*s, %d, %d\n",
415		newIfIndex, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
416		ifrp->ifr_addr.sa_family, elen);
417      if (strcmp(ifrp->ifr_name, name) == 0) {
418	IfIndex = newIfIndex;
419	close(s);
420	free(buffer);
421	return (newIfIndex);
422      }
423      newIfIndex++;
424    }
425    len -= elen;
426    ifrp = (struct ifreq *) ((char *) ifrp + elen);
427    ifrp++;
428  }
429
430  close(s);
431  free(buffer);
432  return (-1);
433}
434