route.c revision 18885
150477Speter/*
2290494Sbapt *	      PPP Routing related Module
3290494Sbapt *
412031Sache *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5290083Sbdrewery *
6290494Sbapt *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7290494Sbapt *
8290494Sbapt * Redistribution and use in source and binary forms are permitted
912031Sache * provided that the above copyright notice and this paragraph are
10290494Sbapt * duplicated in all such forms and that any documentation,
11290494Sbapt * advertising materials, and other materials related to such
12302329Sbapt * distribution and use acknowledge that the software was developed
1324275Sache * by the Internet Initiative Japan, Inc.  The name of the
14290494Sbapt * IIJ may not be used to endorse or promote products derived
15290494Sbapt * from this software without specific prior written permission.
16290494Sbapt * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17290494Sbapt * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18290494Sbapt * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19290494Sbapt *
20290494Sbapt * $Id: route.c,v 1.8 1996/10/06 13:32:35 jkh Exp $
21290494Sbapt *
22290494Sbapt */
23290494Sbapt#include <sys/types.h>
24290494Sbapt#include <machine/endian.h>
25290494Sbapt#include <sys/param.h>
26312336Sbapt#include <sys/socket.h>
27290494Sbapt#include <net/route.h>
28290494Sbapt#include <sys/ioctl.h>
29290494Sbapt#include <net/if.h>
30290494Sbapt#include <errno.h>
31290494Sbapt#include <netinet/in_systm.h>
32290494Sbapt#include <netinet/in.h>
33302329Sbapt#include <arpa/inet.h>
34290494Sbapt#if (BSD >= 199306)
35290494Sbapt#include <sys/sysctl.h>
36290494Sbapt#else
37312336Sbapt#include <sys/kinfo.h>
38290494Sbapt#endif
39290494Sbapt#include <stdlib.h>
40290494Sbapt#include <stdio.h>
41290494Sbapt#include <string.h>
42290494Sbapt#include <unistd.h>
43290494Sbapt#include "log.h"
44312336Sbapt
45312336Sbaptstatic int IfIndex;
46290494Sbapt
47290494Sbaptstruct rtmsg {
48290494Sbapt  struct rt_msghdr m_rtm;
49302329Sbapt  char m_space[64];
50302329Sbapt};
51136596Sru
52298121Sbaptstatic int seqno;
53298121Sbapt
54298121Sbaptvoid
55298121SbaptOsSetRoute(cmd, dst, gateway, mask)
56298121Sbaptint cmd;
57298121Sbaptstruct in_addr dst;
58298121Sbaptstruct in_addr gateway;
59298121Sbaptstruct in_addr mask;
60298121Sbapt{
61298121Sbapt  struct rtmsg rtmes;
62298121Sbapt  int s, nb, wb;
63298121Sbapt  char *cp;
64298121Sbapt  u_long *lp;
65298121Sbapt  struct sockaddr_in rtdata;
66298121Sbapt
67298121Sbapt  s = socket(PF_ROUTE, SOCK_RAW, 0);
68298121Sbapt  if (s < 0)
69298121Sbapt    logprintf("socket\n");
70298121Sbapt
71298121Sbapt  bzero(&rtmes, sizeof(rtmes));
72298121Sbapt  rtmes.m_rtm.rtm_version = RTM_VERSION;
73298121Sbapt  rtmes.m_rtm.rtm_type = cmd;
74298121Sbapt  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
75298121Sbapt  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
76298121Sbapt  rtmes.m_rtm.rtm_seq = ++seqno;
77298121Sbapt  rtmes.m_rtm.rtm_pid = getpid();
78298121Sbapt  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
79298121Sbapt
80298121Sbapt  bzero(&rtdata, sizeof(rtdata));
81298121Sbapt  rtdata.sin_len = 16;
82298121Sbapt  rtdata.sin_family = AF_INET;
83298121Sbapt  rtdata.sin_port = 0;
84298121Sbapt  rtdata.sin_addr = dst;
85298121Sbapt
86298121Sbapt  cp = rtmes.m_space;
87298121Sbapt  bcopy(&rtdata, cp, 16);
88298121Sbapt  cp += 16;
89298121Sbapt  if (gateway.s_addr) {
90298121Sbapt    rtdata.sin_addr = gateway;
91298121Sbapt    bcopy(&rtdata, cp, 16);
92298121Sbapt    cp += 16;
93298121Sbapt  }
94298121Sbapt
95298121Sbapt  if (dst.s_addr == INADDR_ANY)
96298121Sbapt    mask.s_addr = INADDR_ANY;
97298121Sbapt
98298121Sbapt  lp = (u_long *)cp;
99298121Sbapt
100298121Sbapt  if (mask.s_addr) {
101298121Sbapt    *lp++ = 8;
102298121Sbapt    cp += sizeof(int);
103298121Sbapt    *lp = mask.s_addr;
104298121Sbapt  } else
105298121Sbapt    *lp = 0;
106298121Sbapt  cp += sizeof(u_long);
107298121Sbapt
108298121Sbapt  nb = cp - (char *)&rtmes;
109298121Sbapt  rtmes.m_rtm.rtm_msglen = nb;
110298121Sbapt  wb = write(s, &rtmes, nb);
111298121Sbapt  if (wb < 0) {
112298121Sbapt     LogPrintf(LOG_TCPIP_BIT, "Already set route addr dst=%x, gateway=%x\n"
113298121Sbapt         ,dst.s_addr, gateway.s_addr);
114298121Sbapt  }
115298121Sbapt#ifdef DEBUG
116298121Sbapt  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
117298121Sbapt#endif
118298121Sbapt  close(s);
119298121Sbapt}
120298121Sbapt
121298121Sbaptstatic void
122298121Sbaptp_sockaddr(sa, width)
123298121Sbaptstruct sockaddr *sa;
124298121Sbaptint width;
125298121Sbapt{
126312336Sbapt  register char *cp;
127312336Sbapt  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
128298121Sbapt
129312336Sbapt  cp = (sin->sin_addr.s_addr == 0) ? "default" :
130298121Sbapt	   inet_ntoa(sin->sin_addr);
131298121Sbapt  printf("%-*.*s ", width, width, cp);
132298121Sbapt}
133298121Sbapt
134298121Sbaptstruct bits {
135298121Sbapt  short b_mask;
136298121Sbapt  char  b_val;
137298121Sbapt} bits[] = {
138298121Sbapt  { RTF_UP,	  'U' },
139298121Sbapt  { RTF_GATEWAY,  'G' },
140298121Sbapt  { RTF_HOST,	  'H' },
141298121Sbapt  { RTF_DYNAMIC,  'D' },
142298121Sbapt  { RTF_MODIFIED, 'M' },
143298121Sbapt  { RTF_CLONING,  'C' },
144298121Sbapt  { RTF_XRESOLVE, 'X' },
145298121Sbapt  { RTF_LLINFO,   'L' },
146298121Sbapt  { RTF_REJECT,   'R' },
147298121Sbapt  { 0 }
148298121Sbapt};
149298121Sbapt
150298121Sbaptstatic void
151298121Sbaptp_flags(f, format)
152298121Sbaptregister int f;
153298121Sbaptchar *format;
154298121Sbapt{
155298121Sbapt  char name[33], *flags;
156298121Sbapt  register struct bits *p = bits;
157312336Sbapt
158312336Sbapt  for (flags = name; p->b_mask; p++)
159302329Sbapt    if (p->b_mask & f)
160302329Sbapt      *flags++ = p->b_val;
161312336Sbapt  *flags = '\0';
162312336Sbapt  printf(format, name);
163312336Sbapt}
164312336Sbapt
165312336Sbaptint
166312336SbaptShowRoute()
167298121Sbapt{
168298121Sbapt  struct rt_msghdr *rtm;
169292453Sbapt  struct sockaddr *sa;
170292453Sbapt  char *sp, *ep, *cp;
171292453Sbapt  u_char *wp;
172292453Sbapt  int *lp;
173292453Sbapt  int needed, nb;
174302329Sbapt  u_long mask;
175292453Sbapt#if (BSD >= 199306)
176292453Sbapt  int mib[6];
177292453Sbapt#endif
178292453Sbapt
179292453Sbapt#if (BSD >= 199306)
180292453Sbapt  mib[0] = CTL_NET;
181292453Sbapt  mib[1] = PF_ROUTE;
182292453Sbapt  mib[2] = 0;
183292453Sbapt  mib[3] = 0;
184292453Sbapt  mib[4] = NET_RT_DUMP;
185292453Sbapt  mib[5] = 0;
186292453Sbapt  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
187292453Sbapt    perror("sysctl-estimate");
188292453Sbapt    return(1);
189292453Sbapt  }
190292453Sbapt#else
191292453Sbapt  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
192292453Sbapt#endif
193292453Sbapt  if (needed < 0)
194292453Sbapt    return(1);
195292453Sbapt  sp = malloc(needed);
196292453Sbapt  if (sp == NULL)
197292453Sbapt    return(1);
198292453Sbapt#if (BSD >= 199306)
199292453Sbapt  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
200292453Sbapt    perror("sysctl-getroute");
201292453Sbapt    free(sp);
202292453Sbapt    return(1);
203292453Sbapt  }
204312336Sbapt#else
205292453Sbapt  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
206292453Sbapt    free(sp);
207302329Sbapt    return(1);
208292453Sbapt#endif
209136596Sru  ep = sp + needed;
210290494Sbapt
211136596Sru  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
212136596Sru    rtm = (struct rt_msghdr *)cp;
213292453Sbapt    sa = (struct sockaddr *)(rtm + 1);
214292453Sbapt    mask = 0xffffffff;
215292453Sbapt    if (rtm->rtm_addrs == RTA_DST)
216290494Sbapt      p_sockaddr(sa, 36);
217136596Sru    else {
218290494Sbapt      wp = (u_char *)cp + rtm->rtm_msglen;
219290494Sbapt      p_sockaddr(sa, 16);
22023228Swosch      if (sa->sa_len == 0)
22112031Sache	sa->sa_len = sizeof(long);
222298121Sbapt      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
223298121Sbapt      p_sockaddr(sa, 18);
224298125Sbapt      lp = (int *)(sa->sa_len + (char *)sa);
225298121Sbapt      if ((char *)lp < (char *)wp && *lp) {
226298121Sbapt#ifdef DEBUG
227302329Sbapt	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
228298121Sbapt#endif
229298121Sbapt	wp = (u_char *)(lp + 1);
230298121Sbapt	mask = 0;
23112031Sache	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