GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/route/route.c Lines: 395 1143 34.6 %
Date: 2017-11-13 Branches: 250 800 31.3 %

Line Branch Exec Source
1
/*	$OpenBSD: route.c,v 1.206 2017/10/18 07:31:31 mpi 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_media.h>
39
#include <net/if_types.h>
40
#include <net/route.h>
41
#include <netinet/in.h>
42
#include <netmpls/mpls.h>
43
44
#ifdef BFD
45
#include <sys/time.h>
46
#include <net/bfd.h>
47
#endif
48
49
#include <arpa/inet.h>
50
#include <netdb.h>
51
52
#include <errno.h>
53
#include <fcntl.h>
54
#include <unistd.h>
55
#include <limits.h>
56
#include <stdio.h>
57
#include <ctype.h>
58
#include <stddef.h>
59
#include <stdlib.h>
60
#include <string.h>
61
#include <time.h>
62
#include <paths.h>
63
#include <err.h>
64
65
#include "keywords.h"
66
#include "show.h"
67
68
const struct if_status_description
69
			if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
70
71
union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_label, so_src;
72
73
typedef union sockunion *sup;
74
pid_t	pid;
75
int	rtm_addrs, s;
76
int	forcehost, forcenet, Fflag, nflag, af, qflag, tflag, Tflag;
77
int	iflag, verbose, aflen = sizeof(struct sockaddr_in);
78
int	locking, lockrest, debugonly;
79
u_long	mpls_flags = MPLS_OP_LOCAL;
80
u_long	rtm_inits;
81
uid_t	uid;
82
u_int	tableid;
83
84
struct rt_metrics	rt_metrics;
85
86
int	 flushroutes(int, char **);
87
int	 newroute(int, char **);
88
int	 show(int, char *[]);
89
int	 keycmp(const void *, const void *);
90
int	 keyword(char *);
91
void	 monitor(int, char *[]);
92
int	 prefixlen(char *);
93
void	 sockaddr(char *, struct sockaddr *);
94
void	 sodump(sup, char *);
95
char	*priorityname(uint8_t);
96
uint8_t	 getpriority(char *);
97
void	 print_getmsg(struct rt_msghdr *, int);
98
#ifdef BFD
99
const char *bfd_state(unsigned int);
100
const char *bfd_diag(unsigned int);
101
const char *bfd_calc_uptime(time_t);
102
void	 print_bfdmsg(struct rt_msghdr *);
103
void	 print_sabfd(struct sockaddr_bfd *, int);
104
#endif
105
const char *get_linkstate(int, int);
106
void	 print_rtmsg(struct rt_msghdr *, int);
107
void	 pmsg_common(struct rt_msghdr *);
108
void	 pmsg_addrs(char *, int);
109
void	 bprintf(FILE *, int, char *);
110
void	 mask_addr(union sockunion *, union sockunion *, int);
111
int	 inet6_makenetandmask(struct sockaddr_in6 *, char *);
112
int	 getaddr(int, char *, struct hostent **);
113
void	 getmplslabel(char *, int);
114
int	 rtmsg(int, int, int, uint8_t);
115
__dead void usage(char *);
116
void	 set_metric(char *, int);
117
void	 inet_makenetandmask(u_int32_t, struct sockaddr_in *, int);
118
void	 interfaces(void);
119
void	 getlabel(char *);
120
int	 gettable(const char *);
121
int	 rdomain(int, char **);
122
void	 print_rtdns(struct sockaddr_rtdns *);
123
void	 print_rtstatic(struct sockaddr_rtstatic *);
124
void	 print_rtsearch(struct sockaddr_rtsearch *);
125
126
__dead void
127
usage(char *cp)
128
{
129
	extern char *__progname;
130
131
	if (cp)
132
		warnx("botched keyword: %s", cp);
133
	fprintf(stderr,
134
	    "usage: %s [-dnqtv] [-T tableid] command [[modifiers] args]\n",
135
	    __progname);
136
	fprintf(stderr,
137
	    "commands: add, change, delete, exec, flush, get, monitor, show\n");
138
	exit(1);
139
}
140
141
#define ROUNDUP(a) \
142
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
143
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
144
145
int
146
main(int argc, char **argv)
147
{
148
	int ch;
149
	int rval = 0;
150
	int kw;
151
	int Terr = 0;
152
153
1512
	if (argc < 2)
154
		usage(NULL);
155
156
756
	tableid = getrtable();
157
4656
	while ((ch = getopt(argc, argv, "dnqtT:v")) != -1)
158

3132
		switch (ch) {
159
		case 'n':
160
			nflag = 1;
161
756
			break;
162
		case 'q':
163
			qflag = 1;
164
			break;
165
		case 'v':
166
			verbose = 1;
167
			break;
168
		case 't':
169
			tflag = 1;
170
48
			break;
171
		case 'T':
172
756
			Terr = gettable(optarg);
173
			Tflag = 1;
174
756
			break;
175
		case 'd':
176
			debugonly = 1;
177
			break;
178
		default:
179
			usage(NULL);
180
			/* NOTREACHED */
181
		}
182
756
	argc -= optind;
183
756
	argv += optind;
184
185
756
	pid = getpid();
186
756
	uid = geteuid();
187
756
	if (*argv == NULL)
188
		usage(NULL);
189
190
756
	kw = keyword(*argv);
191
756
	if (Tflag && Terr != 0 && kw != K_ADD) {
192
		errno = Terr;
193
		err(1, "routing table %d", tableid);
194
	}
195
756
	if (kw == K_EXEC)
196
		exit(rdomain(argc - 1, argv + 1));
197
198
756
	s = socket(PF_ROUTE, SOCK_RAW, 0);
199
756
	if (s == -1)
200
		err(1, "socket");
201
756
	if (kw == K_MONITOR) {
202
		unsigned int filter = 0;
203
		int af = 0;
204
205
		while (--argc > 0) {
206
			if (**(++argv)== '-')
207
				switch (keyword(*argv + 1)) {
208
				case K_INET:
209
					af = AF_INET;
210
					break;
211
				case K_INET6:
212
					af = AF_INET6;
213
					break;
214
				case K_IFACE:
215
				case K_INTERFACE:
216
					filter = ROUTE_FILTER(RTM_IFINFO) |
217
					    ROUTE_FILTER(RTM_IFANNOUNCE);
218
					break;
219
				default:
220
					usage(*argv);
221
					/* NOTREACHED */
222
				}
223
			else
224
				usage(*argv);
225
		}
226
		if (setsockopt(s, AF_ROUTE, ROUTE_MSGFILTER, &filter,
227
		    sizeof(filter)) == -1)
228
			err(1, "setsockopt(ROUTE_MSGFILTER)");
229
	}
230
	/* force socket onto table user requested */
231

1512
	if (Tflag == 1 && Terr == 0 &&
232
756
	    setsockopt(s, AF_ROUTE, ROUTE_TABLEFILTER,
233
756
	    &tableid, sizeof(tableid)) == -1)
234
		err(1, "setsockopt(ROUTE_TABLEFILTER)");
235
236
756
	switch (kw) {
237
	case K_SHOW:
238
		uid = 0;
239
		exit(show(argc, argv));
240
		break;
241
	case K_FLUSH:
242
		exit(flushroutes(argc, argv));
243
		break;
244
	}
245
246
606
	if (pledge("stdio rpath dns flock cpath wpath", NULL) == -1)
247
		err(1, "pledge");
248
249

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


48
	switch (key) {
419
	case K_MTU:
420
42
		rt_metrics.rmx_mtu = strtonum(value, 0, UINT_MAX, &errstr);
421
42
		if (errstr)
422
			errx(1, "set_metric mtu: %s is %s", value, errstr);
423
		flag = RTV_MTU;
424
42
		break;
425
	case K_EXPIRE:
426
6
		relative_expire = strtonum(value, 0, INT_MAX, &errstr);
427
6
		if (errstr)
428
			errx(1, "set_metric expire: %s is %s", value, errstr);
429
18
		rt_metrics.rmx_expire = relative_expire ?
430
6
		    relative_expire + time(NULL) : 0;
431
		flag = RTV_EXPIRE;
432
6
		break;
433
	case K_HOPCOUNT:
434
	case K_RECVPIPE:
435
	case K_SENDPIPE:
436
	case K_SSTHRESH:
437
	case K_RTT:
438
	case K_RTTVAR:
439
		/* no longer used, only for compatibility */
440
		return;
441
	default:
442
		errx(1, "king bula sez: set_metric with invalid key");
443
	}
444
48
	rtm_inits |= flag;
445
48
	if (lockrest || locking)
446
6
		rt_metrics.rmx_locks |= flag;
447
48
	if (locking)
448
6
		locking = 0;
449
96
}
450
451
int
452
newroute(int argc, char **argv)
453
{
454
	char *cmd, *dest = "", *gateway = "", *error;
455
	int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC;
456
	int fmask = 0;
457
	int key;
458
	uint8_t prio = 0;
459
1212
	struct hostent *hp = NULL;
460
461
606
	if (uid)
462
		errx(1, "must be root to alter routing table");
463
606
	cmd = argv[0];
464
606
	if (*cmd != 'g')
465
600
		shutdown(s, SHUT_RD); /* Don't want to read back our messages */
466
4824
	while (--argc > 0) {
467
1806
		if (**(++argv)== '-') {
468











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

654
	if (forcenet && !(rtm_addrs & RTA_NETMASK))
658
		errx(1, "netmask missing");
659
606
	flags |= RTF_UP;
660
606
	if (ishost)
661
36
		flags |= RTF_HOST;
662
606
	if (iflag == 0)
663
606
		flags |= RTF_GATEWAY;
664
606
	for (attempts = 1; ; attempts++) {
665
606
		errno = 0;
666
606
		if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0)
667
			break;
668

162
		if (errno != ENETUNREACH && errno != ESRCH)
669
			break;
670

72
		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
671
			hp->h_addr_list++;
672
			memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0],
673
			    hp->h_length);
674
		} else
675
			break;
676
	}
677
606
	oerrno = errno;
678

1200
	if (!qflag && (*cmd != 'g' || ret != 0)) {
679
588
		printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
680
588
		if (*gateway) {
681
546
			printf(": gateway %s", gateway);
682
546
			if (attempts > 1 && ret == 0 && af == AF_INET)
683
			    printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
684
		}
685
588
		if (ret == 0)
686
534
			printf("\n");
687
588
		if (ret != 0) {
688

54
			switch (oerrno) {
689
			case ESRCH:
690
				error = "not in table";
691
18
				break;
692
			case EBUSY:
693
				error = "entry in use";
694
				break;
695
			case ENOBUFS:
696
				error = "routing table overflow";
697
				break;
698
			default:
699
36
				error = strerror(oerrno);
700
36
				break;
701
			}
702
54
			printf(": %s\n", error);
703
54
		}
704
	}
705
1212
	return (ret != 0);
706
606
}
707
708
int
709
show(int argc, char *argv[])
710
{
711
	int		 af = 0;
712
	char		 prio = 0;
713
714
786
	while (--argc > 0) {
715
168
		if (**(++argv)== '-')
716


168
			switch (keyword(*argv + 1)) {
717
			case K_INET:
718
				af = AF_INET;
719
138
				break;
720
			case K_INET6:
721
				af = AF_INET6;
722
12
				break;
723
			case K_LINK:
724
				af = AF_LINK;
725
				break;
726
			case K_MPLS:
727
				af = AF_MPLS;
728
				break;
729
			case K_GATEWAY:
730
18
				Fflag = 1;
731
18
				break;
732
			case K_LABEL:
733
				if (!--argc)
734
					usage(1+*argv);
735
				getlabel(*++argv);
736
				break;
737
			case K_PRIORITY:
738
				if (!--argc)
739
					usage(1+*argv);
740
				prio = getpriority(*++argv);
741
				break;
742
			default:
743
				usage(*argv);
744
				/* NOTREACHED */
745
			}
746
		else
747
			usage(*argv);
748
	}
749
750
150
	p_rttables(af, tableid, Tflag, prio);
751
150
	return (0);
752
}
753
754
void
755
inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits)
756
{
757
	u_int32_t addr, mask = 0;
758
	char *cp;
759
760
1032
	rtm_addrs |= RTA_NETMASK;
761
516
	if (net == 0 && bits == 0)
762
		mask = addr = 0;
763
516
	else if (bits) {
764
		addr = net;
765
516
		mask = 0xffffffff << (32 - bits);
766
516
	} else if (net < 128) {
767
		addr = net << IN_CLASSA_NSHIFT;
768
		mask = IN_CLASSA_NET;
769
	} else if (net < 65536) {
770
		addr = net << IN_CLASSB_NSHIFT;
771
		mask = IN_CLASSB_NET;
772
	} else if (net < 16777216L) {
773
		addr = net << IN_CLASSC_NSHIFT;
774
		mask = IN_CLASSC_NET;
775
	} else {
776
		addr = net;
777
		if ((addr & IN_CLASSA_HOST) == 0)
778
			mask = IN_CLASSA_NET;
779
		else if ((addr & IN_CLASSB_HOST) == 0)
780
			mask = IN_CLASSB_NET;
781
		else if ((addr & IN_CLASSC_HOST) == 0)
782
			mask = IN_CLASSC_NET;
783
		else
784
			mask = 0xffffffff;
785
	}
786
516
	addr &= mask;
787
516
	sin->sin_addr.s_addr = htonl(addr);
788
	sin = &so_mask.sin;
789
516
	sin->sin_addr.s_addr = htonl(mask);
790
516
	sin->sin_len = 0;
791
516
	sin->sin_family = 0;
792
	cp = (char *)(&sin->sin_addr + 1);
793

2100
	while (*--cp == '\0' && cp > (char *)sin)
794
534
		continue;
795
516
	sin->sin_len = 1 + cp - (char *)sin;
796
516
}
797
798
/*
799
 * XXX the function may need more improvement...
800
 */
801
int
802
inet6_makenetandmask(struct sockaddr_in6 *sin6, char *plen)
803
{
804
84
	struct in6_addr in6;
805
42
	const char *errstr;
806
	int i, len, q, r;
807
808
42
	if (NULL==plen) {
809


24
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
810
		    sin6->sin6_scope_id == 0) {
811
			plen = "0";
812
24
		} else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
813
			/* aggregatable global unicast - RFC2374 */
814
			memset(&in6, 0, sizeof(in6));
815
			if (!memcmp(&sin6->sin6_addr.s6_addr[8],
816
			    &in6.s6_addr[8], 8))
817
				plen = "64";
818
		}
819
	}
820
821

60
	if (!plen || strcmp(plen, "128") == 0)
822
24
		return (1);
823
	else {
824
18
		rtm_addrs |= RTA_NETMASK;
825
18
		prefixlen(plen);
826
827
18
		len = strtonum(plen, 0, 128, &errstr);
828
18
		if (errstr)
829
			errx(1, "prefixlen %s is %s", plen, errstr);
830
831
18
		q = (128-len) >> 3;
832
18
		r = (128-len) & 7;
833
		i = 15;
834
835
324
		while (q-- > 0)
836
144
			sin6->sin6_addr.s6_addr[i--] = 0;
837
18
		if (r > 0)
838
			sin6->sin6_addr.s6_addr[i] &= 0xff << r;
839
840
18
		return (0);
841
	}
842
42
}
843
844
/*
845
 * Interpret an argument as a network address of some kind,
846
 * returning 1 if a host address, 0 if a network address.
847
 */
848
int
849
getaddr(int which, char *s, struct hostent **hpp)
850
{
851
	sup su = NULL;
852
	struct hostent *hp;
853
	struct netent *np;
854
	int afamily, bits;
855
856
2424
	if (af == 0) {
857
576
		if (strchr(s, ':') != NULL) {
858
			af = AF_INET6;
859
			aflen = sizeof(struct sockaddr_in6);
860
		} else {
861
			af = AF_INET;
862
			aflen = sizeof(struct sockaddr_in);
863
		}
864
576
	}
865
1212
	afamily = af;	/* local copy of af so we can change it */
866
867
1212
	rtm_addrs |= which;
868

1212
	switch (which) {
869
	case RTA_DST:
870
		su = &so_dst;
871
606
		break;
872
	case RTA_GATEWAY:
873
		su = &so_gate;
874
558
		break;
875
	case RTA_NETMASK:
876
		su = &so_mask;
877
36
		break;
878
	case RTA_IFP:
879
		su = &so_ifp;
880
		afamily = AF_LINK;
881
6
		break;
882
	case RTA_IFA:
883
		su = &so_ifa;
884
6
		break;
885
	default:
886
		errx(1, "internal error");
887
		/* NOTREACHED */
888
	}
889
1212
	su->sa.sa_len = aflen;
890
1212
	su->sa.sa_family = afamily;
891
892
1212
	if (strcmp(s, "default") == 0) {
893
48
		switch (which) {
894
		case RTA_DST:
895
12
			forcenet++;
896
12
			getaddr(RTA_NETMASK, s, NULL);
897
12
			break;
898
		case RTA_NETMASK:
899
12
			su->sa.sa_len = 0;
900
12
		}
901
24
		return (0);
902
	}
903
904

1188
	switch (afamily) {
905
	case AF_INET6:
906
	    {
907
66
		struct addrinfo hints, *res;
908
66
		char            buf[
909
		   sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")
910
		];
911
		char           *sep;
912
913
66
		if (strlcpy(buf, s, sizeof buf) >= sizeof buf) {
914
			errx(1, "%s: bad value", s);
915
		}
916
917
66
		sep = strchr(buf, '/');
918
66
		if (sep != NULL)
919
18
			*sep++ = '\0';
920
66
		memset(&hints, 0, sizeof(hints));
921
66
		hints.ai_family = afamily;	/*AF_INET6*/
922
66
		hints.ai_flags = AI_NUMERICHOST;
923
66
		hints.ai_socktype = SOCK_DGRAM;		/*dummy*/
924
66
		if (getaddrinfo(buf, "0", &hints, &res) != 0) {
925
			hints.ai_flags = 0;
926
			if (getaddrinfo(buf, "0", &hints, &res) != 0)
927
				errx(1, "%s: bad value", s);
928
		}
929
66
		if (sizeof(su->sin6) != res->ai_addrlen)
930
			errx(1, "%s: bad value", s);
931
66
		if (res->ai_next)
932
			errx(1, "%s: resolved to multiple values", s);
933
66
		memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
934
66
		freeaddrinfo(res);
935

66
		if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
936

66
		     IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) ||
937

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

2424
	NEXTADDR(RTA_DST, so_dst);
1184

2280
	NEXTADDR(RTA_GATEWAY, so_gate);
1185

2304
	NEXTADDR(RTA_NETMASK, so_mask);
1186

642
	NEXTADDR(RTA_IFP, so_ifp);
1187

624
	NEXTADDR(RTA_IFA, so_ifa);
1188

606
	NEXTADDR(RTA_LABEL, so_label);
1189

606
	NEXTADDR(RTA_SRC, so_src);
1190
606
	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1191
606
	if (verbose)
1192
		print_rtmsg(&rtm, l);
1193
606
	if (debugonly)
1194
		return (0);
1195
606
	if (write(s, &m_rtmsg, l) != l) {
1196
54
		return (-1);
1197
	}
1198
552
	if (cmd == RTM_GET) {
1199
6
		do {
1200
6
			l = read(s, &m_rtmsg, sizeof(m_rtmsg));
1201

18
		} while (l > 0 && (rtm.rtm_version != RTM_VERSION ||
1202
12
		    rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1203
6
		if (l == -1)
1204
			warn("read from routing socket");
1205
		else
1206
6
			print_getmsg(&rtm, l);
1207
	}
1208
#undef rtm
1209
552
	return (0);
1210
606
}
1211
1212
void
1213
mask_addr(union sockunion *addr, union sockunion *mask, int which)
1214
{
1215
1140
	int olen = mask->sa.sa_len;
1216
570
	char *cp1 = olen + (char *)mask, *cp2;
1217
1218
2004
	for (mask->sa.sa_len = 0; cp1 > (char *)mask; )
1219
990
		if (*--cp1 != '\0') {
1220
558
			mask->sa.sa_len = 1 + cp1 - (char *)mask;
1221
558
			break;
1222
		}
1223
570
	if ((rtm_addrs & which) == 0)
1224
		return;
1225

570
	switch (addr->sa.sa_family) {
1226
	case AF_INET:
1227
	case AF_INET6:
1228
	case 0:
1229
570
		return;
1230
	}
1231
	cp1 = mask->sa.sa_len + 1 + (char *)addr;
1232
	cp2 = addr->sa.sa_len + 1 + (char *)addr;
1233
	while (cp2 > cp1)
1234
		*--cp2 = '\0';
1235
	cp2 = mask->sa.sa_len + 1 + (char *)mask;
1236
	while (cp1 > addr->sa.sa_data)
1237
		*--cp1 &= *--cp2;
1238
570
}
1239
1240
char *msgtypes[] = {
1241
	"",
1242
	"RTM_ADD: Add Route",
1243
	"RTM_DELETE: Delete Route",
1244
	"RTM_CHANGE: Change Metrics or flags",
1245
	"RTM_GET: Report Metrics",
1246
	"RTM_LOSING: Kernel Suspects Partitioning",
1247
	"RTM_REDIRECT: Told to use different route",
1248
	"RTM_MISS: Lookup failed on this address",
1249
	"RTM_LOCK: fix specified metrics",
1250
	"RTM_OLDADD: caused by SIOCADDRT",
1251
	"RTM_OLDDEL: caused by SIOCDELRT",
1252
	"RTM_RESOLVE: Route created by cloning",
1253
	"RTM_NEWADDR: address being added to iface",
1254
	"RTM_DELADDR: address being removed from iface",
1255
	"RTM_IFINFO: iface status change",
1256
	"RTM_IFANNOUNCE: iface arrival/departure",
1257
	"RTM_DESYNC: route socket overflow",
1258
	"RTM_INVALIDATE: invalidate cache of L2 route",
1259
	"RTM_BFD: bidirectional forwarding detection",
1260
	"RTM_PROPOSAL: config proposal"
1261
};
1262
1263
char metricnames[] =
1264
"\011priority\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1265
char routeflags[] =
1266
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010XMASK_PRESENT"
1267
"\011CLONING\012MULTICAST\013LLINFO\014STATIC\015BLACKHOLE\016PROTO3\017PROTO2"
1268
"\020PROTO1\021CLONED\022CACHED\023MPATH\025MPLS\026LOCAL\027BROADCAST"
1269
"\030CONNECTED\031BFD";
1270
char ifnetflags[] =
1271
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC"
1272
"\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1273
char addrnames[] =
1274
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\012SRCMASK\013LABEL\014BFD\015DNS\016STATIC\017SEARCH";
1275
1276
const char *
1277
get_linkstate(int mt, int link_state)
1278
{
1279
	const struct if_status_description *p;
1280
	static char buf[8];
1281
1282
	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1283
		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
1284
			return (p->ifs_string);
1285
	}
1286
	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1287
	return buf;
1288
}
1289
1290
void
1291
print_rtmsg(struct rt_msghdr *rtm, int msglen)
1292
{
1293
	long long relative_expire;
1294
	struct if_msghdr *ifm;
1295
	struct ifa_msghdr *ifam;
1296
	struct if_announcemsghdr *ifan;
1297
	char ifname[IF_NAMESIZE];
1298
1299
	if (verbose == 0)
1300
		return;
1301
	if (rtm->rtm_version != RTM_VERSION) {
1302
		warnx("routing message version %d not understood",
1303
		    rtm->rtm_version);
1304
		return;
1305
	}
1306
	if (rtm->rtm_type > 0 &&
1307
	    rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
1308
		printf("%s", msgtypes[rtm->rtm_type]);
1309
	else
1310
		printf("[rtm_type %d out of range]", rtm->rtm_type);
1311
1312
	printf(": len %d", rtm->rtm_msglen);
1313
	switch (rtm->rtm_type) {
1314
	case RTM_DESYNC:
1315
		printf("\n");
1316
		break;
1317
	case RTM_IFINFO:
1318
		ifm = (struct if_msghdr *)rtm;
1319
		(void) printf(", if# %d, ", ifm->ifm_index);
1320
		if (if_indextoname(ifm->ifm_index, ifname) != NULL)
1321
			printf("name: %s, ", ifname);
1322
		printf("link: %s, mtu: %u, flags:",
1323
		    get_linkstate(ifm->ifm_data.ifi_type,
1324
		        ifm->ifm_data.ifi_link_state),
1325
		    ifm->ifm_data.ifi_mtu);
1326
		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1327
		pmsg_addrs((char *)ifm + ifm->ifm_hdrlen, ifm->ifm_addrs);
1328
		break;
1329
	case RTM_NEWADDR:
1330
	case RTM_DELADDR:
1331
		ifam = (struct ifa_msghdr *)rtm;
1332
		printf(", metric %d, flags:", ifam->ifam_metric);
1333
		bprintf(stdout, ifam->ifam_flags, routeflags);
1334
		pmsg_addrs((char *)ifam + ifam->ifam_hdrlen, ifam->ifam_addrs);
1335
		break;
1336
	case RTM_IFANNOUNCE:
1337
		ifan = (struct if_announcemsghdr *)rtm;
1338
		printf(", if# %d, name %s, what: ",
1339
		    ifan->ifan_index, ifan->ifan_name);
1340
		switch (ifan->ifan_what) {
1341
		case IFAN_ARRIVAL:
1342
			printf("arrival");
1343
			break;
1344
		case IFAN_DEPARTURE:
1345
			printf("departure");
1346
			break;
1347
		default:
1348
			printf("#%d", ifan->ifan_what);
1349
			break;
1350
		}
1351
		printf("\n");
1352
		break;
1353
#ifdef BFD
1354
	case RTM_BFD:
1355
		print_bfdmsg(rtm);
1356
		break;
1357
#endif
1358
	case RTM_PROPOSAL:
1359
		printf(", source ");
1360
		switch (rtm->rtm_priority) {
1361
		case RTP_PROPOSAL_STATIC:
1362
			printf("static");
1363
			break;
1364
		case RTP_PROPOSAL_DHCLIENT:
1365
			printf("dhcp");
1366
			break;
1367
		case RTP_PROPOSAL_SLAAC:
1368
			printf("slaac");
1369
			break;
1370
		default:
1371
			printf("unknown");
1372
			break;
1373
		}
1374
		printf(" table %u, ifidx %u, ",
1375
		    rtm->rtm_tableid, rtm->rtm_index);
1376
		printf("pid: %ld, seq %d, errno %d\nflags:",
1377
		    (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1378
		bprintf(stdout, rtm->rtm_flags, routeflags);
1379
		printf("\nfmask:");
1380
		bprintf(stdout, rtm->rtm_fmask, routeflags);
1381
		if (verbose) {
1382
#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1383
			relative_expire = rtm->rtm_rmx.rmx_expire ?
1384
			    rtm->rtm_rmx.rmx_expire - time(NULL) : 0;
1385
			printf("\nuse: %8llu   mtu: %8u%c   expire: %8lld%c",
1386
			    rtm->rtm_rmx.rmx_pksent,
1387
			    rtm->rtm_rmx.rmx_mtu, lock(MTU),
1388
			    relative_expire, lock(EXPIRE));
1389
#undef lock
1390
		}
1391
		printf("\nlocks: ");
1392
		bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1393
		printf(" inits: ");
1394
		bprintf(stdout, rtm->rtm_inits, metricnames);
1395
		pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen),
1396
		   rtm->rtm_addrs & ~(RTA_STATIC | RTA_SEARCH | RTA_DNS));
1397
		printf("Static Routes:\n");
1398
		if (rtm->rtm_addrs & RTA_STATIC) {
1399
			char *next = (char *)rtm + rtm->rtm_hdrlen;
1400
			struct sockaddr	*sa, *rti_info[RTAX_MAX];
1401
			struct sockaddr_rtstatic *rtstatic;
1402
			sa = (struct sockaddr *)next;
1403
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1404
			rtstatic = (struct sockaddr_rtstatic *)
1405
			    rti_info[RTAX_STATIC];
1406
			if (rtstatic != NULL) {
1407
				printf(" ");
1408
				print_rtstatic(rtstatic);
1409
			}
1410
		}
1411
		printf("Domain search:\n");
1412
		if (rtm->rtm_addrs & RTA_SEARCH) {
1413
			char *next = (char *)rtm + rtm->rtm_hdrlen;
1414
			struct sockaddr	*sa, *rti_info[RTAX_MAX];
1415
			struct sockaddr_rtsearch *rtsearch;
1416
			sa = (struct sockaddr *)next;
1417
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1418
			rtsearch = (struct sockaddr_rtsearch *)
1419
			    rti_info[RTAX_SEARCH];
1420
			if (rtsearch != NULL) {
1421
				printf(" ");
1422
				print_rtsearch(rtsearch);
1423
			}
1424
		}
1425
		printf("Domain Name Servers:\n");
1426
		if (rtm->rtm_addrs & RTA_DNS) {
1427
			char *next = (char *)rtm + rtm->rtm_hdrlen;
1428
			struct sockaddr	*sa, *rti_info[RTAX_MAX];
1429
			struct sockaddr_rtdns *rtdns;
1430
			sa = (struct sockaddr *)next;
1431
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1432
			rtdns = (struct sockaddr_rtdns *)rti_info[RTAX_DNS];
1433
			if (rtdns != NULL) {
1434
				printf(" ");
1435
				print_rtdns(rtdns);
1436
			}
1437
		}
1438
		break;
1439
	default:
1440
		printf(", priority %d, table %u, ifidx %u, ",
1441
		    rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index);
1442
		printf("pid: %ld, seq %d, errno %d\nflags:",
1443
		    (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1444
		bprintf(stdout, rtm->rtm_flags, routeflags);
1445
		printf("\nfmask:");
1446
		bprintf(stdout, rtm->rtm_fmask, routeflags);
1447
		if (verbose) {
1448
#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1449
			relative_expire = rtm->rtm_rmx.rmx_expire ?
1450
			    rtm->rtm_rmx.rmx_expire - time(NULL) : 0;
1451
			printf("\nuse: %8llu   mtu: %8u%c   expire: %8lld%c",
1452
			    rtm->rtm_rmx.rmx_pksent,
1453
			    rtm->rtm_rmx.rmx_mtu, lock(MTU),
1454
			    relative_expire, lock(EXPIRE));
1455
#undef lock
1456
		}
1457
		pmsg_common(rtm);
1458
	}
1459
}
1460
1461
char *
1462
priorityname(uint8_t prio)
1463
{
1464


12
	switch (prio) {
1465
	case RTP_NONE:
1466
		return ("none");
1467
	case RTP_LOCAL:
1468
		return ("local");
1469
	case RTP_CONNECTED:
1470
		return ("connected");
1471
	case RTP_STATIC:
1472
6
		return ("static");
1473
	case RTP_OSPF:
1474
		return ("ospf");
1475
	case RTP_ISIS:
1476
		return ("is-is");
1477
	case RTP_RIP:
1478
		return ("rip");
1479
	case RTP_BGP:
1480
		return ("bgp");
1481
	case RTP_DEFAULT:
1482
		return ("default");
1483
	default:
1484
		return ("");
1485
	}
1486
6
}
1487
1488
uint8_t
1489
getpriority(char *priostr)
1490
{
1491
432
	const char *errstr;
1492
	uint8_t prio;
1493
1494

216
	switch (keyword(priostr)) {
1495
	case K_LOCAL:
1496
		prio = RTP_LOCAL;
1497
		break;
1498
	case K_CONNECTED:
1499
		prio = RTP_CONNECTED;
1500
		break;
1501
	case K_STATIC:
1502
		prio = RTP_STATIC;
1503
		break;
1504
	case K_OSPF:
1505
		prio = RTP_OSPF;
1506
		break;
1507
	case K_RIP:
1508
		prio = RTP_RIP;
1509
		break;
1510
	case K_BGP:
1511
		prio = RTP_BGP;
1512
		break;
1513
	default:
1514
216
		prio = strtonum(priostr, -RTP_MAX, RTP_MAX, &errstr);
1515
216
		if (errstr)
1516
			errx(1, "priority is %s: %s", errstr, priostr);
1517
	}
1518
1519
216
	return (prio);
1520
216
}
1521
1522
void
1523
print_getmsg(struct rt_msghdr *rtm, int msglen)
1524
{
1525
	long long relative_expire;
1526
	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1527
	struct sockaddr_dl *ifp = NULL;
1528
	struct sockaddr_rtlabel *sa_rl = NULL;
1529
#ifdef BFD
1530
	struct sockaddr_bfd *sa_bfd = NULL;
1531
#endif
1532
	struct sockaddr *mpls = NULL;
1533
	struct sockaddr *sa;
1534
	char *cp;
1535
	int i;
1536
1537
12
	printf("   route to: %s\n", routename(&so_dst.sa));
1538
6
	if (rtm->rtm_version != RTM_VERSION) {
1539
		warnx("routing message version %d not understood",
1540
		    rtm->rtm_version);
1541
		return;
1542
	}
1543
6
	if (rtm->rtm_msglen > msglen)
1544
		warnx("message length mismatch, in packet %d, returned %d",
1545
		    rtm->rtm_msglen, msglen);
1546
6
	if (rtm->rtm_errno) {
1547
		warnx("RTM_GET: %s (errno %d)",
1548
		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1549
		return;
1550
	}
1551
6
	cp = ((char *)rtm + rtm->rtm_hdrlen);
1552
6
	if (rtm->rtm_addrs)
1553
396
		for (i = 1; i; i <<= 1)
1554
192
			if (i & rtm->rtm_addrs) {
1555
60
				sa = (struct sockaddr *)cp;
1556


60
				switch (i) {
1557
				case RTA_DST:
1558
					dst = sa;
1559
6
					break;
1560
				case RTA_GATEWAY:
1561
					gate = sa;
1562
6
					break;
1563
				case RTA_NETMASK:
1564
					mask = sa;
1565
6
					break;
1566
				case RTA_IFA:
1567
					ifa = sa;
1568
6
					break;
1569
				case RTA_IFP:
1570

12
					if (sa->sa_family == AF_LINK &&
1571
6
					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1572
6
						ifp = (struct sockaddr_dl *)sa;
1573
					break;
1574
				case RTA_SRC:
1575
					mpls = sa;
1576
					break;
1577
				case RTA_LABEL:
1578
					sa_rl = (struct sockaddr_rtlabel *)sa;
1579
					break;
1580
#ifdef BFD
1581
				case RTA_BFD:
1582
					sa_bfd = (struct sockaddr_bfd *)sa;
1583
					break;
1584
#endif
1585
				}
1586
90
				ADVANCE(cp, sa);
1587
30
			}
1588
6
	if (dst && mask)
1589
6
		mask->sa_family = dst->sa_family;	/* XXX */
1590
6
	if (dst)
1591
6
		printf("destination: %s\n", routename(dst));
1592
6
	if (mask) {
1593
6
		int savenflag = nflag;
1594
1595
6
		nflag = 1;
1596
6
		printf("       mask: %s\n", routename(mask));
1597
6
		nflag = savenflag;
1598
6
	}
1599

12
	if (gate && rtm->rtm_flags & RTF_GATEWAY)
1600
6
		printf("    gateway: %s\n", routename(gate));
1601
6
	if (ifp)
1602
6
		printf("  interface: %.*s\n",
1603
6
		    ifp->sdl_nlen, ifp->sdl_data);
1604
6
	if (ifa)
1605
6
		printf(" if address: %s\n", routename(ifa));
1606
6
	if (mpls) {
1607
		printf(" mpls label: %s %s\n", mpls_op(rtm->rtm_mpls),
1608
		    routename(mpls));
1609
	}
1610
12
	printf("   priority: %u (%s)\n", rtm->rtm_priority,
1611
6
	   priorityname(rtm->rtm_priority));
1612
6
	printf("      flags: ");
1613
6
	bprintf(stdout, rtm->rtm_flags, routeflags);
1614
6
	printf("\n");
1615
6
	if (sa_rl != NULL)
1616
		printf("      label: %s\n", sa_rl->sr_label);
1617
#ifdef BFD
1618
6
	if (sa_bfd)
1619
		print_sabfd(sa_bfd, rtm->rtm_fmask);
1620
#endif
1621
1622
#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1623
12
	relative_expire = rtm->rtm_rmx.rmx_expire ?
1624
	    rtm->rtm_rmx.rmx_expire - time(NULL) : 0;
1625
6
	printf("     use       mtu    expire\n");
1626
6
	printf("%8llu  %8u%c %8lld%c\n",
1627
6
	    rtm->rtm_rmx.rmx_pksent,
1628
6
	    rtm->rtm_rmx.rmx_mtu, lock(MTU),
1629
6
	    relative_expire, lock(EXPIRE));
1630
#undef lock
1631
#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1632
6
	if (verbose)
1633
		pmsg_common(rtm);
1634
6
	else if (rtm->rtm_addrs &~ RTA_IGN) {
1635
		printf("sockaddrs: ");
1636
		bprintf(stdout, rtm->rtm_addrs, addrnames);
1637
		putchar('\n');
1638
	}
1639
#undef	RTA_IGN
1640
12
}
1641
1642
#ifdef BFD
1643
const char *
1644
bfd_state(unsigned int state)
1645
{
1646
	switch (state) {
1647
	case BFD_STATE_ADMINDOWN:
1648
		return("admindown");
1649
		break;
1650
	case BFD_STATE_DOWN:
1651
		return("down");
1652
		break;
1653
	case BFD_STATE_INIT:
1654
		return("init");
1655
		break;
1656
	case BFD_STATE_UP:
1657
		return("up");
1658
		break;
1659
	}
1660
	return "invalid";
1661
}
1662
1663
const char *
1664
bfd_diag(unsigned int diag)
1665
{
1666
	switch (diag) {
1667
	case BFD_DIAG_NONE:
1668
		return("none");
1669
		break;
1670
	case BFD_DIAG_EXPIRED:
1671
		return("expired");
1672
		break;
1673
	case BFD_DIAG_ECHO_FAILED:
1674
		return("echo-failed");
1675
		break;
1676
	case BFD_DIAG_NEIGHBOR_SIGDOWN:
1677
		return("neighbor-down");
1678
		break;
1679
	case BFD_DIAG_FIB_RESET:
1680
		return("fib-reset");
1681
		break;
1682
	case BFD_DIAG_PATH_DOWN:
1683
		return("path-down");
1684
		break;
1685
	case BFD_DIAG_CONCAT_PATH_DOWN:
1686
		return("concat-path-down");
1687
		break;
1688
	case BFD_DIAG_ADMIN_DOWN:
1689
		return("admindown");
1690
		break;
1691
	case BFD_DIAG_CONCAT_REVERSE_DOWN:
1692
		return("concat-reverse-down");
1693
		break;
1694
	}
1695
	return "invalid";
1696
}
1697
1698
const char *
1699
bfd_calc_uptime(time_t time)
1700
{
1701
	static char buf[256];
1702
	struct tm *tp;
1703
	const char *fmt;
1704
1705
	if (time > 2*86400)
1706
		fmt = "%dd%kh%Mm%Ss";
1707
	else if (time > 2*3600)
1708
		fmt = "%kh%Mm%Ss";
1709
	else if (time > 2*60)
1710
		fmt = "%Mm%Ss";
1711
	else
1712
		fmt = "%Ss";
1713
1714
	tp = localtime(&time);
1715
	(void)strftime(buf, sizeof(buf), fmt, tp);
1716
	return (buf);
1717
}
1718
1719
void
1720
print_bfdmsg(struct rt_msghdr *rtm)
1721
{
1722
	struct bfd_msghdr *bfdm = (struct bfd_msghdr *)rtm;
1723
1724
	printf("\n");
1725
	print_sabfd(&bfdm->bm_sa, rtm->rtm_fmask);
1726
	pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs);
1727
}
1728
1729
void
1730
print_sabfd(struct sockaddr_bfd *sa_bfd, int fmask)
1731
{
1732
	struct timeval tv;
1733
1734
	gettimeofday(&tv, NULL);
1735
1736
	printf("        BFD:");
1737
1738
	/* only show the state, unless verbose or -bfd */
1739
	if (!verbose && ((fmask & RTF_BFD) != RTF_BFD)) {
1740
		printf(" %s\n", bfd_state(sa_bfd->bs_state));
1741
		return;
1742
	}
1743
1744
	switch (sa_bfd->bs_mode) {
1745
	case BFD_MODE_ASYNC:
1746
		printf(" async");
1747
		break;
1748
	case BFD_MODE_DEMAND:
1749
		printf(" demand");
1750
		break;
1751
	default:
1752
		printf(" unknown %u", sa_bfd->bs_mode);
1753
		break;
1754
	}
1755
1756
	printf(" state %s", bfd_state(sa_bfd->bs_state));
1757
	printf(" remote %s", bfd_state(sa_bfd->bs_remotestate));
1758
	printf(" laststate %s", bfd_state(sa_bfd->bs_laststate));
1759
1760
	printf(" error %d", sa_bfd->bs_error);
1761
	printf("\n            ");
1762
	printf(" diag %s", bfd_diag(sa_bfd->bs_localdiag));
1763
	printf(" remote %s", bfd_diag(sa_bfd->bs_remotediag));
1764
	printf("\n            ");
1765
	printf(" discr %u", sa_bfd->bs_localdiscr);
1766
	printf(" remote %u", sa_bfd->bs_remotediscr);
1767
	printf("\n            ");
1768
	printf(" uptime %s", bfd_calc_uptime(tv.tv_sec - sa_bfd->bs_uptime));
1769
	if (sa_bfd->bs_lastuptime)
1770
		printf(" last state time %s",
1771
		    bfd_calc_uptime(sa_bfd->bs_lastuptime));
1772
	printf("\n            ");
1773
	printf(" mintx %u", sa_bfd->bs_mintx);
1774
	printf(" minrx %u", sa_bfd->bs_minrx);
1775
	printf(" minecho %u", sa_bfd->bs_minecho);
1776
	printf(" multiplier %u", sa_bfd->bs_multiplier);
1777
	printf("\n");
1778
}
1779
#endif /* BFD */
1780
1781
void
1782
pmsg_common(struct rt_msghdr *rtm)
1783
{
1784
	printf("\nlocks: ");
1785
	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1786
	printf(" inits: ");
1787
	bprintf(stdout, rtm->rtm_inits, metricnames);
1788
	pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs);
1789
}
1790
1791
void
1792
pmsg_addrs(char *cp, int addrs)
1793
{
1794
	struct sockaddr *sa;
1795
	int family = AF_UNSPEC;
1796
	int i;
1797
	char *p;
1798
1799
	if (addrs != 0) {
1800
		printf("\nsockaddrs: ");
1801
		bprintf(stdout, addrs, addrnames);
1802
		putchar('\n');
1803
		/* first run, search for address family */
1804
		p = cp;
1805
		for (i = 1; i; i <<= 1)
1806
			if (i & addrs) {
1807
				sa = (struct sockaddr *)p;
1808
				if (family == AF_UNSPEC)
1809
					switch (i) {
1810
					case RTA_DST:
1811
					case RTA_IFA:
1812
						family = sa->sa_family;
1813
					}
1814
				ADVANCE(p, sa);
1815
			}
1816
		/* second run, set address family for mask and print */
1817
		p = cp;
1818
		for (i = 1; i; i <<= 1)
1819
			if (i & addrs) {
1820
				sa = (struct sockaddr *)p;
1821
				if (family != AF_UNSPEC)
1822
					switch (i) {
1823
					case RTA_NETMASK:
1824
						sa->sa_family = family;
1825
					}
1826
				printf(" %s", routename(sa));
1827
				ADVANCE(p, sa);
1828
			}
1829
	}
1830
	putchar('\n');
1831
	fflush(stdout);
1832
}
1833
1834
void
1835
bprintf(FILE *fp, int b, char *s)
1836
{
1837
	int i;
1838
	int gotsome = 0;
1839
1840
12
	if (b == 0)
1841
		return;
1842
300
	while ((i = *s++)) {
1843
144
		if ((b & (1 << (i-1)))) {
1844
30
			if (gotsome == 0)
1845
6
				i = '<';
1846
			else
1847
				i = ',';
1848
60
			putc(i, fp);
1849
			gotsome = 1;
1850
348
			for (; (i = *s) > 32; s++)
1851
288
				putc(i, fp);
1852
		} else
1853
1776
			while (*s > 32)
1854
774
				s++;
1855
	}
1856
6
	if (gotsome)
1857
12
		putc('>', fp);
1858
12
}
1859
1860
int
1861
keycmp(const void *key, const void *kt)
1862
{
1863
19128
	return (strcmp(key, ((struct keytab *)kt)->kt_cp));
1864
}
1865
1866
int
1867
keyword(char *cp)
1868
{
1869
	struct keytab *kt;
1870
1871
3648
	kt = bsearch(cp, keywords, sizeof(keywords)/sizeof(keywords[0]),
1872
	    sizeof(keywords[0]), keycmp);
1873
1824
	if (!kt)
1874
216
		return (0);
1875
1876
1608
	return (kt->kt_i);
1877
1824
}
1878
1879
void
1880
sodump(sup su, char *which)
1881
{
1882
	switch (su->sa.sa_family) {
1883
	case AF_LINK:
1884
		printf("%s: link %s; ", which, link_ntoa(&su->sdl));
1885
		break;
1886
	case AF_INET:
1887
		printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr));
1888
		break;
1889
	case AF_INET6:
1890
	    {
1891
		char ntop_buf[NI_MAXHOST];
1892
1893
		printf("%s: inet6 %s; ",
1894
		    which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1895
		    ntop_buf, sizeof(ntop_buf)));
1896
		break;
1897
	    }
1898
	}
1899
	fflush(stdout);
1900
}
1901
1902
/* States*/
1903
#define VIRGIN	0
1904
#define GOTONE	1
1905
#define GOTTWO	2
1906
/* Inputs */
1907
#define	DIGIT	(4*0)
1908
#define	END	(4*1)
1909
#define DELIM	(4*2)
1910
1911
void
1912
sockaddr(char *addr, struct sockaddr *sa)
1913
{
1914
	char *cp = (char *)sa;
1915
	int size = sa->sa_len;
1916
	char *cplim = cp + size;
1917
	int byte = 0, state = VIRGIN, new = 0;
1918
1919
	memset(cp, 0, size);
1920
	cp++;
1921
	do {
1922
		if ((*addr >= '0') && (*addr <= '9')) {
1923
			new = *addr - '0';
1924
		} else if ((*addr >= 'a') && (*addr <= 'f')) {
1925
			new = *addr - 'a' + 10;
1926
		} else if ((*addr >= 'A') && (*addr <= 'F')) {
1927
			new = *addr - 'A' + 10;
1928
		} else if (*addr == '\0')
1929
			state |= END;
1930
		else
1931
			state |= DELIM;
1932
		addr++;
1933
		switch (state /* | INPUT */) {
1934
		case GOTTWO | DIGIT:
1935
			*cp++ = byte; /*FALLTHROUGH*/
1936
		case VIRGIN | DIGIT:
1937
			state = GOTONE; byte = new; continue;
1938
		case GOTONE | DIGIT:
1939
			state = GOTTWO; byte = new + (byte << 4); continue;
1940
		default: /* | DELIM */
1941
			state = VIRGIN; *cp++ = byte; byte = 0; continue;
1942
		case GOTONE | END:
1943
		case GOTTWO | END:
1944
			*cp++ = byte; /* FALLTHROUGH */
1945
		case VIRGIN | END:
1946
			break;
1947
		}
1948
		break;
1949
	} while (cp < cplim);
1950
	sa->sa_len = cp - (char *)sa;
1951
}
1952
1953
void
1954
getlabel(char *name)
1955
{
1956
	so_label.rtlabel.sr_len = sizeof(so_label.rtlabel);
1957
	so_label.rtlabel.sr_family = AF_UNSPEC;
1958
	if (strlcpy(so_label.rtlabel.sr_label, name,
1959
	    sizeof(so_label.rtlabel.sr_label)) >=
1960
	    sizeof(so_label.rtlabel.sr_label))
1961
		errx(1, "label too long");
1962
	rtm_addrs |= RTA_LABEL;
1963
}
1964
1965
int
1966
gettable(const char *s)
1967
{
1968
1512
	const char		*errstr;
1969
756
	struct rt_tableinfo      info;
1970
756
	int			 mib[6];
1971
756
	size_t			 len;
1972
1973
756
	tableid = strtonum(s, 0, RT_TABLEID_MAX, &errstr);
1974
756
	if (errstr)
1975
		errx(1, "invalid table id: %s", errstr);
1976
1977
756
	mib[0] = CTL_NET;
1978
756
	mib[1] = PF_ROUTE;
1979
756
	mib[2] = 0;
1980
756
	mib[3] = 0;
1981
756
	mib[4] = NET_RT_TABLE;
1982
756
	mib[5] = tableid;
1983
1984
756
	len = sizeof(info);
1985
756
	if (sysctl(mib, 6, &info, &len, NULL, 0) == -1)
1986
		return (errno);
1987
	else
1988
756
		return (0);
1989
756
}
1990
1991
int
1992
rdomain(int argc, char **argv)
1993
{
1994
	if (!argc)
1995
		usage(NULL);
1996
	if (setrtable(tableid) == -1)
1997
		err(1, "setrtable");
1998
	execvp(*argv, argv);
1999
	warn("%s", argv[0]);
2000
	return (errno == ENOENT ? 127 : 126);
2001
}
2002
2003
/*
2004
 * Print RTM_PROPOSAL DNS server addresses.
2005
 */
2006
void
2007
print_rtdns(struct sockaddr_rtdns *rtdns)
2008
{
2009
	struct in_addr	 server;
2010
	struct in6_addr	 in6;
2011
	size_t		 srclen, offset;
2012
	unsigned int	 servercnt;
2013
	int		 i;
2014
	char		*src = rtdns->sr_dns;
2015
	char		 ntopbuf[INET6_ADDRSTRLEN];
2016
2017
	offset = offsetof(struct sockaddr_rtdns, sr_dns);
2018
	if (rtdns->sr_len <= offset) {
2019
		printf("<invalid sr_len (%d <= %zu)>\n", rtdns->sr_len,
2020
		    offset);
2021
		return;
2022
	}
2023
	srclen = rtdns->sr_len - offset;
2024
	if (srclen > sizeof(rtdns->sr_dns)) {
2025
		printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2026
		    sizeof(rtdns->sr_dns));
2027
		return;
2028
	}
2029
2030
	switch (rtdns->sr_family) {
2031
	case AF_INET:
2032
		/* An array of IPv4 addresses. */
2033
		servercnt = srclen / sizeof(struct in_addr);
2034
		if (servercnt * sizeof(struct in_addr) != srclen) {
2035
			printf("<invalid server count>\n");
2036
			return;
2037
		}
2038
		for (i = 0; i < servercnt; i++) {
2039
			memcpy(&server.s_addr, src, sizeof(server.s_addr));
2040
			printf("%s ", inet_ntoa(server));
2041
			src += sizeof(struct in_addr);
2042
		}
2043
		break;
2044
	case AF_INET6:
2045
		servercnt = srclen / sizeof(struct in6_addr);
2046
		if (servercnt * sizeof(struct in6_addr) != srclen) {
2047
			printf("<invalid server count>\n");
2048
			return;
2049
		}
2050
		for (i = 0; i < servercnt; i++) {
2051
			memcpy(&in6, src, sizeof(in6));
2052
			src += sizeof(in6);
2053
			printf("%s ", inet_ntop(AF_INET6, &in6, ntopbuf,
2054
			    INET6_ADDRSTRLEN));
2055
		}
2056
		break;
2057
	default:
2058
		break;
2059
	}
2060
	printf("\n");
2061
}
2062
2063
/*
2064
 * Print RTM_PROPOSAL static routes.
2065
 */
2066
void
2067
print_rtstatic(struct sockaddr_rtstatic *rtstatic)
2068
{
2069
	struct sockaddr_in6	 gateway6;
2070
	struct in6_addr		 prefix;
2071
	struct in_addr		 dest, gateway;
2072
	size_t			 srclen, offset;
2073
	int			 bits, bytes, error;
2074
	uint8_t			 prefixlen;
2075
	unsigned char		*src = rtstatic->sr_static;
2076
	char			 ntoabuf[INET_ADDRSTRLEN];
2077
	char			 hbuf[NI_MAXHOST];
2078
	char			 ntopbuf[INET6_ADDRSTRLEN];
2079
2080
	offset = offsetof(struct sockaddr_rtstatic, sr_static);
2081
	if (rtstatic->sr_len <= offset) {
2082
		printf("<invalid sr_len (%d <= %zu)>\n", rtstatic->sr_len,
2083
		    offset);
2084
		return;
2085
	}
2086
	srclen = rtstatic->sr_len - offset;
2087
	if (srclen > sizeof(rtstatic->sr_static)) {
2088
		printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2089
		    sizeof(rtstatic->sr_static));
2090
		return;
2091
	}
2092
2093
	switch (rtstatic->sr_family) {
2094
	case AF_INET:
2095
		/* AF_INET -> RFC 3442 encoded static routes. */
2096
		while (srclen) {
2097
			bits = *src;
2098
			src++;
2099
			srclen--;
2100
			bytes = (bits + 7) / 8;
2101
			if (srclen < bytes || bytes > sizeof(dest.s_addr))
2102
				break;
2103
			memset(&dest, 0, sizeof(dest));
2104
			memcpy(&dest.s_addr, src, bytes);
2105
			src += bytes;
2106
			srclen -= bytes;
2107
			strlcpy(ntoabuf, inet_ntoa(dest), sizeof(ntoabuf));
2108
			if (srclen < sizeof(gateway.s_addr))
2109
				break;
2110
			memcpy(&gateway.s_addr, src, sizeof(gateway.s_addr));
2111
			src += sizeof(gateway.s_addr);
2112
			srclen -= sizeof(gateway.s_addr);
2113
			printf("%s/%u %s ", ntoabuf, bits, inet_ntoa(gateway));
2114
		}
2115
		break;
2116
	case AF_INET6:
2117
		while (srclen >= sizeof(prefixlen) + sizeof(prefix) +
2118
		    sizeof(gateway6)) {
2119
			memcpy(&prefixlen, src, sizeof(prefixlen));
2120
			srclen -= sizeof(prefixlen);
2121
			src += sizeof(prefixlen);
2122
2123
			memcpy(&prefix, src, sizeof(prefix));
2124
			srclen -= sizeof(prefix);
2125
			src += sizeof(prefix);
2126
2127
			memcpy(&gateway6, src, sizeof(gateway6));
2128
			srclen -= sizeof(gateway6);
2129
			src += sizeof(gateway6);
2130
2131
			if ((error = getnameinfo((struct sockaddr *)&gateway6,
2132
			    gateway6.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
2133
			    NI_NUMERICHOST | NI_NUMERICSERV))) {
2134
				warnx("cannot get gateway address: %s",
2135
				    gai_strerror(error));
2136
				return;
2137
			}
2138
			printf("%s/%u %s ", inet_ntop(AF_INET6, &prefix,
2139
			    ntopbuf, INET6_ADDRSTRLEN), prefixlen, hbuf);
2140
		}
2141
		break;
2142
	default:
2143
		printf("<unknown address family %d>", rtstatic->sr_family);
2144
		break;
2145
	}
2146
	printf("\n");
2147
}
2148
2149
/*
2150
 * Print RTM_PROPOSAL domain search list.
2151
 */
2152
void
2153
print_rtsearch(struct sockaddr_rtsearch *rtsearch)
2154
{
2155
	char	*src = rtsearch->sr_search;
2156
	size_t	 srclen, offset;
2157
2158
	offset = offsetof(struct sockaddr_rtsearch, sr_search);
2159
	if (rtsearch->sr_len <= offset) {
2160
		printf("<invalid sr_len (%d <= %zu)>\n", rtsearch->sr_len,
2161
		    offset);
2162
		return;
2163
	}
2164
	srclen = rtsearch->sr_len - offset;
2165
	if (srclen > sizeof(rtsearch->sr_search)) {
2166
		printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2167
		    sizeof(rtsearch->sr_search));
2168
		return;
2169
	}
2170
2171
	printf("%.*s\n", (int)srclen, src);
2172
}