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