diff options
Diffstat (limited to 'route.c')
-rw-r--r-- | route.c | 452 |
1 files changed, 0 insertions, 452 deletions
diff --git a/route.c b/route.c deleted file mode 100644 index ee3533100..000000000 --- a/route.c +++ /dev/null | |||
@@ -1,452 +0,0 @@ | |||
1 | /* 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 | * | ||
18 | * $Id: route.c,v 1.13 2001/09/05 19:32:00 andersen Exp $ | ||
19 | * | ||
20 | * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> | ||
21 | * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> | ||
22 | */ | ||
23 | |||
24 | #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> | ||
39 | #include "busybox.h" | ||
40 | |||
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 | |||
60 | static int | ||
61 | INET_resolve(char *name, struct sockaddr *sa) | ||
62 | { | ||
63 | struct sockaddr_in *s_in = (struct sockaddr_in *)sa; | ||
64 | |||
65 | s_in->sin_family = AF_INET; | ||
66 | s_in->sin_port = 0; | ||
67 | |||
68 | /* Default is special, meaning 0.0.0.0. */ | ||
69 | if (strcmp(name, "default")==0) { | ||
70 | s_in->sin_addr.s_addr = INADDR_ANY; | ||
71 | return 1; | ||
72 | } | ||
73 | /* Look to see if it's a dotted quad. */ | ||
74 | if (inet_aton(name, &s_in->sin_addr)) { | ||
75 | 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 | |||
101 | static int | ||
102 | INET_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 | |||
111 | if (*args == NULL) | ||
112 | show_usage(); | ||
113 | if (strcmp(*args, "-net")==0) { | ||
114 | xflag = 1; | ||
115 | args++; | ||
116 | } else if (strcmp(*args, "-host")==0) { | ||
117 | xflag = 2; | ||
118 | args++; | ||
119 | } | ||
120 | 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) { | ||
127 | error_msg(_("can't resolve %s"), target); | ||
128 | return EXIT_FAILURE; /* XXX change to E_something */ | ||
129 | } | ||
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) { | ||
150 | if (strcmp(*args, "metric")==0) { | ||
151 | int metric; | ||
152 | |||
153 | args++; | ||
154 | if (!*args || !isdigit(**args)) | ||
155 | show_usage(); | ||
156 | metric = atoi(*args); | ||
157 | #if HAVE_NEW_ADDRT | ||
158 | rt.rt_metric = metric + 1; | ||
159 | #else | ||
160 | ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */ | ||
161 | #endif | ||
162 | args++; | ||
163 | continue; | ||
164 | } | ||
165 | |||
166 | if (strcmp(*args, "netmask")==0) { | ||
167 | struct sockaddr mask; | ||
168 | |||
169 | args++; | ||
170 | if (!*args || mask_in_addr(rt)) | ||
171 | show_usage(); | ||
172 | safe_strncpy(netmask, *args, (sizeof netmask)); | ||
173 | if ((isnet = INET_resolve(netmask, &mask)) < 0) { | ||
174 | error_msg(_("can't resolve netmask %s"), netmask); | ||
175 | return E_LOOKUP; | ||
176 | } | ||
177 | rt.rt_genmask = full_mask(mask); | ||
178 | args++; | ||
179 | continue; | ||
180 | } | ||
181 | |||
182 | if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { | ||
183 | args++; | ||
184 | if (!*args) | ||
185 | show_usage(); | ||
186 | if (rt.rt_flags & RTF_GATEWAY) | ||
187 | show_usage(); | ||
188 | safe_strncpy(gateway, *args, (sizeof gateway)); | ||
189 | if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { | ||
190 | error_msg(_("can't resolve gw %s"), gateway); | ||
191 | return E_LOOKUP; | ||
192 | } | ||
193 | if (isnet) { | ||
194 | error_msg( | ||
195 | _("%s: cannot use a NETWORK as gateway!"), | ||
196 | gateway); | ||
197 | return E_OPTERR; | ||
198 | } | ||
199 | rt.rt_flags |= RTF_GATEWAY; | ||
200 | args++; | ||
201 | continue; | ||
202 | } | ||
203 | |||
204 | if (strcmp(*args, "mss")==0) { | ||
205 | args++; | ||
206 | rt.rt_flags |= RTF_MSS; | ||
207 | if (!*args) | ||
208 | show_usage(); | ||
209 | rt.rt_mss = atoi(*args); | ||
210 | args++; | ||
211 | if (rt.rt_mss < 64 || rt.rt_mss > 32768) { | ||
212 | error_msg(_("Invalid MSS.")); | ||
213 | return E_OPTERR; | ||
214 | } | ||
215 | continue; | ||
216 | } | ||
217 | |||
218 | if (strcmp(*args, "window")==0) { | ||
219 | args++; | ||
220 | if (!*args) | ||
221 | show_usage(); | ||
222 | rt.rt_flags |= RTF_WINDOW; | ||
223 | rt.rt_window = atoi(*args); | ||
224 | args++; | ||
225 | if (rt.rt_window < 128) { | ||
226 | error_msg(_("Invalid window.")); | ||
227 | return E_OPTERR; | ||
228 | } | ||
229 | continue; | ||
230 | } | ||
231 | |||
232 | if (strcmp(*args, "irtt")==0) { | ||
233 | args++; | ||
234 | if (!*args) | ||
235 | show_usage(); | ||
236 | 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)) { | ||
243 | error_msg(_("Invalid initial rtt.")); | ||
244 | return E_OPTERR; | ||
245 | } | ||
246 | #endif | ||
247 | #else | ||
248 | ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */ | ||
249 | #endif | ||
250 | continue; | ||
251 | } | ||
252 | |||
253 | if (strcmp(*args, "reject")==0) { | ||
254 | args++; | ||
255 | #if HAVE_RTF_REJECT | ||
256 | rt.rt_flags |= RTF_REJECT; | ||
257 | #else | ||
258 | ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */ | ||
259 | #endif | ||
260 | continue; | ||
261 | } | ||
262 | if (strcmp(*args, "mod")==0) { | ||
263 | args++; | ||
264 | rt.rt_flags |= RTF_MODIFIED; | ||
265 | continue; | ||
266 | } | ||
267 | if (strcmp(*args, "dyn")==0) { | ||
268 | args++; | ||
269 | rt.rt_flags |= RTF_DYNAMIC; | ||
270 | continue; | ||
271 | } | ||
272 | if (strcmp(*args, "reinstate")==0) { | ||
273 | args++; | ||
274 | rt.rt_flags |= RTF_REINSTATE; | ||
275 | continue; | ||
276 | } | ||
277 | if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { | ||
278 | args++; | ||
279 | if (rt.rt_dev || *args == NULL) | ||
280 | show_usage(); | ||
281 | rt.rt_dev = *args++; | ||
282 | continue; | ||
283 | } | ||
284 | /* nothing matches */ | ||
285 | if (!rt.rt_dev) { | ||
286 | rt.rt_dev = *args++; | ||
287 | if (*args) | ||
288 | show_usage(); /* must be last to catch typos */ | ||
289 | } else { | ||
290 | show_usage(); | ||
291 | } | ||
292 | } | ||
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) { | ||
304 | error_msg( | ||
305 | _("netmask %.8x doesn't make sense with host route"), | ||
306 | (unsigned int)mask); | ||
307 | return E_OPTERR; | ||
308 | } | ||
309 | if (mask & (mask + 1)) { | ||
310 | error_msg(_("bogus netmask %s"), netmask); | ||
311 | return E_OPTERR; | ||
312 | } | ||
313 | mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; | ||
314 | if (mask & ~mask_in_addr(rt)) { | ||
315 | error_msg(_("netmask doesn't match route address")); | ||
316 | return E_OPTERR; | ||
317 | } | ||
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"); | ||
326 | return E_SOCK; | ||
327 | } | ||
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); | ||
333 | return E_SOCK; | ||
334 | } | ||
335 | } else { | ||
336 | if (ioctl(skfd, SIOCADDRT, &rt) < 0) { | ||
337 | perror("SIOCADDRT"); | ||
338 | close(skfd); | ||
339 | return E_SOCK; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | /* Close the socket. */ | ||
344 | (void) close(skfd); | ||
345 | return EXIT_SUCCESS; | ||
346 | } | ||
347 | |||
348 | #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 | |||
365 | static void displayroutes(void) | ||
366 | { | ||
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[64]; | ||
374 | unsigned long int d,g,m; | ||
375 | |||
376 | char sdest[16], sgw[16]; | ||
377 | |||
378 | |||
379 | FILE *fp = xfopen("/proc/net/route", "r"); | ||
380 | |||
381 | 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%X%d%d%d%lx", | ||
388 | &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { | ||
389 | error_msg_and_die( "Unsuported kernel route format\n"); | ||
390 | } | ||
391 | if(nl==1) | ||
392 | printf("Kernel IP routing table\n" | ||
393 | "Destination Gateway Genmask Flags Metric Ref Use Iface\n"); | ||
394 | |||
395 | ifl = 0; /* parse flags */ | ||
396 | if(flgs&RTF_UP) { | ||
397 | if(flgs&RTF_REJECT) | ||
398 | flags[ifl++]='!'; | ||
399 | else | ||
400 | flags[ifl++]='U'; | ||
401 | if(flgs&RTF_GATEWAY) | ||
402 | flags[ifl++]='G'; | ||
403 | if(flgs&RTF_HOST) | ||
404 | flags[ifl++]='H'; | ||
405 | if(flgs&RTF_REINSTATE) | ||
406 | flags[ifl++]='R'; | ||
407 | if(flgs&RTF_DYNAMIC) | ||
408 | flags[ifl++]='D'; | ||
409 | if(flgs&RTF_MODIFIED) | ||
410 | flags[ifl++]='M'; | ||
411 | flags[ifl]=0; | ||
412 | dest.s_addr = d; | ||
413 | gw.s_addr = g; | ||
414 | mask.s_addr = m; | ||
415 | strcpy(sdest, (dest.s_addr==0 ? "default" : | ||
416 | inet_ntoa(dest))); | ||
417 | strcpy(sgw, (gw.s_addr==0 ? "*" : | ||
418 | inet_ntoa(gw))); | ||
419 | printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", | ||
420 | sdest, sgw, | ||
421 | inet_ntoa(mask), | ||
422 | flags, metric, ref, use, buff); | ||
423 | } | ||
424 | } | ||
425 | nl++; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | int route_main(int argc, char **argv) | ||
430 | { | ||
431 | int what = 0; | ||
432 | |||
433 | argc--; | ||
434 | argv++; | ||
435 | |||
436 | if (*argv == NULL) { | ||
437 | displayroutes(); | ||
438 | return EXIT_SUCCESS; | ||
439 | } else { | ||
440 | /* check verb */ | ||
441 | if (strcmp(*argv, "add")==0) | ||
442 | what = RTACTION_ADD; | ||
443 | else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) | ||
444 | what = RTACTION_DEL; | ||
445 | else if (strcmp(*argv, "flush")==0) | ||
446 | what = RTACTION_FLUSH; | ||
447 | else | ||
448 | show_usage(); | ||
449 | } | ||
450 | |||
451 | return INET_setroute(what, 0, ++argv); | ||
452 | } | ||