1 | #ifdef __rtems__ |
---|
2 | #define __need_getopt_newlib |
---|
3 | #include <getopt.h> |
---|
4 | #endif |
---|
5 | /* |
---|
6 | * Copyright (c) 1983, 1989, 1991, 1993 |
---|
7 | * The Regents of the University of California. All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * 4. Neither the name of the University nor the names of its contributors |
---|
18 | * may be used to endorse or promote products derived from this software |
---|
19 | * without specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
31 | * SUCH DAMAGE. |
---|
32 | */ |
---|
33 | |
---|
34 | #ifndef lint |
---|
35 | static const char copyright[] = |
---|
36 | "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ |
---|
37 | The Regents of the University of California. All rights reserved.\n"; |
---|
38 | #endif /* not lint */ |
---|
39 | |
---|
40 | #ifndef lint |
---|
41 | #if 0 |
---|
42 | static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; |
---|
43 | #endif |
---|
44 | static const char rcsid[] = |
---|
45 | "$FreeBSD$"; |
---|
46 | #endif /* not lint */ |
---|
47 | |
---|
48 | #include <rtems/bsd/sys/param.h> |
---|
49 | #include <sys/file.h> |
---|
50 | #include <sys/socket.h> |
---|
51 | #include <sys/ioctl.h> |
---|
52 | #include <sys/sysctl.h> |
---|
53 | #include <rtems/bsd/sys/types.h> |
---|
54 | |
---|
55 | #include <net/if.h> |
---|
56 | #include <net/route.h> |
---|
57 | #include <net/if_dl.h> |
---|
58 | #include <netinet/in.h> |
---|
59 | #include <netinet/if_ether.h> |
---|
60 | #include <netatalk/at.h> |
---|
61 | #include <arpa/inet.h> |
---|
62 | #include <netdb.h> |
---|
63 | |
---|
64 | #include <ctype.h> |
---|
65 | #include <err.h> |
---|
66 | #include <errno.h> |
---|
67 | #include <paths.h> |
---|
68 | #include <stdio.h> |
---|
69 | #include <stdlib.h> |
---|
70 | #include <string.h> |
---|
71 | #include <sysexits.h> |
---|
72 | #include <unistd.h> |
---|
73 | #include <ifaddrs.h> |
---|
74 | |
---|
75 | struct keytab { |
---|
76 | char *kt_cp; |
---|
77 | int kt_i; |
---|
78 | } keywords[] = { |
---|
79 | #include "keywords.h" |
---|
80 | {0, 0} |
---|
81 | }; |
---|
82 | |
---|
83 | struct ortentry route; |
---|
84 | union sockunion { |
---|
85 | struct sockaddr sa; |
---|
86 | struct sockaddr_in sin; |
---|
87 | #ifdef INET6 |
---|
88 | struct sockaddr_in6 sin6; |
---|
89 | #endif |
---|
90 | struct sockaddr_at sat; |
---|
91 | struct sockaddr_dl sdl; |
---|
92 | struct sockaddr_inarp sinarp; |
---|
93 | struct sockaddr_storage ss; /* added to avoid memory overrun */ |
---|
94 | } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; |
---|
95 | |
---|
96 | typedef union sockunion *sup; |
---|
97 | int pid, rtm_addrs; |
---|
98 | int s; |
---|
99 | int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword(); |
---|
100 | int iflag, verbose, aflen = sizeof (struct sockaddr_in); |
---|
101 | int locking, lockrest, debugonly; |
---|
102 | struct rt_metrics rt_metrics; |
---|
103 | u_long rtm_inits; |
---|
104 | uid_t uid; |
---|
105 | int atalk_aton(const char *, struct at_addr *); |
---|
106 | char *atalk_ntoa(struct at_addr); |
---|
107 | const char *routename(), *netname(); |
---|
108 | void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); |
---|
109 | void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr(); |
---|
110 | #ifdef INET6 |
---|
111 | static int inet6_makenetandmask(struct sockaddr_in6 *, char *); |
---|
112 | #endif |
---|
113 | int getaddr(), rtmsg(), x25_makemask(); |
---|
114 | int prefixlen(); |
---|
115 | extern char *iso_ntoa(); |
---|
116 | |
---|
117 | void usage(const char *) __dead2; |
---|
118 | |
---|
119 | #ifdef __rtems__ |
---|
120 | |
---|
121 | static int main_route(int argc, char **argv); |
---|
122 | |
---|
123 | static int rtems_shell_main_route(int argc, char *argv[]) |
---|
124 | { |
---|
125 | rtems_shell_globals_t route_globals; |
---|
126 | rtems_shell_globals = &route_globals; |
---|
127 | memset (rtems_shell_globals, 0, sizeof (route_globals)); |
---|
128 | route_globals.exit_code = 1; |
---|
129 | if (setjmp (route_globals.exit_jmp) == 0) |
---|
130 | return main_route ( argc, argv); |
---|
131 | return route_globals.exit_code; |
---|
132 | } |
---|
133 | |
---|
134 | #endif |
---|
135 | |
---|
136 | |
---|
137 | void |
---|
138 | usage(cp) |
---|
139 | const char *cp; |
---|
140 | { |
---|
141 | if (cp) |
---|
142 | warnx("bad keyword: %s", cp); |
---|
143 | (void) fprintf(stderr, |
---|
144 | "usage: route [-dnqtv] command [[modifiers] args]\n"); |
---|
145 | exit(EX_USAGE); |
---|
146 | /* NOTREACHED */ |
---|
147 | } |
---|
148 | |
---|
149 | #ifdef __rtems__ |
---|
150 | int |
---|
151 | main_route(argc, argv) |
---|
152 | #else |
---|
153 | main(argc, argv) |
---|
154 | #endif |
---|
155 | int argc; |
---|
156 | char **argv; |
---|
157 | { |
---|
158 | int ch; |
---|
159 | #ifdef __rtems__ |
---|
160 | struct getopt_data getopt_reent; |
---|
161 | #define optind getopt_reent.optind |
---|
162 | #define optarg getopt_reent.optarg |
---|
163 | #define opterr getopt_reent.opterr |
---|
164 | #define optopt getopt_reent.optopt |
---|
165 | #endif |
---|
166 | |
---|
167 | if (argc < 2) |
---|
168 | usage((char *)NULL); |
---|
169 | |
---|
170 | #ifdef __rtems__ |
---|
171 | memset(&getopt_reent, 0, sizeof(getopt_data)); |
---|
172 | while ((ch = getopt_r(argc, argv, "nqdtv", &getopt_reent)) != -1) |
---|
173 | #else |
---|
174 | while ((ch = getopt(argc, argv, "nqdtv")) != -1) |
---|
175 | #endif |
---|
176 | switch(ch) { |
---|
177 | case 'n': |
---|
178 | nflag = 1; |
---|
179 | break; |
---|
180 | case 'q': |
---|
181 | qflag = 1; |
---|
182 | break; |
---|
183 | case 'v': |
---|
184 | verbose = 1; |
---|
185 | break; |
---|
186 | case 't': |
---|
187 | tflag = 1; |
---|
188 | break; |
---|
189 | case 'd': |
---|
190 | debugonly = 1; |
---|
191 | break; |
---|
192 | case '?': |
---|
193 | default: |
---|
194 | usage((char *)NULL); |
---|
195 | } |
---|
196 | argc -= optind; |
---|
197 | argv += optind; |
---|
198 | |
---|
199 | pid = getpid(); |
---|
200 | uid = geteuid(); |
---|
201 | if (tflag) |
---|
202 | s = open(_PATH_DEVNULL, O_WRONLY, 0); |
---|
203 | else |
---|
204 | s = socket(PF_ROUTE, SOCK_RAW, 0); |
---|
205 | if (s < 0) |
---|
206 | err(EX_OSERR, "socket"); |
---|
207 | if (*argv) |
---|
208 | switch (keyword(*argv)) { |
---|
209 | case K_GET: |
---|
210 | case K_SHOW: |
---|
211 | uid = 0; |
---|
212 | /* FALLTHROUGH */ |
---|
213 | |
---|
214 | case K_CHANGE: |
---|
215 | case K_ADD: |
---|
216 | case K_DEL: |
---|
217 | case K_DELETE: |
---|
218 | newroute(argc, argv); |
---|
219 | /* NOTREACHED */ |
---|
220 | |
---|
221 | case K_MONITOR: |
---|
222 | monitor(); |
---|
223 | /* NOTREACHED */ |
---|
224 | |
---|
225 | case K_FLUSH: |
---|
226 | flushroutes(argc, argv); |
---|
227 | exit(0); |
---|
228 | /* NOTREACHED */ |
---|
229 | } |
---|
230 | usage(*argv); |
---|
231 | /* NOTREACHED */ |
---|
232 | } |
---|
233 | |
---|
234 | /* |
---|
235 | * Purge all entries in the routing tables not |
---|
236 | * associated with network interfaces. |
---|
237 | */ |
---|
238 | void |
---|
239 | flushroutes(argc, argv) |
---|
240 | int argc; |
---|
241 | char *argv[]; |
---|
242 | { |
---|
243 | size_t needed; |
---|
244 | int mib[6], rlen, seqno, count = 0; |
---|
245 | char *buf, *next, *lim; |
---|
246 | struct rt_msghdr *rtm; |
---|
247 | |
---|
248 | if (uid && !debugonly) { |
---|
249 | errx(EX_NOPERM, "must be root to alter routing table"); |
---|
250 | } |
---|
251 | shutdown(s, SHUT_RD); /* Don't want to read back our messages */ |
---|
252 | if (argc > 1) { |
---|
253 | argv++; |
---|
254 | if (argc == 2 && **argv == '-') |
---|
255 | switch (keyword(*argv + 1)) { |
---|
256 | case K_INET: |
---|
257 | af = AF_INET; |
---|
258 | break; |
---|
259 | #ifdef INET6 |
---|
260 | case K_INET6: |
---|
261 | af = AF_INET6; |
---|
262 | break; |
---|
263 | #endif |
---|
264 | case K_ATALK: |
---|
265 | af = AF_APPLETALK; |
---|
266 | break; |
---|
267 | case K_LINK: |
---|
268 | af = AF_LINK; |
---|
269 | break; |
---|
270 | default: |
---|
271 | goto bad; |
---|
272 | } else |
---|
273 | bad: usage(*argv); |
---|
274 | } |
---|
275 | retry: |
---|
276 | mib[0] = CTL_NET; |
---|
277 | mib[1] = PF_ROUTE; |
---|
278 | mib[2] = 0; /* protocol */ |
---|
279 | mib[3] = 0; /* wildcard address family */ |
---|
280 | mib[4] = NET_RT_DUMP; |
---|
281 | mib[5] = 0; /* no flags */ |
---|
282 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) |
---|
283 | err(EX_OSERR, "route-sysctl-estimate"); |
---|
284 | if ((buf = malloc(needed)) == NULL) |
---|
285 | errx(EX_OSERR, "malloc failed"); |
---|
286 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { |
---|
287 | if (errno == ENOMEM && count++ < 10) { |
---|
288 | warnx("Routing table grew, retrying"); |
---|
289 | sleep(1); |
---|
290 | free(buf); |
---|
291 | goto retry; |
---|
292 | } |
---|
293 | err(EX_OSERR, "route-sysctl-get"); |
---|
294 | } |
---|
295 | lim = buf + needed; |
---|
296 | if (verbose) |
---|
297 | (void) printf("Examining routing table from sysctl\n"); |
---|
298 | seqno = 0; /* ??? */ |
---|
299 | for (next = buf; next < lim; next += rtm->rtm_msglen) { |
---|
300 | rtm = (struct rt_msghdr *)next; |
---|
301 | if (verbose) |
---|
302 | print_rtmsg(rtm, rtm->rtm_msglen); |
---|
303 | if ((rtm->rtm_flags & RTF_GATEWAY) == 0) |
---|
304 | continue; |
---|
305 | if (af) { |
---|
306 | struct sockaddr *sa = (struct sockaddr *)(rtm + 1); |
---|
307 | |
---|
308 | if (sa->sa_family != af) |
---|
309 | continue; |
---|
310 | } |
---|
311 | if (debugonly) |
---|
312 | continue; |
---|
313 | rtm->rtm_type = RTM_DELETE; |
---|
314 | rtm->rtm_seq = seqno; |
---|
315 | rlen = write(s, next, rtm->rtm_msglen); |
---|
316 | if (rlen < 0 && errno == EPERM) |
---|
317 | err(1, "write to routing socket"); |
---|
318 | if (rlen < (int)rtm->rtm_msglen) { |
---|
319 | warn("write to routing socket"); |
---|
320 | (void) printf("got only %d for rlen\n", rlen); |
---|
321 | free(buf); |
---|
322 | goto retry; |
---|
323 | break; |
---|
324 | } |
---|
325 | seqno++; |
---|
326 | if (qflag) |
---|
327 | continue; |
---|
328 | if (verbose) |
---|
329 | print_rtmsg(rtm, rlen); |
---|
330 | else { |
---|
331 | struct sockaddr *sa = (struct sockaddr *)(rtm + 1); |
---|
332 | (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? |
---|
333 | routename(sa) : netname(sa)); |
---|
334 | sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); |
---|
335 | (void) printf("%-20.20s ", routename(sa)); |
---|
336 | (void) printf("done\n"); |
---|
337 | } |
---|
338 | } |
---|
339 | } |
---|
340 | |
---|
341 | const char * |
---|
342 | routename(sa) |
---|
343 | struct sockaddr *sa; |
---|
344 | { |
---|
345 | char *cp; |
---|
346 | static char line[MAXHOSTNAMELEN + 1]; |
---|
347 | struct hostent *hp; |
---|
348 | static char domain[MAXHOSTNAMELEN + 1]; |
---|
349 | static int first = 1, n; |
---|
350 | |
---|
351 | if (first) { |
---|
352 | first = 0; |
---|
353 | if (gethostname(domain, MAXHOSTNAMELEN) == 0 && |
---|
354 | (cp = strchr(domain, '.'))) { |
---|
355 | domain[MAXHOSTNAMELEN] = '\0'; |
---|
356 | (void) strcpy(domain, cp + 1); |
---|
357 | } else |
---|
358 | domain[0] = 0; |
---|
359 | } |
---|
360 | |
---|
361 | if (sa->sa_len == 0) |
---|
362 | strcpy(line, "default"); |
---|
363 | else switch (sa->sa_family) { |
---|
364 | |
---|
365 | case AF_INET: |
---|
366 | { struct in_addr in; |
---|
367 | in = ((struct sockaddr_in *)sa)->sin_addr; |
---|
368 | |
---|
369 | cp = 0; |
---|
370 | if (in.s_addr == INADDR_ANY || sa->sa_len < 4) |
---|
371 | cp = "default"; |
---|
372 | if (cp == 0 && !nflag) { |
---|
373 | hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), |
---|
374 | AF_INET); |
---|
375 | if (hp) { |
---|
376 | if ((cp = strchr(hp->h_name, '.')) && |
---|
377 | !strcmp(cp + 1, domain)) |
---|
378 | *cp = 0; |
---|
379 | cp = hp->h_name; |
---|
380 | } |
---|
381 | } |
---|
382 | if (cp) { |
---|
383 | strncpy(line, cp, sizeof(line) - 1); |
---|
384 | line[sizeof(line) - 1] = '\0'; |
---|
385 | } else |
---|
386 | (void) sprintf(line, "%s", inet_ntoa(in)); |
---|
387 | break; |
---|
388 | } |
---|
389 | |
---|
390 | #ifdef INET6 |
---|
391 | case AF_INET6: |
---|
392 | { |
---|
393 | struct sockaddr_in6 sin6; /* use static var for safety */ |
---|
394 | int niflags = 0; |
---|
395 | |
---|
396 | memset(&sin6, 0, sizeof(sin6)); |
---|
397 | memcpy(&sin6, sa, sa->sa_len); |
---|
398 | sin6.sin6_len = sizeof(struct sockaddr_in6); |
---|
399 | sin6.sin6_family = AF_INET6; |
---|
400 | #ifdef __KAME__ |
---|
401 | if (sa->sa_len == sizeof(struct sockaddr_in6) && |
---|
402 | (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || |
---|
403 | IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && |
---|
404 | sin6.sin6_scope_id == 0) { |
---|
405 | sin6.sin6_scope_id = |
---|
406 | ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); |
---|
407 | sin6.sin6_addr.s6_addr[2] = 0; |
---|
408 | sin6.sin6_addr.s6_addr[3] = 0; |
---|
409 | } |
---|
410 | #endif |
---|
411 | if (nflag) |
---|
412 | niflags |= NI_NUMERICHOST; |
---|
413 | if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, |
---|
414 | line, sizeof(line), NULL, 0, niflags) != 0) |
---|
415 | strncpy(line, "invalid", sizeof(line)); |
---|
416 | |
---|
417 | return(line); |
---|
418 | } |
---|
419 | #endif |
---|
420 | |
---|
421 | case AF_APPLETALK: |
---|
422 | (void) snprintf(line, sizeof(line), "atalk %s", |
---|
423 | atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); |
---|
424 | break; |
---|
425 | |
---|
426 | case AF_LINK: |
---|
427 | return (link_ntoa((struct sockaddr_dl *)sa)); |
---|
428 | |
---|
429 | default: |
---|
430 | { u_short *s = (u_short *)sa; |
---|
431 | u_short *slim = s + ((sa->sa_len + 1) >> 1); |
---|
432 | char *cp = line + sprintf(line, "(%d)", sa->sa_family); |
---|
433 | char *cpe = line + sizeof(line); |
---|
434 | |
---|
435 | while (++s < slim && cp < cpe) /* start with sa->sa_data */ |
---|
436 | if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0) |
---|
437 | cp += n; |
---|
438 | else |
---|
439 | *cp = '\0'; |
---|
440 | break; |
---|
441 | } |
---|
442 | } |
---|
443 | return (line); |
---|
444 | } |
---|
445 | |
---|
446 | /* |
---|
447 | * Return the name of the network whose address is given. |
---|
448 | * The address is assumed to be that of a net or subnet, not a host. |
---|
449 | */ |
---|
450 | const char * |
---|
451 | netname(sa) |
---|
452 | struct sockaddr *sa; |
---|
453 | { |
---|
454 | char *cp = 0; |
---|
455 | static char line[MAXHOSTNAMELEN + 1]; |
---|
456 | struct netent *np = 0; |
---|
457 | u_long net, mask; |
---|
458 | u_long i; |
---|
459 | int n, subnetshift; |
---|
460 | |
---|
461 | switch (sa->sa_family) { |
---|
462 | |
---|
463 | case AF_INET: |
---|
464 | { struct in_addr in; |
---|
465 | in = ((struct sockaddr_in *)sa)->sin_addr; |
---|
466 | |
---|
467 | i = in.s_addr = ntohl(in.s_addr); |
---|
468 | if (in.s_addr == 0) |
---|
469 | cp = "default"; |
---|
470 | else if (!nflag) { |
---|
471 | if (IN_CLASSA(i)) { |
---|
472 | mask = IN_CLASSA_NET; |
---|
473 | subnetshift = 8; |
---|
474 | } else if (IN_CLASSB(i)) { |
---|
475 | mask = IN_CLASSB_NET; |
---|
476 | subnetshift = 8; |
---|
477 | } else { |
---|
478 | mask = IN_CLASSC_NET; |
---|
479 | subnetshift = 4; |
---|
480 | } |
---|
481 | /* |
---|
482 | * If there are more bits than the standard mask |
---|
483 | * would suggest, subnets must be in use. |
---|
484 | * Guess at the subnet mask, assuming reasonable |
---|
485 | * width subnet fields. |
---|
486 | */ |
---|
487 | while (in.s_addr &~ mask) |
---|
488 | mask = (long)mask >> subnetshift; |
---|
489 | net = in.s_addr & mask; |
---|
490 | while ((mask & 1) == 0) |
---|
491 | mask >>= 1, net >>= 1; |
---|
492 | np = getnetbyaddr(net, AF_INET); |
---|
493 | if (np) |
---|
494 | cp = np->n_name; |
---|
495 | } |
---|
496 | #define C(x) (unsigned)((x) & 0xff) |
---|
497 | if (cp) |
---|
498 | strncpy(line, cp, sizeof(line)); |
---|
499 | else if ((in.s_addr & 0xffffff) == 0) |
---|
500 | (void) sprintf(line, "%u", C(in.s_addr >> 24)); |
---|
501 | else if ((in.s_addr & 0xffff) == 0) |
---|
502 | (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), |
---|
503 | C(in.s_addr >> 16)); |
---|
504 | else if ((in.s_addr & 0xff) == 0) |
---|
505 | (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), |
---|
506 | C(in.s_addr >> 16), C(in.s_addr >> 8)); |
---|
507 | else |
---|
508 | (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), |
---|
509 | C(in.s_addr >> 16), C(in.s_addr >> 8), |
---|
510 | C(in.s_addr)); |
---|
511 | #undef C |
---|
512 | break; |
---|
513 | } |
---|
514 | |
---|
515 | #ifdef INET6 |
---|
516 | case AF_INET6: |
---|
517 | { |
---|
518 | struct sockaddr_in6 sin6; /* use static var for safety */ |
---|
519 | int niflags = 0; |
---|
520 | |
---|
521 | memset(&sin6, 0, sizeof(sin6)); |
---|
522 | memcpy(&sin6, sa, sa->sa_len); |
---|
523 | sin6.sin6_len = sizeof(struct sockaddr_in6); |
---|
524 | sin6.sin6_family = AF_INET6; |
---|
525 | #ifdef __KAME__ |
---|
526 | if (sa->sa_len == sizeof(struct sockaddr_in6) && |
---|
527 | (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || |
---|
528 | IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && |
---|
529 | sin6.sin6_scope_id == 0) { |
---|
530 | sin6.sin6_scope_id = |
---|
531 | ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); |
---|
532 | sin6.sin6_addr.s6_addr[2] = 0; |
---|
533 | sin6.sin6_addr.s6_addr[3] = 0; |
---|
534 | } |
---|
535 | #endif |
---|
536 | if (nflag) |
---|
537 | niflags |= NI_NUMERICHOST; |
---|
538 | if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, |
---|
539 | line, sizeof(line), NULL, 0, niflags) != 0) |
---|
540 | strncpy(line, "invalid", sizeof(line)); |
---|
541 | |
---|
542 | return(line); |
---|
543 | } |
---|
544 | #endif |
---|
545 | |
---|
546 | case AF_APPLETALK: |
---|
547 | (void) snprintf(line, sizeof(line), "atalk %s", |
---|
548 | atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); |
---|
549 | break; |
---|
550 | |
---|
551 | case AF_LINK: |
---|
552 | return (link_ntoa((struct sockaddr_dl *)sa)); |
---|
553 | |
---|
554 | |
---|
555 | default: |
---|
556 | { u_short *s = (u_short *)sa->sa_data; |
---|
557 | u_short *slim = s + ((sa->sa_len + 1)>>1); |
---|
558 | char *cp = line + sprintf(line, "af %d:", sa->sa_family); |
---|
559 | char *cpe = line + sizeof(line); |
---|
560 | |
---|
561 | while (s < slim && cp < cpe) |
---|
562 | if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0) |
---|
563 | cp += n; |
---|
564 | else |
---|
565 | *cp = '\0'; |
---|
566 | break; |
---|
567 | } |
---|
568 | } |
---|
569 | return (line); |
---|
570 | } |
---|
571 | |
---|
572 | void |
---|
573 | set_metric(value, key) |
---|
574 | char *value; |
---|
575 | int key; |
---|
576 | { |
---|
577 | int flag = 0; |
---|
578 | u_long noval, *valp = &noval; |
---|
579 | |
---|
580 | switch (key) { |
---|
581 | #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break |
---|
582 | caseof(K_MTU, RTV_MTU, rmx_mtu); |
---|
583 | caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); |
---|
584 | caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); |
---|
585 | caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); |
---|
586 | caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); |
---|
587 | caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); |
---|
588 | caseof(K_RTT, RTV_RTT, rmx_rtt); |
---|
589 | caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); |
---|
590 | caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); |
---|
591 | } |
---|
592 | rtm_inits |= flag; |
---|
593 | if (lockrest || locking) |
---|
594 | rt_metrics.rmx_locks |= flag; |
---|
595 | if (locking) |
---|
596 | locking = 0; |
---|
597 | *valp = atoi(value); |
---|
598 | } |
---|
599 | |
---|
600 | void |
---|
601 | newroute(argc, argv) |
---|
602 | int argc; |
---|
603 | char **argv; |
---|
604 | { |
---|
605 | char *cmd, *dest = "", *gateway = "", *err; |
---|
606 | int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC; |
---|
607 | int key; |
---|
608 | struct hostent *hp = 0; |
---|
609 | |
---|
610 | if (uid) { |
---|
611 | errx(EX_NOPERM, "must be root to alter routing table"); |
---|
612 | } |
---|
613 | cmd = argv[0]; |
---|
614 | if (*cmd != 'g' && *cmd != 's') |
---|
615 | shutdown(s, SHUT_RD); /* Don't want to read back our messages */ |
---|
616 | |
---|
617 | while (--argc > 0) { |
---|
618 | if (**(++argv)== '-') { |
---|
619 | switch (key = keyword(1 + *argv)) { |
---|
620 | case K_LINK: |
---|
621 | af = AF_LINK; |
---|
622 | aflen = sizeof(struct sockaddr_dl); |
---|
623 | break; |
---|
624 | case K_INET: |
---|
625 | af = AF_INET; |
---|
626 | aflen = sizeof(struct sockaddr_in); |
---|
627 | break; |
---|
628 | #ifdef INET6 |
---|
629 | case K_INET6: |
---|
630 | af = AF_INET6; |
---|
631 | aflen = sizeof(struct sockaddr_in6); |
---|
632 | break; |
---|
633 | #endif |
---|
634 | case K_ATALK: |
---|
635 | af = AF_APPLETALK; |
---|
636 | aflen = sizeof(struct sockaddr_at); |
---|
637 | break; |
---|
638 | case K_SA: |
---|
639 | af = PF_ROUTE; |
---|
640 | aflen = sizeof(union sockunion); |
---|
641 | break; |
---|
642 | case K_IFACE: |
---|
643 | case K_INTERFACE: |
---|
644 | iflag++; |
---|
645 | break; |
---|
646 | case K_NOSTATIC: |
---|
647 | flags &= ~RTF_STATIC; |
---|
648 | break; |
---|
649 | case K_LOCK: |
---|
650 | locking = 1; |
---|
651 | break; |
---|
652 | case K_LOCKREST: |
---|
653 | lockrest = 1; |
---|
654 | break; |
---|
655 | case K_HOST: |
---|
656 | forcehost++; |
---|
657 | break; |
---|
658 | case K_REJECT: |
---|
659 | flags |= RTF_REJECT; |
---|
660 | break; |
---|
661 | case K_BLACKHOLE: |
---|
662 | flags |= RTF_BLACKHOLE; |
---|
663 | break; |
---|
664 | case K_PROTO1: |
---|
665 | flags |= RTF_PROTO1; |
---|
666 | break; |
---|
667 | case K_PROTO2: |
---|
668 | flags |= RTF_PROTO2; |
---|
669 | break; |
---|
670 | case K_PROXY: |
---|
671 | proxy = 1; |
---|
672 | break; |
---|
673 | case K_XRESOLVE: |
---|
674 | flags |= RTF_XRESOLVE; |
---|
675 | break; |
---|
676 | case K_STATIC: |
---|
677 | flags |= RTF_STATIC; |
---|
678 | break; |
---|
679 | case K_STICKY: |
---|
680 | flags |= RTF_STICKY; |
---|
681 | break; |
---|
682 | case K_NOSTICK: |
---|
683 | flags &= ~RTF_STICKY; |
---|
684 | break; |
---|
685 | case K_IFA: |
---|
686 | if (!--argc) |
---|
687 | usage((char *)NULL); |
---|
688 | (void) getaddr(RTA_IFA, *++argv, 0); |
---|
689 | break; |
---|
690 | case K_IFP: |
---|
691 | if (!--argc) |
---|
692 | usage((char *)NULL); |
---|
693 | (void) getaddr(RTA_IFP, *++argv, 0); |
---|
694 | break; |
---|
695 | case K_GENMASK: |
---|
696 | if (!--argc) |
---|
697 | usage((char *)NULL); |
---|
698 | (void) getaddr(RTA_GENMASK, *++argv, 0); |
---|
699 | break; |
---|
700 | case K_GATEWAY: |
---|
701 | if (!--argc) |
---|
702 | usage((char *)NULL); |
---|
703 | (void) getaddr(RTA_GATEWAY, *++argv, 0); |
---|
704 | break; |
---|
705 | case K_DST: |
---|
706 | if (!--argc) |
---|
707 | usage((char *)NULL); |
---|
708 | ishost = getaddr(RTA_DST, *++argv, &hp); |
---|
709 | dest = *argv; |
---|
710 | break; |
---|
711 | case K_NETMASK: |
---|
712 | if (!--argc) |
---|
713 | usage((char *)NULL); |
---|
714 | (void) getaddr(RTA_NETMASK, *++argv, 0); |
---|
715 | /* FALLTHROUGH */ |
---|
716 | case K_NET: |
---|
717 | forcenet++; |
---|
718 | break; |
---|
719 | case K_PREFIXLEN: |
---|
720 | if (!--argc) |
---|
721 | usage((char *)NULL); |
---|
722 | if (prefixlen(*++argv) == -1) { |
---|
723 | forcenet = 0; |
---|
724 | ishost = 1; |
---|
725 | } else { |
---|
726 | forcenet = 1; |
---|
727 | ishost = 0; |
---|
728 | } |
---|
729 | break; |
---|
730 | case K_MTU: |
---|
731 | case K_HOPCOUNT: |
---|
732 | case K_EXPIRE: |
---|
733 | case K_RECVPIPE: |
---|
734 | case K_SENDPIPE: |
---|
735 | case K_SSTHRESH: |
---|
736 | case K_RTT: |
---|
737 | case K_RTTVAR: |
---|
738 | case K_WEIGHT: |
---|
739 | if (!--argc) |
---|
740 | usage((char *)NULL); |
---|
741 | set_metric(*++argv, key); |
---|
742 | break; |
---|
743 | default: |
---|
744 | usage(1+*argv); |
---|
745 | } |
---|
746 | } else { |
---|
747 | if ((rtm_addrs & RTA_DST) == 0) { |
---|
748 | dest = *argv; |
---|
749 | ishost = getaddr(RTA_DST, *argv, &hp); |
---|
750 | } else if ((rtm_addrs & RTA_GATEWAY) == 0) { |
---|
751 | gateway = *argv; |
---|
752 | (void) getaddr(RTA_GATEWAY, *argv, &hp); |
---|
753 | } else { |
---|
754 | (void) getaddr(RTA_NETMASK, *argv, 0); |
---|
755 | forcenet = 1; |
---|
756 | } |
---|
757 | } |
---|
758 | } |
---|
759 | if (forcehost) { |
---|
760 | ishost = 1; |
---|
761 | #ifdef INET6 |
---|
762 | if (af == AF_INET6) { |
---|
763 | rtm_addrs &= ~RTA_NETMASK; |
---|
764 | memset((void *)&so_mask, 0, sizeof(so_mask)); |
---|
765 | } |
---|
766 | #endif |
---|
767 | } |
---|
768 | if (forcenet) |
---|
769 | ishost = 0; |
---|
770 | flags |= RTF_UP; |
---|
771 | if (ishost) |
---|
772 | flags |= RTF_HOST; |
---|
773 | if (iflag == 0) |
---|
774 | flags |= RTF_GATEWAY; |
---|
775 | if (proxy) { |
---|
776 | so_dst.sinarp.sin_other = SIN_PROXY; |
---|
777 | flags |= RTF_ANNOUNCE; |
---|
778 | } |
---|
779 | for (attempts = 1; ; attempts++) { |
---|
780 | errno = 0; |
---|
781 | if ((ret = rtmsg(*cmd, flags)) == 0) |
---|
782 | break; |
---|
783 | if (errno != ENETUNREACH && errno != ESRCH) |
---|
784 | break; |
---|
785 | if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { |
---|
786 | hp->h_addr_list++; |
---|
787 | memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0], |
---|
788 | MIN(hp->h_length, sizeof(so_gate.sin.sin_addr))); |
---|
789 | } else |
---|
790 | break; |
---|
791 | } |
---|
792 | if (*cmd == 'g' || *cmd == 's') |
---|
793 | exit(ret != 0); |
---|
794 | if (!qflag) { |
---|
795 | oerrno = errno; |
---|
796 | (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest); |
---|
797 | if (*gateway) { |
---|
798 | (void) printf(": gateway %s", gateway); |
---|
799 | if (attempts > 1 && ret == 0 && af == AF_INET) |
---|
800 | (void) printf(" (%s)", |
---|
801 | inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); |
---|
802 | } |
---|
803 | if (ret == 0) { |
---|
804 | (void) printf("\n"); |
---|
805 | } else { |
---|
806 | switch (oerrno) { |
---|
807 | case ESRCH: |
---|
808 | err = "not in table"; |
---|
809 | break; |
---|
810 | case EBUSY: |
---|
811 | err = "entry in use"; |
---|
812 | break; |
---|
813 | case ENOBUFS: |
---|
814 | err = "not enough memory"; |
---|
815 | break; |
---|
816 | case EADDRINUSE: |
---|
817 | /* handle recursion avoidance in rt_setgate() */ |
---|
818 | err = "gateway uses the same route"; |
---|
819 | break; |
---|
820 | case EEXIST: |
---|
821 | err = "route already in table"; |
---|
822 | break; |
---|
823 | default: |
---|
824 | err = strerror(oerrno); |
---|
825 | break; |
---|
826 | } |
---|
827 | (void) printf(": %s\n", err); |
---|
828 | } |
---|
829 | } |
---|
830 | exit(ret != 0); |
---|
831 | } |
---|
832 | |
---|
833 | void |
---|
834 | inet_makenetandmask(net, sin, bits) |
---|
835 | u_long net, bits; |
---|
836 | struct sockaddr_in *sin; |
---|
837 | { |
---|
838 | u_long addr, mask = 0; |
---|
839 | char *cp; |
---|
840 | |
---|
841 | rtm_addrs |= RTA_NETMASK; |
---|
842 | /* |
---|
843 | * XXX: This approach unable to handle 0.0.0.1/32 correctly |
---|
844 | * as inet_network() converts 0.0.0.1 and 1 equally. |
---|
845 | */ |
---|
846 | if (net <= 0xff) |
---|
847 | addr = net << IN_CLASSA_NSHIFT; |
---|
848 | else if (net <= 0xffff) |
---|
849 | addr = net << IN_CLASSB_NSHIFT; |
---|
850 | else if (net <= 0xffffff) |
---|
851 | addr = net << IN_CLASSC_NSHIFT; |
---|
852 | else |
---|
853 | addr = net; |
---|
854 | /* |
---|
855 | * If no /xx was specified we must cacluate the |
---|
856 | * CIDR address. |
---|
857 | */ |
---|
858 | if ((bits == 0) && (addr != 0)) { |
---|
859 | u_long i, j; |
---|
860 | for(i=0,j=0xff; i<4; i++) { |
---|
861 | if (addr & j) { |
---|
862 | break; |
---|
863 | } |
---|
864 | j <<= 8; |
---|
865 | } |
---|
866 | /* i holds the first non zero bit */ |
---|
867 | bits = 32 - (i*8); |
---|
868 | } |
---|
869 | if (bits != 0) |
---|
870 | mask = 0xffffffff << (32 - bits); |
---|
871 | |
---|
872 | sin->sin_addr.s_addr = htonl(addr); |
---|
873 | sin = &so_mask.sin; |
---|
874 | sin->sin_addr.s_addr = htonl(mask); |
---|
875 | sin->sin_len = 0; |
---|
876 | sin->sin_family = 0; |
---|
877 | cp = (char *)(&sin->sin_addr + 1); |
---|
878 | while (*--cp == 0 && cp > (char *)sin) |
---|
879 | ; |
---|
880 | sin->sin_len = 1 + cp - (char *)sin; |
---|
881 | } |
---|
882 | |
---|
883 | #ifdef INET6 |
---|
884 | /* |
---|
885 | * XXX the function may need more improvement... |
---|
886 | */ |
---|
887 | static int |
---|
888 | inet6_makenetandmask(sin6, plen) |
---|
889 | struct sockaddr_in6 *sin6; |
---|
890 | char *plen; |
---|
891 | { |
---|
892 | struct in6_addr in6; |
---|
893 | |
---|
894 | if (!plen) { |
---|
895 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && |
---|
896 | sin6->sin6_scope_id == 0) { |
---|
897 | plen = "0"; |
---|
898 | } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { |
---|
899 | /* aggregatable global unicast - RFC2374 */ |
---|
900 | memset(&in6, 0, sizeof(in6)); |
---|
901 | if (!memcmp(&sin6->sin6_addr.s6_addr[8], |
---|
902 | &in6.s6_addr[8], 8)) |
---|
903 | plen = "64"; |
---|
904 | } |
---|
905 | } |
---|
906 | |
---|
907 | if (!plen || strcmp(plen, "128") == 0) |
---|
908 | return 1; |
---|
909 | rtm_addrs |= RTA_NETMASK; |
---|
910 | (void)prefixlen(plen); |
---|
911 | return 0; |
---|
912 | } |
---|
913 | #endif |
---|
914 | |
---|
915 | /* |
---|
916 | * Interpret an argument as a network address of some kind, |
---|
917 | * returning 1 if a host address, 0 if a network address. |
---|
918 | */ |
---|
919 | int |
---|
920 | getaddr(which, s, hpp) |
---|
921 | int which; |
---|
922 | char *s; |
---|
923 | struct hostent **hpp; |
---|
924 | { |
---|
925 | sup su; |
---|
926 | struct hostent *hp; |
---|
927 | struct netent *np; |
---|
928 | u_long val; |
---|
929 | char *q; |
---|
930 | int afamily; /* local copy of af so we can change it */ |
---|
931 | |
---|
932 | if (af == 0) { |
---|
933 | af = AF_INET; |
---|
934 | aflen = sizeof(struct sockaddr_in); |
---|
935 | } |
---|
936 | afamily = af; |
---|
937 | rtm_addrs |= which; |
---|
938 | switch (which) { |
---|
939 | case RTA_DST: |
---|
940 | su = &so_dst; |
---|
941 | break; |
---|
942 | case RTA_GATEWAY: |
---|
943 | su = &so_gate; |
---|
944 | if (iflag) { |
---|
945 | struct ifaddrs *ifap, *ifa; |
---|
946 | struct sockaddr_dl *sdl = NULL; |
---|
947 | |
---|
948 | if (getifaddrs(&ifap)) |
---|
949 | err(1, "getifaddrs"); |
---|
950 | |
---|
951 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
---|
952 | if (ifa->ifa_addr->sa_family != AF_LINK) |
---|
953 | continue; |
---|
954 | |
---|
955 | if (strcmp(s, ifa->ifa_name)) |
---|
956 | continue; |
---|
957 | |
---|
958 | sdl = (struct sockaddr_dl *)ifa->ifa_addr; |
---|
959 | } |
---|
960 | /* If we found it, then use it */ |
---|
961 | if (sdl) { |
---|
962 | /* |
---|
963 | * Copy is safe since we have a |
---|
964 | * sockaddr_storage member in sockunion{}. |
---|
965 | * Note that we need to copy before calling |
---|
966 | * freeifaddrs(). |
---|
967 | */ |
---|
968 | memcpy(&su->sdl, sdl, sdl->sdl_len); |
---|
969 | } |
---|
970 | freeifaddrs(ifap); |
---|
971 | if (sdl) |
---|
972 | return(1); |
---|
973 | } |
---|
974 | break; |
---|
975 | case RTA_NETMASK: |
---|
976 | su = &so_mask; |
---|
977 | break; |
---|
978 | case RTA_GENMASK: |
---|
979 | su = &so_genmask; |
---|
980 | break; |
---|
981 | case RTA_IFP: |
---|
982 | su = &so_ifp; |
---|
983 | afamily = AF_LINK; |
---|
984 | break; |
---|
985 | case RTA_IFA: |
---|
986 | su = &so_ifa; |
---|
987 | break; |
---|
988 | default: |
---|
989 | usage("internal error"); |
---|
990 | /*NOTREACHED*/ |
---|
991 | } |
---|
992 | su->sa.sa_len = aflen; |
---|
993 | su->sa.sa_family = afamily; /* cases that don't want it have left already */ |
---|
994 | if (strcmp(s, "default") == 0) { |
---|
995 | /* |
---|
996 | * Default is net 0.0.0.0/0 |
---|
997 | */ |
---|
998 | switch (which) { |
---|
999 | case RTA_DST: |
---|
1000 | forcenet++; |
---|
1001 | #if 0 |
---|
1002 | bzero(su, sizeof(*su)); /* for readability */ |
---|
1003 | #endif |
---|
1004 | (void) getaddr(RTA_NETMASK, s, 0); |
---|
1005 | break; |
---|
1006 | #if 0 |
---|
1007 | case RTA_NETMASK: |
---|
1008 | case RTA_GENMASK: |
---|
1009 | bzero(su, sizeof(*su)); /* for readability */ |
---|
1010 | #endif |
---|
1011 | } |
---|
1012 | return (0); |
---|
1013 | } |
---|
1014 | switch (afamily) { |
---|
1015 | #ifdef INET6 |
---|
1016 | case AF_INET6: |
---|
1017 | { |
---|
1018 | struct addrinfo hints, *res; |
---|
1019 | int ecode; |
---|
1020 | |
---|
1021 | q = NULL; |
---|
1022 | if (which == RTA_DST && (q = strchr(s, '/')) != NULL) |
---|
1023 | *q = '\0'; |
---|
1024 | memset(&hints, 0, sizeof(hints)); |
---|
1025 | hints.ai_family = afamily; /*AF_INET6*/ |
---|
1026 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
---|
1027 | ecode = getaddrinfo(s, NULL, &hints, &res); |
---|
1028 | if (ecode != 0 || res->ai_family != AF_INET6 || |
---|
1029 | res->ai_addrlen != sizeof(su->sin6)) { |
---|
1030 | (void) fprintf(stderr, "%s: %s\n", s, |
---|
1031 | gai_strerror(ecode)); |
---|
1032 | exit(1); |
---|
1033 | } |
---|
1034 | memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); |
---|
1035 | #ifdef __KAME__ |
---|
1036 | if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || |
---|
1037 | IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) && |
---|
1038 | su->sin6.sin6_scope_id) { |
---|
1039 | *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = |
---|
1040 | htons(su->sin6.sin6_scope_id); |
---|
1041 | su->sin6.sin6_scope_id = 0; |
---|
1042 | } |
---|
1043 | #endif |
---|
1044 | freeaddrinfo(res); |
---|
1045 | if (q != NULL) |
---|
1046 | *q++ = '/'; |
---|
1047 | if (which == RTA_DST) |
---|
1048 | return (inet6_makenetandmask(&su->sin6, q)); |
---|
1049 | return (0); |
---|
1050 | } |
---|
1051 | #endif /* INET6 */ |
---|
1052 | |
---|
1053 | case AF_APPLETALK: |
---|
1054 | if (!atalk_aton(s, &su->sat.sat_addr)) |
---|
1055 | errx(EX_NOHOST, "bad address: %s", s); |
---|
1056 | rtm_addrs |= RTA_NETMASK; |
---|
1057 | return(forcehost || su->sat.sat_addr.s_node != 0); |
---|
1058 | |
---|
1059 | case AF_LINK: |
---|
1060 | link_addr(s, &su->sdl); |
---|
1061 | return (1); |
---|
1062 | |
---|
1063 | |
---|
1064 | case PF_ROUTE: |
---|
1065 | su->sa.sa_len = sizeof(*su); |
---|
1066 | sockaddr(s, &su->sa); |
---|
1067 | return (1); |
---|
1068 | |
---|
1069 | case AF_INET: |
---|
1070 | default: |
---|
1071 | break; |
---|
1072 | } |
---|
1073 | |
---|
1074 | if (hpp == NULL) |
---|
1075 | hpp = &hp; |
---|
1076 | *hpp = NULL; |
---|
1077 | |
---|
1078 | q = strchr(s,'/'); |
---|
1079 | if (q && which == RTA_DST) { |
---|
1080 | *q = '\0'; |
---|
1081 | if ((val = inet_network(s)) != INADDR_NONE) { |
---|
1082 | inet_makenetandmask( |
---|
1083 | val, &su->sin, strtoul(q+1, 0, 0)); |
---|
1084 | return (0); |
---|
1085 | } |
---|
1086 | *q = '/'; |
---|
1087 | } |
---|
1088 | if ((which != RTA_DST || forcenet == 0) && |
---|
1089 | inet_aton(s, &su->sin.sin_addr)) { |
---|
1090 | val = su->sin.sin_addr.s_addr; |
---|
1091 | if (which != RTA_DST || forcehost || |
---|
1092 | inet_lnaof(su->sin.sin_addr) != INADDR_ANY) |
---|
1093 | return (1); |
---|
1094 | else { |
---|
1095 | val = ntohl(val); |
---|
1096 | goto netdone; |
---|
1097 | } |
---|
1098 | } |
---|
1099 | if (which == RTA_DST && forcehost == 0 && |
---|
1100 | ((val = inet_network(s)) != INADDR_NONE || |
---|
1101 | ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) { |
---|
1102 | netdone: |
---|
1103 | inet_makenetandmask(val, &su->sin, 0); |
---|
1104 | return (0); |
---|
1105 | } |
---|
1106 | hp = gethostbyname(s); |
---|
1107 | if (hp) { |
---|
1108 | *hpp = hp; |
---|
1109 | su->sin.sin_family = hp->h_addrtype; |
---|
1110 | memmove((char *)&su->sin.sin_addr, hp->h_addr, |
---|
1111 | MIN(hp->h_length, sizeof(su->sin.sin_addr))); |
---|
1112 | return (1); |
---|
1113 | } |
---|
1114 | errx(EX_NOHOST, "bad address: %s", s); |
---|
1115 | } |
---|
1116 | |
---|
1117 | int |
---|
1118 | prefixlen(s) |
---|
1119 | char *s; |
---|
1120 | { |
---|
1121 | int len = atoi(s), q, r; |
---|
1122 | int max; |
---|
1123 | char *p; |
---|
1124 | |
---|
1125 | rtm_addrs |= RTA_NETMASK; |
---|
1126 | switch (af) { |
---|
1127 | #ifdef INET6 |
---|
1128 | case AF_INET6: |
---|
1129 | max = 128; |
---|
1130 | p = (char *)&so_mask.sin6.sin6_addr; |
---|
1131 | break; |
---|
1132 | #endif |
---|
1133 | case AF_INET: |
---|
1134 | max = 32; |
---|
1135 | p = (char *)&so_mask.sin.sin_addr; |
---|
1136 | break; |
---|
1137 | default: |
---|
1138 | (void) fprintf(stderr, "prefixlen not supported in this af\n"); |
---|
1139 | exit(1); |
---|
1140 | /*NOTREACHED*/ |
---|
1141 | } |
---|
1142 | |
---|
1143 | if (len < 0 || max < len) { |
---|
1144 | (void) fprintf(stderr, "%s: bad value\n", s); |
---|
1145 | exit(1); |
---|
1146 | } |
---|
1147 | |
---|
1148 | q = len >> 3; |
---|
1149 | r = len & 7; |
---|
1150 | so_mask.sa.sa_family = af; |
---|
1151 | so_mask.sa.sa_len = aflen; |
---|
1152 | memset((void *)p, 0, max / 8); |
---|
1153 | if (q > 0) |
---|
1154 | memset((void *)p, 0xff, q); |
---|
1155 | if (r > 0) |
---|
1156 | *((u_char *)p + q) = (0xff00 >> r) & 0xff; |
---|
1157 | if (len == max) |
---|
1158 | return -1; |
---|
1159 | else |
---|
1160 | return len; |
---|
1161 | } |
---|
1162 | |
---|
1163 | void |
---|
1164 | interfaces() |
---|
1165 | { |
---|
1166 | size_t needed; |
---|
1167 | int mib[6]; |
---|
1168 | char *buf, *lim, *next, count = 0; |
---|
1169 | struct rt_msghdr *rtm; |
---|
1170 | |
---|
1171 | retry2: |
---|
1172 | mib[0] = CTL_NET; |
---|
1173 | mib[1] = PF_ROUTE; |
---|
1174 | mib[2] = 0; /* protocol */ |
---|
1175 | mib[3] = 0; /* wildcard address family */ |
---|
1176 | mib[4] = NET_RT_IFLIST; |
---|
1177 | mib[5] = 0; /* no flags */ |
---|
1178 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) |
---|
1179 | err(EX_OSERR, "route-sysctl-estimate"); |
---|
1180 | if ((buf = malloc(needed)) == NULL) |
---|
1181 | errx(EX_OSERR, "malloc failed"); |
---|
1182 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { |
---|
1183 | if (errno == ENOMEM && count++ < 10) { |
---|
1184 | warnx("Routing table grew, retrying"); |
---|
1185 | sleep(1); |
---|
1186 | free(buf); |
---|
1187 | goto retry2; |
---|
1188 | } |
---|
1189 | err(EX_OSERR, "actual retrieval of interface table"); |
---|
1190 | } |
---|
1191 | lim = buf + needed; |
---|
1192 | for (next = buf; next < lim; next += rtm->rtm_msglen) { |
---|
1193 | rtm = (struct rt_msghdr *)next; |
---|
1194 | print_rtmsg(rtm, rtm->rtm_msglen); |
---|
1195 | } |
---|
1196 | } |
---|
1197 | |
---|
1198 | void |
---|
1199 | monitor() |
---|
1200 | { |
---|
1201 | int n; |
---|
1202 | char msg[2048]; |
---|
1203 | |
---|
1204 | verbose = 1; |
---|
1205 | if (debugonly) { |
---|
1206 | interfaces(); |
---|
1207 | exit(0); |
---|
1208 | } |
---|
1209 | for(;;) { |
---|
1210 | time_t now; |
---|
1211 | n = read(s, msg, 2048); |
---|
1212 | now = time(NULL); |
---|
1213 | (void) printf("\ngot message of size %d on %s", n, ctime(&now)); |
---|
1214 | print_rtmsg((struct rt_msghdr *)msg, n); |
---|
1215 | } |
---|
1216 | } |
---|
1217 | |
---|
1218 | struct { |
---|
1219 | struct rt_msghdr m_rtm; |
---|
1220 | char m_space[512]; |
---|
1221 | } m_rtmsg; |
---|
1222 | |
---|
1223 | int |
---|
1224 | rtmsg(cmd, flags) |
---|
1225 | int cmd, flags; |
---|
1226 | { |
---|
1227 | static int seq; |
---|
1228 | int rlen; |
---|
1229 | char *cp = m_rtmsg.m_space; |
---|
1230 | int l; |
---|
1231 | |
---|
1232 | #define NEXTADDR(w, u) \ |
---|
1233 | if (rtm_addrs & (w)) {\ |
---|
1234 | l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\ |
---|
1235 | if (verbose) sodump(&(u),#u);\ |
---|
1236 | } |
---|
1237 | |
---|
1238 | errno = 0; |
---|
1239 | memset(&m_rtmsg, 0, sizeof(m_rtmsg)); |
---|
1240 | if (cmd == 'a') |
---|
1241 | cmd = RTM_ADD; |
---|
1242 | else if (cmd == 'c') |
---|
1243 | cmd = RTM_CHANGE; |
---|
1244 | else if (cmd == 'g' || cmd == 's') { |
---|
1245 | cmd = RTM_GET; |
---|
1246 | if (so_ifp.sa.sa_family == 0) { |
---|
1247 | so_ifp.sa.sa_family = AF_LINK; |
---|
1248 | so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); |
---|
1249 | rtm_addrs |= RTA_IFP; |
---|
1250 | } |
---|
1251 | } else |
---|
1252 | cmd = RTM_DELETE; |
---|
1253 | #define rtm m_rtmsg.m_rtm |
---|
1254 | rtm.rtm_type = cmd; |
---|
1255 | rtm.rtm_flags = flags; |
---|
1256 | rtm.rtm_version = RTM_VERSION; |
---|
1257 | rtm.rtm_seq = ++seq; |
---|
1258 | rtm.rtm_addrs = rtm_addrs; |
---|
1259 | rtm.rtm_rmx = rt_metrics; |
---|
1260 | rtm.rtm_inits = rtm_inits; |
---|
1261 | |
---|
1262 | if (rtm_addrs & RTA_NETMASK) |
---|
1263 | mask_addr(); |
---|
1264 | NEXTADDR(RTA_DST, so_dst); |
---|
1265 | NEXTADDR(RTA_GATEWAY, so_gate); |
---|
1266 | NEXTADDR(RTA_NETMASK, so_mask); |
---|
1267 | NEXTADDR(RTA_GENMASK, so_genmask); |
---|
1268 | NEXTADDR(RTA_IFP, so_ifp); |
---|
1269 | NEXTADDR(RTA_IFA, so_ifa); |
---|
1270 | rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; |
---|
1271 | if (verbose) |
---|
1272 | print_rtmsg(&rtm, l); |
---|
1273 | if (debugonly) |
---|
1274 | return (0); |
---|
1275 | if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { |
---|
1276 | if (errno == EPERM) |
---|
1277 | err(1, "writing to routing socket"); |
---|
1278 | warn("writing to routing socket"); |
---|
1279 | return (-1); |
---|
1280 | } |
---|
1281 | if (cmd == RTM_GET) { |
---|
1282 | do { |
---|
1283 | l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); |
---|
1284 | } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); |
---|
1285 | if (l < 0) |
---|
1286 | warn("read from routing socket"); |
---|
1287 | else |
---|
1288 | print_getmsg(&rtm, l); |
---|
1289 | } |
---|
1290 | #undef rtm |
---|
1291 | return (0); |
---|
1292 | } |
---|
1293 | |
---|
1294 | void |
---|
1295 | mask_addr() |
---|
1296 | { |
---|
1297 | int olen = so_mask.sa.sa_len; |
---|
1298 | char *cp1 = olen + (char *)&so_mask, *cp2; |
---|
1299 | |
---|
1300 | for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) |
---|
1301 | if (*--cp1 != 0) { |
---|
1302 | so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; |
---|
1303 | break; |
---|
1304 | } |
---|
1305 | if ((rtm_addrs & RTA_DST) == 0) |
---|
1306 | return; |
---|
1307 | switch (so_dst.sa.sa_family) { |
---|
1308 | case AF_INET: |
---|
1309 | #ifdef INET6 |
---|
1310 | case AF_INET6: |
---|
1311 | #endif |
---|
1312 | case AF_APPLETALK: |
---|
1313 | case 0: |
---|
1314 | return; |
---|
1315 | } |
---|
1316 | cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; |
---|
1317 | cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; |
---|
1318 | while (cp2 > cp1) |
---|
1319 | *--cp2 = 0; |
---|
1320 | cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; |
---|
1321 | while (cp1 > so_dst.sa.sa_data) |
---|
1322 | *--cp1 &= *--cp2; |
---|
1323 | } |
---|
1324 | |
---|
1325 | char *msgtypes[] = { |
---|
1326 | "", |
---|
1327 | "RTM_ADD: Add Route", |
---|
1328 | "RTM_DELETE: Delete Route", |
---|
1329 | "RTM_CHANGE: Change Metrics or flags", |
---|
1330 | "RTM_GET: Report Metrics", |
---|
1331 | "RTM_LOSING: Kernel Suspects Partitioning", |
---|
1332 | "RTM_REDIRECT: Told to use different route", |
---|
1333 | "RTM_MISS: Lookup failed on this address", |
---|
1334 | "RTM_LOCK: fix specified metrics", |
---|
1335 | "RTM_OLDADD: caused by SIOCADDRT", |
---|
1336 | "RTM_OLDDEL: caused by SIOCDELRT", |
---|
1337 | "RTM_RESOLVE: Route created by cloning", |
---|
1338 | "RTM_NEWADDR: address being added to iface", |
---|
1339 | "RTM_DELADDR: address being removed from iface", |
---|
1340 | "RTM_IFINFO: iface status change", |
---|
1341 | "RTM_NEWMADDR: new multicast group membership on iface", |
---|
1342 | "RTM_DELMADDR: multicast group membership removed from iface", |
---|
1343 | "RTM_IFANNOUNCE: interface arrival/departure", |
---|
1344 | 0, |
---|
1345 | }; |
---|
1346 | |
---|
1347 | char metricnames[] = |
---|
1348 | "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" |
---|
1349 | "\1mtu"; |
---|
1350 | char routeflags[] = |
---|
1351 | "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" |
---|
1352 | "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" |
---|
1353 | "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" |
---|
1354 | "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; |
---|
1355 | char ifnetflags[] = |
---|
1356 | "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" |
---|
1357 | "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" |
---|
1358 | "\017LINK2\020MULTICAST"; |
---|
1359 | char addrnames[] = |
---|
1360 | "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; |
---|
1361 | |
---|
1362 | void |
---|
1363 | print_rtmsg(rtm, msglen) |
---|
1364 | struct rt_msghdr *rtm; |
---|
1365 | int msglen; |
---|
1366 | { |
---|
1367 | struct if_msghdr *ifm; |
---|
1368 | struct ifa_msghdr *ifam; |
---|
1369 | #ifdef RTM_NEWMADDR |
---|
1370 | struct ifma_msghdr *ifmam; |
---|
1371 | #endif |
---|
1372 | struct if_announcemsghdr *ifan; |
---|
1373 | char *state; |
---|
1374 | |
---|
1375 | if (verbose == 0) |
---|
1376 | return; |
---|
1377 | if (rtm->rtm_version != RTM_VERSION) { |
---|
1378 | (void) printf("routing message version %d not understood\n", |
---|
1379 | rtm->rtm_version); |
---|
1380 | return; |
---|
1381 | } |
---|
1382 | if (msgtypes[rtm->rtm_type] != NULL) |
---|
1383 | (void)printf("%s: ", msgtypes[rtm->rtm_type]); |
---|
1384 | else |
---|
1385 | (void)printf("#%d: ", rtm->rtm_type); |
---|
1386 | (void)printf("len %d, ", rtm->rtm_msglen); |
---|
1387 | switch (rtm->rtm_type) { |
---|
1388 | case RTM_IFINFO: |
---|
1389 | ifm = (struct if_msghdr *)rtm; |
---|
1390 | (void) printf("if# %d, ", ifm->ifm_index); |
---|
1391 | switch (ifm->ifm_data.ifi_link_state) { |
---|
1392 | case LINK_STATE_DOWN: |
---|
1393 | state = "down"; |
---|
1394 | break; |
---|
1395 | case LINK_STATE_UP: |
---|
1396 | state = "up"; |
---|
1397 | break; |
---|
1398 | default: |
---|
1399 | state = "unknown"; |
---|
1400 | break; |
---|
1401 | } |
---|
1402 | (void) printf("link: %s, flags:", state); |
---|
1403 | bprintf(stdout, ifm->ifm_flags, ifnetflags); |
---|
1404 | pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); |
---|
1405 | break; |
---|
1406 | case RTM_NEWADDR: |
---|
1407 | case RTM_DELADDR: |
---|
1408 | ifam = (struct ifa_msghdr *)rtm; |
---|
1409 | (void) printf("metric %d, flags:", ifam->ifam_metric); |
---|
1410 | bprintf(stdout, ifam->ifam_flags, routeflags); |
---|
1411 | pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); |
---|
1412 | break; |
---|
1413 | #ifdef RTM_NEWMADDR |
---|
1414 | case RTM_NEWMADDR: |
---|
1415 | case RTM_DELMADDR: |
---|
1416 | ifmam = (struct ifma_msghdr *)rtm; |
---|
1417 | pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs); |
---|
1418 | break; |
---|
1419 | #endif |
---|
1420 | case RTM_IFANNOUNCE: |
---|
1421 | ifan = (struct if_announcemsghdr *)rtm; |
---|
1422 | (void) printf("if# %d, what: ", ifan->ifan_index); |
---|
1423 | switch (ifan->ifan_what) { |
---|
1424 | case IFAN_ARRIVAL: |
---|
1425 | printf("arrival"); |
---|
1426 | break; |
---|
1427 | case IFAN_DEPARTURE: |
---|
1428 | printf("departure"); |
---|
1429 | break; |
---|
1430 | default: |
---|
1431 | printf("#%d", ifan->ifan_what); |
---|
1432 | break; |
---|
1433 | } |
---|
1434 | printf("\n"); |
---|
1435 | break; |
---|
1436 | |
---|
1437 | default: |
---|
1438 | (void) printf("pid: %ld, seq %d, errno %d, flags:", |
---|
1439 | (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); |
---|
1440 | bprintf(stdout, rtm->rtm_flags, routeflags); |
---|
1441 | pmsg_common(rtm); |
---|
1442 | } |
---|
1443 | } |
---|
1444 | |
---|
1445 | void |
---|
1446 | print_getmsg(rtm, msglen) |
---|
1447 | struct rt_msghdr *rtm; |
---|
1448 | int msglen; |
---|
1449 | { |
---|
1450 | struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; |
---|
1451 | struct sockaddr_dl *ifp = NULL; |
---|
1452 | struct sockaddr *sa; |
---|
1453 | char *cp; |
---|
1454 | int i; |
---|
1455 | |
---|
1456 | (void) printf(" route to: %s\n", routename(&so_dst)); |
---|
1457 | if (rtm->rtm_version != RTM_VERSION) { |
---|
1458 | warnx("routing message version %d not understood", |
---|
1459 | rtm->rtm_version); |
---|
1460 | return; |
---|
1461 | } |
---|
1462 | if (rtm->rtm_msglen > msglen) { |
---|
1463 | warnx("message length mismatch, in packet %d, returned %d", |
---|
1464 | rtm->rtm_msglen, msglen); |
---|
1465 | } |
---|
1466 | if (rtm->rtm_errno) { |
---|
1467 | errno = rtm->rtm_errno; |
---|
1468 | warn("message indicates error %d", errno); |
---|
1469 | return; |
---|
1470 | } |
---|
1471 | cp = ((char *)(rtm + 1)); |
---|
1472 | if (rtm->rtm_addrs) |
---|
1473 | for (i = 1; i; i <<= 1) |
---|
1474 | if (i & rtm->rtm_addrs) { |
---|
1475 | sa = (struct sockaddr *)cp; |
---|
1476 | switch (i) { |
---|
1477 | case RTA_DST: |
---|
1478 | dst = sa; |
---|
1479 | break; |
---|
1480 | case RTA_GATEWAY: |
---|
1481 | gate = sa; |
---|
1482 | break; |
---|
1483 | case RTA_NETMASK: |
---|
1484 | mask = sa; |
---|
1485 | break; |
---|
1486 | case RTA_IFP: |
---|
1487 | if (sa->sa_family == AF_LINK && |
---|
1488 | ((struct sockaddr_dl *)sa)->sdl_nlen) |
---|
1489 | ifp = (struct sockaddr_dl *)sa; |
---|
1490 | break; |
---|
1491 | } |
---|
1492 | cp += SA_SIZE(sa); |
---|
1493 | } |
---|
1494 | if (dst && mask) |
---|
1495 | mask->sa_family = dst->sa_family; /* XXX */ |
---|
1496 | if (dst) |
---|
1497 | (void)printf("destination: %s\n", routename(dst)); |
---|
1498 | if (mask) { |
---|
1499 | int savenflag = nflag; |
---|
1500 | |
---|
1501 | nflag = 1; |
---|
1502 | (void)printf(" mask: %s\n", routename(mask)); |
---|
1503 | nflag = savenflag; |
---|
1504 | } |
---|
1505 | if (gate && rtm->rtm_flags & RTF_GATEWAY) |
---|
1506 | (void)printf(" gateway: %s\n", routename(gate)); |
---|
1507 | if (ifp) |
---|
1508 | (void)printf(" interface: %.*s\n", |
---|
1509 | ifp->sdl_nlen, ifp->sdl_data); |
---|
1510 | (void)printf(" flags: "); |
---|
1511 | bprintf(stdout, rtm->rtm_flags, routeflags); |
---|
1512 | |
---|
1513 | #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') |
---|
1514 | #define msec(u) (((u) + 500) / 1000) /* usec to msec */ |
---|
1515 | |
---|
1516 | (void) printf("\n%s\n", "\ |
---|
1517 | recvpipe sendpipe ssthresh rtt,msec mtu weight expire"); |
---|
1518 | printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); |
---|
1519 | printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); |
---|
1520 | printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); |
---|
1521 | printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); |
---|
1522 | printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); |
---|
1523 | printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); |
---|
1524 | if (rtm->rtm_rmx.rmx_expire) |
---|
1525 | rtm->rtm_rmx.rmx_expire -= time(0); |
---|
1526 | printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); |
---|
1527 | #undef lock |
---|
1528 | #undef msec |
---|
1529 | #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) |
---|
1530 | if (verbose) |
---|
1531 | pmsg_common(rtm); |
---|
1532 | else if (rtm->rtm_addrs &~ RTA_IGN) { |
---|
1533 | (void) printf("sockaddrs: "); |
---|
1534 | bprintf(stdout, rtm->rtm_addrs, addrnames); |
---|
1535 | putchar('\n'); |
---|
1536 | } |
---|
1537 | #undef RTA_IGN |
---|
1538 | } |
---|
1539 | |
---|
1540 | void |
---|
1541 | pmsg_common(rtm) |
---|
1542 | struct rt_msghdr *rtm; |
---|
1543 | { |
---|
1544 | (void) printf("\nlocks: "); |
---|
1545 | bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); |
---|
1546 | (void) printf(" inits: "); |
---|
1547 | bprintf(stdout, rtm->rtm_inits, metricnames); |
---|
1548 | pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); |
---|
1549 | } |
---|
1550 | |
---|
1551 | void |
---|
1552 | pmsg_addrs(cp, addrs) |
---|
1553 | char *cp; |
---|
1554 | int addrs; |
---|
1555 | { |
---|
1556 | struct sockaddr *sa; |
---|
1557 | int i; |
---|
1558 | |
---|
1559 | if (addrs == 0) { |
---|
1560 | (void) putchar('\n'); |
---|
1561 | return; |
---|
1562 | } |
---|
1563 | (void) printf("\nsockaddrs: "); |
---|
1564 | bprintf(stdout, addrs, addrnames); |
---|
1565 | (void) putchar('\n'); |
---|
1566 | for (i = 1; i; i <<= 1) |
---|
1567 | if (i & addrs) { |
---|
1568 | sa = (struct sockaddr *)cp; |
---|
1569 | (void) printf(" %s", routename(sa)); |
---|
1570 | cp += SA_SIZE(sa); |
---|
1571 | } |
---|
1572 | (void) putchar('\n'); |
---|
1573 | (void) fflush(stdout); |
---|
1574 | } |
---|
1575 | |
---|
1576 | void |
---|
1577 | bprintf(fp, b, s) |
---|
1578 | FILE *fp; |
---|
1579 | int b; |
---|
1580 | u_char *s; |
---|
1581 | { |
---|
1582 | int i; |
---|
1583 | int gotsome = 0; |
---|
1584 | |
---|
1585 | if (b == 0) |
---|
1586 | return; |
---|
1587 | while ((i = *s++) != 0) { |
---|
1588 | if (b & (1 << (i-1))) { |
---|
1589 | if (gotsome == 0) |
---|
1590 | i = '<'; |
---|
1591 | else |
---|
1592 | i = ','; |
---|
1593 | (void) putc(i, fp); |
---|
1594 | gotsome = 1; |
---|
1595 | for (; (i = *s) > 32; s++) |
---|
1596 | (void) putc(i, fp); |
---|
1597 | } else |
---|
1598 | while (*s > 32) |
---|
1599 | s++; |
---|
1600 | } |
---|
1601 | if (gotsome) |
---|
1602 | (void) putc('>', fp); |
---|
1603 | } |
---|
1604 | |
---|
1605 | int |
---|
1606 | keyword(cp) |
---|
1607 | char *cp; |
---|
1608 | { |
---|
1609 | struct keytab *kt = keywords; |
---|
1610 | |
---|
1611 | while (kt->kt_cp && strcmp(kt->kt_cp, cp)) |
---|
1612 | kt++; |
---|
1613 | return kt->kt_i; |
---|
1614 | } |
---|
1615 | |
---|
1616 | void |
---|
1617 | sodump(su, which) |
---|
1618 | sup su; |
---|
1619 | char *which; |
---|
1620 | { |
---|
1621 | switch (su->sa.sa_family) { |
---|
1622 | case AF_LINK: |
---|
1623 | (void) printf("%s: link %s; ", |
---|
1624 | which, link_ntoa(&su->sdl)); |
---|
1625 | break; |
---|
1626 | case AF_INET: |
---|
1627 | (void) printf("%s: inet %s; ", |
---|
1628 | which, inet_ntoa(su->sin.sin_addr)); |
---|
1629 | break; |
---|
1630 | case AF_APPLETALK: |
---|
1631 | (void) printf("%s: atalk %s; ", |
---|
1632 | which, atalk_ntoa(su->sat.sat_addr)); |
---|
1633 | break; |
---|
1634 | } |
---|
1635 | (void) fflush(stdout); |
---|
1636 | } |
---|
1637 | |
---|
1638 | /* States*/ |
---|
1639 | #define VIRGIN 0 |
---|
1640 | #define GOTONE 1 |
---|
1641 | #define GOTTWO 2 |
---|
1642 | /* Inputs */ |
---|
1643 | #define DIGIT (4*0) |
---|
1644 | #define END (4*1) |
---|
1645 | #define DELIM (4*2) |
---|
1646 | |
---|
1647 | void |
---|
1648 | sockaddr(addr, sa) |
---|
1649 | char *addr; |
---|
1650 | struct sockaddr *sa; |
---|
1651 | { |
---|
1652 | char *cp = (char *)sa; |
---|
1653 | int size = sa->sa_len; |
---|
1654 | char *cplim = cp + size; |
---|
1655 | int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; |
---|
1656 | |
---|
1657 | memset(cp, 0, size); |
---|
1658 | cp++; |
---|
1659 | do { |
---|
1660 | if ((*addr >= '0') && (*addr <= '9')) { |
---|
1661 | new = *addr - '0'; |
---|
1662 | } else if ((*addr >= 'a') && (*addr <= 'f')) { |
---|
1663 | new = *addr - 'a' + 10; |
---|
1664 | } else if ((*addr >= 'A') && (*addr <= 'F')) { |
---|
1665 | new = *addr - 'A' + 10; |
---|
1666 | } else if (*addr == 0) |
---|
1667 | state |= END; |
---|
1668 | else |
---|
1669 | state |= DELIM; |
---|
1670 | addr++; |
---|
1671 | switch (state /* | INPUT */) { |
---|
1672 | case GOTTWO | DIGIT: |
---|
1673 | *cp++ = byte; /*FALLTHROUGH*/ |
---|
1674 | case VIRGIN | DIGIT: |
---|
1675 | state = GOTONE; byte = new; continue; |
---|
1676 | case GOTONE | DIGIT: |
---|
1677 | state = GOTTWO; byte = new + (byte << 4); continue; |
---|
1678 | default: /* | DELIM */ |
---|
1679 | state = VIRGIN; *cp++ = byte; byte = 0; continue; |
---|
1680 | case GOTONE | END: |
---|
1681 | case GOTTWO | END: |
---|
1682 | *cp++ = byte; /* FALLTHROUGH */ |
---|
1683 | case VIRGIN | END: |
---|
1684 | break; |
---|
1685 | } |
---|
1686 | break; |
---|
1687 | } while (cp < cplim); |
---|
1688 | sa->sa_len = cp - (char *)sa; |
---|
1689 | } |
---|
1690 | |
---|
1691 | int |
---|
1692 | atalk_aton(const char *text, struct at_addr *addr) |
---|
1693 | { |
---|
1694 | u_int net, node; |
---|
1695 | |
---|
1696 | if (sscanf(text, "%u.%u", &net, &node) != 2 |
---|
1697 | || net > 0xffff || node > 0xff) |
---|
1698 | return(0); |
---|
1699 | addr->s_net = htons(net); |
---|
1700 | addr->s_node = node; |
---|
1701 | return(1); |
---|
1702 | } |
---|
1703 | |
---|
1704 | char * |
---|
1705 | atalk_ntoa(struct at_addr at) |
---|
1706 | { |
---|
1707 | static char buf[20]; |
---|
1708 | |
---|
1709 | (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); |
---|
1710 | return(buf); |
---|
1711 | } |
---|
1712 | |
---|
1713 | #ifdef __rtems__ |
---|
1714 | #include <rtems/shell.h> |
---|
1715 | |
---|
1716 | rtems_shell_cmd_t rtems_shell_ROUTE_Command = { |
---|
1717 | "route", /* name */ |
---|
1718 | "route [args]", /* usage */ |
---|
1719 | "net", /* topic */ |
---|
1720 | rtems_shell_main_route, /* command */ |
---|
1721 | NULL, /* alias */ |
---|
1722 | NULL /* next */ |
---|
1723 | }; |
---|
1724 | #endif |
---|