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