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