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