route.c revision 13389
1133808Spjd/*
2142727Spjd *	      PPP Routing related Module
3133808Spjd *
4133808Spjd *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5133808Spjd *
6133808Spjd *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
7133808Spjd *
8133808Spjd * Redistribution and use in source and binary forms are permitted
9133808Spjd * provided that the above copyright notice and this paragraph are
10133808Spjd * duplicated in all such forms and that any documentation,
11133808Spjd * advertising materials, and other materials related to such
12133808Spjd * distribution and use acknowledge that the software was developed
13155175Spjd * by the Internet Initiative Japan, Inc.  The name of the
14133808Spjd * IIJ may not be used to endorse or promote products derived
15133808Spjd * from this software without specific prior written permission.
16133808Spjd * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17133808Spjd * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18133808Spjd * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19133808Spjd *
20133808Spjd * $Id: route.c,v 1.4 1995/07/08 06:08:52 amurai Exp $
21133808Spjd *
22133808Spjd */
23133808Spjd#include <sys/types.h>
24133808Spjd#include <machine/endian.h>
25133808Spjd#include <sys/param.h>
26133808Spjd#include <sys/socket.h>
27133808Spjd#include <net/route.h>
28133808Spjd#include <sys/ioctl.h>
29133808Spjd#include <net/if.h>
30133808Spjd#include <errno.h>
31133808Spjd#include <netinet/in_systm.h>
32133808Spjd#include <netinet/in.h>
33133808Spjd#include <arpa/inet.h>
34133808Spjd#if (BSD >= 199306)
35133808Spjd#include <sys/sysctl.h>
36133808Spjd#else
37133808Spjd#include <sys/kinfo.h>
38133808Spjd#endif
39133808Spjd#include <stdlib.h>
40133808Spjd#include <stdio.h>
41133808Spjd#include <string.h>
42133808Spjd#include <unistd.h>
43133808Spjd#include "log.h"
44133808Spjd
45133808Spjdstatic int IfIndex;
46133808Spjd
47133808Spjdstruct rtmsg {
48133808Spjd  struct rt_msghdr m_rtm;
49133808Spjd  char m_space[64];
50133808Spjd};
51133808Spjd
52133808Spjdstatic int seqno;
53133808Spjd
54143586Spjdvoid
55143586SpjdOsSetRoute(cmd, dst, gateway, mask)
56143586Spjdint cmd;
57133808Spjdstruct in_addr dst;
58133808Spjdstruct in_addr gateway;
59133808Spjdstruct in_addr mask;
60133808Spjd{
61133808Spjd  struct rtmsg rtmes;
62133808Spjd  int s, nb, wb;
63134124Spjd  char *cp;
64134124Spjd  u_long *lp;
65134168Spjd  struct sockaddr_in rtdata;
66134168Spjd
67133808Spjd  s = socket(PF_ROUTE, SOCK_RAW, 0);
68143586Spjd  if (s < 0)
69143586Spjd    logprintf("socket\n");
70133808Spjd
71143586Spjd  bzero(&rtmes, sizeof(rtmes));
72143586Spjd  rtmes.m_rtm.rtm_version = RTM_VERSION;
73143586Spjd  rtmes.m_rtm.rtm_type = cmd;
74133808Spjd  rtmes.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
75133808Spjd  if (cmd == RTM_ADD) rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
76133808Spjd  rtmes.m_rtm.rtm_seq = ++seqno;
77133808Spjd  rtmes.m_rtm.rtm_pid = getpid();
78133808Spjd  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
79143586Spjd
80143586Spjd  bzero(&rtdata, sizeof(rtdata));
81133808Spjd  rtdata.sin_len = 16;
82133808Spjd  rtdata.sin_family = AF_INET;
83133808Spjd  rtdata.sin_port = 0;
84133808Spjd  rtdata.sin_addr = dst;
85133808Spjd
86134124Spjd  cp = rtmes.m_space;
87134168Spjd  bcopy(&rtdata, cp, 16);
88133808Spjd  cp += 16;
89143586Spjd  if (gateway.s_addr) {
90143586Spjd    rtdata.sin_addr = gateway;
91133808Spjd    bcopy(&rtdata, cp, 16);
92143586Spjd    cp += 16;
93143586Spjd  }
94143586Spjd
95133808Spjd  if (dst.s_addr == INADDR_ANY)
96133808Spjd    mask.s_addr = INADDR_ANY;
97133808Spjd
98133808Spjd  lp = (u_long *)cp;
99143586Spjd
100143586Spjd  if (mask.s_addr) {
101133808Spjd    *lp++ = 8;
102133808Spjd    cp += sizeof(int);
103133808Spjd    *lp = mask.s_addr;
104133808Spjd  } else
105133808Spjd    *lp = 0;
106143586Spjd  cp += sizeof(u_long);
107143586Spjd
108133808Spjd  nb = cp - (char *)&rtmes;
109133808Spjd  rtmes.m_rtm.rtm_msglen = nb;
110133808Spjd  wb = write(s, &rtmes, nb);
111133808Spjd  if (wb < 0) {
112133808Spjd     LogPrintf(LOG_TCPIP, "Already set route addr dst=%x, gateway=%x\n"
113133808Spjd         ,dst.s_addr, gateway.s_addr);
114133808Spjd  }
115133808Spjd#ifdef DEBUG
116133808Spjd  logprintf("wrote %d: dst = %x, gateway = %x\n", nb, dst.s_addr, gateway.s_addr);
117133808Spjd#endif
118133808Spjd  close(s);
119133808Spjd}
120133808Spjd
121133808Spjdstatic void
122153190Spjdp_sockaddr(sa, width)
123133808Spjdstruct sockaddr *sa;
124133808Spjdint width;
125133808Spjd{
126133808Spjd  register char *cp;
127133808Spjd  register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
128133808Spjd
129133808Spjd  cp = (sin->sin_addr.s_addr == 0) ? "default" :
130133808Spjd	   inet_ntoa(sin->sin_addr);
131133808Spjd  printf("%-*.*s ", width, width, cp);
132133808Spjd}
133133808Spjd
134133808Spjdstruct bits {
135133808Spjd  short b_mask;
136133808Spjd  char  b_val;
137133808Spjd} bits[] = {
138133808Spjd  { RTF_UP,	  'U' },
139133808Spjd  { RTF_GATEWAY,  'G' },
140133808Spjd  { RTF_HOST,	  'H' },
141133808Spjd  { RTF_DYNAMIC,  'D' },
142133808Spjd  { RTF_MODIFIED, 'M' },
143134420Spjd  { RTF_CLONING,  'C' },
144134420Spjd  { RTF_XRESOLVE, 'X' },
145153190Spjd  { RTF_LLINFO,   'L' },
146133808Spjd  { RTF_REJECT,   'R' },
147153190Spjd  { 0 }
148153190Spjd};
149133808Spjd
150133808Spjdstatic void
151133808Spjdp_flags(f, format)
152153190Spjdregister int f;
153133808Spjdchar *format;
154133808Spjd{
155133808Spjd  char name[33], *flags;
156133808Spjd  register struct bits *p = bits;
157133808Spjd
158133808Spjd  for (flags = name; p->b_mask; p++)
159153190Spjd    if (p->b_mask & f)
160133808Spjd      *flags++ = p->b_val;
161147947Spjd  *flags = '\0';
162153190Spjd  printf(format, name);
163133808Spjd}
164133808Spjd
165139295Spjdint
166133808SpjdShowRoute()
167133808Spjd{
168153190Spjd  struct rt_msghdr *rtm;
169153190Spjd  struct sockaddr *sa;
170133808Spjd  char *sp, *ep, *cp;
171153190Spjd  u_char *wp;
172153190Spjd  int *lp;
173134124Spjd  int needed, nb;
174153190Spjd  u_long mask;
175153190Spjd#if (BSD >= 199306)
176134168Spjd  int mib[6];
177153190Spjd#endif
178134168Spjd
179134168Spjd#if (BSD >= 199306)
180134168Spjd  mib[0] = CTL_NET;
181153190Spjd  mib[1] = PF_ROUTE;
182133808Spjd  mib[2] = 0;
183133808Spjd  mib[3] = 0;
184133808Spjd  mib[4] = NET_RT_DUMP;
185133808Spjd  mib[5] = 0;
186133808Spjd  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
187133808Spjd    perror("sysctl-estimate");
188133808Spjd    return(1);
189153190Spjd  }
190153190Spjd#else
191133808Spjd  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
192133808Spjd#endif
193133808Spjd  if (needed < 0)
194133808Spjd    return(1);
195133808Spjd  sp = malloc(needed);
196133808Spjd  if (sp == NULL)
197133808Spjd    return(1);
198133808Spjd#if (BSD >= 199306)
199133808Spjd  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
200133808Spjd    perror("sysctl-getroute");
201133808Spjd    return(1);
202133808Spjd  }
203133808Spjd#else
204133808Spjd  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
205133808Spjd    return(1);
206153190Spjd#endif
207153190Spjd  ep = sp + needed;
208133808Spjd
209133808Spjd  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
210133808Spjd    rtm = (struct rt_msghdr *)cp;
211133808Spjd    sa = (struct sockaddr *)(rtm + 1);
212153190Spjd    mask = 0xffffffff;
213153190Spjd    if (rtm->rtm_addrs == RTA_DST)
214133808Spjd      p_sockaddr(sa, 36);
215133808Spjd    else {
216133808Spjd      wp = (u_char *)cp + rtm->rtm_msglen;
217133808Spjd      p_sockaddr(sa, 16);
218133808Spjd      if (sa->sa_len == 0)
219133808Spjd	sa->sa_len = sizeof(long);
220133808Spjd      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
221133808Spjd      p_sockaddr(sa, 18);
222133808Spjd      lp = (int *)(sa->sa_len + (char *)sa);
223133808Spjd      if ((char *)lp < (char *)wp && *lp) {
224133808Spjd#ifdef DEBUG
225153190Spjd	logprintf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
226153190Spjd#endif
227142727Spjd	wp = (u_char *)(lp + 1);
228142727Spjd	mask = 0;
229142727Spjd	for (nb = *lp; nb > 4; nb--) {
230134420Spjd	  mask <<= 8;
231134420Spjd	  mask |= *wp++;
232142727Spjd	}
233134420Spjd	for (nb = 8 - *lp; nb > 0; nb--)
234134420Spjd	  mask <<= 8;
235133808Spjd      }
236142727Spjd    }
237153190Spjd    printf("%08lx  ", mask);
238133808Spjd    p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
239133808Spjd    printf("(%d)\n", rtm->rtm_index);
240133808Spjd  }
241133808Spjd
242133808Spjd  return(1);
243133808Spjd}
244153190Spjd
245134539Spjd/*
246134539Spjd *  Delete routes associated with our interface
247134539Spjd */
248134539Spjdvoid
249134539SpjdDeleteIfRoutes(all)
250134539Spjdint all;
251133808Spjd{
252133808Spjd  struct rt_msghdr *rtm;
253133808Spjd  struct sockaddr *sa;
254133808Spjd  struct in_addr dstnet, gateway;
255133808Spjd  int needed;
256133808Spjd  char *sp, *cp, *ep;
257133808Spjd  u_long mask;
258133808Spjd  int *lp, nb;
259133808Spjd  u_char *wp;
260133808Spjd#if (BSD >= 199306)
261133808Spjd  int mib[6];
262133808Spjd#endif
263133808Spjd
264133808Spjd#ifdef DEBUG
265133808Spjd  logprintf("DeleteIfRoutes (%d)\n", IfIndex);
266133808Spjd#endif
267133808Spjd#if (BSD >= 199306)
268153190Spjd  mib[0] = CTL_NET;
269133808Spjd  mib[1] = PF_ROUTE;
270153190Spjd  mib[2] = 0;
271153190Spjd  mib[3] = 0;
272133808Spjd  mib[4] = NET_RT_DUMP;
273133808Spjd  mib[5] = 0;
274133808Spjd  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
275133808Spjd    perror("sysctl-estimate");
276153190Spjd    return;
277153190Spjd  }
278133808Spjd#else
279133808Spjd  needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0);
280133808Spjd#endif
281133808Spjd
282133808Spjd  if (needed < 0)
283133808Spjd    return;
284133808Spjd
285133808Spjd  sp = malloc(needed);
286155175Spjd  if (sp == NULL)
287133808Spjd    return;
288133808Spjd
289133808Spjd#if (BSD >= 199306)
290133808Spjd  if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
291133808Spjd    free(sp);
292133808Spjd    perror("sysctl-getroute");
293133808Spjd    return;
294133808Spjd  }
295153190Spjd#else
296133808Spjd  if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0) {
297153190Spjd    free(sp);
298153190Spjd    return;
299133808Spjd  }
300133808Spjd#endif
301133808Spjd  ep = sp + needed;
302133808Spjd
303153190Spjd  for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
304153190Spjd    rtm = (struct rt_msghdr *)cp;
305133808Spjd    sa = (struct sockaddr *)(rtm + 1);
306133808Spjd#ifdef DEBUG
307133808Spjd    logprintf("addrs: %x, index: %d, flags: %x, dstnet: %x\n",
308133808Spjd	rtm->rtm_addrs, rtm->rtm_index, rtm->rtm_flags,
309133808Spjd	((struct sockaddr_in *)sa)->sin_addr);
310133808Spjd#endif
311133808Spjd    if (rtm->rtm_addrs != RTA_DST &&
312133808Spjd       (rtm->rtm_index == IfIndex) &&
313133808Spjd       (all || (rtm->rtm_flags & RTF_GATEWAY))) {
314133808Spjd      dstnet = ((struct sockaddr_in *)sa)->sin_addr;
315133808Spjd      wp = (u_char *)cp + rtm->rtm_msglen;
316133808Spjd      if (sa->sa_len == 0)
317133808Spjd	sa->sa_len = sizeof(long);
318133808Spjd      sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
319133808Spjd      gateway = ((struct sockaddr_in *)sa)->sin_addr;
320133808Spjd      lp = (int *)(sa->sa_len + (char *)sa);
321133808Spjd      mask = 0;
322133808Spjd      if ((char *)lp < (char *)wp && *lp) {
323133808Spjd#ifdef DEBUG
324	printf(" flag = %x, rest = %d", rtm->rtm_flags, *lp);
325#endif
326	wp = (u_char *)(lp + 1);
327	for (nb = *lp; nb > 4; nb--) {
328	  mask <<= 8;
329	  mask |= *wp++;
330	}
331	for (nb = 8 - *lp; nb > 0; nb--)
332	  mask <<= 8;
333      }
334#ifdef DEBUG
335      logprintf("## %s ", inet_ntoa(dstnet));
336      logprintf(" %s  %d\n", inet_ntoa(gateway), rtm->rtm_index);
337#endif
338      if (dstnet.s_addr == INADDR_ANY) {
339        gateway.s_addr = INADDR_ANY;
340        mask = INADDR_ANY;
341      }
342      OsSetRoute(RTM_DELETE, dstnet, gateway, htonl(mask));
343    }
344#ifdef DEBUG
345    else if (rtm->rtm_index == IfIndex) {
346      logprintf("??? addrs: %x, flags = %x\n", rtm->rtm_addrs, rtm->rtm_flags);
347    }
348#endif
349  }
350  free(sp);
351}
352
353int
354GetIfIndex(name)
355char *name;
356{
357  struct ifreq *ifrp;
358  int s, len, elen, index;
359  struct ifconf ifconfs;
360  struct ifreq reqbuf[32];
361
362  s = socket(AF_INET, SOCK_DGRAM, 0);
363  if (s < 0) {
364    perror("socket");
365    return(-1);
366  }
367
368  ifconfs.ifc_len = sizeof(reqbuf);
369  ifconfs.ifc_buf = (caddr_t)reqbuf;
370  if (ioctl(s, SIOCGIFCONF, &ifconfs) < 0) {
371    perror("IFCONF");
372    return(-1);
373  }
374
375  ifrp = ifconfs.ifc_req;
376
377  index = 1;
378  for (len = ifconfs.ifc_len; len > 0; len -= sizeof(struct ifreq)) {
379    elen = ifrp->ifr_addr.sa_len - sizeof(struct sockaddr);
380    if (ifrp->ifr_addr.sa_family == AF_LINK) {
381#ifdef DEBUG
382      logprintf("%d: %-*.*s, %d, %d\n", index, IFNAMSIZ, IFNAMSIZ, ifrp->ifr_name,
383	   ifrp->ifr_addr.sa_family, elen);
384#endif
385      if (strcmp(ifrp->ifr_name, name) == 0) {
386        IfIndex = index;
387        return(index);
388      }
389      index++;
390    }
391
392    len -= elen;
393    ifrp = (struct ifreq *)((char *)ifrp + elen);
394    ifrp++;
395  }
396
397  close(s);
398  return(-1);
399}
400