blob: bb88307a82adb88686c68082d82ecc61ccd2be95 [file] [log] [blame]
Eric Andersenec455952001-02-14 08:11:27 +00001/* route
2 *
3 * Similar to the standard Unix route, but with only the necessary
4 * parts for AF_INET
5 *
6 * Bjorn Wesen, Axis Communications AB
7 *
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')
11 *
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.
17 *
Eric Andersen863a3e12001-08-27 17:57:27 +000018 * $Id: route.c,v 1.12 2001/08/27 17:57:27 andersen Exp $
Eric Andersenec455952001-02-14 08:11:27 +000019 *
Eric Andersen68be2ab2001-02-14 19:26:39 +000020 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
Eric Andersen26d53eb2001-03-07 06:33:01 +000021 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
Eric Andersenec455952001-02-14 08:11:27 +000022 */
23
Eric Andersenec455952001-02-14 08:11:27 +000024#include <sys/types.h>
25#include <sys/ioctl.h>
26#include <sys/socket.h>
27#include <net/route.h>
28#include <linux/param.h> // HZ
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <stdio.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <stdlib.h>
35#include <string.h>
36#include <getopt.h>
37#include <unistd.h>
38#include <ctype.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000039#include "busybox.h"
Eric Andersenec455952001-02-14 08:11:27 +000040
41#define _(x) x
42
43#define RTACTION_ADD 1
44#define RTACTION_DEL 2
45#define RTACTION_HELP 3
46#define RTACTION_FLUSH 4
47#define RTACTION_SHOW 5
48
49#define E_NOTFOUND 8
50#define E_SOCK 7
51#define E_LOOKUP 6
52#define E_VERSION 5
53#define E_USAGE 4
54#define E_OPTERR 3
55#define E_INTERN 2
56#define E_NOSUPP 1
57
58/* resolve XXX.YYY.ZZZ.QQQ -> binary */
59
60static int
61INET_resolve(char *name, struct sockaddr *sa)
62{
Eric Andersen1ca20a72001-03-21 07:34:27 +000063 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
Eric Andersenec455952001-02-14 08:11:27 +000064
Eric Andersen1ca20a72001-03-21 07:34:27 +000065 s_in->sin_family = AF_INET;
66 s_in->sin_port = 0;
Eric Andersenec455952001-02-14 08:11:27 +000067
68 /* Default is special, meaning 0.0.0.0. */
Mark Whitley99806ad2001-02-15 23:00:48 +000069 if (strcmp(name, "default")==0) {
Eric Andersen1ca20a72001-03-21 07:34:27 +000070 s_in->sin_addr.s_addr = INADDR_ANY;
Mark Whitley99806ad2001-02-15 23:00:48 +000071 return 1;
Eric Andersenec455952001-02-14 08:11:27 +000072 }
73 /* Look to see if it's a dotted quad. */
Eric Andersen1ca20a72001-03-21 07:34:27 +000074 if (inet_aton(name, &s_in->sin_addr)) {
Eric Andersenec455952001-02-14 08:11:27 +000075 return 0;
76 }
77 /* guess not.. */
78 return -1;
79}
80
81#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
82#define HAVE_NEW_ADDRT 1
83#endif
84#ifdef RTF_IRTT /* route */
85#define HAVE_RTF_IRTT 1
86#endif
87#ifdef RTF_REJECT /* route */
88#define HAVE_RTF_REJECT 1
89#endif
90
91#if HAVE_NEW_ADDRT
92#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
93#define full_mask(x) (x)
94#else
95#define mask_in_addr(x) ((x).rt_genmask)
96#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
97#endif
98
99/* add or delete a route depending on action */
100
101static int
102INET_setroute(int action, int options, char **args)
103{
104 struct rtentry rt;
105 char target[128], gateway[128] = "NONE", netmask[128] = "default";
106 int xflag, isnet;
107 int skfd;
108
109 xflag = 0;
110
Eric Andersena3c84812001-08-23 22:05:33 +0000111 if (*args == NULL)
112 show_usage();
Mark Whitley99806ad2001-02-15 23:00:48 +0000113 if (strcmp(*args, "-net")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000114 xflag = 1;
115 args++;
Mark Whitley99806ad2001-02-15 23:00:48 +0000116 } else if (strcmp(*args, "-host")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000117 xflag = 2;
118 args++;
119 }
Eric Andersenec455952001-02-14 08:11:27 +0000120 safe_strncpy(target, *args++, (sizeof target));
121
122 /* Clean out the RTREQ structure. */
123 memset((char *) &rt, 0, sizeof(struct rtentry));
124
125
126 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000127 error_msg(_("can't resolve %s"), target);
128 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersenec455952001-02-14 08:11:27 +0000129 }
130
131 switch (xflag) {
132 case 1:
133 isnet = 1;
134 break;
135
136 case 2:
137 isnet = 0;
138 break;
139
140 default:
141 break;
142 }
143
144 /* Fill in the other fields. */
145 rt.rt_flags = (RTF_UP | RTF_HOST);
146 if (isnet)
147 rt.rt_flags &= ~RTF_HOST;
148
149 while (*args) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000150 if (strcmp(*args, "metric")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000151 int metric;
152
153 args++;
154 if (!*args || !isdigit(**args))
Eric Andersen67991cf2001-02-14 21:23:06 +0000155 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000156 metric = atoi(*args);
157#if HAVE_NEW_ADDRT
158 rt.rt_metric = metric + 1;
159#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000160 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000161#endif
162 args++;
163 continue;
164 }
165
Mark Whitley99806ad2001-02-15 23:00:48 +0000166 if (strcmp(*args, "netmask")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000167 struct sockaddr mask;
168
169 args++;
170 if (!*args || mask_in_addr(rt))
Eric Andersen67991cf2001-02-14 21:23:06 +0000171 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000172 safe_strncpy(netmask, *args, (sizeof netmask));
173 if ((isnet = INET_resolve(netmask, &mask)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000174 error_msg(_("can't resolve netmask %s"), netmask);
175 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000176 }
177 rt.rt_genmask = full_mask(mask);
178 args++;
179 continue;
180 }
181
Mark Whitley99806ad2001-02-15 23:00:48 +0000182 if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000183 args++;
184 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000185 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000186 if (rt.rt_flags & RTF_GATEWAY)
Eric Andersen67991cf2001-02-14 21:23:06 +0000187 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000188 safe_strncpy(gateway, *args, (sizeof gateway));
189 if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000190 error_msg(_("can't resolve gw %s"), gateway);
191 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000192 }
193 if (isnet) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000194 error_msg(
195 _("%s: cannot use a NETWORK as gateway!"),
Eric Andersenec455952001-02-14 08:11:27 +0000196 gateway);
Mark Whitley99806ad2001-02-15 23:00:48 +0000197 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000198 }
199 rt.rt_flags |= RTF_GATEWAY;
200 args++;
201 continue;
202 }
203
Mark Whitley99806ad2001-02-15 23:00:48 +0000204 if (strcmp(*args, "mss")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000205 args++;
206 rt.rt_flags |= RTF_MSS;
207 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000208 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000209 rt.rt_mss = atoi(*args);
210 args++;
211 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000212 error_msg(_("Invalid MSS."));
213 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000214 }
215 continue;
216 }
217
Mark Whitley99806ad2001-02-15 23:00:48 +0000218 if (strcmp(*args, "window")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000219 args++;
220 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000221 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000222 rt.rt_flags |= RTF_WINDOW;
223 rt.rt_window = atoi(*args);
224 args++;
225 if (rt.rt_window < 128) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000226 error_msg(_("Invalid window."));
227 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000228 }
229 continue;
230 }
231
Mark Whitley99806ad2001-02-15 23:00:48 +0000232 if (strcmp(*args, "irtt")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000233 args++;
234 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000235 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000236 args++;
237#if HAVE_RTF_IRTT
238 rt.rt_flags |= RTF_IRTT;
239 rt.rt_irtt = atoi(*(args - 1));
240 rt.rt_irtt *= (HZ / 100); /* FIXME */
241#if 0 /* FIXME: do we need to check anything of this? */
242 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000243 error_msg(_("Invalid initial rtt."));
244 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000245 }
246#endif
247#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000248 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000249#endif
250 continue;
251 }
252
Mark Whitley99806ad2001-02-15 23:00:48 +0000253 if (strcmp(*args, "reject")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000254 args++;
255#if HAVE_RTF_REJECT
256 rt.rt_flags |= RTF_REJECT;
257#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000258 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000259#endif
260 continue;
261 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000262 if (strcmp(*args, "mod")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000263 args++;
264 rt.rt_flags |= RTF_MODIFIED;
265 continue;
266 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000267 if (strcmp(*args, "dyn")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000268 args++;
269 rt.rt_flags |= RTF_DYNAMIC;
270 continue;
271 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000272 if (strcmp(*args, "reinstate")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000273 args++;
274 rt.rt_flags |= RTF_REINSTATE;
275 continue;
276 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000277 if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000278 args++;
279 if (rt.rt_dev || *args == NULL)
Eric Andersen67991cf2001-02-14 21:23:06 +0000280 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000281 rt.rt_dev = *args++;
282 continue;
283 }
284 /* nothing matches */
285 if (!rt.rt_dev) {
286 rt.rt_dev = *args++;
287 if (*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000288 show_usage(); /* must be last to catch typos */
Mark Whitley99806ad2001-02-15 23:00:48 +0000289 } else {
Eric Andersen67991cf2001-02-14 21:23:06 +0000290 show_usage();
Mark Whitley99806ad2001-02-15 23:00:48 +0000291 }
Eric Andersenec455952001-02-14 08:11:27 +0000292 }
293
294#if HAVE_RTF_REJECT
295 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
296 rt.rt_dev = "lo";
297#endif
298
299 /* sanity checks.. */
300 if (mask_in_addr(rt)) {
301 unsigned long mask = mask_in_addr(rt);
302 mask = ~ntohl(mask);
303 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000304 error_msg(
305 _("netmask %.8x doesn't make sense with host route"),
Eric Andersenec455952001-02-14 08:11:27 +0000306 (unsigned int)mask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000307 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000308 }
309 if (mask & (mask + 1)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000310 error_msg(_("bogus netmask %s"), netmask);
311 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000312 }
313 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
314 if (mask & ~mask_in_addr(rt)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000315 error_msg(_("netmask doesn't match route address"));
316 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000317 }
318 }
319 /* Fill out netmask if still unset */
320 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
321 mask_in_addr(rt) = 0xffffffff;
322
323 /* Create a socket to the INET kernel. */
324 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
325 perror("socket");
Mark Whitley99806ad2001-02-15 23:00:48 +0000326 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000327 }
328 /* Tell the kernel to accept this route. */
329 if (action == RTACTION_DEL) {
330 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
331 perror("SIOCDELRT");
332 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000333 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000334 }
335 } else {
336 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
337 perror("SIOCADDRT");
338 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000339 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000340 }
341 }
342
343 /* Close the socket. */
344 (void) close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000345 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000346}
347
Eric Andersen863a3e12001-08-27 17:57:27 +0000348#ifndef RTF_UP
349/* Keep this in sync with /usr/src/linux/include/linux/route.h */
350#define RTF_UP 0x0001 /* route usable */
351#define RTF_GATEWAY 0x0002 /* destination is a gateway */
352#define RTF_HOST 0x0004 /* host entry (net otherwise) */
353#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
354#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
355#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
356#define RTF_MTU 0x0040 /* specific MTU for this route */
357#ifndef RTF_MSS
358#define RTF_MSS RTF_MTU /* Compatibility :-( */
359#endif
360#define RTF_WINDOW 0x0080 /* per route window clamping */
361#define RTF_IRTT 0x0100 /* Initial round trip time */
362#define RTF_REJECT 0x0200 /* Reject route */
363#endif
364
Eric Andersen3e6ff902001-03-09 21:24:12 +0000365static void displayroutes(void)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000366{
367 char buff[256];
368 int nl = 0 ;
369 struct in_addr dest;
370 struct in_addr gw;
371 struct in_addr mask;
372 int flgs, ref, use, metric;
373 char flags[4];
374 unsigned long int d,g,m;
375
376 char sdest[16], sgw[16];
377
378
Eric Andersenf1bbb222001-02-18 20:12:25 +0000379 FILE *fp = xfopen("/proc/net/route", "r");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000380
Eric Andersen68be2ab2001-02-14 19:26:39 +0000381 while( fgets(buff, sizeof(buff), fp) != NULL ) {
382 if(nl) {
383 int ifl = 0;
384 while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
385 ifl++;
386 buff[ifl]=0; /* interface */
387 if(sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx",
388 &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
389 error_msg_and_die( "Unsuported kernel route format\n");
390 }
Eric Andersen863a3e12001-08-27 17:57:27 +0000391 if(nl==1)
Mark Whitley825ae5a2001-02-15 23:31:40 +0000392 printf("Kernel IP routing table\n"
393"Destination Gateway Genmask Flags Metric Ref Use Iface\n");
Mark Whitley825ae5a2001-02-15 23:31:40 +0000394
Eric Andersen68be2ab2001-02-14 19:26:39 +0000395 ifl = 0; /* parse flags */
Eric Andersen863a3e12001-08-27 17:57:27 +0000396 if(flgs&RTF_UP)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000397 flags[ifl++]='U';
Eric Andersen863a3e12001-08-27 17:57:27 +0000398 if(flgs&RTF_GATEWAY)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000399 flags[ifl++]='G';
Eric Andersen863a3e12001-08-27 17:57:27 +0000400 if(flgs&RTF_HOST)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000401 flags[ifl++]='H';
Eric Andersen863a3e12001-08-27 17:57:27 +0000402 if(flgs&RTF_REINSTATE)
403 flags[ifl++]='R';
404 if(flgs&RTF_DYNAMIC)
405 flags[ifl++]='D';
406 if(flgs&RTF_MODIFIED)
407 flags[ifl++]='H';
408 if(flgs&RTF_REJECT)
409 flags[ifl++]='!';
Eric Andersen68be2ab2001-02-14 19:26:39 +0000410 flags[ifl]=0;
Eric Andersenf1bbb222001-02-18 20:12:25 +0000411 dest.s_addr = d;
412 gw.s_addr = g;
413 mask.s_addr = m;
Eric Andersen68be2ab2001-02-14 19:26:39 +0000414 strcpy(sdest, (dest.s_addr==0 ? "default" :
415 inet_ntoa(dest)));
416 strcpy(sgw, (gw.s_addr==0 ? "*" :
417 inet_ntoa(gw)));
Eric Andersen26d53eb2001-03-07 06:33:01 +0000418 printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n",
Eric Andersen68be2ab2001-02-14 19:26:39 +0000419 sdest, sgw,
420 inet_ntoa(mask),
421 flags, metric, ref, use, buff);
422 }
423 nl++;
424 }
425}
426
Eric Andersenec455952001-02-14 08:11:27 +0000427int route_main(int argc, char **argv)
428{
429 int what = 0;
430
431 argc--;
432 argv++;
433
434 if (*argv == NULL) {
Eric Andersen68be2ab2001-02-14 19:26:39 +0000435 displayroutes();
Eric Andersen26d53eb2001-03-07 06:33:01 +0000436 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000437 } else {
438 /* check verb */
Mark Whitley99806ad2001-02-15 23:00:48 +0000439 if (strcmp(*argv, "add")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000440 what = RTACTION_ADD;
Mark Whitley99806ad2001-02-15 23:00:48 +0000441 else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000442 what = RTACTION_DEL;
Mark Whitley99806ad2001-02-15 23:00:48 +0000443 else if (strcmp(*argv, "flush")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000444 what = RTACTION_FLUSH;
445 else
Eric Andersen67991cf2001-02-14 21:23:06 +0000446 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000447 }
448
Mark Whitley99806ad2001-02-15 23:00:48 +0000449 return INET_setroute(what, 0, ++argv);
Eric Andersenec455952001-02-14 08:11:27 +0000450}