GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/route/route.c Lines: 382 944 40.5 %
Date: 2016-12-06 Branches: 228 724 31.5 %

Line Branch Exec Source
1
/*	$OpenBSD: route.c,v 1.184 2016/07/09 20:39:17 tedu Exp $	*/
2
/*	$NetBSD: route.c,v 1.16 1996/04/15 18:27:05 cgd Exp $	*/
3
4
/*
5
 * Copyright (c) 1983, 1989, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/socket.h>
34
#include <sys/sysctl.h>
35
36
#include <net/if.h>
37
#include <net/if_dl.h>
38
#include <net/if_types.h>
39
#include <net/route.h>
40
#include <netinet/in.h>
41
#include <arpa/inet.h>
42
#include <netdb.h>
43
44
#include <errno.h>
45
#include <fcntl.h>
46
#include <unistd.h>
47
#include <limits.h>
48
#include <stdio.h>
49
#include <ctype.h>
50
#include <stddef.h>
51
#include <stdlib.h>
52
#include <string.h>
53
#include <paths.h>
54
#include <err.h>
55
#include <net/if_media.h>
56
#include <netmpls/mpls.h>
57
58
#include "keywords.h"
59
#include "show.h"
60
61
const struct if_status_description
62
			if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
63
64
union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_label, so_src;
65
66
typedef union sockunion *sup;
67
pid_t	pid;
68
int	rtm_addrs, s;
69
int	forcehost, forcenet, Fflag, nflag, af, qflag, tflag, Tflag;
70
int	iflag, verbose, aflen = sizeof(struct sockaddr_in);
71
int	locking, lockrest, debugonly;
72
u_long	mpls_flags = MPLS_OP_LOCAL;
73
u_long	rtm_inits;
74
uid_t	uid;
75
u_int	tableid;
76
77
struct rt_metrics	rt_metrics;
78
79
int	 flushroutes(int, char **);
80
int	 newroute(int, char **);
81
int	 show(int, char *[]);
82
int	 keycmp(const void *, const void *);
83
int	 keyword(char *);
84
void	 monitor(int, char *[]);
85
int	 prefixlen(char *);
86
void	 sockaddr(char *, struct sockaddr *);
87
void	 sodump(sup, char *);
88
char	*priorityname(uint8_t);
89
uint8_t	 getpriority(char *);
90
void	 print_getmsg(struct rt_msghdr *, int);
91
const char *get_linkstate(int, int);
92
void	 print_rtmsg(struct rt_msghdr *, int);
93
void	 pmsg_common(struct rt_msghdr *);
94
void	 pmsg_addrs(char *, int);
95
void	 bprintf(FILE *, int, char *);
96
void	 mask_addr(union sockunion *, union sockunion *, int);
97
int	 inet6_makenetandmask(struct sockaddr_in6 *, char *);
98
int	 getaddr(int, char *, struct hostent **);
99
void	 getmplslabel(char *, int);
100
int	 rtmsg(int, int, int, uint8_t);
101
__dead void usage(char *);
102
void	 set_metric(char *, int);
103
void	 inet_makenetandmask(u_int32_t, struct sockaddr_in *, int);
104
void	 interfaces(void);
105
void	 getlabel(char *);
106
int	 gettable(const char *);
107
int	 rdomain(int, char **);
108
109
__dead void
110
usage(char *cp)
111
{
112
	extern char *__progname;
113
114
	if (cp)
115
		warnx("botched keyword: %s", cp);
116
	fprintf(stderr,
117
	    "usage: %s [-dnqtv] [-T tableid] command [[modifiers] args]\n",
118
	    __progname);
119
	fprintf(stderr,
120
	    "commands: add, change, delete, exec, flush, get, monitor, show\n");
121
	exit(1);
122
}
123
124
#define ROUNDUP(a) \
125
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
126
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
127
128
int
129
main(int argc, char **argv)
130
50
{
131
	int ch;
132
50
	int rval = 0;
133
	int kw;
134
50
	int Terr = 0;
135
136
50
	if (argc < 2)
137
		usage(NULL);
138
139
50
	tableid = getrtable();
140
208
	while ((ch = getopt(argc, argv, "dnqtT:v")) != -1)
141

108
		switch (ch) {
142
		case 'n':
143
50
			nflag = 1;
144
50
			break;
145
		case 'q':
146
			qflag = 1;
147
			break;
148
		case 'v':
149
			verbose = 1;
150
			break;
151
		case 't':
152
8
			tflag = 1;
153
8
			break;
154
		case 'T':
155
50
			Terr = gettable(optarg);
156
50
			Tflag = 1;
157
50
			break;
158
		case 'd':
159
			debugonly = 1;
160
			break;
161
		default:
162
			usage(NULL);
163
			/* NOTREACHED */
164
		}
165
50
	argc -= optind;
166
50
	argv += optind;
167
168
50
	pid = getpid();
169
50
	uid = geteuid();
170
50
	if (*argv == NULL)
171
		usage(NULL);
172
173
50
	kw = keyword(*argv);
174

50
	if (Tflag && Terr != 0 && kw != K_ADD) {
175
		errno = Terr;
176
		err(1, "routing table %d", tableid);
177
	}
178
50
	if (kw == K_EXEC)
179
		exit(rdomain(argc - 1, argv + 1));
180
181
50
	s = socket(PF_ROUTE, SOCK_RAW, 0);
182
50
	if (s == -1)
183
		err(1, "socket");
184
50
	if (kw == K_MONITOR) {
185
		unsigned int filter = 0;
186
		int af = 0;
187
188
		while (--argc > 0) {
189
			if (**(++argv)== '-')
190
				switch (keyword(*argv + 1)) {
191
				case K_INET:
192
					af = AF_INET;
193
					break;
194
				case K_INET6:
195
					af = AF_INET6;
196
					break;
197
				case K_IFACE:
198
				case K_INTERFACE:
199
					filter = ROUTE_FILTER(RTM_IFINFO) |
200
					    ROUTE_FILTER(RTM_IFANNOUNCE);
201
					break;
202
				default:
203
					usage(*argv);
204
					/* NOTREACHED */
205
				}
206
			else
207
				usage(*argv);
208
		}
209
		if (setsockopt(s, AF_ROUTE, ROUTE_MSGFILTER, &filter,
210
		    sizeof(filter)) == -1)
211
			err(1, "setsockopt(ROUTE_MSGFILTER)");
212
	}
213
	/* force socket onto table user requested */
214

50
	if (Tflag == 1 && Terr == 0 &&
215
	    setsockopt(s, AF_ROUTE, ROUTE_TABLEFILTER,
216
	    &tableid, sizeof(tableid)) == -1)
217
		err(1, "setsockopt(ROUTE_TABLEFILTER)");
218
219
50
	switch (kw) {
220
	case K_SHOW:
221
5
		uid = 0;
222
5
		exit(show(argc, argv));
223
		break;
224
	case K_FLUSH:
225
		exit(flushroutes(argc, argv));
226
		break;
227
	}
228
229
45
	if (pledge("stdio rpath dns cpath wpath", NULL) == -1)
230
		err(1, "pledge");
231
232

45
	switch (kw) {
233
	case K_GET:
234
1
		uid = 0;
235
		/* FALLTHROUGH */
236
	case K_CHANGE:
237
	case K_ADD:
238
	case K_DELETE:
239
45
		rval = newroute(argc, argv);
240
44
		break;
241
	case K_MONITOR:
242
		monitor(argc, argv);
243
		break;
244
	default:
245
		usage(*argv);
246
		/* NOTREACHED */
247
	}
248
44
	exit(rval);
249
}
250
251
/*
252
 * Purge all entries in the routing tables not
253
 * associated with network interfaces.
254
 */
255
int
256
flushroutes(int argc, char **argv)
257
{
258
	size_t needed;
259
	int mib[7], rlen, seqno;
260
	char *buf = NULL, *next, *lim = NULL;
261
	struct rt_msghdr *rtm;
262
	struct sockaddr *sa;
263
	uint8_t prio = 0;
264
	unsigned int ifindex = 0;
265
266
	if (uid)
267
		errx(1, "must be root to alter routing table");
268
	shutdown(s, SHUT_RD); /* Don't want to read back our messages */
269
	while (--argc > 0) {
270
		if (**(++argv) == '-')
271
			switch (keyword(*argv + 1)) {
272
			case K_INET:
273
				af = AF_INET;
274
				break;
275
			case K_INET6:
276
				af = AF_INET6;
277
				break;
278
			case K_LINK:
279
				af = AF_LINK;
280
				break;
281
			case K_MPLS:
282
				af = AF_MPLS;
283
				break;
284
			case K_IFACE:
285
			case K_INTERFACE:
286
				if (!--argc)
287
					usage(1+*argv);
288
				ifindex = if_nametoindex(*++argv);
289
				if (ifindex == 0)
290
					errx(1, "no such interface %s", *argv);
291
				break;
292
			case K_PRIORITY:
293
				if (!--argc)
294
					usage(1+*argv);
295
				prio = getpriority(*++argv);
296
				break;
297
			default:
298
				usage(*argv);
299
				/* NOTREACHED */
300
			}
301
		else
302
			usage(*argv);
303
	}
304
	mib[0] = CTL_NET;
305
	mib[1] = PF_ROUTE;
306
	mib[2] = 0;		/* protocol */
307
	mib[3] = 0;		/* wildcard address family */
308
	mib[4] = NET_RT_DUMP;
309
	mib[5] = 0;		/* no flags */
310
	mib[6] = tableid;
311
	while (1) {
312
		if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1)
313
			err(1, "route-sysctl-estimate");
314
		if (needed == 0)
315
			break;
316
		if ((buf = realloc(buf, needed)) == NULL)
317
			err(1, "realloc");
318
		if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) {
319
			if (errno == ENOMEM)
320
				continue;
321
			err(1, "actual retrieval of routing table");
322
		}
323
		lim = buf + needed;
324
		break;
325
	}
326
327
	if (pledge("stdio rpath dns cpath wpath", NULL) == -1)
328
		err(1, "pledge");
329
330
	if (verbose) {
331
		printf("Examining routing table from sysctl\n");
332
		if (af)
333
			printf("(address family %s)\n", (*argv + 1));
334
	}
335
	if (buf == NULL)
336
		return (1);
337
338
	seqno = 0;
339
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
340
		rtm = (struct rt_msghdr *)next;
341
		if (rtm->rtm_version != RTM_VERSION)
342
			continue;
343
		if (verbose)
344
			print_rtmsg(rtm, rtm->rtm_msglen);
345
		if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_STATIC|RTF_LLINFO)) == 0)
346
			continue;
347
		if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0)
348
			continue;
349
		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
350
		if (af && sa->sa_family != af)
351
			continue;
352
		if (ifindex && rtm->rtm_index != ifindex)
353
			continue;
354
		if (prio && rtm->rtm_priority != prio)
355
			continue;
356
		if (sa->sa_family == AF_KEY)
357
			continue;  /* Don't flush SPD */
358
		if (debugonly)
359
			continue;
360
		rtm->rtm_type = RTM_DELETE;
361
		rtm->rtm_seq = seqno;
362
		rtm->rtm_tableid = tableid;
363
		rlen = write(s, next, rtm->rtm_msglen);
364
		if (rlen < (int)rtm->rtm_msglen) {
365
			warn("write to routing socket");
366
			printf("got only %d for rlen\n", rlen);
367
			break;
368
		}
369
		seqno++;
370
		if (qflag)
371
			continue;
372
		if (verbose)
373
			print_rtmsg(rtm, rlen);
374
		else {
375
			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
376
			printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
377
			    routename(sa) : netname(sa, NULL)); /* XXX extract
378
								   netmask */
379
			sa = (struct sockaddr *)
380
			    (ROUNDUP(sa->sa_len) + (char *)sa);
381
			printf("%-20.20s ", routename(sa));
382
			printf("done\n");
383
		}
384
	}
385
	free(buf);
386
	return (0);
387
}
388
389
void
390
set_metric(char *value, int key)
391
1
{
392
	long long relative_expire;
393
	const char *errstr;
394
1
	int flag = 0;
395
396

1
	switch (key) {
397
	case K_MTU:
398
1
		rt_metrics.rmx_mtu = strtonum(value, 0, UINT_MAX, &errstr);
399
1
		if (errstr)
400
			errx(1, "set_metric mtu: %s is %s", value, errstr);
401
1
		flag = RTV_MTU;
402
1
		break;
403
	case K_EXPIRE:
404
		relative_expire = strtonum(value, 0, INT_MAX, &errstr);
405
		if (errstr)
406
			errx(1, "set_metric expire: %s is %s", value, errstr);
407
		rt_metrics.rmx_expire = relative_expire ?
408
		    relative_expire + time(NULL) : 0;
409
		flag = RTV_EXPIRE;
410
		break;
411
	case K_HOPCOUNT:
412
	case K_RECVPIPE:
413
	case K_SENDPIPE:
414
	case K_SSTHRESH:
415
	case K_RTT:
416
	case K_RTTVAR:
417
		/* no longer used, only for compatibility */
418
		return;
419
	default:
420
		errx(1, "king bula sez: set_metric with invalid key");
421
	}
422
1
	rtm_inits |= flag;
423

1
	if (lockrest || locking)
424
		rt_metrics.rmx_locks |= flag;
425
1
	if (locking)
426
		locking = 0;
427
}
428
429
int
430
newroute(int argc, char **argv)
431
45
{
432
45
	char *cmd, *dest = "", *gateway = "", *error;
433
45
	int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC;
434
45
	int fmask = 0;
435
	int key;
436
45
	uint8_t prio = 0;
437
45
	struct hostent *hp = NULL;
438
439
45
	if (uid)
440
		errx(1, "must be root to alter routing table");
441
45
	cmd = argv[0];
442
45
	if (*cmd != 'g')
443
44
		shutdown(s, SHUT_RD); /* Don't want to read back our messages */
444
171
	while (--argc > 0) {
445
126
		if (**(++argv)== '-') {
446








45
			switch (key = keyword(1 + *argv)) {
447
			case K_LINK:
448
				af = AF_LINK;
449
				aflen = sizeof(struct sockaddr_dl);
450
				break;
451
			case K_INET:
452
				af = AF_INET;
453
				aflen = sizeof(struct sockaddr_in);
454
				break;
455
			case K_INET6:
456
5
				af = AF_INET6;
457
5
				aflen = sizeof(struct sockaddr_in6);
458
5
				break;
459
			case K_SA:
460
				af = PF_ROUTE;
461
				aflen = sizeof(union sockunion);
462
				break;
463
			case K_MPLS:
464
				af = AF_MPLS;
465
				aflen = sizeof(struct sockaddr_mpls);
466
				fmask |= RTF_MPLS;
467
				break;
468
			case K_MPLSLABEL:
469
				if (!--argc)
470
					usage(1+*argv);
471
				if (af != AF_INET && af != AF_INET6)
472
					errx(1, "-mplslabel requires "
473
					    "-inet or -inet6");
474
				getmplslabel(*++argv, 0);
475
				mpls_flags = MPLS_OP_PUSH;
476
				flags |= RTF_MPLS;
477
				break;
478
			case K_IN:
479
				if (!--argc)
480
					usage(1+*argv);
481
				if (af != AF_MPLS)
482
					errx(1, "-in requires -mpls");
483
				getmplslabel(*++argv, 1);
484
				break;
485
			case K_OUT:
486
				if (!--argc)
487
					usage(1+*argv);
488
				if (af != AF_MPLS)
489
					errx(1, "-out requires -mpls");
490
				if (mpls_flags == MPLS_OP_LOCAL)
491
					errx(1, "-out requires -push, -pop, "
492
					    "-swap");
493
				getmplslabel(*++argv, 0);
494
				flags |= RTF_MPLS;
495
				break;
496
			case K_POP:
497
				if (af != AF_MPLS)
498
					errx(1, "-pop requires -mpls");
499
				mpls_flags = MPLS_OP_POP;
500
				break;
501
			case K_PUSH:
502
				if (af != AF_MPLS)
503
					errx(1, "-push requires -mpls");
504
				mpls_flags = MPLS_OP_PUSH;
505
				break;
506
			case K_SWAP:
507
				if (af != AF_MPLS)
508
					errx(1, "-swap requires -mpls");
509
				mpls_flags = MPLS_OP_SWAP;
510
				break;
511
			case K_IFACE:
512
			case K_INTERFACE:
513
				iflag++;
514
				break;
515
			case K_NOSTATIC:
516
				flags &= ~RTF_STATIC;
517
				break;
518
			case K_LLINFO:
519
				flags |= RTF_LLINFO;
520
				break;
521
			case K_LOCK:
522
				locking = 1;
523
				break;
524
			case K_LOCKREST:
525
				lockrest = 1;
526
				break;
527
			case K_HOST:
528
				forcehost++;
529
				break;
530
			case K_REJECT:
531
				flags |= RTF_REJECT;
532
				break;
533
			case K_BLACKHOLE:
534
				flags |= RTF_BLACKHOLE;
535
				break;
536
			case K_PROTO1:
537
				flags |= RTF_PROTO1;
538
				break;
539
			case K_PROTO2:
540
				flags |= RTF_PROTO2;
541
				break;
542
			case K_CLONING:
543
				flags |= RTF_CLONING;
544
				break;
545
			case K_STATIC:
546
				flags |= RTF_STATIC;
547
				break;
548
			case K_IFA:
549
				if (!--argc)
550
					usage(1+*argv);
551
				getaddr(RTA_IFA, *++argv, NULL);
552
				break;
553
			case K_IFP:
554
				if (!--argc)
555
					usage(1+*argv);
556
				getaddr(RTA_IFP, *++argv, NULL);
557
				break;
558
			case K_GATEWAY:
559
3
				if (!--argc)
560
					usage(1+*argv);
561
3
				getaddr(RTA_GATEWAY, *++argv, NULL);
562
3
				gateway = *argv;
563
3
				break;
564
			case K_DST:
565
4
				if (!--argc)
566
					usage(1+*argv);
567
4
				ishost = getaddr(RTA_DST, *++argv, &hp);
568
4
				dest = *argv;
569
4
				break;
570
			case K_LABEL:
571
				if (!--argc)
572
					usage(1+*argv);
573
				getlabel(*++argv);
574
				break;
575
			case K_NETMASK:
576
4
				if (!--argc)
577
					usage(1+*argv);
578
4
				getaddr(RTA_NETMASK, *++argv, NULL);
579
				/* FALLTHROUGH */
580
			case K_NET:
581
8
				forcenet++;
582
8
				break;
583
			case K_PREFIXLEN:
584
				if (!--argc)
585
					usage(1+*argv);
586
				ishost = prefixlen(*++argv);
587
				break;
588
			case K_MPATH:
589
10
				flags |= RTF_MPATH;
590
10
				break;
591
			case K_MTU:
592
			case K_HOPCOUNT:
593
			case K_EXPIRE:
594
			case K_RECVPIPE:
595
			case K_SENDPIPE:
596
			case K_SSTHRESH:
597
			case K_RTT:
598
			case K_RTTVAR:
599
1
				if (!--argc)
600
					usage(1+*argv);
601
1
				set_metric(*++argv, key);
602
1
				break;
603
			case K_PRIORITY:
604
14
				if (!--argc)
605
					usage(1+*argv);
606
14
				prio = getpriority(*++argv);
607
14
				break;
608
			default:
609
				usage(1+*argv);
610
				/* NOTREACHED */
611
			}
612
		} else {
613
81
			if ((rtm_addrs & RTA_DST) == 0) {
614
41
				dest = *argv;
615
41
				ishost = getaddr(RTA_DST, *argv, &hp);
616
40
			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
617
40
				gateway = *argv;
618
40
				getaddr(RTA_GATEWAY, *argv, &hp);
619
			} else
620
				usage(NULL);
621
		}
622
	}
623
45
	if (forcehost)
624
		ishost = 1;
625
45
	if (forcenet)
626
6
		ishost = 0;
627

45
	if (forcenet && !(rtm_addrs & RTA_NETMASK))
628
		errx(1, "netmask missing");
629
45
	flags |= RTF_UP;
630
45
	if (ishost)
631
3
		flags |= RTF_HOST;
632
45
	if (iflag == 0)
633
45
		flags |= RTF_GATEWAY;
634
45
	for (attempts = 1; ; attempts++) {
635
45
		errno = 0;
636
45
		if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0)
637
30
			break;
638

15
		if (errno != ENETUNREACH && errno != ESRCH)
639
15
			break;
640
		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
641
			hp->h_addr_list++;
642
			memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0],
643
			    hp->h_length);
644
		} else
645
			break;
646
	}
647
45
	if (*cmd == 'g') {
648

1
		if (ret != 0 && qflag == 0)
649
			warn("writing to routing socket");
650
1
		exit(0);
651
	}
652
44
	oerrno = errno;
653
44
	if (!qflag) {
654
44
		printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
655
44
		if (*gateway) {
656
43
			printf(": gateway %s", gateway);
657

43
			if (attempts > 1 && ret == 0 && af == AF_INET)
658
			    printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
659
		}
660
44
		if (ret == 0)
661
29
			printf("\n");
662
44
		if (ret != 0) {
663

15
			switch (oerrno) {
664
			case ESRCH:
665
				error = "not in table";
666
				break;
667
			case EBUSY:
668
				error = "entry in use";
669
				break;
670
			case ENOBUFS:
671
				error = "routing table overflow";
672
				break;
673
			default:
674
15
				error = strerror(oerrno);
675
				break;
676
			}
677
15
			printf(": %s\n", error);
678
		}
679
	}
680
44
	return (ret != 0);
681
}
682
683
int
684
show(int argc, char *argv[])
685
5
{
686
5
	int		 af = 0;
687
5
	char		 prio = 0;
688
689
15
	while (--argc > 0) {
690
5
		if (**(++argv)== '-')
691


5
			switch (keyword(*argv + 1)) {
692
			case K_INET:
693
4
				af = AF_INET;
694
4
				break;
695
			case K_INET6:
696
1
				af = AF_INET6;
697
1
				break;
698
			case K_LINK:
699
				af = AF_LINK;
700
				break;
701
			case K_MPLS:
702
				af = AF_MPLS;
703
				break;
704
			case K_GATEWAY:
705
				Fflag = 1;
706
				break;
707
			case K_LABEL:
708
				if (!--argc)
709
					usage(1+*argv);
710
				getlabel(*++argv);
711
				break;
712
			case K_PRIORITY:
713
				if (!--argc)
714
					usage(1+*argv);
715
				prio = getpriority(*++argv);
716
				break;
717
			default:
718
				usage(*argv);
719
				/* NOTREACHED */
720
			}
721
		else
722
			usage(*argv);
723
	}
724
725
5
	p_rttables(af, tableid, Tflag, prio);
726
5
	return (0);
727
}
728
729
void
730
inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits)
731
35
{
732
35
	u_int32_t addr, mask = 0;
733
	char *cp;
734
735
35
	rtm_addrs |= RTA_NETMASK;
736
35
	if (net == 0 && bits == 0)
737
		mask = addr = 0;
738
35
	else if (bits) {
739
35
		addr = net;
740
35
		mask = 0xffffffff << (32 - bits);
741
	} else if (net < 128) {
742
		addr = net << IN_CLASSA_NSHIFT;
743
		mask = IN_CLASSA_NET;
744
	} else if (net < 65536) {
745
		addr = net << IN_CLASSB_NSHIFT;
746
		mask = IN_CLASSB_NET;
747
	} else if (net < 16777216L) {
748
		addr = net << IN_CLASSC_NSHIFT;
749
		mask = IN_CLASSC_NET;
750
	} else {
751
		addr = net;
752
		if ((addr & IN_CLASSA_HOST) == 0)
753
			mask = IN_CLASSA_NET;
754
		else if ((addr & IN_CLASSB_HOST) == 0)
755
			mask = IN_CLASSB_NET;
756
		else if ((addr & IN_CLASSC_HOST) == 0)
757
			mask = IN_CLASSC_NET;
758
		else
759
			mask = 0xffffffff;
760
	}
761
35
	addr &= mask;
762
35
	sin->sin_addr.s_addr = htonl(addr);
763
35
	sin = &so_mask.sin;
764
35
	sin->sin_addr.s_addr = htonl(mask);
765
35
	sin->sin_len = 0;
766
35
	sin->sin_family = 0;
767
35
	cp = (char *)(&sin->sin_addr + 1);
768

76
	while (*--cp == '\0' && cp > (char *)sin)
769
		continue;
770
35
	sin->sin_len = 1 + cp - (char *)sin;
771
35
}
772
773
/*
774
 * XXX the function may need more improvement...
775
 */
776
int
777
inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
778
6
{
779
	struct in6_addr in6;
780
	const char *errstr;
781
	int i, len, q, r;
782
783
6
	if (NULL==plen) {
784


3
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
785
		    sin6->sin6_scope_id == 0) {
786
			plen = "0";
787
3
		} else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
788
			/* aggregatable global unicast - RFC2374 */
789
			memset(&in6, 0, sizeof(in6));
790
			if (!memcmp(&sin6->sin6_addr.s6_addr[8],
791
			    &in6.s6_addr[8], 8))
792
				plen = "64";
793
		}
794
	}
795
796

6
	if (!plen || strcmp(plen, "128") == 0)
797
3
		return (1);
798
	else {
799
3
		rtm_addrs |= RTA_NETMASK;
800
3
		prefixlen(plen);
801
802
3
		len = strtonum(plen, 0, 128, &errstr);
803
3
		if (errstr)
804
			errx(1, "prefixlen %s is %s", plen, errstr);
805
806
3
		q = (128-len) >> 3;
807
3
		r = (128-len) & 7;
808
3
		i = 15;
809
810
30
		while (q-- > 0)
811
24
			sin6->sin6_addr.s6_addr[i--] = 0;
812
3
		if (r > 0)
813
			sin6->sin6_addr.s6_addr[i] &= 0xff << r;
814
815
3
		return (0);
816
	}
817
}
818
819
/*
820
 * Interpret an argument as a network address of some kind,
821
 * returning 1 if a host address, 0 if a network address.
822
 */
823
int
824
getaddr(int which, char *s, struct hostent **hpp)
825
92
{
826
92
	sup su = NULL;
827
	struct hostent *hp;
828
	struct netent *np;
829
	int afamily, bits;
830
831
92
	if (af == 0) {
832
40
		if (strchr(s, ':') != NULL) {
833
1
			af = AF_INET6;
834
1
			aflen = sizeof(struct sockaddr_in6);
835
		} else {
836
39
			af = AF_INET;
837
39
			aflen = sizeof(struct sockaddr_in);
838
		}
839
	}
840
92
	afamily = af;	/* local copy of af so we can change it */
841
842
92
	rtm_addrs |= which;
843

92
	switch (which) {
844
	case RTA_DST:
845
45
		su = &so_dst;
846
45
		break;
847
	case RTA_GATEWAY:
848
43
		su = &so_gate;
849
43
		break;
850
	case RTA_NETMASK:
851
4
		su = &so_mask;
852
4
		break;
853
	case RTA_IFP:
854
		su = &so_ifp;
855
		afamily = AF_LINK;
856
		break;
857
	case RTA_IFA:
858
		su = &so_ifa;
859
		break;
860
	default:
861
		errx(1, "internal error");
862
		/* NOTREACHED */
863
	}
864
92
	su->sa.sa_len = aflen;
865
92
	su->sa.sa_family = afamily;
866
867
92
	if (strcmp(s, "default") == 0) {
868
		switch (which) {
869
		case RTA_DST:
870
			forcenet++;
871
			getaddr(RTA_NETMASK, s, NULL);
872
			break;
873
		case RTA_NETMASK:
874
			su->sa.sa_len = 0;
875
		}
876
		return (0);
877
	}
878
879

92
	switch (afamily) {
880
	case AF_INET6:
881
	    {
882
		struct addrinfo hints, *res;
883
		char            buf[
884
		   sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")
885
		];
886
		char           *sep;
887
888
10
		if (strlcpy(buf, s, sizeof buf) >= sizeof buf) {
889
			errx(1, "%s: bad value", s);
890
		}
891
892
10
		sep = strchr(buf, '/');
893
10
		if (sep != NULL)
894
3
			*sep++ = '\0';
895
10
		memset(&hints, 0, sizeof(hints));
896
10
		hints.ai_family = afamily;	/*AF_INET6*/
897
10
		hints.ai_flags = AI_NUMERICHOST;
898
10
		hints.ai_socktype = SOCK_DGRAM;		/*dummy*/
899
10
		if (getaddrinfo(buf, "0", &hints, &res) != 0) {
900
			hints.ai_flags = 0;
901
			if (getaddrinfo(buf, "0", &hints, &res) != 0)
902
				errx(1, "%s: bad value", s);
903
		}
904
10
		if (sizeof(su->sin6) != res->ai_addrlen)
905
			errx(1, "%s: bad value", s);
906
10
		if (res->ai_next)
907
			errx(1, "%s: resolved to multiple values", s);
908
10
		memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
909
10
		freeaddrinfo(res);
910



10
		if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
911
		     IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) ||
912
		     IN6_IS_ADDR_MC_INTFACELOCAL(&su->sin6.sin6_addr)) &&
913
		    su->sin6.sin6_scope_id) {
914
			*(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
915
				htons(su->sin6.sin6_scope_id);
916
			su->sin6.sin6_scope_id = 0;
917
		}
918
10
		if (hints.ai_flags == AI_NUMERICHOST) {
919
10
			if (which == RTA_DST)
920
6
				return (inet6_makenetandmask(&su->sin6, sep));
921
4
			return (0);
922
		} else
923
			return (1);
924
	    }
925
926
	case AF_LINK:
927
		su->sdl.sdl_index = if_nametoindex(s);
928
		memset(&su->sdl.sdl_data, 0, sizeof(su->sdl.sdl_data));
929
		return (1);
930
	case AF_MPLS:
931
		errx(1, "mpls labels require -in or -out switch");
932
	case PF_ROUTE:
933
		su->sa.sa_len = sizeof(*su);
934
		sockaddr(s, &su->sa);
935
		return (1);
936
937
	case AF_INET:
938
82
		if (hpp != NULL)
939
75
			*hpp = NULL;
940

82
		if (which == RTA_DST && !forcehost) {
941
39
			bits = inet_net_pton(AF_INET, s, &su->sin.sin_addr,
942
			    sizeof(su->sin.sin_addr));
943
39
			if (bits == 32)
944
4
				return (1);
945
35
			if (bits >= 0) {
946
35
				inet_makenetandmask(ntohl(
947
				    su->sin.sin_addr.s_addr),
948
				    &su->sin, bits);
949
35
				return (0);
950
			}
951
			np = getnetbyname(s);
952
			if (np != NULL && np->n_net != 0) {
953
				inet_makenetandmask(np->n_net, &su->sin, 0);
954
				return (0);
955
			}
956
			if (forcenet)
957
				errx(1, "%s: not a network", s);
958
		}
959
43
		if (inet_pton(AF_INET, s, &su->sin.sin_addr) == 1)
960
43
			return (1);
961
		hp = gethostbyname(s);
962
		if (hp != NULL) {
963
			if (hpp != NULL)
964
				*hpp = hp;
965
			su->sin.sin_addr = *(struct in_addr *)hp->h_addr;
966
			return (1);
967
		}
968
		errx(1, "%s: bad address", s);
969
		/* NOTREACHED */
970
971
	default:
972
		errx(1, "%d: bad address family", afamily);
973
		/* NOTREACHED */
974
	}
975
}
976
977
void
978
getmplslabel(char *s, int in)
979
{
980
	sup su = NULL;
981
	const char *errstr;
982
	u_int32_t label;
983
984
	label = strtonum(s, 0, 0x000fffff, &errstr);
985
	if (errstr)
986
		errx(1, "bad label: %s is %s", s, errstr);
987
	if (in) {
988
		rtm_addrs |= RTA_DST;
989
		su = &so_dst;
990
		su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET);
991
	} else {
992
		rtm_addrs |= RTA_SRC;
993
		su = &so_src;
994
		su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET);
995
	}
996
997
	su->sa.sa_len = sizeof(struct sockaddr_mpls);
998
	su->sa.sa_family = AF_MPLS;
999
}
1000
1001
int
1002
prefixlen(char *s)
1003
3
{
1004
	const char *errstr;
1005
	int len, q, r;
1006
	int max;
1007
1008
3
	switch (af) {
1009
	case AF_INET:
1010
		max = sizeof(struct in_addr) * 8;
1011
		break;
1012
	case AF_INET6:
1013
3
		max = sizeof(struct in6_addr) * 8;
1014
3
		break;
1015
	default:
1016
		errx(1, "prefixlen is not supported with af %d", af);
1017
		/* NOTREACHED */
1018
	}
1019
1020
3
	rtm_addrs |= RTA_NETMASK;
1021
3
	len = strtonum(s, 0, max, &errstr);
1022
3
	if (errstr)
1023
		errx(1, "prefixlen %s is %s", s, errstr);
1024
1025
3
	q = len >> 3;
1026
3
	r = len & 7;
1027
3
	switch (af) {
1028
	case AF_INET:
1029
		memset(&so_mask, 0, sizeof(so_mask));
1030
		so_mask.sin.sin_family = AF_INET;
1031
		so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1032
		so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len));
1033
		break;
1034
	case AF_INET6:
1035
3
		so_mask.sin6.sin6_family = AF_INET6;
1036
3
		so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1037
3
		memset((void *)&so_mask.sin6.sin6_addr, 0,
1038
			sizeof(so_mask.sin6.sin6_addr));
1039
3
		if (q > 0)
1040
3
			memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1041
3
		if (r > 0)
1042
			*((u_char *)&so_mask.sin6.sin6_addr + q) =
1043
			    (0xff00 >> r) & 0xff;
1044
		break;
1045
	}
1046
3
	return (len == max);
1047
}
1048
1049
void
1050
interfaces(void)
1051
{
1052
	size_t needed;
1053
	int mib[6];
1054
	char *buf = NULL, *lim, *next;
1055
	struct rt_msghdr *rtm;
1056
1057
	mib[0] = CTL_NET;
1058
	mib[1] = PF_ROUTE;
1059
	mib[2] = 0;		/* protocol */
1060
	mib[3] = 0;		/* wildcard address family */
1061
	mib[4] = NET_RT_IFLIST;
1062
	mib[5] = 0;		/* no flags */
1063
	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1064
		err(1, "route-sysctl-estimate");
1065
	if (needed) {
1066
		if ((buf = malloc(needed)) == NULL)
1067
			err(1, "malloc");
1068
		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1069
			err(1, "actual retrieval of interface table");
1070
		lim = buf + needed;
1071
		for (next = buf; next < lim; next += rtm->rtm_msglen) {
1072
			rtm = (struct rt_msghdr *)next;
1073
			print_rtmsg(rtm, rtm->rtm_msglen);
1074
		}
1075
		free(buf);
1076
	}
1077
}
1078
1079
void
1080
monitor(int argc, char *argv[])
1081
{
1082
	int n;
1083
	char msg[2048];
1084
	time_t now;
1085
1086
	if (pledge("stdio rpath dns cpath wpath", NULL) == -1)
1087
		err(1, "pledge");
1088
1089
	verbose = 1;
1090
	if (debugonly) {
1091
		interfaces();
1092
		exit(0);
1093
	}
1094
	for (;;) {
1095
		if ((n = read(s, msg, sizeof(msg))) == -1) {
1096
			if (errno == EINTR)
1097
				continue;
1098
			err(1, "read");
1099
		}
1100
		now = time(NULL);
1101
		printf("got message of size %d on %s", n, ctime(&now));
1102
		print_rtmsg((struct rt_msghdr *)msg, n);
1103
	}
1104
}
1105
1106
struct {
1107
	struct rt_msghdr	m_rtm;
1108
	char			m_space[512];
1109
} m_rtmsg;
1110
1111
int
1112
rtmsg(int cmd, int flags, int fmask, uint8_t prio)
1113
45
{
1114
	static int seq;
1115
45
	char *cp = m_rtmsg.m_space;
1116
	int l;
1117
1118
#define NEXTADDR(w, u)				\
1119
	if (rtm_addrs & (w)) {			\
1120
		l = ROUNDUP(u.sa.sa_len);	\
1121
		memcpy(cp, &(u), l);		\
1122
		cp += l;			\
1123
		if (verbose)			\
1124
			sodump(&(u), #u);	\
1125
	}
1126
1127
45
	errno = 0;
1128
45
	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1129
45
	if (cmd == 'a')
1130
39
		cmd = RTM_ADD;
1131
6
	else if (cmd == 'c')
1132
1
		cmd = RTM_CHANGE;
1133
5
	else if (cmd == 'g') {
1134
1
		cmd = RTM_GET;
1135
1
		if (so_ifp.sa.sa_family == 0) {
1136
1
			so_ifp.sa.sa_family = AF_LINK;
1137
1
			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1138
1
			rtm_addrs |= RTA_IFP;
1139
		}
1140
	} else
1141
4
		cmd = RTM_DELETE;
1142
#define rtm m_rtmsg.m_rtm
1143
45
	rtm.rtm_type = cmd;
1144
45
	rtm.rtm_flags = flags;
1145
45
	rtm.rtm_fmask = fmask;
1146
45
	rtm.rtm_version = RTM_VERSION;
1147
45
	rtm.rtm_seq = ++seq;
1148
45
	rtm.rtm_addrs = rtm_addrs;
1149
45
	rtm.rtm_rmx = rt_metrics;
1150
45
	rtm.rtm_inits = rtm_inits;
1151
45
	rtm.rtm_tableid = tableid;
1152
45
	rtm.rtm_priority = prio;
1153
45
	rtm.rtm_mpls = mpls_flags;
1154
45
	rtm.rtm_hdrlen = sizeof(rtm);
1155
1156
45
	if (rtm_addrs & RTA_NETMASK)
1157
42
		mask_addr(&so_dst, &so_mask, RTA_DST);
1158

45
	NEXTADDR(RTA_DST, so_dst);
1159

45
	NEXTADDR(RTA_GATEWAY, so_gate);
1160

45
	NEXTADDR(RTA_NETMASK, so_mask);
1161

45
	NEXTADDR(RTA_IFP, so_ifp);
1162

45
	NEXTADDR(RTA_IFA, so_ifa);
1163

45
	NEXTADDR(RTA_LABEL, so_label);
1164

45
	NEXTADDR(RTA_SRC, so_src);
1165
45
	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1166
45
	if (verbose)
1167
		print_rtmsg(&rtm, l);
1168
45
	if (debugonly)
1169
		return (0);
1170
45
	if (write(s, &m_rtmsg, l) != l) {
1171
15
		return (-1);
1172
	}
1173
30
	if (cmd == RTM_GET) {
1174
		do {
1175
1
			l = read(s, &m_rtmsg, sizeof(m_rtmsg));
1176
		} while (l > 0 && (rtm.rtm_version != RTM_VERSION ||
1177


1
		    rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1178
1
		if (l == -1)
1179
			warn("read from routing socket");
1180
		else
1181
1
			print_getmsg(&rtm, l);
1182
	}
1183
#undef rtm
1184
30
	return (0);
1185
}
1186
1187
void
1188
mask_addr(union sockunion *addr, union sockunion *mask, int which)
1189
42
{
1190
42
	int olen = mask->sa.sa_len;
1191
42
	char *cp1 = olen + (char *)mask, *cp2;
1192
1193
156
	for (mask->sa.sa_len = 0; cp1 > (char *)mask; )
1194
114
		if (*--cp1 != '\0') {
1195
42
			mask->sa.sa_len = 1 + cp1 - (char *)mask;
1196
42
			break;
1197
		}
1198
42
	if ((rtm_addrs & which) == 0)
1199
		return;
1200
42
	switch (addr->sa.sa_family) {
1201
	case AF_INET:
1202
	case AF_INET6:
1203
	case 0:
1204
		return;
1205
	}
1206
	cp1 = mask->sa.sa_len + 1 + (char *)addr;
1207
	cp2 = addr->sa.sa_len + 1 + (char *)addr;
1208
	while (cp2 > cp1)
1209
		*--cp2 = '\0';
1210
	cp2 = mask->sa.sa_len + 1 + (char *)mask;
1211
	while (cp1 > addr->sa.sa_data)
1212
		*--cp1 &= *--cp2;
1213
}
1214
1215
char *msgtypes[] = {
1216
	"",
1217
	"RTM_ADD: Add Route",
1218
	"RTM_DELETE: Delete Route",
1219
	"RTM_CHANGE: Change Metrics or flags",
1220
	"RTM_GET: Report Metrics",
1221
	"RTM_LOSING: Kernel Suspects Partitioning",
1222
	"RTM_REDIRECT: Told to use different route",
1223
	"RTM_MISS: Lookup failed on this address",
1224
	"RTM_LOCK: fix specified metrics",
1225
	"RTM_OLDADD: caused by SIOCADDRT",
1226
	"RTM_OLDDEL: caused by SIOCDELRT",
1227
	"RTM_RESOLVE: Route created by cloning",
1228
	"RTM_NEWADDR: address being added to iface",
1229
	"RTM_DELADDR: address being removed from iface",
1230
	"RTM_IFINFO: iface status change",
1231
	"RTM_IFANNOUNCE: iface arrival/departure",
1232
	"RTM_DESYNC: route socket overflow",
1233
};
1234
1235
char metricnames[] =
1236
"\011priority\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1237
char routeflags[] =
1238
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING"
1239
"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016PROTO3\017PROTO2\020PROTO1\021CLONED\023MPATH\025MPLS\026LOCAL\027BROADCAST";
1240
char ifnetflags[] =
1241
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC"
1242
"\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1243
char addrnames[] =
1244
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\12SRCMASK\013LABEL";
1245
1246
const char *
1247
get_linkstate(int mt, int link_state)
1248
{
1249
	const struct if_status_description *p;
1250
	static char buf[8];
1251
1252
	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1253
		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
1254
			return (p->ifs_string);
1255
	}
1256
	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1257
	return buf;
1258
}
1259
1260
void
1261
print_rtmsg(struct rt_msghdr *rtm, int msglen)
1262
{
1263
	long long relative_expire;
1264
	struct if_msghdr *ifm;
1265
	struct ifa_msghdr *ifam;
1266
	struct if_announcemsghdr *ifan;
1267
	char ifname[IF_NAMESIZE];
1268
1269
	if (verbose == 0)
1270
		return;
1271
	if (rtm->rtm_version != RTM_VERSION) {
1272
		warnx("routing message version %d not understood",
1273
		    rtm->rtm_version);
1274
		return;
1275
	}
1276
	if (rtm->rtm_type > 0 &&
1277
	    rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
1278
		printf("%s", msgtypes[rtm->rtm_type]);
1279
	else
1280
		printf("[rtm_type %d out of range]", rtm->rtm_type);
1281
1282
	printf(": len %d", rtm->rtm_msglen);
1283
	switch (rtm->rtm_type) {
1284
	case RTM_DESYNC:
1285
		printf("\n");
1286
		break;
1287
	case RTM_IFINFO:
1288
		ifm = (struct if_msghdr *)rtm;
1289
		(void) printf(", if# %d, ", ifm->ifm_index);
1290
		if (if_indextoname(ifm->ifm_index, ifname) != NULL)
1291
			printf("name: %s, ", ifname);
1292
		printf("link: %s, flags:",
1293
		    get_linkstate(ifm->ifm_data.ifi_type,
1294
		    ifm->ifm_data.ifi_link_state));
1295
		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1296
		pmsg_addrs((char *)ifm + ifm->ifm_hdrlen, ifm->ifm_addrs);
1297
		break;
1298
	case RTM_NEWADDR:
1299
	case RTM_DELADDR:
1300
		ifam = (struct ifa_msghdr *)rtm;
1301
		printf(", metric %d, flags:", ifam->ifam_metric);
1302
		bprintf(stdout, ifam->ifam_flags, routeflags);
1303
		pmsg_addrs((char *)ifam + ifam->ifam_hdrlen, ifam->ifam_addrs);
1304
		break;
1305
	case RTM_IFANNOUNCE:
1306
		ifan = (struct if_announcemsghdr *)rtm;
1307
		printf(", if# %d, name %s, what: ",
1308
		    ifan->ifan_index, ifan->ifan_name);
1309
		switch (ifan->ifan_what) {
1310
		case IFAN_ARRIVAL:
1311
			printf("arrival");
1312
			break;
1313
		case IFAN_DEPARTURE:
1314
			printf("departure");
1315
			break;
1316
		default:
1317
			printf("#%d", ifan->ifan_what);
1318
			break;
1319
		}
1320
		printf("\n");
1321
		break;
1322
	default:
1323
		printf(", priority %d, table %u, ifidx %u, ",
1324
		    rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index);
1325
		printf("pid: %ld, seq %d, errno %d\nflags:",
1326
		    (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1327
		bprintf(stdout, rtm->rtm_flags, routeflags);
1328
		if (verbose) {
1329
#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1330
			relative_expire = rtm->rtm_rmx.rmx_expire ?
1331
			    rtm->rtm_rmx.rmx_expire - time(NULL) : 0;
1332
			printf("\nuse: %8llu   mtu: %8u%c   expire: %8lld%c",
1333
			    rtm->rtm_rmx.rmx_pksent,
1334
			    rtm->rtm_rmx.rmx_mtu, lock(MTU),
1335
			    relative_expire, lock(EXPIRE));
1336
#undef lock
1337
		}
1338
		pmsg_common(rtm);
1339
	}
1340
}
1341
1342
char *
1343
priorityname(uint8_t prio)
1344
1
{
1345


1
	switch (prio) {
1346
	case RTP_NONE:
1347
		return ("none");
1348
	case RTP_LOCAL:
1349
		return ("local");
1350
	case RTP_CONNECTED:
1351
		return ("connected");
1352
	case RTP_STATIC:
1353
1
		return ("static");
1354
	case RTP_OSPF:
1355
		return ("ospf");
1356
	case RTP_ISIS:
1357
		return ("is-is");
1358
	case RTP_RIP:
1359
		return ("rip");
1360
	case RTP_BGP:
1361
		return ("bgp");
1362
	case RTP_DEFAULT:
1363
		return ("default");
1364
	default:
1365
		return ("");
1366
	}
1367
}
1368
1369
uint8_t
1370
getpriority(char *priostr)
1371
14
{
1372
	const char *errstr;
1373
	uint8_t prio;
1374
1375

14
	switch (keyword(priostr)) {
1376
	case K_LOCAL:
1377
		prio = RTP_LOCAL;
1378
		break;
1379
	case K_CONNECTED:
1380
		prio = RTP_CONNECTED;
1381
		break;
1382
	case K_STATIC:
1383
		prio = RTP_STATIC;
1384
		break;
1385
	case K_OSPF:
1386
		prio = RTP_OSPF;
1387
		break;
1388
	case K_RIP:
1389
		prio = RTP_RIP;
1390
		break;
1391
	case K_BGP:
1392
		prio = RTP_BGP;
1393
		break;
1394
	default:
1395
14
		prio = strtonum(priostr, -RTP_MAX, RTP_MAX, &errstr);
1396
14
		if (errstr)
1397
			errx(1, "priority is %s: %s", errstr, priostr);
1398
	}
1399
1400
14
	return (prio);
1401
}
1402
1403
void
1404
print_getmsg(struct rt_msghdr *rtm, int msglen)
1405
1
{
1406
	long long relative_expire;
1407
1
	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1408
1
	struct sockaddr_dl *ifp = NULL;
1409
1
	struct sockaddr_rtlabel *sa_rl = NULL;
1410
1
	struct sockaddr *mpls = NULL;
1411
	struct sockaddr *sa;
1412
	char *cp;
1413
	int i;
1414
1415
1
	printf("   route to: %s\n", routename(&so_dst.sa));
1416
1
	if (rtm->rtm_version != RTM_VERSION) {
1417
		warnx("routing message version %d not understood",
1418
		    rtm->rtm_version);
1419
		return;
1420
	}
1421
1
	if (rtm->rtm_msglen > msglen)
1422
		warnx("message length mismatch, in packet %d, returned %d",
1423
		    rtm->rtm_msglen, msglen);
1424
1
	if (rtm->rtm_errno) {
1425
		warnx("RTM_GET: %s (errno %d)",
1426
		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1427
		return;
1428
	}
1429
1
	cp = ((char *)rtm + rtm->rtm_hdrlen);
1430
1
	if (rtm->rtm_addrs)
1431
33
		for (i = 1; i; i <<= 1)
1432
32
			if (i & rtm->rtm_addrs) {
1433
5
				sa = (struct sockaddr *)cp;
1434


5
				switch (i) {
1435
				case RTA_DST:
1436
1
					dst = sa;
1437
1
					break;
1438
				case RTA_GATEWAY:
1439
1
					gate = sa;
1440
1
					break;
1441
				case RTA_NETMASK:
1442
1
					mask = sa;
1443
1
					break;
1444
				case RTA_IFA:
1445
1
					ifa = sa;
1446
1
					break;
1447
				case RTA_IFP:
1448

1
					if (sa->sa_family == AF_LINK &&
1449
					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1450
1
						ifp = (struct sockaddr_dl *)sa;
1451
					break;
1452
				case RTA_SRC:
1453
					mpls = sa;
1454
					break;
1455
				case RTA_LABEL:
1456
					sa_rl = (struct sockaddr_rtlabel *)sa;
1457
					break;
1458
				}
1459
5
				ADVANCE(cp, sa);
1460
			}
1461
1
	if (dst && mask)
1462
1
		mask->sa_family = dst->sa_family;	/* XXX */
1463
1
	if (dst)
1464
1
		printf("destination: %s\n", routename(dst));
1465
1
	if (mask) {
1466
1
		int savenflag = nflag;
1467
1468
1
		nflag = 1;
1469
1
		printf("       mask: %s\n", routename(mask));
1470
1
		nflag = savenflag;
1471
	}
1472

1
	if (gate && rtm->rtm_flags & RTF_GATEWAY)
1473
1
		printf("    gateway: %s\n", routename(gate));
1474
1
	if (ifp)
1475
1
		printf("  interface: %.*s\n",
1476
		    ifp->sdl_nlen, ifp->sdl_data);
1477
1
	if (ifa)
1478
1
		printf(" if address: %s\n", routename(ifa));
1479
1
	if (mpls) {
1480
		printf(" mpls label: %s %s\n", mpls_op(rtm->rtm_mpls),
1481
		    routename(mpls));
1482
	}
1483
1
	printf("   priority: %u (%s)\n", rtm->rtm_priority,
1484
	   priorityname(rtm->rtm_priority));
1485
1
	printf("      flags: ");
1486
1
	bprintf(stdout, rtm->rtm_flags, routeflags);
1487
1
	printf("\n");
1488
1
	if (sa_rl != NULL)
1489
		printf("      label: %s\n", sa_rl->sr_label);
1490
1491
#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1492
1
	relative_expire = rtm->rtm_rmx.rmx_expire ?
1493
	    rtm->rtm_rmx.rmx_expire - time(NULL) : 0;
1494
1
	printf("     use       mtu    expire\n");
1495

1
	printf("%8llu  %8u%c %8lld%c\n",
1496
	    rtm->rtm_rmx.rmx_pksent,
1497
	    rtm->rtm_rmx.rmx_mtu, lock(MTU),
1498
	    relative_expire, lock(EXPIRE));
1499
#undef lock
1500
#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1501
1
	if (verbose)
1502
		pmsg_common(rtm);
1503
1
	else if (rtm->rtm_addrs &~ RTA_IGN) {
1504
		printf("sockaddrs: ");
1505
		bprintf(stdout, rtm->rtm_addrs, addrnames);
1506
		putchar('\n');
1507
	}
1508
#undef	RTA_IGN
1509
}
1510
1511
void
1512
pmsg_common(struct rt_msghdr *rtm)
1513
{
1514
	printf("\nlocks: ");
1515
	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1516
	printf(" inits: ");
1517
	bprintf(stdout, rtm->rtm_inits, metricnames);
1518
	pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs);
1519
}
1520
1521
void
1522
pmsg_addrs(char *cp, int addrs)
1523
{
1524
	struct sockaddr *sa;
1525
	int family = AF_UNSPEC;
1526
	int i;
1527
	char *p;
1528
1529
	if (addrs != 0) {
1530
		printf("\nsockaddrs: ");
1531
		bprintf(stdout, addrs, addrnames);
1532
		putchar('\n');
1533
		/* first run, search for address family */
1534
		p = cp;
1535
		for (i = 1; i; i <<= 1)
1536
			if (i & addrs) {
1537
				sa = (struct sockaddr *)p;
1538
				if (family == AF_UNSPEC)
1539
					switch (i) {
1540
					case RTA_DST:
1541
					case RTA_IFA:
1542
						family = sa->sa_family;
1543
					}
1544
				ADVANCE(p, sa);
1545
			}
1546
		/* second run, set address family for mask and print */
1547
		p = cp;
1548
		for (i = 1; i; i <<= 1)
1549
			if (i & addrs) {
1550
				sa = (struct sockaddr *)p;
1551
				if (family != AF_UNSPEC)
1552
					switch (i) {
1553
					case RTA_NETMASK:
1554
						sa->sa_family = family;
1555
					}
1556
				printf(" %s", routename(sa));
1557
				ADVANCE(p, sa);
1558
			}
1559
	}
1560
	putchar('\n');
1561
	fflush(stdout);
1562
}
1563
1564
void
1565
bprintf(FILE *fp, int b, char *s)
1566
1
{
1567
	int i;
1568
1
	int gotsome = 0;
1569
1570
1
	if (b == 0)
1571
		return;
1572
22
	while ((i = *s++)) {
1573
21
		if ((b & (1 << (i-1)))) {
1574
5
			if (gotsome == 0)
1575
1
				i = '<';
1576
			else
1577
4
				i = ',';
1578
5
			putc(i, fp);
1579
5
			gotsome = 1;
1580
29
			for (; (i = *s) > 32; s++)
1581
24
				putc(i, fp);
1582
		} else
1583
125
			while (*s > 32)
1584
109
				s++;
1585
	}
1586
1
	if (gotsome)
1587
1
		putc('>', fp);
1588
}
1589
1590
int
1591
keycmp(const void *key, const void *kt)
1592
630
{
1593
630
	return (strcmp(key, ((struct keytab *)kt)->kt_cp));
1594
}
1595
1596
int
1597
keyword(char *cp)
1598
114
{
1599
	struct keytab *kt;
1600
1601
114
	kt = bsearch(cp, keywords, sizeof(keywords)/sizeof(keywords[0]),
1602
	    sizeof(keywords[0]), keycmp);
1603
114
	if (!kt)
1604
14
		return (0);
1605
1606
100
	return (kt->kt_i);
1607
}
1608
1609
void
1610
sodump(sup su, char *which)
1611
{
1612
	switch (su->sa.sa_family) {
1613
	case AF_LINK:
1614
		printf("%s: link %s; ", which, link_ntoa(&su->sdl));
1615
		break;
1616
	case AF_INET:
1617
		printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr));
1618
		break;
1619
	case AF_INET6:
1620
	    {
1621
		char ntop_buf[NI_MAXHOST];
1622
1623
		printf("%s: inet6 %s; ",
1624
		    which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1625
		    ntop_buf, sizeof(ntop_buf)));
1626
		break;
1627
	    }
1628
	}
1629
	fflush(stdout);
1630
}
1631
1632
/* States*/
1633
#define VIRGIN	0
1634
#define GOTONE	1
1635
#define GOTTWO	2
1636
/* Inputs */
1637
#define	DIGIT	(4*0)
1638
#define	END	(4*1)
1639
#define DELIM	(4*2)
1640
1641
void
1642
sockaddr(char *addr, struct sockaddr *sa)
1643
{
1644
	char *cp = (char *)sa;
1645
	int size = sa->sa_len;
1646
	char *cplim = cp + size;
1647
	int byte = 0, state = VIRGIN, new = 0;
1648
1649
	memset(cp, 0, size);
1650
	cp++;
1651
	do {
1652
		if ((*addr >= '0') && (*addr <= '9')) {
1653
			new = *addr - '0';
1654
		} else if ((*addr >= 'a') && (*addr <= 'f')) {
1655
			new = *addr - 'a' + 10;
1656
		} else if ((*addr >= 'A') && (*addr <= 'F')) {
1657
			new = *addr - 'A' + 10;
1658
		} else if (*addr == '\0')
1659
			state |= END;
1660
		else
1661
			state |= DELIM;
1662
		addr++;
1663
		switch (state /* | INPUT */) {
1664
		case GOTTWO | DIGIT:
1665
			*cp++ = byte; /*FALLTHROUGH*/
1666
		case VIRGIN | DIGIT:
1667
			state = GOTONE; byte = new; continue;
1668
		case GOTONE | DIGIT:
1669
			state = GOTTWO; byte = new + (byte << 4); continue;
1670
		default: /* | DELIM */
1671
			state = VIRGIN; *cp++ = byte; byte = 0; continue;
1672
		case GOTONE | END:
1673
		case GOTTWO | END:
1674
			*cp++ = byte; /* FALLTHROUGH */
1675
		case VIRGIN | END:
1676
			break;
1677
		}
1678
		break;
1679
	} while (cp < cplim);
1680
	sa->sa_len = cp - (char *)sa;
1681
}
1682
1683
void
1684
getlabel(char *name)
1685
{
1686
	so_label.rtlabel.sr_len = sizeof(so_label.rtlabel);
1687
	so_label.rtlabel.sr_family = AF_UNSPEC;
1688
	if (strlcpy(so_label.rtlabel.sr_label, name,
1689
	    sizeof(so_label.rtlabel.sr_label)) >=
1690
	    sizeof(so_label.rtlabel.sr_label))
1691
		errx(1, "label too long");
1692
	rtm_addrs |= RTA_LABEL;
1693
}
1694
1695
int
1696
gettable(const char *s)
1697
50
{
1698
	const char		*errstr;
1699
	struct rt_tableinfo      info;
1700
	int			 mib[6];
1701
	size_t			 len;
1702
1703
50
	tableid = strtonum(s, 0, RT_TABLEID_MAX, &errstr);
1704
50
	if (errstr)
1705
		errx(1, "invalid table id: %s", errstr);
1706
1707
50
	mib[0] = CTL_NET;
1708
50
	mib[1] = PF_ROUTE;
1709
50
	mib[2] = 0;
1710
50
	mib[3] = 0;
1711
50
	mib[4] = NET_RT_TABLE;
1712
50
	mib[5] = tableid;
1713
1714
50
	len = sizeof(info);
1715
50
	if (sysctl(mib, 6, &info, &len, NULL, 0) == -1)
1716
		return (errno);
1717
	else
1718
50
		return (0);
1719
}
1720
1721
int
1722
rdomain(int argc, char **argv)
1723
{
1724
	if (!argc)
1725
		usage(NULL);
1726
	if (setrtable(tableid) == -1)
1727
		err(1, "setrtable");
1728
	execvp(*argv, argv);
1729
	warn("%s", argv[0]);
1730
	return (errno == ENOENT ? 127 : 126);
1731
}