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