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