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