3 * Similar to the standard Unix route, but with only the necessary
6 * Bjorn Wesen, Axis Communications AB
8 * Author of the original route:
9 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10 * (derived from FvK's 'route.c 1.70 01/04/94')
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version.
18 * $Id: route.c,v 1.14 2001/11/10 11:22:43 andersen Exp $
20 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
21 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
24 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include "inet_common.h"
27 #include <net/route.h>
28 #include <linux/param.h> // HZ
41 #define RTACTION_ADD 1
42 #define RTACTION_DEL 2
43 #define RTACTION_HELP 3
44 #define RTACTION_FLUSH 4
45 #define RTACTION_SHOW 5
56 #if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
57 #define HAVE_NEW_ADDRT 1
59 #ifdef RTF_IRTT /* route */
60 #define HAVE_RTF_IRTT 1
62 #ifdef RTF_REJECT /* route */
63 #define HAVE_RTF_REJECT 1
67 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
68 #define full_mask(x) (x)
70 #define mask_in_addr(x) ((x).rt_genmask)
71 #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
76 /* add or delete a route depending on action */
79 INET_setroute(int action, int options, char **args)
82 char target[128], gateway[128] = "NONE";
83 const char *netmask = bb_INET_default;
91 if (strcmp(*args, "-net")==0) {
94 } else if (strcmp(*args, "-host")==0) {
100 safe_strncpy(target, *args++, (sizeof target));
102 /* Clean out the RTREQ structure. */
103 memset((char *) &rt, 0, sizeof(struct rtentry));
106 if ((isnet = INET_resolve(target, (struct sockaddr_in *)&rt.rt_dst, xflag!=1)) < 0) {
107 error_msg(_("can't resolve %s"), target);
108 return EXIT_FAILURE; /* XXX change to E_something */
124 /* Fill in the other fields. */
125 rt.rt_flags = (RTF_UP | RTF_HOST);
127 rt.rt_flags &= ~RTF_HOST;
130 if (strcmp(*args, "metric")==0) {
134 if (!*args || !isdigit(**args))
136 metric = atoi(*args);
138 rt.rt_metric = metric + 1;
140 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
146 if (strcmp(*args, "netmask")==0) {
147 struct sockaddr mask;
150 if (!*args || mask_in_addr(rt))
153 if ((isnet = INET_resolve(netmask, (struct sockaddr_in *)&mask, 0)) < 0) {
154 error_msg(_("can't resolve netmask %s"), netmask);
157 rt.rt_genmask = full_mask(mask);
162 if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
166 if (rt.rt_flags & RTF_GATEWAY)
168 safe_strncpy(gateway, *args, (sizeof gateway));
169 if ((isnet = INET_resolve(gateway, (struct sockaddr_in *)&rt.rt_gateway, 1)) < 0) {
170 error_msg(_("can't resolve gw %s"), gateway);
175 _("%s: cannot use a NETWORK as gateway!"),
179 rt.rt_flags |= RTF_GATEWAY;
184 if (strcmp(*args, "mss")==0) {
186 rt.rt_flags |= RTF_MSS;
189 rt.rt_mss = atoi(*args);
191 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
192 error_msg(_("Invalid MSS."));
198 if (strcmp(*args, "window")==0) {
202 rt.rt_flags |= RTF_WINDOW;
203 rt.rt_window = atoi(*args);
205 if (rt.rt_window < 128) {
206 error_msg(_("Invalid window."));
212 if (strcmp(*args, "irtt")==0) {
218 rt.rt_flags |= RTF_IRTT;
219 rt.rt_irtt = atoi(*(args - 1));
220 rt.rt_irtt *= (HZ / 100); /* FIXME */
221 #if 0 /* FIXME: do we need to check anything of this? */
222 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
223 error_msg(_("Invalid initial rtt."));
228 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
233 if (strcmp(*args, "reject")==0) {
236 rt.rt_flags |= RTF_REJECT;
238 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
242 if (strcmp(*args, "mod")==0) {
244 rt.rt_flags |= RTF_MODIFIED;
247 if (strcmp(*args, "dyn")==0) {
249 rt.rt_flags |= RTF_DYNAMIC;
252 if (strcmp(*args, "reinstate")==0) {
254 rt.rt_flags |= RTF_REINSTATE;
257 if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
259 if (rt.rt_dev || *args == NULL)
264 /* nothing matches */
268 show_usage(); /* must be last to catch typos */
275 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
279 /* sanity checks.. */
280 if (mask_in_addr(rt)) {
281 unsigned long mask = mask_in_addr(rt);
283 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
285 _("netmask %.8x doesn't make sense with host route"),
289 if (mask & (mask + 1)) {
290 error_msg(_("bogus netmask %s"), netmask);
293 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
294 if (mask & ~mask_in_addr(rt)) {
295 error_msg(_("netmask doesn't match route address"));
299 /* Fill out netmask if still unset */
300 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
301 mask_in_addr(rt) = 0xffffffff;
303 /* Create a socket to the INET kernel. */
304 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
308 /* Tell the kernel to accept this route. */
309 if (action == RTACTION_DEL) {
310 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
316 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
323 /* Close the socket. */
329 /* Keep this in sync with /usr/src/linux/include/linux/route.h */
330 #define RTF_UP 0x0001 /* route usable */
331 #define RTF_GATEWAY 0x0002 /* destination is a gateway */
332 #define RTF_HOST 0x0004 /* host entry (net otherwise) */
333 #define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
334 #define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
335 #define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
336 #define RTF_MTU 0x0040 /* specific MTU for this route */
338 #define RTF_MSS RTF_MTU /* Compatibility :-( */
340 #define RTF_WINDOW 0x0080 /* per route window clamping */
341 #define RTF_IRTT 0x0100 /* Initial round trip time */
342 #define RTF_REJECT 0x0200 /* Reject route */
345 static void displayroutes(int noresolve)
352 int flgs, ref, use, metric;
354 unsigned long int d,g,m;
356 char sdest[16], sgw[16];
358 FILE *fp = xfopen("/proc/net/route", "r");
363 while( fgets(buff, sizeof(buff), fp) != NULL ) {
367 struct sockaddr_in s_addr;
369 while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
371 buff[ifl]=0; /* interface */
372 if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx",
373 &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
374 error_msg_and_die( "Unsuported kernel route format\n");
377 printf("Kernel IP routing table\n"
378 "Destination Gateway Genmask Flags Metric Ref Use Iface\n");
380 ifl = 0; /* parse flags */
390 if(flgs&RTF_REINSTATE)
394 if(flgs&RTF_MODIFIED)
400 memset(&s_addr, 0, sizeof(struct sockaddr_in));
401 s_addr.sin_family = AF_INET;
402 s_addr.sin_addr = dest;
403 numeric = noresolve | 0x8000; /* default instead of * */
404 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
405 numeric = noresolve | 0x4000; /* host instead of net */
406 s_addr.sin_addr = gw;
407 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
408 printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
411 flags, metric, ref, use, buff);
418 int route_main(int argc, char **argv)
425 if (*argv == NULL || (*(argv+1)==NULL && strcmp(*argv, "-n")==0)) {
426 displayroutes(*argv != NULL);
430 if (strcmp(*argv, "add")==0)
432 else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
434 else if (strcmp(*argv, "flush")==0)
435 what = RTACTION_FLUSH;
440 return INET_setroute(what, 0, ++argv);