blob: fe8fd915e48779bdeff518875a28fe10b05d4e3f [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 *
Mark Whitley99806ad2001-02-15 23:00:48 +000018 * $Id: route.c,v 1.4 2001/02/15 23:00:48 markw 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>
Mark Whitley99806ad2001-02-15 23:00:48 +000021 * busybox style adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
22 * displayroute() format now matches net-tools-1.57/lib/inet_gr.c line 173.
Eric Andersenec455952001-02-14 08:11:27 +000023 */
24
25#include "busybox.h"
26#include <sys/types.h>
27#include <sys/ioctl.h>
28#include <sys/socket.h>
29#include <net/route.h>
30#include <linux/param.h> // HZ
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <stdio.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdlib.h>
37#include <string.h>
38#include <getopt.h>
39#include <unistd.h>
40#include <ctype.h>
41
42#define _(x) x
43
44#define RTACTION_ADD 1
45#define RTACTION_DEL 2
46#define RTACTION_HELP 3
47#define RTACTION_FLUSH 4
48#define RTACTION_SHOW 5
49
50#define E_NOTFOUND 8
51#define E_SOCK 7
52#define E_LOOKUP 6
53#define E_VERSION 5
54#define E_USAGE 4
55#define E_OPTERR 3
56#define E_INTERN 2
57#define E_NOSUPP 1
58
59/* resolve XXX.YYY.ZZZ.QQQ -> binary */
60
61static int
62INET_resolve(char *name, struct sockaddr *sa)
63{
64 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
65
66 sin->sin_family = AF_INET;
67 sin->sin_port = 0;
68
69 /* Default is special, meaning 0.0.0.0. */
Mark Whitley99806ad2001-02-15 23:00:48 +000070 if (strcmp(name, "default")==0) {
Eric Andersenec455952001-02-14 08:11:27 +000071 sin->sin_addr.s_addr = INADDR_ANY;
Mark Whitley99806ad2001-02-15 23:00:48 +000072 return 1;
Eric Andersenec455952001-02-14 08:11:27 +000073 }
74 /* Look to see if it's a dotted quad. */
75 if (inet_aton(name, &sin->sin_addr)) {
76 return 0;
77 }
78 /* guess not.. */
79 return -1;
80}
81
82#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
83#define HAVE_NEW_ADDRT 1
84#endif
85#ifdef RTF_IRTT /* route */
86#define HAVE_RTF_IRTT 1
87#endif
88#ifdef RTF_REJECT /* route */
89#define HAVE_RTF_REJECT 1
90#endif
91
92#if HAVE_NEW_ADDRT
93#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
94#define full_mask(x) (x)
95#else
96#define mask_in_addr(x) ((x).rt_genmask)
97#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
98#endif
99
100/* add or delete a route depending on action */
101
102static int
103INET_setroute(int action, int options, char **args)
104{
105 struct rtentry rt;
106 char target[128], gateway[128] = "NONE", netmask[128] = "default";
107 int xflag, isnet;
108 int skfd;
109
110 xflag = 0;
111
Mark Whitley99806ad2001-02-15 23:00:48 +0000112 if (strcmp(*args, "-net")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000113 xflag = 1;
114 args++;
Mark Whitley99806ad2001-02-15 23:00:48 +0000115 } else if (strcmp(*args, "-host")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000116 xflag = 2;
117 args++;
118 }
119 if (*args == NULL)
Eric Andersen67991cf2001-02-14 21:23:06 +0000120 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000121
122 safe_strncpy(target, *args++, (sizeof target));
123
124 /* Clean out the RTREQ structure. */
125 memset((char *) &rt, 0, sizeof(struct rtentry));
126
127
128 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000129 error_msg(_("can't resolve %s"), target);
130 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersenec455952001-02-14 08:11:27 +0000131 }
132
133 switch (xflag) {
134 case 1:
135 isnet = 1;
136 break;
137
138 case 2:
139 isnet = 0;
140 break;
141
142 default:
143 break;
144 }
145
146 /* Fill in the other fields. */
147 rt.rt_flags = (RTF_UP | RTF_HOST);
148 if (isnet)
149 rt.rt_flags &= ~RTF_HOST;
150
151 while (*args) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000152 if (strcmp(*args, "metric")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000153 int metric;
154
155 args++;
156 if (!*args || !isdigit(**args))
Eric Andersen67991cf2001-02-14 21:23:06 +0000157 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000158 metric = atoi(*args);
159#if HAVE_NEW_ADDRT
160 rt.rt_metric = metric + 1;
161#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000162 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000163#endif
164 args++;
165 continue;
166 }
167
Mark Whitley99806ad2001-02-15 23:00:48 +0000168 if (strcmp(*args, "netmask")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000169 struct sockaddr mask;
170
171 args++;
172 if (!*args || mask_in_addr(rt))
Eric Andersen67991cf2001-02-14 21:23:06 +0000173 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000174 safe_strncpy(netmask, *args, (sizeof netmask));
175 if ((isnet = INET_resolve(netmask, &mask)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000176 error_msg(_("can't resolve netmask %s"), netmask);
177 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000178 }
179 rt.rt_genmask = full_mask(mask);
180 args++;
181 continue;
182 }
183
Mark Whitley99806ad2001-02-15 23:00:48 +0000184 if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000185 args++;
186 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000187 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000188 if (rt.rt_flags & RTF_GATEWAY)
Eric Andersen67991cf2001-02-14 21:23:06 +0000189 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000190 safe_strncpy(gateway, *args, (sizeof gateway));
191 if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000192 error_msg(_("can't resolve gw %s"), gateway);
193 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000194 }
195 if (isnet) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000196 error_msg(
197 _("%s: cannot use a NETWORK as gateway!"),
Eric Andersenec455952001-02-14 08:11:27 +0000198 gateway);
Mark Whitley99806ad2001-02-15 23:00:48 +0000199 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000200 }
201 rt.rt_flags |= RTF_GATEWAY;
202 args++;
203 continue;
204 }
205
Mark Whitley99806ad2001-02-15 23:00:48 +0000206 if (strcmp(*args, "mss")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000207 args++;
208 rt.rt_flags |= RTF_MSS;
209 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000210 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000211 rt.rt_mss = atoi(*args);
212 args++;
213 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000214 error_msg(_("Invalid MSS."));
215 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000216 }
217 continue;
218 }
219
Mark Whitley99806ad2001-02-15 23:00:48 +0000220 if (strcmp(*args, "window")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000221 args++;
222 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000223 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000224 rt.rt_flags |= RTF_WINDOW;
225 rt.rt_window = atoi(*args);
226 args++;
227 if (rt.rt_window < 128) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000228 error_msg(_("Invalid window."));
229 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000230 }
231 continue;
232 }
233
Mark Whitley99806ad2001-02-15 23:00:48 +0000234 if (strcmp(*args, "irtt")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000235 args++;
236 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000237 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000238 args++;
239#if HAVE_RTF_IRTT
240 rt.rt_flags |= RTF_IRTT;
241 rt.rt_irtt = atoi(*(args - 1));
242 rt.rt_irtt *= (HZ / 100); /* FIXME */
243#if 0 /* FIXME: do we need to check anything of this? */
244 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000245 error_msg(_("Invalid initial rtt."));
246 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000247 }
248#endif
249#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000250 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000251#endif
252 continue;
253 }
254
Mark Whitley99806ad2001-02-15 23:00:48 +0000255 if (strcmp(*args, "reject")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000256 args++;
257#if HAVE_RTF_REJECT
258 rt.rt_flags |= RTF_REJECT;
259#else
Mark Whitley99806ad2001-02-15 23:00:48 +0000260 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000261#endif
262 continue;
263 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000264 if (strcmp(*args, "mod")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000265 args++;
266 rt.rt_flags |= RTF_MODIFIED;
267 continue;
268 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000269 if (strcmp(*args, "dyn")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000270 args++;
271 rt.rt_flags |= RTF_DYNAMIC;
272 continue;
273 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000274 if (strcmp(*args, "reinstate")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000275 args++;
276 rt.rt_flags |= RTF_REINSTATE;
277 continue;
278 }
Mark Whitley99806ad2001-02-15 23:00:48 +0000279 if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000280 args++;
281 if (rt.rt_dev || *args == NULL)
Eric Andersen67991cf2001-02-14 21:23:06 +0000282 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000283 rt.rt_dev = *args++;
284 continue;
285 }
286 /* nothing matches */
287 if (!rt.rt_dev) {
288 rt.rt_dev = *args++;
289 if (*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000290 show_usage(); /* must be last to catch typos */
Mark Whitley99806ad2001-02-15 23:00:48 +0000291 } else {
Eric Andersen67991cf2001-02-14 21:23:06 +0000292 show_usage();
Mark Whitley99806ad2001-02-15 23:00:48 +0000293 }
Eric Andersenec455952001-02-14 08:11:27 +0000294 }
295
296#if HAVE_RTF_REJECT
297 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
298 rt.rt_dev = "lo";
299#endif
300
301 /* sanity checks.. */
302 if (mask_in_addr(rt)) {
303 unsigned long mask = mask_in_addr(rt);
304 mask = ~ntohl(mask);
305 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000306 error_msg(
307 _("netmask %.8x doesn't make sense with host route"),
Eric Andersenec455952001-02-14 08:11:27 +0000308 (unsigned int)mask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000309 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000310 }
311 if (mask & (mask + 1)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000312 error_msg(_("bogus netmask %s"), netmask);
313 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000314 }
315 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
316 if (mask & ~mask_in_addr(rt)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000317 error_msg(_("netmask doesn't match route address"));
318 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000319 }
320 }
321 /* Fill out netmask if still unset */
322 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
323 mask_in_addr(rt) = 0xffffffff;
324
325 /* Create a socket to the INET kernel. */
326 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
327 perror("socket");
Mark Whitley99806ad2001-02-15 23:00:48 +0000328 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000329 }
330 /* Tell the kernel to accept this route. */
331 if (action == RTACTION_DEL) {
332 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
333 perror("SIOCDELRT");
334 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000335 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000336 }
337 } else {
338 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
339 perror("SIOCADDRT");
340 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000341 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000342 }
343 }
344
345 /* Close the socket. */
346 (void) close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000347 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000348}
349
Eric Andersen68be2ab2001-02-14 19:26:39 +0000350void displayroutes(void)
351{
352 char buff[256];
353 int nl = 0 ;
354 struct in_addr dest;
355 struct in_addr gw;
356 struct in_addr mask;
357 int flgs, ref, use, metric;
358 char flags[4];
359 unsigned long int d,g,m;
360
361 char sdest[16], sgw[16];
362
363
364 FILE *fp = fopen("/proc/net/route", "r");
365
366 if(fp==0) {
367 perror_msg_and_die("/proc/net/route");
368 }
369 while( fgets(buff, sizeof(buff), fp) != NULL ) {
370 if(nl) {
371 int ifl = 0;
372 while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
373 ifl++;
374 buff[ifl]=0; /* interface */
375 if(sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx",
376 &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
377 error_msg_and_die( "Unsuported kernel route format\n");
378 }
379 dest.s_addr = d;
380 gw.s_addr = g;
381 mask.s_addr = m;
382 if(nl==1)
383 printf("Kernel IP routing table\n\
384Destination\tGateway\t\tGenmask\t\tFlags Metric Ref Use Iface\n");
385
386 ifl = 0; /* parse flags */
387 if(flgs&1)
388 flags[ifl++]='U';
389 if(flgs&2)
390 flags[ifl++]='G';
391 if(flgs&4)
392 flags[ifl++]='H';
393 flags[ifl]=0;
394 strcpy(sdest, (dest.s_addr==0 ? "default" :
395 inet_ntoa(dest)));
396 strcpy(sgw, (gw.s_addr==0 ? "*" :
397 inet_ntoa(gw)));
Mark Whitley99806ad2001-02-15 23:00:48 +0000398 printf("%-15s %-15s %-15s %-5s %-6d %-2d %7d %s\n",
Eric Andersen68be2ab2001-02-14 19:26:39 +0000399 sdest, sgw,
400 inet_ntoa(mask),
401 flags, metric, ref, use, buff);
402 }
403 nl++;
404 }
405}
406
Eric Andersenec455952001-02-14 08:11:27 +0000407int route_main(int argc, char **argv)
408{
409 int what = 0;
410
411 argc--;
412 argv++;
413
414 if (*argv == NULL) {
Eric Andersen68be2ab2001-02-14 19:26:39 +0000415 displayroutes();
416 exit(EXIT_SUCCESS);
Eric Andersenec455952001-02-14 08:11:27 +0000417 } else {
418 /* check verb */
Mark Whitley99806ad2001-02-15 23:00:48 +0000419 if (strcmp(*argv, "add")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000420 what = RTACTION_ADD;
Mark Whitley99806ad2001-02-15 23:00:48 +0000421 else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000422 what = RTACTION_DEL;
Mark Whitley99806ad2001-02-15 23:00:48 +0000423 else if (strcmp(*argv, "flush")==0)
Eric Andersenec455952001-02-14 08:11:27 +0000424 what = RTACTION_FLUSH;
425 else
Eric Andersen67991cf2001-02-14 21:23:06 +0000426 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000427 }
428
Mark Whitley99806ad2001-02-15 23:00:48 +0000429 return INET_setroute(what, 0, ++argv);
Eric Andersenec455952001-02-14 08:11:27 +0000430}