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