xref: /f-stack/tools/route/route.c (revision d4a07e70)
122ce4affSfengbojiang /*-
222ce4affSfengbojiang  * SPDX-License-Identifier: BSD-3-Clause
322ce4affSfengbojiang  *
4144c6bcdSlogwang  * Copyright (c) 1983, 1989, 1991, 1993
5144c6bcdSlogwang  *	The Regents of the University of California.  All rights reserved.
6144c6bcdSlogwang  *
7144c6bcdSlogwang  * Redistribution and use in source and binary forms, with or without
8144c6bcdSlogwang  * modification, are permitted provided that the following conditions
9144c6bcdSlogwang  * are met:
10144c6bcdSlogwang  * 1. Redistributions of source code must retain the above copyright
11144c6bcdSlogwang  *    notice, this list of conditions and the following disclaimer.
12144c6bcdSlogwang  * 2. Redistributions in binary form must reproduce the above copyright
13144c6bcdSlogwang  *    notice, this list of conditions and the following disclaimer in the
14144c6bcdSlogwang  *    documentation and/or other materials provided with the distribution.
1522ce4affSfengbojiang  * 3. Neither the name of the University nor the names of its contributors
16144c6bcdSlogwang  *    may be used to endorse or promote products derived from this software
17144c6bcdSlogwang  *    without specific prior written permission.
18144c6bcdSlogwang  *
19144c6bcdSlogwang  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20144c6bcdSlogwang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21144c6bcdSlogwang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22144c6bcdSlogwang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23144c6bcdSlogwang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24144c6bcdSlogwang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25144c6bcdSlogwang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26144c6bcdSlogwang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27144c6bcdSlogwang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28144c6bcdSlogwang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29144c6bcdSlogwang  * SUCH DAMAGE.
30144c6bcdSlogwang  */
31144c6bcdSlogwang 
32144c6bcdSlogwang #ifndef lint
33144c6bcdSlogwang static const char copyright[] =
34144c6bcdSlogwang "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
35144c6bcdSlogwang 	The Regents of the University of California.  All rights reserved.\n";
36144c6bcdSlogwang #endif /* not lint */
37144c6bcdSlogwang 
38144c6bcdSlogwang #ifndef lint
39144c6bcdSlogwang #if 0
40144c6bcdSlogwang static char sccsid[] = "@(#)route.c	8.6 (Berkeley) 4/28/95";
41144c6bcdSlogwang #endif
42144c6bcdSlogwang #endif /* not lint */
43144c6bcdSlogwang 
44144c6bcdSlogwang #include <sys/cdefs.h>
45*d4a07e70Sfengbojiang #ifndef FSTACK
46144c6bcdSlogwang __FBSDID("$FreeBSD$");
47*d4a07e70Sfengbojiang #endif
48144c6bcdSlogwang 
49144c6bcdSlogwang #include <sys/param.h>
50144c6bcdSlogwang #include <sys/file.h>
51144c6bcdSlogwang #include <sys/socket.h>
52144c6bcdSlogwang #include <sys/ioctl.h>
53144c6bcdSlogwang #include <sys/sysctl.h>
54144c6bcdSlogwang #include <sys/types.h>
55144c6bcdSlogwang #include <sys/queue.h>
56144c6bcdSlogwang 
57144c6bcdSlogwang #include <net/if.h>
58144c6bcdSlogwang #include <net/route.h>
59144c6bcdSlogwang #include <net/if_dl.h>
60144c6bcdSlogwang #include <netinet/in.h>
61144c6bcdSlogwang #include <netinet/if_ether.h>
62144c6bcdSlogwang #include <arpa/inet.h>
63144c6bcdSlogwang #include <netdb.h>
64144c6bcdSlogwang 
65144c6bcdSlogwang #include <ctype.h>
66144c6bcdSlogwang #include <err.h>
67144c6bcdSlogwang #include <errno.h>
68144c6bcdSlogwang #include <paths.h>
6922ce4affSfengbojiang #include <signal.h>
70144c6bcdSlogwang #include <stdbool.h>
71144c6bcdSlogwang #include <stdio.h>
72144c6bcdSlogwang #include <stdlib.h>
73144c6bcdSlogwang #include <string.h>
74144c6bcdSlogwang #include <sysexits.h>
75144c6bcdSlogwang #include <time.h>
76144c6bcdSlogwang #include <unistd.h>
77144c6bcdSlogwang #include <ifaddrs.h>
78144c6bcdSlogwang 
79*d4a07e70Sfengbojiang #ifdef FSTACK
80*d4a07e70Sfengbojiang #include "rtioctl.h"
81*d4a07e70Sfengbojiang #include "compat.h"
82*d4a07e70Sfengbojiang #include "ff_ipc.h"
83*d4a07e70Sfengbojiang 
84*d4a07e70Sfengbojiang #define socket(a, b, c) rt_socket((a), (b), (c))
85*d4a07e70Sfengbojiang #define shutdown(a, b) rt_shutdown((a), (b))
86*d4a07e70Sfengbojiang #define setsockopt(a, b, c, d, e) rt_setsockopt((a), (b), (c), (d), (e))
87*d4a07e70Sfengbojiang 
88*d4a07e70Sfengbojiang #define write(a, b, c) rtioctl((b), (c), (0))
89*d4a07e70Sfengbojiang 
90*d4a07e70Sfengbojiang #ifndef __unused
91*d4a07e70Sfengbojiang #define __unused __attribute__((__unused__))
92*d4a07e70Sfengbojiang #endif
93*d4a07e70Sfengbojiang 
94*d4a07e70Sfengbojiang #endif
95*d4a07e70Sfengbojiang 
96144c6bcdSlogwang struct fibl {
97144c6bcdSlogwang 	TAILQ_ENTRY(fibl)	fl_next;
98144c6bcdSlogwang 
99144c6bcdSlogwang 	int	fl_num;
100144c6bcdSlogwang 	int	fl_error;
101144c6bcdSlogwang 	int	fl_errno;
102144c6bcdSlogwang };
103144c6bcdSlogwang 
104144c6bcdSlogwang static struct keytab {
105144c6bcdSlogwang 	const char	*kt_cp;
106144c6bcdSlogwang 	int	kt_i;
107144c6bcdSlogwang } const keywords[] = {
108144c6bcdSlogwang #include "keywords.h"
109144c6bcdSlogwang 	{0, 0}
110144c6bcdSlogwang };
111144c6bcdSlogwang 
112144c6bcdSlogwang static struct sockaddr_storage so[RTAX_MAX];
113144c6bcdSlogwang static int	pid, rtm_addrs;
114144c6bcdSlogwang static int	s;
115*d4a07e70Sfengbojiang #ifndef FSTACK
116144c6bcdSlogwang static int	nflag, af, qflag, tflag;
117*d4a07e70Sfengbojiang #else
118*d4a07e70Sfengbojiang static int	nflag = 1;
119*d4a07e70Sfengbojiang static int	af, qflag, tflag;
120*d4a07e70Sfengbojiang #endif
121144c6bcdSlogwang static int	verbose, aflen;
122144c6bcdSlogwang static int	locking, lockrest, debugonly;
123144c6bcdSlogwang static struct rt_metrics rt_metrics;
124144c6bcdSlogwang static u_long  rtm_inits;
125144c6bcdSlogwang static uid_t	uid;
126144c6bcdSlogwang static int	defaultfib;
127144c6bcdSlogwang static int	numfibs;
128144c6bcdSlogwang static char	domain[MAXHOSTNAMELEN + 1];
129144c6bcdSlogwang static bool	domain_initialized;
130144c6bcdSlogwang static int	rtm_seq;
131144c6bcdSlogwang static char	rt_line[NI_MAXHOST];
132144c6bcdSlogwang static char	net_line[MAXHOSTNAMELEN + 1];
133144c6bcdSlogwang 
134144c6bcdSlogwang static struct {
135144c6bcdSlogwang 	struct	rt_msghdr m_rtm;
136144c6bcdSlogwang 	char	m_space[512];
137144c6bcdSlogwang } m_rtmsg;
138144c6bcdSlogwang 
139144c6bcdSlogwang static TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
140144c6bcdSlogwang 
141144c6bcdSlogwang static void	printb(int, const char *);
142144c6bcdSlogwang static void	flushroutes(int argc, char *argv[]);
143144c6bcdSlogwang static int	flushroutes_fib(int);
144144c6bcdSlogwang static int	getaddr(int, char *, struct hostent **, int);
145144c6bcdSlogwang static int	keyword(const char *);
146144c6bcdSlogwang #ifdef INET
14722ce4affSfengbojiang static void	inet_makemask(struct sockaddr_in *, u_long);
148144c6bcdSlogwang #endif
149144c6bcdSlogwang #ifdef INET6
150144c6bcdSlogwang static int	inet6_makenetandmask(struct sockaddr_in6 *, const char *);
151144c6bcdSlogwang #endif
152*d4a07e70Sfengbojiang #ifndef FSTACK
153144c6bcdSlogwang static void	interfaces(void);
154144c6bcdSlogwang static void	monitor(int, char*[]);
155*d4a07e70Sfengbojiang #endif
156144c6bcdSlogwang static const char	*netname(struct sockaddr *);
157144c6bcdSlogwang static void	newroute(int, char **);
158144c6bcdSlogwang static int	newroute_fib(int, char *, int);
159144c6bcdSlogwang static void	pmsg_addrs(char *, int, size_t);
160144c6bcdSlogwang static void	pmsg_common(struct rt_msghdr *, size_t);
161144c6bcdSlogwang static int	prefixlen(const char *);
162144c6bcdSlogwang static void	print_getmsg(struct rt_msghdr *, int, int);
163144c6bcdSlogwang static void	print_rtmsg(struct rt_msghdr *, size_t);
164144c6bcdSlogwang static const char	*routename(struct sockaddr *);
165144c6bcdSlogwang static int	rtmsg(int, int, int);
166144c6bcdSlogwang static void	set_metric(char *, int);
167144c6bcdSlogwang static int	set_sofib(int);
168144c6bcdSlogwang static void	sockaddr(char *, struct sockaddr *, size_t);
169144c6bcdSlogwang static void	sodump(struct sockaddr *, const char *);
170144c6bcdSlogwang static int	fiboptlist_csv(const char *, struct fibl_head_t *);
171144c6bcdSlogwang static int	fiboptlist_range(const char *, struct fibl_head_t *);
172144c6bcdSlogwang 
173144c6bcdSlogwang static void usage(const char *) __dead2;
174144c6bcdSlogwang 
17522ce4affSfengbojiang #define	READ_TIMEOUT	10
17622ce4affSfengbojiang static volatile sig_atomic_t stop_read;
17722ce4affSfengbojiang 
17822ce4affSfengbojiang static void
stopit(int sig __unused)17922ce4affSfengbojiang stopit(int sig __unused)
18022ce4affSfengbojiang {
18122ce4affSfengbojiang 
18222ce4affSfengbojiang 	stop_read = 1;
18322ce4affSfengbojiang }
18422ce4affSfengbojiang 
185144c6bcdSlogwang static void
usage(const char * cp)186144c6bcdSlogwang usage(const char *cp)
187144c6bcdSlogwang {
188144c6bcdSlogwang 	if (cp != NULL)
189144c6bcdSlogwang 		warnx("bad keyword: %s", cp);
190*d4a07e70Sfengbojiang #ifndef FSTACK
191144c6bcdSlogwang 	errx(EX_USAGE, "usage: route [-46dnqtv] command [[modifiers] args]");
192*d4a07e70Sfengbojiang #else
193*d4a07e70Sfengbojiang 	errx(EX_USAGE, "usage: route -p <f-stack proc_id> [-46dnqtv] command [[modifiers] args]");
194*d4a07e70Sfengbojiang #endif
195144c6bcdSlogwang 	/* NOTREACHED */
196144c6bcdSlogwang }
197144c6bcdSlogwang 
198144c6bcdSlogwang int
main(int argc,char ** argv)199144c6bcdSlogwang main(int argc, char **argv)
200144c6bcdSlogwang {
201144c6bcdSlogwang 	int ch;
202144c6bcdSlogwang 	size_t len;
203144c6bcdSlogwang 
204144c6bcdSlogwang 	if (argc < 2)
205144c6bcdSlogwang 		usage(NULL);
206144c6bcdSlogwang 
207*d4a07e70Sfengbojiang #ifndef FSTACK
208144c6bcdSlogwang 	while ((ch = getopt(argc, argv, "46nqdtv")) != -1)
209*d4a07e70Sfengbojiang #else
210*d4a07e70Sfengbojiang 	ff_ipc_init();
211*d4a07e70Sfengbojiang 	while ((ch = getopt(argc, argv, "46nqdtvp:")) != -1)
212*d4a07e70Sfengbojiang #endif
213144c6bcdSlogwang 		switch(ch) {
214144c6bcdSlogwang 		case '4':
215144c6bcdSlogwang #ifdef INET
216144c6bcdSlogwang 			af = AF_INET;
217144c6bcdSlogwang 			aflen = sizeof(struct sockaddr_in);
218144c6bcdSlogwang #else
219144c6bcdSlogwang 			errx(1, "IPv4 support is not compiled in");
220144c6bcdSlogwang #endif
221144c6bcdSlogwang 			break;
222144c6bcdSlogwang 		case '6':
223144c6bcdSlogwang #ifdef INET6
224144c6bcdSlogwang 			af = AF_INET6;
225144c6bcdSlogwang 			aflen = sizeof(struct sockaddr_in6);
226144c6bcdSlogwang #else
227144c6bcdSlogwang 			errx(1, "IPv6 support is not compiled in");
228144c6bcdSlogwang #endif
229144c6bcdSlogwang 			break;
230144c6bcdSlogwang 		case 'n':
231144c6bcdSlogwang 			nflag = 1;
232144c6bcdSlogwang 			break;
233144c6bcdSlogwang 		case 'q':
234144c6bcdSlogwang 			qflag = 1;
235144c6bcdSlogwang 			break;
236144c6bcdSlogwang 		case 'v':
237144c6bcdSlogwang 			verbose = 1;
238144c6bcdSlogwang 			break;
239144c6bcdSlogwang 		case 't':
240144c6bcdSlogwang 			tflag = 1;
241144c6bcdSlogwang 			break;
242144c6bcdSlogwang 		case 'd':
243144c6bcdSlogwang 			debugonly = 1;
244144c6bcdSlogwang 			break;
245*d4a07e70Sfengbojiang #ifdef FSTACK
246*d4a07e70Sfengbojiang 		case 'p':
247*d4a07e70Sfengbojiang 			ff_set_proc_id(atoi(optarg));
248*d4a07e70Sfengbojiang 			break;
249*d4a07e70Sfengbojiang #endif
250144c6bcdSlogwang 		case '?':
251144c6bcdSlogwang 		default:
252144c6bcdSlogwang 			usage(NULL);
253144c6bcdSlogwang 		}
254144c6bcdSlogwang 	argc -= optind;
255144c6bcdSlogwang 	argv += optind;
256144c6bcdSlogwang 
257144c6bcdSlogwang 	pid = getpid();
258144c6bcdSlogwang 	uid = geteuid();
259144c6bcdSlogwang 	if (tflag)
260144c6bcdSlogwang 		s = open(_PATH_DEVNULL, O_WRONLY, 0);
261144c6bcdSlogwang 	else
262144c6bcdSlogwang 		s = socket(PF_ROUTE, SOCK_RAW, 0);
263144c6bcdSlogwang 	if (s < 0)
264144c6bcdSlogwang 		err(EX_OSERR, "socket");
265144c6bcdSlogwang 
266144c6bcdSlogwang 	len = sizeof(numfibs);
267144c6bcdSlogwang 	if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1)
268144c6bcdSlogwang 		numfibs = -1;
269144c6bcdSlogwang 
270144c6bcdSlogwang 	len = sizeof(defaultfib);
271144c6bcdSlogwang 	if (numfibs != -1 &&
272144c6bcdSlogwang 	    sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL,
273144c6bcdSlogwang 		0) == -1)
274144c6bcdSlogwang 		defaultfib = -1;
275144c6bcdSlogwang 
276144c6bcdSlogwang 	if (*argv != NULL)
277144c6bcdSlogwang 		switch (keyword(*argv)) {
278144c6bcdSlogwang 		case K_GET:
279144c6bcdSlogwang 		case K_SHOW:
280144c6bcdSlogwang 			uid = 0;
281144c6bcdSlogwang 			/* FALLTHROUGH */
282144c6bcdSlogwang 
283144c6bcdSlogwang 		case K_CHANGE:
284144c6bcdSlogwang 		case K_ADD:
285144c6bcdSlogwang 		case K_DEL:
286144c6bcdSlogwang 		case K_DELETE:
287144c6bcdSlogwang 			newroute(argc, argv);
288144c6bcdSlogwang 			/* NOTREACHED */
289144c6bcdSlogwang 
290144c6bcdSlogwang 		case K_MONITOR:
291*d4a07e70Sfengbojiang #ifndef FSTACK
292144c6bcdSlogwang 			monitor(argc, argv);
293*d4a07e70Sfengbojiang #else
294*d4a07e70Sfengbojiang 			usage(*argv);
295*d4a07e70Sfengbojiang #endif
296144c6bcdSlogwang 			/* NOTREACHED */
297144c6bcdSlogwang 
298144c6bcdSlogwang 		case K_FLUSH:
299144c6bcdSlogwang 			flushroutes(argc, argv);
300*d4a07e70Sfengbojiang #ifdef FSTACK
301*d4a07e70Sfengbojiang 			ff_ipc_exit();
302*d4a07e70Sfengbojiang #endif
303144c6bcdSlogwang 			exit(0);
304144c6bcdSlogwang 			/* NOTREACHED */
305144c6bcdSlogwang 		}
306144c6bcdSlogwang 	usage(*argv);
307*d4a07e70Sfengbojiang #ifdef FSTACK
308*d4a07e70Sfengbojiang 	ff_ipc_exit();
309*d4a07e70Sfengbojiang #endif
310144c6bcdSlogwang 	/* NOTREACHED */
311144c6bcdSlogwang }
312144c6bcdSlogwang 
313144c6bcdSlogwang static int
set_sofib(int fib)314144c6bcdSlogwang set_sofib(int fib)
315144c6bcdSlogwang {
316144c6bcdSlogwang 
317144c6bcdSlogwang 	if (fib < 0)
318144c6bcdSlogwang 		return (0);
319*d4a07e70Sfengbojiang #ifdef FSTACK
320*d4a07e70Sfengbojiang 	return (rt_setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
321*d4a07e70Sfengbojiang 	    sizeof(fib)));
322*d4a07e70Sfengbojiang #endif
323144c6bcdSlogwang 	return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
324144c6bcdSlogwang 	    sizeof(fib)));
325144c6bcdSlogwang }
326144c6bcdSlogwang 
327144c6bcdSlogwang static int
fiboptlist_range(const char * arg,struct fibl_head_t * flh)328144c6bcdSlogwang fiboptlist_range(const char *arg, struct fibl_head_t *flh)
329144c6bcdSlogwang {
330144c6bcdSlogwang 	struct fibl *fl;
331144c6bcdSlogwang 	char *str0, *str, *token, *endptr;
332144c6bcdSlogwang 	int fib[2], i, error;
333144c6bcdSlogwang 
334144c6bcdSlogwang 	str0 = str = strdup(arg);
335144c6bcdSlogwang 	error = 0;
336144c6bcdSlogwang 	i = 0;
337144c6bcdSlogwang 	while ((token = strsep(&str, "-")) != NULL) {
338144c6bcdSlogwang 		switch (i) {
339144c6bcdSlogwang 		case 0:
340144c6bcdSlogwang 		case 1:
341144c6bcdSlogwang 			errno = 0;
342144c6bcdSlogwang 			fib[i] = strtol(token, &endptr, 0);
343144c6bcdSlogwang 			if (errno == 0) {
344144c6bcdSlogwang 				if (*endptr != '\0' ||
345144c6bcdSlogwang 				    fib[i] < 0 ||
346144c6bcdSlogwang 				    (numfibs != -1 && fib[i] > numfibs - 1))
347144c6bcdSlogwang 					errno = EINVAL;
348144c6bcdSlogwang 			}
349144c6bcdSlogwang 			if (errno)
350144c6bcdSlogwang 				error = 1;
351144c6bcdSlogwang 			break;
352144c6bcdSlogwang 		default:
353144c6bcdSlogwang 			error = 1;
354144c6bcdSlogwang 		}
355144c6bcdSlogwang 		if (error)
356144c6bcdSlogwang 			goto fiboptlist_range_ret;
357144c6bcdSlogwang 		i++;
358144c6bcdSlogwang 	}
359144c6bcdSlogwang 	if (fib[0] >= fib[1]) {
360144c6bcdSlogwang 		error = 1;
361144c6bcdSlogwang 		goto fiboptlist_range_ret;
362144c6bcdSlogwang 	}
363144c6bcdSlogwang 	for (i = fib[0]; i <= fib[1]; i++) {
364144c6bcdSlogwang 		fl = calloc(1, sizeof(*fl));
365144c6bcdSlogwang 		if (fl == NULL) {
366144c6bcdSlogwang 			error = 1;
367144c6bcdSlogwang 			goto fiboptlist_range_ret;
368144c6bcdSlogwang 		}
369144c6bcdSlogwang 		fl->fl_num = i;
370144c6bcdSlogwang 		TAILQ_INSERT_TAIL(flh, fl, fl_next);
371144c6bcdSlogwang 	}
372144c6bcdSlogwang fiboptlist_range_ret:
373144c6bcdSlogwang 	free(str0);
374144c6bcdSlogwang 	return (error);
375144c6bcdSlogwang }
376144c6bcdSlogwang 
377144c6bcdSlogwang #define	ALLSTRLEN	64
378144c6bcdSlogwang static int
fiboptlist_csv(const char * arg,struct fibl_head_t * flh)379144c6bcdSlogwang fiboptlist_csv(const char *arg, struct fibl_head_t *flh)
380144c6bcdSlogwang {
381144c6bcdSlogwang 	struct fibl *fl;
382144c6bcdSlogwang 	char *str0, *str, *token, *endptr;
383144c6bcdSlogwang 	int fib, error;
384144c6bcdSlogwang 
385144c6bcdSlogwang 	str0 = str = NULL;
386144c6bcdSlogwang 	if (strcmp("all", arg) == 0) {
387144c6bcdSlogwang 		str = calloc(1, ALLSTRLEN);
388144c6bcdSlogwang 		if (str == NULL) {
389144c6bcdSlogwang 			error = 1;
390144c6bcdSlogwang 			goto fiboptlist_csv_ret;
391144c6bcdSlogwang 		}
392144c6bcdSlogwang 		if (numfibs > 1)
393144c6bcdSlogwang 			snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1);
394144c6bcdSlogwang 		else
395144c6bcdSlogwang 			snprintf(str, ALLSTRLEN - 1, "%d", 0);
396144c6bcdSlogwang 	} else if (strcmp("default", arg) == 0) {
397144c6bcdSlogwang 		str0 = str = calloc(1, ALLSTRLEN);
398144c6bcdSlogwang 		if (str == NULL) {
399144c6bcdSlogwang 			error = 1;
400144c6bcdSlogwang 			goto fiboptlist_csv_ret;
401144c6bcdSlogwang 		}
402144c6bcdSlogwang 		snprintf(str, ALLSTRLEN - 1, "%d", defaultfib);
403144c6bcdSlogwang 	} else
404144c6bcdSlogwang 		str0 = str = strdup(arg);
405144c6bcdSlogwang 
406144c6bcdSlogwang 	error = 0;
407144c6bcdSlogwang 	while ((token = strsep(&str, ",")) != NULL) {
408144c6bcdSlogwang 		if (*token != '-' && strchr(token, '-') != NULL) {
409144c6bcdSlogwang 			error = fiboptlist_range(token, flh);
410144c6bcdSlogwang 			if (error)
411144c6bcdSlogwang 				goto fiboptlist_csv_ret;
412144c6bcdSlogwang 		} else {
413144c6bcdSlogwang 			errno = 0;
414144c6bcdSlogwang 			fib = strtol(token, &endptr, 0);
415144c6bcdSlogwang 			if (errno == 0) {
416144c6bcdSlogwang 				if (*endptr != '\0' ||
417144c6bcdSlogwang 				    fib < 0 ||
418144c6bcdSlogwang 				    (numfibs != -1 && fib > numfibs - 1))
419144c6bcdSlogwang 					errno = EINVAL;
420144c6bcdSlogwang 			}
421144c6bcdSlogwang 			if (errno) {
422144c6bcdSlogwang 				error = 1;
423144c6bcdSlogwang 				goto fiboptlist_csv_ret;
424144c6bcdSlogwang 			}
425144c6bcdSlogwang 			fl = calloc(1, sizeof(*fl));
426144c6bcdSlogwang 			if (fl == NULL) {
427144c6bcdSlogwang 				error = 1;
428144c6bcdSlogwang 				goto fiboptlist_csv_ret;
429144c6bcdSlogwang 			}
430144c6bcdSlogwang 			fl->fl_num = fib;
431144c6bcdSlogwang 			TAILQ_INSERT_TAIL(flh, fl, fl_next);
432144c6bcdSlogwang 		}
433144c6bcdSlogwang 	}
434144c6bcdSlogwang fiboptlist_csv_ret:
435144c6bcdSlogwang 	if (str0 != NULL)
436144c6bcdSlogwang 		free(str0);
437144c6bcdSlogwang 	return (error);
438144c6bcdSlogwang }
439144c6bcdSlogwang 
440144c6bcdSlogwang /*
441144c6bcdSlogwang  * Purge all entries in the routing tables not
442144c6bcdSlogwang  * associated with network interfaces.
443144c6bcdSlogwang  */
444144c6bcdSlogwang static void
flushroutes(int argc,char * argv[])445144c6bcdSlogwang flushroutes(int argc, char *argv[])
446144c6bcdSlogwang {
447144c6bcdSlogwang 	struct fibl *fl;
448144c6bcdSlogwang 	int error;
449144c6bcdSlogwang 
450144c6bcdSlogwang 	if (uid != 0 && !debugonly && !tflag)
451144c6bcdSlogwang 		errx(EX_NOPERM, "must be root to alter routing table");
452144c6bcdSlogwang 	shutdown(s, SHUT_RD); /* Don't want to read back our messages */
453144c6bcdSlogwang 
454144c6bcdSlogwang 	TAILQ_INIT(&fibl_head);
455144c6bcdSlogwang 	while (argc > 1) {
456144c6bcdSlogwang 		argc--;
457144c6bcdSlogwang 		argv++;
458144c6bcdSlogwang 		if (**argv != '-')
459144c6bcdSlogwang 			usage(*argv);
460144c6bcdSlogwang 		switch (keyword(*argv + 1)) {
461144c6bcdSlogwang #ifdef INET
462144c6bcdSlogwang 		case K_4:
463144c6bcdSlogwang 		case K_INET:
464144c6bcdSlogwang 			af = AF_INET;
465144c6bcdSlogwang 			break;
466144c6bcdSlogwang #endif
467144c6bcdSlogwang #ifdef INET6
468144c6bcdSlogwang 		case K_6:
469144c6bcdSlogwang 		case K_INET6:
470144c6bcdSlogwang 			af = AF_INET6;
471144c6bcdSlogwang 			break;
472144c6bcdSlogwang #endif
473144c6bcdSlogwang 		case K_LINK:
474144c6bcdSlogwang 			af = AF_LINK;
475144c6bcdSlogwang 			break;
476144c6bcdSlogwang 		case K_FIB:
477144c6bcdSlogwang 			if (!--argc)
478144c6bcdSlogwang 				usage(*argv);
479144c6bcdSlogwang 			error = fiboptlist_csv(*++argv, &fibl_head);
480144c6bcdSlogwang 			if (error)
481144c6bcdSlogwang 				errx(EX_USAGE, "invalid fib number: %s", *argv);
482144c6bcdSlogwang 			break;
483144c6bcdSlogwang 		default:
484144c6bcdSlogwang 			usage(*argv);
485144c6bcdSlogwang 		}
486144c6bcdSlogwang 	}
487144c6bcdSlogwang 	if (TAILQ_EMPTY(&fibl_head)) {
488144c6bcdSlogwang 		error = fiboptlist_csv("default", &fibl_head);
489144c6bcdSlogwang 		if (error)
490144c6bcdSlogwang 			errx(EX_OSERR, "fiboptlist_csv failed.");
491144c6bcdSlogwang 	}
492144c6bcdSlogwang 	TAILQ_FOREACH(fl, &fibl_head, fl_next)
493144c6bcdSlogwang 		flushroutes_fib(fl->fl_num);
494144c6bcdSlogwang }
495144c6bcdSlogwang 
496144c6bcdSlogwang static int
flushroutes_fib(int fib)497144c6bcdSlogwang flushroutes_fib(int fib)
498144c6bcdSlogwang {
499144c6bcdSlogwang 	struct rt_msghdr *rtm;
500144c6bcdSlogwang 	size_t needed;
501144c6bcdSlogwang 	char *buf, *next, *lim;
502144c6bcdSlogwang 	int mib[7], rlen, seqno, count = 0;
503144c6bcdSlogwang 	int error;
504144c6bcdSlogwang 
505144c6bcdSlogwang 	error = set_sofib(fib);
506144c6bcdSlogwang 	if (error) {
507144c6bcdSlogwang 		warn("fib number %d is ignored", fib);
508144c6bcdSlogwang 		return (error);
509144c6bcdSlogwang 	}
510144c6bcdSlogwang 
511144c6bcdSlogwang retry:
512144c6bcdSlogwang 	mib[0] = CTL_NET;
513144c6bcdSlogwang 	mib[1] = PF_ROUTE;
514144c6bcdSlogwang 	mib[2] = 0;		/* protocol */
515144c6bcdSlogwang 	mib[3] = AF_UNSPEC;
516144c6bcdSlogwang 	mib[4] = NET_RT_DUMP;
517144c6bcdSlogwang 	mib[5] = 0;		/* no flags */
518144c6bcdSlogwang 	mib[6] = fib;
519144c6bcdSlogwang 	if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
520144c6bcdSlogwang 		err(EX_OSERR, "route-sysctl-estimate");
521144c6bcdSlogwang 	if ((buf = malloc(needed)) == NULL)
522144c6bcdSlogwang 		errx(EX_OSERR, "malloc failed");
523144c6bcdSlogwang 	if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
524144c6bcdSlogwang 		if (errno == ENOMEM && count++ < 10) {
525144c6bcdSlogwang 			warnx("Routing table grew, retrying");
526144c6bcdSlogwang 			sleep(1);
527144c6bcdSlogwang 			free(buf);
528144c6bcdSlogwang 			goto retry;
529144c6bcdSlogwang 		}
530144c6bcdSlogwang 		err(EX_OSERR, "route-sysctl-get");
531144c6bcdSlogwang 	}
532144c6bcdSlogwang 	lim = buf + needed;
533144c6bcdSlogwang 	if (verbose)
534144c6bcdSlogwang 		(void)printf("Examining routing table from sysctl\n");
535144c6bcdSlogwang 	seqno = 0;		/* ??? */
536144c6bcdSlogwang 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
537144c6bcdSlogwang 		rtm = (struct rt_msghdr *)(void *)next;
538144c6bcdSlogwang 		if (verbose)
539144c6bcdSlogwang 			print_rtmsg(rtm, rtm->rtm_msglen);
540144c6bcdSlogwang 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
541144c6bcdSlogwang 			continue;
542144c6bcdSlogwang 		if (af != 0) {
543144c6bcdSlogwang 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
544144c6bcdSlogwang 
545144c6bcdSlogwang 			if (sa->sa_family != af)
546144c6bcdSlogwang 				continue;
547144c6bcdSlogwang 		}
548144c6bcdSlogwang 		if (debugonly)
549144c6bcdSlogwang 			continue;
550144c6bcdSlogwang 		rtm->rtm_type = RTM_DELETE;
551144c6bcdSlogwang 		rtm->rtm_seq = seqno;
552144c6bcdSlogwang 		rlen = write(s, next, rtm->rtm_msglen);
553144c6bcdSlogwang 		if (rlen < 0 && errno == EPERM)
554144c6bcdSlogwang 			err(1, "write to routing socket");
555144c6bcdSlogwang 		if (rlen < (int)rtm->rtm_msglen) {
556144c6bcdSlogwang 			warn("write to routing socket");
557144c6bcdSlogwang 			(void)printf("got only %d for rlen\n", rlen);
558144c6bcdSlogwang 			free(buf);
559144c6bcdSlogwang 			goto retry;
560144c6bcdSlogwang 			break;
561144c6bcdSlogwang 		}
562144c6bcdSlogwang 		seqno++;
563144c6bcdSlogwang 		if (qflag)
564144c6bcdSlogwang 			continue;
565144c6bcdSlogwang 		if (verbose)
566144c6bcdSlogwang 			print_rtmsg(rtm, rlen);
567144c6bcdSlogwang 		else {
568144c6bcdSlogwang 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
569144c6bcdSlogwang 
570144c6bcdSlogwang 			printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
571144c6bcdSlogwang 			    routename(sa) : netname(sa));
572144c6bcdSlogwang 			sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
573144c6bcdSlogwang 			printf("%-20.20s ", routename(sa));
574144c6bcdSlogwang 			if (fib >= 0)
575144c6bcdSlogwang 				printf("-fib %-3d ", fib);
576144c6bcdSlogwang 			printf("done\n");
577144c6bcdSlogwang 		}
578144c6bcdSlogwang 	}
57922ce4affSfengbojiang 	free(buf);
580144c6bcdSlogwang 	return (error);
581144c6bcdSlogwang }
582144c6bcdSlogwang 
583144c6bcdSlogwang static const char *
routename(struct sockaddr * sa)584144c6bcdSlogwang routename(struct sockaddr *sa)
585144c6bcdSlogwang {
586144c6bcdSlogwang 	struct sockaddr_dl *sdl;
587144c6bcdSlogwang 	const char *cp;
588144c6bcdSlogwang 	int n;
589144c6bcdSlogwang 
590144c6bcdSlogwang 	if (!domain_initialized) {
591144c6bcdSlogwang 		domain_initialized = true;
592144c6bcdSlogwang 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
593144c6bcdSlogwang 		    (cp = strchr(domain, '.'))) {
594144c6bcdSlogwang 			domain[MAXHOSTNAMELEN] = '\0';
595144c6bcdSlogwang 			(void)strcpy(domain, cp + 1);
596144c6bcdSlogwang 		} else
597144c6bcdSlogwang 			domain[0] = '\0';
598144c6bcdSlogwang 	}
599144c6bcdSlogwang 
600144c6bcdSlogwang 	/* If the address is zero-filled, use "default". */
601144c6bcdSlogwang 	if (sa->sa_len == 0 && nflag == 0)
602144c6bcdSlogwang 		return ("default");
603144c6bcdSlogwang #if defined(INET) || defined(INET6)
604144c6bcdSlogwang 	switch (sa->sa_family) {
605144c6bcdSlogwang #ifdef INET
606144c6bcdSlogwang 	case AF_INET:
607144c6bcdSlogwang 		/* If the address is zero-filled, use "default". */
608144c6bcdSlogwang 		if (nflag == 0 &&
609144c6bcdSlogwang 		    ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr ==
610144c6bcdSlogwang 		    INADDR_ANY)
611144c6bcdSlogwang 			return("default");
612144c6bcdSlogwang 		break;
613144c6bcdSlogwang #endif
614144c6bcdSlogwang #ifdef INET6
615144c6bcdSlogwang 	case AF_INET6:
616144c6bcdSlogwang 		/* If the address is zero-filled, use "default". */
617144c6bcdSlogwang 		if (nflag == 0 &&
618144c6bcdSlogwang 		    IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr))
619144c6bcdSlogwang 			return("default");
620144c6bcdSlogwang 		break;
621144c6bcdSlogwang #endif
622144c6bcdSlogwang 	}
623144c6bcdSlogwang #endif
624144c6bcdSlogwang 
625144c6bcdSlogwang 	switch (sa->sa_family) {
626144c6bcdSlogwang #if defined(INET) || defined(INET6)
627144c6bcdSlogwang #ifdef INET
628144c6bcdSlogwang 	case AF_INET:
629144c6bcdSlogwang #endif
630144c6bcdSlogwang #ifdef INET6
631144c6bcdSlogwang 	case AF_INET6:
632144c6bcdSlogwang #endif
633144c6bcdSlogwang 	{
634144c6bcdSlogwang 		struct sockaddr_storage ss;
635144c6bcdSlogwang 		int error;
636144c6bcdSlogwang 		char *p;
637144c6bcdSlogwang 
638144c6bcdSlogwang 		memset(&ss, 0, sizeof(ss));
639144c6bcdSlogwang 		if (sa->sa_len == 0)
640144c6bcdSlogwang 			ss.ss_family = sa->sa_family;
641144c6bcdSlogwang 		else
642144c6bcdSlogwang 			memcpy(&ss, sa, sa->sa_len);
643144c6bcdSlogwang 		/* Expand sa->sa_len because it could be shortened. */
644144c6bcdSlogwang 		if (sa->sa_family == AF_INET)
645144c6bcdSlogwang 			ss.ss_len = sizeof(struct sockaddr_in);
646144c6bcdSlogwang 		else if (sa->sa_family == AF_INET6)
647144c6bcdSlogwang 			ss.ss_len = sizeof(struct sockaddr_in6);
648*d4a07e70Sfengbojiang #ifndef FSTACK
649144c6bcdSlogwang 		error = getnameinfo((struct sockaddr *)&ss, ss.ss_len,
650144c6bcdSlogwang 		    rt_line, sizeof(rt_line), NULL, 0,
651144c6bcdSlogwang 		    (nflag == 0) ? 0 : NI_NUMERICHOST);
652*d4a07e70Sfengbojiang #else
653*d4a07e70Sfengbojiang 		const char *dst = NULL;
654*d4a07e70Sfengbojiang 		error = 0;
655*d4a07e70Sfengbojiang 		struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
656*d4a07e70Sfengbojiang #ifdef INET6
657*d4a07e70Sfengbojiang 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
658*d4a07e70Sfengbojiang 		if (sa->sa_family == AF_INET6)
659*d4a07e70Sfengbojiang 			dst = inet_ntop(AF_INET6_LINUX, &sin6->sin6_addr, rt_line, sizeof(rt_line));
660*d4a07e70Sfengbojiang 		else
661*d4a07e70Sfengbojiang #endif
662*d4a07e70Sfengbojiang 			dst = inet_ntop(AF_INET, &sin->sin_addr, rt_line, sizeof(rt_line));
663*d4a07e70Sfengbojiang 		if (dst == NULL) {
664*d4a07e70Sfengbojiang 			error = EAI_NONAME;
665*d4a07e70Sfengbojiang 		}
666*d4a07e70Sfengbojiang #endif
667144c6bcdSlogwang 		if (error) {
668144c6bcdSlogwang 			warnx("getnameinfo(): %s", gai_strerror(error));
669144c6bcdSlogwang 			strncpy(rt_line, "invalid", sizeof(rt_line));
670144c6bcdSlogwang 		}
671144c6bcdSlogwang 
672144c6bcdSlogwang 		/* Remove the domain part if any. */
673144c6bcdSlogwang 		p = strchr(rt_line, '.');
674144c6bcdSlogwang 		if (p != NULL && strcmp(p + 1, domain) == 0)
675144c6bcdSlogwang 			*p = '\0';
676144c6bcdSlogwang 
677144c6bcdSlogwang 		return (rt_line);
678144c6bcdSlogwang 		break;
679144c6bcdSlogwang 	}
680144c6bcdSlogwang #endif
681144c6bcdSlogwang 	case AF_LINK:
682144c6bcdSlogwang 		sdl = (struct sockaddr_dl *)(void *)sa;
683144c6bcdSlogwang 
684144c6bcdSlogwang 		if (sdl->sdl_nlen == 0 &&
685144c6bcdSlogwang 		    sdl->sdl_alen == 0 &&
686144c6bcdSlogwang 		    sdl->sdl_slen == 0) {
687144c6bcdSlogwang 			n = snprintf(rt_line, sizeof(rt_line), "link#%d",
688144c6bcdSlogwang 			    sdl->sdl_index);
689144c6bcdSlogwang 			if (n > (int)sizeof(rt_line))
690144c6bcdSlogwang 			    rt_line[0] = '\0';
691144c6bcdSlogwang 			return (rt_line);
692144c6bcdSlogwang 		} else
693144c6bcdSlogwang 			return (link_ntoa(sdl));
694144c6bcdSlogwang 		break;
695144c6bcdSlogwang 
696144c6bcdSlogwang 	default:
697144c6bcdSlogwang 	    {
698144c6bcdSlogwang 		u_short *sp = (u_short *)(void *)sa;
699144c6bcdSlogwang 		u_short *splim = sp + ((sa->sa_len + 1) >> 1);
700144c6bcdSlogwang 		char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family);
701144c6bcdSlogwang 		char *cpe = rt_line + sizeof(rt_line);
702144c6bcdSlogwang 
703144c6bcdSlogwang 		while (++sp < splim && cps < cpe) /* start with sa->sa_data */
704144c6bcdSlogwang 			if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0)
705144c6bcdSlogwang 				cps += n;
706144c6bcdSlogwang 			else
707144c6bcdSlogwang 				*cps = '\0';
708144c6bcdSlogwang 		break;
709144c6bcdSlogwang 	    }
710144c6bcdSlogwang 	}
711144c6bcdSlogwang 	return (rt_line);
712144c6bcdSlogwang }
713144c6bcdSlogwang 
714144c6bcdSlogwang /*
715144c6bcdSlogwang  * Return the name of the network whose address is given.
716144c6bcdSlogwang  * The address is assumed to be that of a net, not a host.
717144c6bcdSlogwang  */
718144c6bcdSlogwang static const char *
netname(struct sockaddr * sa)719144c6bcdSlogwang netname(struct sockaddr *sa)
720144c6bcdSlogwang {
721144c6bcdSlogwang 	struct sockaddr_dl *sdl;
722144c6bcdSlogwang 	int n;
723144c6bcdSlogwang #ifdef INET
724*d4a07e70Sfengbojiang #ifndef FSTACK
725144c6bcdSlogwang 	struct netent *np = NULL;
726144c6bcdSlogwang 	const char *cp = NULL;
727144c6bcdSlogwang 	u_long i;
728*d4a07e70Sfengbojiang #else
729*d4a07e70Sfengbojiang 	const char *cp = NULL;
730*d4a07e70Sfengbojiang #endif
731144c6bcdSlogwang #endif
732144c6bcdSlogwang 
733144c6bcdSlogwang 	switch (sa->sa_family) {
734144c6bcdSlogwang #ifdef INET
735144c6bcdSlogwang 	case AF_INET:
736144c6bcdSlogwang 	{
737144c6bcdSlogwang 		struct in_addr in;
738144c6bcdSlogwang 
739144c6bcdSlogwang 		in = ((struct sockaddr_in *)(void *)sa)->sin_addr;
740*d4a07e70Sfengbojiang #ifndef FSTACK
741144c6bcdSlogwang 		i = in.s_addr = ntohl(in.s_addr);
742*d4a07e70Sfengbojiang #else
743*d4a07e70Sfengbojiang 		in.s_addr = ntohl(in.s_addr);
744*d4a07e70Sfengbojiang #endif
745144c6bcdSlogwang 		if (in.s_addr == 0)
746144c6bcdSlogwang 			cp = "default";
747*d4a07e70Sfengbojiang #ifndef FSTACK
748144c6bcdSlogwang 		else if (!nflag) {
749144c6bcdSlogwang 			np = getnetbyaddr(i, AF_INET);
750144c6bcdSlogwang 			if (np != NULL)
751144c6bcdSlogwang 				cp = np->n_name;
752144c6bcdSlogwang 		}
753*d4a07e70Sfengbojiang #endif
754*d4a07e70Sfengbojiang 
755144c6bcdSlogwang #define C(x)	(unsigned)((x) & 0xff)
756144c6bcdSlogwang 		if (cp != NULL)
757144c6bcdSlogwang 			strncpy(net_line, cp, sizeof(net_line));
758144c6bcdSlogwang 		else if ((in.s_addr & 0xffffff) == 0)
759144c6bcdSlogwang 			(void)sprintf(net_line, "%u", C(in.s_addr >> 24));
760144c6bcdSlogwang 		else if ((in.s_addr & 0xffff) == 0)
761144c6bcdSlogwang 			(void)sprintf(net_line, "%u.%u", C(in.s_addr >> 24),
762144c6bcdSlogwang 			    C(in.s_addr >> 16));
763144c6bcdSlogwang 		else if ((in.s_addr & 0xff) == 0)
764144c6bcdSlogwang 			(void)sprintf(net_line, "%u.%u.%u", C(in.s_addr >> 24),
765144c6bcdSlogwang 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
766144c6bcdSlogwang 		else
767144c6bcdSlogwang 			(void)sprintf(net_line, "%u.%u.%u.%u", C(in.s_addr >> 24),
768144c6bcdSlogwang 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
769144c6bcdSlogwang 			    C(in.s_addr));
770144c6bcdSlogwang #undef C
771144c6bcdSlogwang 		break;
772144c6bcdSlogwang 	}
773144c6bcdSlogwang #endif
774144c6bcdSlogwang #ifdef INET6
775144c6bcdSlogwang 	case AF_INET6:
776144c6bcdSlogwang 	{
777144c6bcdSlogwang 		struct sockaddr_in6 sin6;
778144c6bcdSlogwang 		int niflags = 0;
779144c6bcdSlogwang 
780144c6bcdSlogwang 		memset(&sin6, 0, sizeof(sin6));
781144c6bcdSlogwang 		memcpy(&sin6, sa, sa->sa_len);
782144c6bcdSlogwang 		sin6.sin6_len = sizeof(sin6);
783144c6bcdSlogwang 		sin6.sin6_family = AF_INET6;
784*d4a07e70Sfengbojiang #ifndef FSTACK
785144c6bcdSlogwang 		if (nflag)
786144c6bcdSlogwang 			niflags |= NI_NUMERICHOST;
787144c6bcdSlogwang 		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
788144c6bcdSlogwang 		    net_line, sizeof(net_line), NULL, 0, niflags) != 0)
789*d4a07e70Sfengbojiang #else
790*d4a07e70Sfengbojiang 		if (inet_ntop(AF_INET6_LINUX, &sin6.sin6_addr, net_line, sizeof(net_line)) == NULL)
791*d4a07e70Sfengbojiang #endif
792144c6bcdSlogwang 			strncpy(net_line, "invalid", sizeof(net_line));
793144c6bcdSlogwang 
794144c6bcdSlogwang 		return(net_line);
795144c6bcdSlogwang 	}
796144c6bcdSlogwang #endif
797144c6bcdSlogwang 	case AF_LINK:
798144c6bcdSlogwang 		sdl = (struct sockaddr_dl *)(void *)sa;
799144c6bcdSlogwang 
800144c6bcdSlogwang 		if (sdl->sdl_nlen == 0 &&
801144c6bcdSlogwang 		    sdl->sdl_alen == 0 &&
802144c6bcdSlogwang 		    sdl->sdl_slen == 0) {
803144c6bcdSlogwang 			n = snprintf(net_line, sizeof(net_line), "link#%d",
804144c6bcdSlogwang 			    sdl->sdl_index);
805144c6bcdSlogwang 			if (n > (int)sizeof(net_line))
806144c6bcdSlogwang 			    net_line[0] = '\0';
807144c6bcdSlogwang 			return (net_line);
808144c6bcdSlogwang 		} else
809144c6bcdSlogwang 			return (link_ntoa(sdl));
810144c6bcdSlogwang 		break;
811144c6bcdSlogwang 
812144c6bcdSlogwang 	default:
813144c6bcdSlogwang 	    {
814144c6bcdSlogwang 		u_short *sp = (u_short *)(void *)sa->sa_data;
815144c6bcdSlogwang 		u_short *splim = sp + ((sa->sa_len + 1)>>1);
816144c6bcdSlogwang 		char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family);
817144c6bcdSlogwang 		char *cpe = net_line + sizeof(net_line);
818144c6bcdSlogwang 
819144c6bcdSlogwang 		while (sp < splim && cps < cpe)
820144c6bcdSlogwang 			if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0)
821144c6bcdSlogwang 				cps += n;
822144c6bcdSlogwang 			else
823144c6bcdSlogwang 				*cps = '\0';
824144c6bcdSlogwang 		break;
825144c6bcdSlogwang 	    }
826144c6bcdSlogwang 	}
827144c6bcdSlogwang 	return (net_line);
828144c6bcdSlogwang }
829144c6bcdSlogwang 
830144c6bcdSlogwang static void
set_metric(char * value,int key)831144c6bcdSlogwang set_metric(char *value, int key)
832144c6bcdSlogwang {
833144c6bcdSlogwang 	int flag = 0;
834144c6bcdSlogwang 	char *endptr;
835144c6bcdSlogwang 	u_long noval, *valp = &noval;
836144c6bcdSlogwang 
837144c6bcdSlogwang 	switch (key) {
838144c6bcdSlogwang #define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
839144c6bcdSlogwang 	caseof(K_MTU, RTV_MTU, rmx_mtu);
840144c6bcdSlogwang 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
841144c6bcdSlogwang 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
842144c6bcdSlogwang 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
843144c6bcdSlogwang 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
844144c6bcdSlogwang 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
845144c6bcdSlogwang 	caseof(K_RTT, RTV_RTT, rmx_rtt);
846144c6bcdSlogwang 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
847144c6bcdSlogwang 	caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight);
848144c6bcdSlogwang 	}
849144c6bcdSlogwang 	rtm_inits |= flag;
850144c6bcdSlogwang 	if (lockrest || locking)
851144c6bcdSlogwang 		rt_metrics.rmx_locks |= flag;
852144c6bcdSlogwang 	if (locking)
853144c6bcdSlogwang 		locking = 0;
854144c6bcdSlogwang 	errno = 0;
855144c6bcdSlogwang 	*valp = strtol(value, &endptr, 0);
856144c6bcdSlogwang 	if (errno == 0 && *endptr != '\0')
857144c6bcdSlogwang 		errno = EINVAL;
858144c6bcdSlogwang 	if (errno)
859144c6bcdSlogwang 		err(EX_USAGE, "%s", value);
860144c6bcdSlogwang 	if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) {
861144c6bcdSlogwang 		struct timespec ts;
862144c6bcdSlogwang 
863144c6bcdSlogwang 		clock_gettime(CLOCK_REALTIME_FAST, &ts);
864144c6bcdSlogwang 		*valp += ts.tv_sec;
865144c6bcdSlogwang 	}
866144c6bcdSlogwang }
867144c6bcdSlogwang 
868144c6bcdSlogwang #define	F_ISHOST	0x01
869144c6bcdSlogwang #define	F_FORCENET	0x02
870144c6bcdSlogwang #define	F_FORCEHOST	0x04
871144c6bcdSlogwang #define	F_PROXY		0x08
872144c6bcdSlogwang #define	F_INTERFACE	0x10
873144c6bcdSlogwang 
874144c6bcdSlogwang static void
newroute(int argc,char ** argv)875144c6bcdSlogwang newroute(int argc, char **argv)
876144c6bcdSlogwang {
87722ce4affSfengbojiang 	struct sigaction sa;
878144c6bcdSlogwang 	struct hostent *hp;
879144c6bcdSlogwang 	struct fibl *fl;
880144c6bcdSlogwang 	char *cmd;
881144c6bcdSlogwang 	const char *dest, *gateway, *errmsg;
882144c6bcdSlogwang 	int key, error, flags, nrflags, fibnum;
883144c6bcdSlogwang 
884144c6bcdSlogwang 	if (uid != 0 && !debugonly && !tflag)
885144c6bcdSlogwang 		errx(EX_NOPERM, "must be root to alter routing table");
886144c6bcdSlogwang 	dest = NULL;
887144c6bcdSlogwang 	gateway = NULL;
888144c6bcdSlogwang 	flags = RTF_STATIC;
889144c6bcdSlogwang 	nrflags = 0;
890144c6bcdSlogwang 	hp = NULL;
891144c6bcdSlogwang 	TAILQ_INIT(&fibl_head);
892144c6bcdSlogwang 
89322ce4affSfengbojiang 	sigemptyset(&sa.sa_mask);
89422ce4affSfengbojiang 	sa.sa_flags = 0;
89522ce4affSfengbojiang 	sa.sa_handler = stopit;
89622ce4affSfengbojiang 	if (sigaction(SIGALRM, &sa, 0) == -1)
89722ce4affSfengbojiang 		warn("sigaction SIGALRM");
89822ce4affSfengbojiang 
899144c6bcdSlogwang 	cmd = argv[0];
900144c6bcdSlogwang 	if (*cmd != 'g' && *cmd != 's')
901144c6bcdSlogwang 		shutdown(s, SHUT_RD); /* Don't want to read back our messages */
902144c6bcdSlogwang 	while (--argc > 0) {
903144c6bcdSlogwang 		if (**(++argv)== '-') {
904144c6bcdSlogwang 			switch (key = keyword(1 + *argv)) {
905144c6bcdSlogwang 			case K_LINK:
906144c6bcdSlogwang 				af = AF_LINK;
907144c6bcdSlogwang 				aflen = sizeof(struct sockaddr_dl);
908144c6bcdSlogwang 				break;
909144c6bcdSlogwang #ifdef INET
910144c6bcdSlogwang 			case K_4:
911144c6bcdSlogwang 			case K_INET:
912144c6bcdSlogwang 				af = AF_INET;
913144c6bcdSlogwang 				aflen = sizeof(struct sockaddr_in);
914144c6bcdSlogwang 				break;
915144c6bcdSlogwang #endif
916144c6bcdSlogwang #ifdef INET6
917144c6bcdSlogwang 			case K_6:
918144c6bcdSlogwang 			case K_INET6:
919144c6bcdSlogwang 				af = AF_INET6;
920144c6bcdSlogwang 				aflen = sizeof(struct sockaddr_in6);
921144c6bcdSlogwang 				break;
922144c6bcdSlogwang #endif
923144c6bcdSlogwang 			case K_SA:
924144c6bcdSlogwang 				af = PF_ROUTE;
925144c6bcdSlogwang 				aflen = sizeof(struct sockaddr_storage);
926144c6bcdSlogwang 				break;
927144c6bcdSlogwang 			case K_IFACE:
928144c6bcdSlogwang 			case K_INTERFACE:
929144c6bcdSlogwang 				nrflags |= F_INTERFACE;
930144c6bcdSlogwang 				break;
931144c6bcdSlogwang 			case K_NOSTATIC:
932144c6bcdSlogwang 				flags &= ~RTF_STATIC;
933144c6bcdSlogwang 				break;
934144c6bcdSlogwang 			case K_LOCK:
935144c6bcdSlogwang 				locking = 1;
936144c6bcdSlogwang 				break;
937144c6bcdSlogwang 			case K_LOCKREST:
938144c6bcdSlogwang 				lockrest = 1;
939144c6bcdSlogwang 				break;
940144c6bcdSlogwang 			case K_HOST:
941144c6bcdSlogwang 				nrflags |= F_FORCEHOST;
942144c6bcdSlogwang 				break;
943144c6bcdSlogwang 			case K_REJECT:
944144c6bcdSlogwang 				flags |= RTF_REJECT;
945144c6bcdSlogwang 				break;
946144c6bcdSlogwang 			case K_BLACKHOLE:
947144c6bcdSlogwang 				flags |= RTF_BLACKHOLE;
948144c6bcdSlogwang 				break;
949144c6bcdSlogwang 			case K_PROTO1:
950144c6bcdSlogwang 				flags |= RTF_PROTO1;
951144c6bcdSlogwang 				break;
952144c6bcdSlogwang 			case K_PROTO2:
953144c6bcdSlogwang 				flags |= RTF_PROTO2;
954144c6bcdSlogwang 				break;
955144c6bcdSlogwang 			case K_PROXY:
956144c6bcdSlogwang 				nrflags |= F_PROXY;
957144c6bcdSlogwang 				break;
958144c6bcdSlogwang 			case K_XRESOLVE:
959144c6bcdSlogwang 				flags |= RTF_XRESOLVE;
960144c6bcdSlogwang 				break;
961144c6bcdSlogwang 			case K_STATIC:
962144c6bcdSlogwang 				flags |= RTF_STATIC;
963144c6bcdSlogwang 				break;
964144c6bcdSlogwang 			case K_STICKY:
965144c6bcdSlogwang 				flags |= RTF_STICKY;
966144c6bcdSlogwang 				break;
967144c6bcdSlogwang 			case K_NOSTICK:
968144c6bcdSlogwang 				flags &= ~RTF_STICKY;
969144c6bcdSlogwang 				break;
970144c6bcdSlogwang 			case K_FIB:
971144c6bcdSlogwang 				if (!--argc)
972144c6bcdSlogwang 					usage(NULL);
973144c6bcdSlogwang 				error = fiboptlist_csv(*++argv, &fibl_head);
974144c6bcdSlogwang 				if (error)
975144c6bcdSlogwang 					errx(EX_USAGE,
976144c6bcdSlogwang 					    "invalid fib number: %s", *argv);
977144c6bcdSlogwang 				break;
978144c6bcdSlogwang 			case K_IFA:
979144c6bcdSlogwang 				if (!--argc)
980144c6bcdSlogwang 					usage(NULL);
981144c6bcdSlogwang 				getaddr(RTAX_IFA, *++argv, 0, nrflags);
982144c6bcdSlogwang 				break;
983144c6bcdSlogwang 			case K_IFP:
984144c6bcdSlogwang 				if (!--argc)
985144c6bcdSlogwang 					usage(NULL);
986144c6bcdSlogwang 				getaddr(RTAX_IFP, *++argv, 0, nrflags);
987144c6bcdSlogwang 				break;
988144c6bcdSlogwang 			case K_GENMASK:
989144c6bcdSlogwang 				if (!--argc)
990144c6bcdSlogwang 					usage(NULL);
991144c6bcdSlogwang 				getaddr(RTAX_GENMASK, *++argv, 0, nrflags);
992144c6bcdSlogwang 				break;
993144c6bcdSlogwang 			case K_GATEWAY:
994144c6bcdSlogwang 				if (!--argc)
995144c6bcdSlogwang 					usage(NULL);
996144c6bcdSlogwang 				getaddr(RTAX_GATEWAY, *++argv, 0, nrflags);
997144c6bcdSlogwang 				gateway = *argv;
998144c6bcdSlogwang 				break;
999144c6bcdSlogwang 			case K_DST:
1000144c6bcdSlogwang 				if (!--argc)
1001144c6bcdSlogwang 					usage(NULL);
1002144c6bcdSlogwang 				if (getaddr(RTAX_DST, *++argv, &hp, nrflags))
1003144c6bcdSlogwang 					nrflags |= F_ISHOST;
1004144c6bcdSlogwang 				dest = *argv;
1005144c6bcdSlogwang 				break;
1006144c6bcdSlogwang 			case K_NETMASK:
1007144c6bcdSlogwang 				if (!--argc)
1008144c6bcdSlogwang 					usage(NULL);
1009144c6bcdSlogwang 				getaddr(RTAX_NETMASK, *++argv, 0, nrflags);
1010144c6bcdSlogwang 				/* FALLTHROUGH */
1011144c6bcdSlogwang 			case K_NET:
1012144c6bcdSlogwang 				nrflags |= F_FORCENET;
1013144c6bcdSlogwang 				break;
1014144c6bcdSlogwang 			case K_PREFIXLEN:
1015144c6bcdSlogwang 				if (!--argc)
1016144c6bcdSlogwang 					usage(NULL);
1017144c6bcdSlogwang 				if (prefixlen(*++argv) == -1) {
1018144c6bcdSlogwang 					nrflags &= ~F_FORCENET;
1019144c6bcdSlogwang 					nrflags |= F_ISHOST;
1020144c6bcdSlogwang 				} else {
1021144c6bcdSlogwang 					nrflags |= F_FORCENET;
1022144c6bcdSlogwang 					nrflags &= ~F_ISHOST;
1023144c6bcdSlogwang 				}
1024144c6bcdSlogwang 				break;
1025144c6bcdSlogwang 			case K_MTU:
1026144c6bcdSlogwang 			case K_HOPCOUNT:
1027144c6bcdSlogwang 			case K_EXPIRE:
1028144c6bcdSlogwang 			case K_RECVPIPE:
1029144c6bcdSlogwang 			case K_SENDPIPE:
1030144c6bcdSlogwang 			case K_SSTHRESH:
1031144c6bcdSlogwang 			case K_RTT:
1032144c6bcdSlogwang 			case K_RTTVAR:
1033144c6bcdSlogwang 			case K_WEIGHT:
1034144c6bcdSlogwang 				if (!--argc)
1035144c6bcdSlogwang 					usage(NULL);
1036144c6bcdSlogwang 				set_metric(*++argv, key);
1037144c6bcdSlogwang 				break;
1038144c6bcdSlogwang 			default:
1039144c6bcdSlogwang 				usage(1+*argv);
1040144c6bcdSlogwang 			}
1041144c6bcdSlogwang 		} else {
1042144c6bcdSlogwang 			if ((rtm_addrs & RTA_DST) == 0) {
1043144c6bcdSlogwang 				dest = *argv;
1044144c6bcdSlogwang 				if (getaddr(RTAX_DST, *argv, &hp, nrflags))
1045144c6bcdSlogwang 					nrflags |= F_ISHOST;
1046144c6bcdSlogwang 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
1047144c6bcdSlogwang 				gateway = *argv;
1048144c6bcdSlogwang 				getaddr(RTAX_GATEWAY, *argv, &hp, nrflags);
1049144c6bcdSlogwang 			} else {
1050144c6bcdSlogwang 				getaddr(RTAX_NETMASK, *argv, 0, nrflags);
1051144c6bcdSlogwang 				nrflags |= F_FORCENET;
1052144c6bcdSlogwang 			}
1053144c6bcdSlogwang 		}
1054144c6bcdSlogwang 	}
1055144c6bcdSlogwang 
1056144c6bcdSlogwang 	/* Do some sanity checks on resulting request */
1057144c6bcdSlogwang 	if (so[RTAX_DST].ss_len == 0) {
1058144c6bcdSlogwang 		warnx("destination parameter required");
1059144c6bcdSlogwang 		usage(NULL);
1060144c6bcdSlogwang 	}
1061144c6bcdSlogwang 
1062144c6bcdSlogwang 	if (so[RTAX_NETMASK].ss_len != 0 &&
1063144c6bcdSlogwang 	    so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) {
1064144c6bcdSlogwang 		warnx("destination and netmask family need to be the same");
1065144c6bcdSlogwang 		usage(NULL);
1066144c6bcdSlogwang 	}
1067144c6bcdSlogwang 
1068144c6bcdSlogwang 	if (nrflags & F_FORCEHOST) {
1069144c6bcdSlogwang 		nrflags |= F_ISHOST;
1070144c6bcdSlogwang #ifdef INET6
1071144c6bcdSlogwang 		if (af == AF_INET6) {
1072144c6bcdSlogwang 			rtm_addrs &= ~RTA_NETMASK;
1073144c6bcdSlogwang 			memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK]));
1074144c6bcdSlogwang 		}
1075144c6bcdSlogwang #endif
1076144c6bcdSlogwang 	}
1077144c6bcdSlogwang 	if (nrflags & F_FORCENET)
1078144c6bcdSlogwang 		nrflags &= ~F_ISHOST;
1079144c6bcdSlogwang 	flags |= RTF_UP;
1080144c6bcdSlogwang 	if (nrflags & F_ISHOST)
1081144c6bcdSlogwang 		flags |= RTF_HOST;
1082144c6bcdSlogwang 	if ((nrflags & F_INTERFACE) == 0)
1083144c6bcdSlogwang 		flags |= RTF_GATEWAY;
1084144c6bcdSlogwang 	if (nrflags & F_PROXY)
1085144c6bcdSlogwang 		flags |= RTF_ANNOUNCE;
1086144c6bcdSlogwang 	if (dest == NULL)
1087144c6bcdSlogwang 		dest = "";
1088144c6bcdSlogwang 	if (gateway == NULL)
1089144c6bcdSlogwang 		gateway = "";
1090144c6bcdSlogwang 
1091144c6bcdSlogwang 	if (TAILQ_EMPTY(&fibl_head)) {
1092144c6bcdSlogwang 		error = fiboptlist_csv("default", &fibl_head);
1093144c6bcdSlogwang 		if (error)
1094144c6bcdSlogwang 			errx(EX_OSERR, "fiboptlist_csv failed.");
1095144c6bcdSlogwang 	}
1096144c6bcdSlogwang 	error = 0;
1097144c6bcdSlogwang 	TAILQ_FOREACH(fl, &fibl_head, fl_next) {
1098144c6bcdSlogwang 		fl->fl_error = newroute_fib(fl->fl_num, cmd, flags);
1099144c6bcdSlogwang 		if (fl->fl_error)
1100144c6bcdSlogwang 			fl->fl_errno = errno;
1101144c6bcdSlogwang 		error += fl->fl_error;
1102144c6bcdSlogwang 	}
110322ce4affSfengbojiang 	if (*cmd == 'g' || *cmd == 's')
1104*d4a07e70Sfengbojiang #ifndef FSTACK
1105144c6bcdSlogwang 		exit(error);
1106*d4a07e70Sfengbojiang #else
1107*d4a07e70Sfengbojiang 	{
1108*d4a07e70Sfengbojiang 		ff_ipc_exit();
1109*d4a07e70Sfengbojiang 		exit(error);
1110*d4a07e70Sfengbojiang 	}
1111*d4a07e70Sfengbojiang #endif
1112144c6bcdSlogwang 
1113144c6bcdSlogwang 	error = 0;
1114144c6bcdSlogwang 	if (!qflag) {
1115144c6bcdSlogwang 		fibnum = 0;
1116144c6bcdSlogwang 		TAILQ_FOREACH(fl, &fibl_head, fl_next) {
1117144c6bcdSlogwang 			if (fl->fl_error == 0)
1118144c6bcdSlogwang 				fibnum++;
1119144c6bcdSlogwang 		}
1120144c6bcdSlogwang 		if (fibnum > 0) {
1121144c6bcdSlogwang 			int firstfib = 1;
1122144c6bcdSlogwang 
1123144c6bcdSlogwang 			printf("%s %s %s", cmd,
1124144c6bcdSlogwang 			    (nrflags & F_ISHOST) ? "host" : "net", dest);
1125144c6bcdSlogwang 			if (*gateway)
1126144c6bcdSlogwang 				printf(": gateway %s", gateway);
1127144c6bcdSlogwang 
1128144c6bcdSlogwang 			if (numfibs > 1) {
1129144c6bcdSlogwang 				TAILQ_FOREACH(fl, &fibl_head, fl_next) {
1130144c6bcdSlogwang 					if (fl->fl_error == 0
1131144c6bcdSlogwang 					    && fl->fl_num >= 0) {
1132144c6bcdSlogwang 						if (firstfib) {
1133144c6bcdSlogwang 							printf(" fib ");
1134144c6bcdSlogwang 							firstfib = 0;
1135144c6bcdSlogwang 						}
1136144c6bcdSlogwang 						printf("%d", fl->fl_num);
1137144c6bcdSlogwang 						if (fibnum-- > 1)
1138144c6bcdSlogwang 							printf(",");
1139144c6bcdSlogwang 					}
1140144c6bcdSlogwang 				}
1141144c6bcdSlogwang 			}
1142144c6bcdSlogwang 			printf("\n");
1143144c6bcdSlogwang 		}
114422ce4affSfengbojiang 	}
1145144c6bcdSlogwang 
1146144c6bcdSlogwang 	fibnum = 0;
1147144c6bcdSlogwang 	TAILQ_FOREACH(fl, &fibl_head, fl_next) {
1148144c6bcdSlogwang 		if (fl->fl_error != 0) {
114922ce4affSfengbojiang 			error = 1;
115022ce4affSfengbojiang 			if (!qflag) {
1151144c6bcdSlogwang 				printf("%s %s %s", cmd, (nrflags & F_ISHOST)
1152144c6bcdSlogwang 				    ? "host" : "net", dest);
1153144c6bcdSlogwang 				if (*gateway)
1154144c6bcdSlogwang 					printf(": gateway %s", gateway);
1155144c6bcdSlogwang 
1156144c6bcdSlogwang 				if (fl->fl_num >= 0)
1157144c6bcdSlogwang 					printf(" fib %d", fl->fl_num);
1158144c6bcdSlogwang 
1159144c6bcdSlogwang 				switch (fl->fl_errno) {
1160144c6bcdSlogwang 				case ESRCH:
1161144c6bcdSlogwang 					errmsg = "not in table";
1162144c6bcdSlogwang 					break;
1163144c6bcdSlogwang 				case EBUSY:
1164144c6bcdSlogwang 					errmsg = "entry in use";
1165144c6bcdSlogwang 					break;
1166144c6bcdSlogwang 				case ENOBUFS:
1167144c6bcdSlogwang 					errmsg = "not enough memory";
1168144c6bcdSlogwang 					break;
1169144c6bcdSlogwang 				case EADDRINUSE:
1170144c6bcdSlogwang 					/*
1171144c6bcdSlogwang 					 * handle recursion avoidance
1172144c6bcdSlogwang 					 * in rt_setgate()
1173144c6bcdSlogwang 					 */
1174144c6bcdSlogwang 					errmsg = "gateway uses the same route";
1175144c6bcdSlogwang 					break;
1176144c6bcdSlogwang 				case EEXIST:
1177144c6bcdSlogwang 					errmsg = "route already in table";
1178144c6bcdSlogwang 					break;
1179144c6bcdSlogwang 				default:
1180144c6bcdSlogwang 					errmsg = strerror(fl->fl_errno);
1181144c6bcdSlogwang 					break;
1182144c6bcdSlogwang 				}
1183144c6bcdSlogwang 				printf(": %s\n", errmsg);
1184144c6bcdSlogwang 			}
1185144c6bcdSlogwang 		}
1186144c6bcdSlogwang 	}
1187*d4a07e70Sfengbojiang #ifdef FSTACK
1188*d4a07e70Sfengbojiang 	ff_ipc_exit();
1189*d4a07e70Sfengbojiang #endif
1190144c6bcdSlogwang 	exit(error);
1191144c6bcdSlogwang }
1192144c6bcdSlogwang 
1193144c6bcdSlogwang static int
newroute_fib(int fib,char * cmd,int flags)1194144c6bcdSlogwang newroute_fib(int fib, char *cmd, int flags)
1195144c6bcdSlogwang {
1196144c6bcdSlogwang 	int error;
1197144c6bcdSlogwang 
1198144c6bcdSlogwang 	error = set_sofib(fib);
1199144c6bcdSlogwang 	if (error) {
1200144c6bcdSlogwang 		warn("fib number %d is ignored", fib);
1201144c6bcdSlogwang 		return (error);
1202144c6bcdSlogwang 	}
1203144c6bcdSlogwang 
1204144c6bcdSlogwang 	error = rtmsg(*cmd, flags, fib);
1205144c6bcdSlogwang 	return (error);
1206144c6bcdSlogwang }
1207144c6bcdSlogwang 
1208144c6bcdSlogwang #ifdef INET
1209144c6bcdSlogwang static void
inet_makemask(struct sockaddr_in * sin_mask,u_long bits)121022ce4affSfengbojiang inet_makemask(struct sockaddr_in *sin_mask, u_long bits)
1211144c6bcdSlogwang {
1212144c6bcdSlogwang 	u_long mask = 0;
1213144c6bcdSlogwang 
1214144c6bcdSlogwang 	rtm_addrs |= RTA_NETMASK;
1215144c6bcdSlogwang 
1216144c6bcdSlogwang 	if (bits != 0)
1217144c6bcdSlogwang 		mask = 0xffffffff << (32 - bits);
1218144c6bcdSlogwang 
1219144c6bcdSlogwang 	sin_mask->sin_addr.s_addr = htonl(mask);
1220144c6bcdSlogwang 	sin_mask->sin_len = sizeof(struct sockaddr_in);
1221144c6bcdSlogwang 	sin_mask->sin_family = AF_INET;
1222144c6bcdSlogwang }
1223144c6bcdSlogwang #endif
1224144c6bcdSlogwang 
1225144c6bcdSlogwang #ifdef INET6
1226144c6bcdSlogwang /*
1227144c6bcdSlogwang  * XXX the function may need more improvement...
1228144c6bcdSlogwang  */
1229144c6bcdSlogwang static int
inet6_makenetandmask(struct sockaddr_in6 * sin6,const char * plen)1230144c6bcdSlogwang inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
1231144c6bcdSlogwang {
1232144c6bcdSlogwang 
1233144c6bcdSlogwang 	if (plen == NULL) {
1234144c6bcdSlogwang 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1235144c6bcdSlogwang 		    sin6->sin6_scope_id == 0)
1236144c6bcdSlogwang 			plen = "0";
1237144c6bcdSlogwang 	}
1238144c6bcdSlogwang 
1239144c6bcdSlogwang 	if (plen == NULL || strcmp(plen, "128") == 0)
1240144c6bcdSlogwang 		return (1);
1241144c6bcdSlogwang 	rtm_addrs |= RTA_NETMASK;
1242144c6bcdSlogwang 	prefixlen(plen);
1243144c6bcdSlogwang 	return (0);
1244144c6bcdSlogwang }
1245144c6bcdSlogwang #endif
1246144c6bcdSlogwang 
1247144c6bcdSlogwang /*
1248144c6bcdSlogwang  * Interpret an argument as a network address of some kind,
1249144c6bcdSlogwang  * returning 1 if a host address, 0 if a network address.
1250144c6bcdSlogwang  */
1251144c6bcdSlogwang static int
getaddr(int idx,char * str,struct hostent ** hpp,int nrflags)1252144c6bcdSlogwang getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
1253144c6bcdSlogwang {
1254144c6bcdSlogwang 	struct sockaddr *sa;
1255144c6bcdSlogwang #if defined(INET)
1256144c6bcdSlogwang 	struct sockaddr_in *sin;
1257144c6bcdSlogwang 	struct hostent *hp;
1258144c6bcdSlogwang 	char *q;
1259144c6bcdSlogwang #elif defined(INET6)
1260144c6bcdSlogwang 	char *q;
1261144c6bcdSlogwang #endif
1262144c6bcdSlogwang 
1263144c6bcdSlogwang 	if (idx < 0 || idx >= RTAX_MAX)
1264144c6bcdSlogwang 		usage("internal error");
1265144c6bcdSlogwang 	if (af == 0) {
1266144c6bcdSlogwang #if defined(INET)
1267144c6bcdSlogwang 		af = AF_INET;
1268144c6bcdSlogwang 		aflen = sizeof(struct sockaddr_in);
1269144c6bcdSlogwang #elif defined(INET6)
1270144c6bcdSlogwang 		af = AF_INET6;
1271144c6bcdSlogwang 		aflen = sizeof(struct sockaddr_in6);
1272144c6bcdSlogwang #else
1273144c6bcdSlogwang 		af = AF_LINK;
1274144c6bcdSlogwang 		aflen = sizeof(struct sockaddr_dl);
1275144c6bcdSlogwang #endif
1276144c6bcdSlogwang 	}
1277144c6bcdSlogwang #ifndef INET
1278144c6bcdSlogwang 	hpp = NULL;
1279144c6bcdSlogwang #endif
1280144c6bcdSlogwang 	rtm_addrs |= (1 << idx);
1281144c6bcdSlogwang 	sa = (struct sockaddr *)&so[idx];
1282144c6bcdSlogwang 	sa->sa_family = af;
1283144c6bcdSlogwang 	sa->sa_len = aflen;
1284144c6bcdSlogwang 
1285144c6bcdSlogwang 	switch (idx) {
1286144c6bcdSlogwang 	case RTAX_GATEWAY:
1287144c6bcdSlogwang 		if (nrflags & F_INTERFACE) {
1288144c6bcdSlogwang 			struct ifaddrs *ifap, *ifa;
1289144c6bcdSlogwang 			struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa;
1290144c6bcdSlogwang 			struct sockaddr_dl *sdl = NULL;
1291144c6bcdSlogwang 
1292144c6bcdSlogwang 			if (getifaddrs(&ifap))
1293144c6bcdSlogwang 				err(EX_OSERR, "getifaddrs");
1294144c6bcdSlogwang 
1295144c6bcdSlogwang 			for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1296144c6bcdSlogwang 				if (ifa->ifa_addr->sa_family != AF_LINK)
1297144c6bcdSlogwang 					continue;
1298144c6bcdSlogwang 
1299144c6bcdSlogwang 				if (strcmp(str, ifa->ifa_name) != 0)
1300144c6bcdSlogwang 					continue;
1301144c6bcdSlogwang 
1302144c6bcdSlogwang 				sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
1303144c6bcdSlogwang 			}
1304144c6bcdSlogwang 			/* If we found it, then use it */
1305144c6bcdSlogwang 			if (sdl != NULL) {
1306144c6bcdSlogwang 				/*
1307144c6bcdSlogwang 				 * Note that we need to copy before calling
1308144c6bcdSlogwang 				 * freeifaddrs().
1309144c6bcdSlogwang 				 */
1310144c6bcdSlogwang 				memcpy(sdl0, sdl, sdl->sdl_len);
1311144c6bcdSlogwang 			}
1312144c6bcdSlogwang 			freeifaddrs(ifap);
1313144c6bcdSlogwang 			if (sdl != NULL)
1314144c6bcdSlogwang 				return(1);
1315144c6bcdSlogwang 			else
1316144c6bcdSlogwang 				errx(EX_DATAERR,
1317144c6bcdSlogwang 				    "interface '%s' does not exist", str);
1318144c6bcdSlogwang 		}
1319144c6bcdSlogwang 		break;
1320144c6bcdSlogwang 	case RTAX_IFP:
1321144c6bcdSlogwang 		sa->sa_family = AF_LINK;
1322144c6bcdSlogwang 		break;
1323144c6bcdSlogwang 	}
1324144c6bcdSlogwang 	if (strcmp(str, "default") == 0) {
1325144c6bcdSlogwang 		/*
1326144c6bcdSlogwang 		 * Default is net 0.0.0.0/0
1327144c6bcdSlogwang 		 */
1328144c6bcdSlogwang 		switch (idx) {
1329144c6bcdSlogwang 		case RTAX_DST:
1330144c6bcdSlogwang 			nrflags |= F_FORCENET;
1331144c6bcdSlogwang 			getaddr(RTAX_NETMASK, str, 0, nrflags);
1332144c6bcdSlogwang 			break;
1333144c6bcdSlogwang 		}
1334144c6bcdSlogwang 		return (0);
1335144c6bcdSlogwang 	}
1336144c6bcdSlogwang 	switch (sa->sa_family) {
1337144c6bcdSlogwang #ifdef INET6
1338144c6bcdSlogwang 	case AF_INET6:
1339144c6bcdSlogwang 	{
1340*d4a07e70Sfengbojiang #ifndef FSTACK
1341144c6bcdSlogwang 		struct addrinfo hints, *res;
1342144c6bcdSlogwang 		int ecode;
1343*d4a07e70Sfengbojiang #endif
1344144c6bcdSlogwang 
1345144c6bcdSlogwang 		q = NULL;
1346144c6bcdSlogwang 		if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL)
1347144c6bcdSlogwang 			*q = '\0';
1348*d4a07e70Sfengbojiang #ifndef FSTACK
1349144c6bcdSlogwang 		memset(&hints, 0, sizeof(hints));
1350144c6bcdSlogwang 		hints.ai_family = sa->sa_family;
1351144c6bcdSlogwang 		hints.ai_socktype = SOCK_DGRAM;
1352144c6bcdSlogwang 		ecode = getaddrinfo(str, NULL, &hints, &res);
1353144c6bcdSlogwang 		if (ecode != 0 || res->ai_family != AF_INET6 ||
1354144c6bcdSlogwang 		    res->ai_addrlen != sizeof(struct sockaddr_in6))
1355144c6bcdSlogwang 			errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode));
1356144c6bcdSlogwang 		memcpy(sa, res->ai_addr, res->ai_addrlen);
1357144c6bcdSlogwang 		freeaddrinfo(res);
1358*d4a07e70Sfengbojiang #else
1359*d4a07e70Sfengbojiang 		if (inet_pton(AF_INET6_LINUX, str, &((struct sockaddr_in6 *)sa)->sin6_addr) == -1)
1360*d4a07e70Sfengbojiang 			errx(EX_OSERR, "%s: %d, %s", str, errno, strerror(errno));
1361*d4a07e70Sfengbojiang #endif
1362144c6bcdSlogwang 		if (q != NULL)
1363144c6bcdSlogwang 			*q++ = '/';
1364144c6bcdSlogwang 		if (idx == RTAX_DST)
1365144c6bcdSlogwang 			return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q));
1366144c6bcdSlogwang 		return (0);
1367144c6bcdSlogwang 	}
1368144c6bcdSlogwang #endif /* INET6 */
1369144c6bcdSlogwang 	case AF_LINK:
1370144c6bcdSlogwang 		link_addr(str, (struct sockaddr_dl *)(void *)sa);
1371144c6bcdSlogwang 		return (1);
1372144c6bcdSlogwang 
1373144c6bcdSlogwang 	case PF_ROUTE:
1374144c6bcdSlogwang 		sockaddr(str, sa, sizeof(struct sockaddr_storage));
1375144c6bcdSlogwang 		return (1);
1376144c6bcdSlogwang #ifdef INET
1377144c6bcdSlogwang 	case AF_INET:
1378144c6bcdSlogwang #endif
1379144c6bcdSlogwang 	default:
1380144c6bcdSlogwang 		break;
1381144c6bcdSlogwang 	}
1382144c6bcdSlogwang 
1383144c6bcdSlogwang #ifdef INET
1384144c6bcdSlogwang 	sin = (struct sockaddr_in *)(void *)sa;
1385144c6bcdSlogwang 	if (hpp == NULL)
1386144c6bcdSlogwang 		hpp = &hp;
1387144c6bcdSlogwang 	*hpp = NULL;
1388144c6bcdSlogwang 
1389144c6bcdSlogwang 	q = strchr(str,'/');
1390144c6bcdSlogwang 	if (q != NULL && idx == RTAX_DST) {
139122ce4affSfengbojiang 		/* A.B.C.D/NUM */
1392144c6bcdSlogwang 		*q = '\0';
139322ce4affSfengbojiang 		if (inet_aton(str, &sin->sin_addr) == 0)
139422ce4affSfengbojiang 			errx(EX_NOHOST, "bad address: %s", str);
139522ce4affSfengbojiang 
139622ce4affSfengbojiang 		int masklen = strtol(q + 1, NULL, 10);
139722ce4affSfengbojiang 		if (masklen < 0 || masklen > 32)
139822ce4affSfengbojiang 			errx(EX_NOHOST, "bad mask length: %s", q + 1);
139922ce4affSfengbojiang 
140022ce4affSfengbojiang 		inet_makemask((struct sockaddr_in *)&so[RTAX_NETMASK],masklen);
1401144c6bcdSlogwang 		return (0);
1402144c6bcdSlogwang 	}
140322ce4affSfengbojiang 	if (inet_aton(str, &sin->sin_addr) != 0)
1404144c6bcdSlogwang 		return (1);
1405144c6bcdSlogwang 
1406*d4a07e70Sfengbojiang #ifndef FSTACK
1407144c6bcdSlogwang 	hp = gethostbyname(str);
1408144c6bcdSlogwang 	if (hp != NULL) {
1409144c6bcdSlogwang 		*hpp = hp;
1410144c6bcdSlogwang 		sin->sin_family = hp->h_addrtype;
1411144c6bcdSlogwang 		memmove((char *)&sin->sin_addr, hp->h_addr,
1412144c6bcdSlogwang 		    MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
1413144c6bcdSlogwang 		return (1);
1414144c6bcdSlogwang 	}
1415144c6bcdSlogwang #endif
1416*d4a07e70Sfengbojiang #endif
1417144c6bcdSlogwang 	errx(EX_NOHOST, "bad address: %s", str);
1418144c6bcdSlogwang }
1419144c6bcdSlogwang 
1420144c6bcdSlogwang static int
prefixlen(const char * str)1421144c6bcdSlogwang prefixlen(const char *str)
1422144c6bcdSlogwang {
1423144c6bcdSlogwang 	int len = atoi(str), q, r;
1424144c6bcdSlogwang 	int max;
1425144c6bcdSlogwang 	char *p;
1426144c6bcdSlogwang 
1427144c6bcdSlogwang 	rtm_addrs |= RTA_NETMASK;
1428144c6bcdSlogwang 	switch (af) {
1429144c6bcdSlogwang #ifdef INET6
1430144c6bcdSlogwang 	case AF_INET6:
1431144c6bcdSlogwang 	{
1432144c6bcdSlogwang 		struct sockaddr_in6 *sin6 =
1433144c6bcdSlogwang 		    (struct sockaddr_in6 *)&so[RTAX_NETMASK];
1434144c6bcdSlogwang 
1435144c6bcdSlogwang 		max = 128;
1436144c6bcdSlogwang 		p = (char *)&sin6->sin6_addr;
1437144c6bcdSlogwang 		sin6->sin6_family = AF_INET6;
1438144c6bcdSlogwang 		sin6->sin6_len = sizeof(*sin6);
1439144c6bcdSlogwang 		break;
1440144c6bcdSlogwang 	}
1441144c6bcdSlogwang #endif
1442144c6bcdSlogwang #ifdef INET
1443144c6bcdSlogwang 	case AF_INET:
1444144c6bcdSlogwang 	{
1445144c6bcdSlogwang 		struct sockaddr_in *sin =
1446144c6bcdSlogwang 		    (struct sockaddr_in *)&so[RTAX_NETMASK];
1447144c6bcdSlogwang 
1448144c6bcdSlogwang 		max = 32;
1449144c6bcdSlogwang 		p = (char *)&sin->sin_addr;
1450144c6bcdSlogwang 		sin->sin_family = AF_INET;
1451144c6bcdSlogwang 		sin->sin_len = sizeof(*sin);
1452144c6bcdSlogwang 		break;
1453144c6bcdSlogwang 	}
1454144c6bcdSlogwang #endif
1455144c6bcdSlogwang 	default:
1456144c6bcdSlogwang 		errx(EX_OSERR, "prefixlen not supported in this af");
1457144c6bcdSlogwang 	}
1458144c6bcdSlogwang 
1459144c6bcdSlogwang 	if (len < 0 || max < len)
1460144c6bcdSlogwang 		errx(EX_USAGE, "%s: invalid prefixlen", str);
1461144c6bcdSlogwang 
1462144c6bcdSlogwang 	q = len >> 3;
1463144c6bcdSlogwang 	r = len & 7;
1464144c6bcdSlogwang 	memset((void *)p, 0, max / 8);
1465144c6bcdSlogwang 	if (q > 0)
1466144c6bcdSlogwang 		memset((void *)p, 0xff, q);
1467144c6bcdSlogwang 	if (r > 0)
1468144c6bcdSlogwang 		*((u_char *)p + q) = (0xff00 >> r) & 0xff;
1469144c6bcdSlogwang 	if (len == max)
1470144c6bcdSlogwang 		return (-1);
1471144c6bcdSlogwang 	else
1472144c6bcdSlogwang 		return (len);
1473144c6bcdSlogwang }
1474144c6bcdSlogwang 
1475*d4a07e70Sfengbojiang #ifndef FSTACK
1476144c6bcdSlogwang static void
interfaces(void)1477144c6bcdSlogwang interfaces(void)
1478144c6bcdSlogwang {
1479144c6bcdSlogwang 	size_t needed;
1480144c6bcdSlogwang 	int mib[6];
1481144c6bcdSlogwang 	char *buf, *lim, *next, count = 0;
1482144c6bcdSlogwang 	struct rt_msghdr *rtm;
1483144c6bcdSlogwang 
1484144c6bcdSlogwang retry2:
1485144c6bcdSlogwang 	mib[0] = CTL_NET;
1486144c6bcdSlogwang 	mib[1] = PF_ROUTE;
1487144c6bcdSlogwang 	mib[2] = 0;		/* protocol */
1488144c6bcdSlogwang 	mib[3] = AF_UNSPEC;
1489144c6bcdSlogwang 	mib[4] = NET_RT_IFLIST;
1490144c6bcdSlogwang 	mib[5] = 0;		/* no flags */
1491144c6bcdSlogwang 	if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
1492144c6bcdSlogwang 		err(EX_OSERR, "route-sysctl-estimate");
1493144c6bcdSlogwang 	if ((buf = malloc(needed)) == NULL)
1494144c6bcdSlogwang 		errx(EX_OSERR, "malloc failed");
1495144c6bcdSlogwang 	if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
1496144c6bcdSlogwang 		if (errno == ENOMEM && count++ < 10) {
1497144c6bcdSlogwang 			warnx("Routing table grew, retrying");
1498144c6bcdSlogwang 			sleep(1);
1499144c6bcdSlogwang 			free(buf);
1500144c6bcdSlogwang 			goto retry2;
1501144c6bcdSlogwang 		}
1502144c6bcdSlogwang 		err(EX_OSERR, "actual retrieval of interface table");
1503144c6bcdSlogwang 	}
1504144c6bcdSlogwang 	lim = buf + needed;
1505144c6bcdSlogwang 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1506144c6bcdSlogwang 		rtm = (struct rt_msghdr *)(void *)next;
1507144c6bcdSlogwang 		print_rtmsg(rtm, rtm->rtm_msglen);
1508144c6bcdSlogwang 	}
150922ce4affSfengbojiang 	free(buf);
1510144c6bcdSlogwang }
1511144c6bcdSlogwang 
1512144c6bcdSlogwang static void
monitor(int argc,char * argv[])1513144c6bcdSlogwang monitor(int argc, char *argv[])
1514144c6bcdSlogwang {
1515144c6bcdSlogwang 	int n, fib, error;
1516144c6bcdSlogwang 	char msg[2048], *endptr;
1517144c6bcdSlogwang 
1518144c6bcdSlogwang 	fib = defaultfib;
1519144c6bcdSlogwang 	while (argc > 1) {
1520144c6bcdSlogwang 		argc--;
1521144c6bcdSlogwang 		argv++;
1522144c6bcdSlogwang 		if (**argv != '-')
1523144c6bcdSlogwang 			usage(*argv);
1524144c6bcdSlogwang 		switch (keyword(*argv + 1)) {
1525144c6bcdSlogwang 		case K_FIB:
1526144c6bcdSlogwang 			if (!--argc)
1527144c6bcdSlogwang 				usage(*argv);
1528144c6bcdSlogwang 			errno = 0;
1529144c6bcdSlogwang 			fib = strtol(*++argv, &endptr, 0);
1530144c6bcdSlogwang 			if (errno == 0) {
1531144c6bcdSlogwang 				if (*endptr != '\0' ||
1532144c6bcdSlogwang 				    fib < 0 ||
1533144c6bcdSlogwang 				    (numfibs != -1 && fib > numfibs - 1))
1534144c6bcdSlogwang 					errno = EINVAL;
1535144c6bcdSlogwang 			}
1536144c6bcdSlogwang 			if (errno)
1537144c6bcdSlogwang 				errx(EX_USAGE, "invalid fib number: %s", *argv);
1538144c6bcdSlogwang 			break;
1539144c6bcdSlogwang 		default:
1540144c6bcdSlogwang 			usage(*argv);
1541144c6bcdSlogwang 		}
1542144c6bcdSlogwang 	}
1543144c6bcdSlogwang 	error = set_sofib(fib);
1544144c6bcdSlogwang 	if (error)
1545144c6bcdSlogwang 		errx(EX_USAGE, "invalid fib number: %d", fib);
1546144c6bcdSlogwang 
1547144c6bcdSlogwang 	verbose = 1;
1548144c6bcdSlogwang 	if (debugonly) {
1549144c6bcdSlogwang 		interfaces();
1550144c6bcdSlogwang 		exit(0);
1551144c6bcdSlogwang 	}
1552144c6bcdSlogwang 	for (;;) {
1553144c6bcdSlogwang 		time_t now;
1554144c6bcdSlogwang 		n = read(s, msg, 2048);
1555144c6bcdSlogwang 		now = time(NULL);
1556144c6bcdSlogwang 		(void)printf("\ngot message of size %d on %s", n, ctime(&now));
1557144c6bcdSlogwang 		print_rtmsg((struct rt_msghdr *)(void *)msg, n);
1558144c6bcdSlogwang 	}
1559144c6bcdSlogwang }
1560*d4a07e70Sfengbojiang #endif
1561144c6bcdSlogwang 
1562144c6bcdSlogwang static int
rtmsg(int cmd,int flags,int fib)1563144c6bcdSlogwang rtmsg(int cmd, int flags, int fib)
1564144c6bcdSlogwang {
1565144c6bcdSlogwang 	int rlen;
1566144c6bcdSlogwang 	char *cp = m_rtmsg.m_space;
1567144c6bcdSlogwang 	int l;
1568144c6bcdSlogwang 
1569144c6bcdSlogwang #define NEXTADDR(w, u)							\
1570144c6bcdSlogwang 	if (rtm_addrs & (w)) {						\
157122ce4affSfengbojiang 		l = SA_SIZE(&(u));					\
1572144c6bcdSlogwang 		memmove(cp, (char *)&(u), l);				\
1573144c6bcdSlogwang 		cp += l;						\
1574144c6bcdSlogwang 		if (verbose)						\
1575144c6bcdSlogwang 			sodump((struct sockaddr *)&(u), #w);		\
1576144c6bcdSlogwang 	}
1577144c6bcdSlogwang 
1578144c6bcdSlogwang 	errno = 0;
1579144c6bcdSlogwang 	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1580144c6bcdSlogwang 	if (cmd == 'a')
1581144c6bcdSlogwang 		cmd = RTM_ADD;
1582144c6bcdSlogwang 	else if (cmd == 'c')
1583144c6bcdSlogwang 		cmd = RTM_CHANGE;
1584144c6bcdSlogwang 	else if (cmd == 'g' || cmd == 's') {
1585144c6bcdSlogwang 		cmd = RTM_GET;
1586144c6bcdSlogwang 		if (so[RTAX_IFP].ss_family == 0) {
1587144c6bcdSlogwang 			so[RTAX_IFP].ss_family = AF_LINK;
1588144c6bcdSlogwang 			so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl);
1589144c6bcdSlogwang 			rtm_addrs |= RTA_IFP;
1590144c6bcdSlogwang 		}
159122ce4affSfengbojiang 	} else {
1592144c6bcdSlogwang 		cmd = RTM_DELETE;
159322ce4affSfengbojiang 		flags |= RTF_PINNED;
159422ce4affSfengbojiang 	}
1595144c6bcdSlogwang #define rtm m_rtmsg.m_rtm
1596144c6bcdSlogwang 	rtm.rtm_type = cmd;
1597144c6bcdSlogwang 	rtm.rtm_flags = flags;
1598144c6bcdSlogwang 	rtm.rtm_version = RTM_VERSION;
1599144c6bcdSlogwang 	rtm.rtm_seq = ++rtm_seq;
1600144c6bcdSlogwang 	rtm.rtm_addrs = rtm_addrs;
1601144c6bcdSlogwang 	rtm.rtm_rmx = rt_metrics;
1602144c6bcdSlogwang 	rtm.rtm_inits = rtm_inits;
1603144c6bcdSlogwang 
1604144c6bcdSlogwang 	NEXTADDR(RTA_DST, so[RTAX_DST]);
1605144c6bcdSlogwang 	NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]);
1606144c6bcdSlogwang 	NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]);
1607144c6bcdSlogwang 	NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]);
1608144c6bcdSlogwang 	NEXTADDR(RTA_IFP, so[RTAX_IFP]);
1609144c6bcdSlogwang 	NEXTADDR(RTA_IFA, so[RTAX_IFA]);
1610144c6bcdSlogwang 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1611144c6bcdSlogwang 	if (verbose)
1612144c6bcdSlogwang 		print_rtmsg(&rtm, l);
1613144c6bcdSlogwang 	if (debugonly)
1614144c6bcdSlogwang 		return (0);
1615*d4a07e70Sfengbojiang #ifndef FSTACK
1616144c6bcdSlogwang 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1617*d4a07e70Sfengbojiang #else
1618*d4a07e70Sfengbojiang 	if (cmd == RTM_GET) {
1619*d4a07e70Sfengbojiang 		rlen = rtioctl((char *)&m_rtmsg, l, sizeof(m_rtmsg));
1620*d4a07e70Sfengbojiang 	} else {
1621*d4a07e70Sfengbojiang 		rlen = write(s, (char *)&m_rtmsg, l);
1622*d4a07e70Sfengbojiang 	}
1623*d4a07e70Sfengbojiang 	if (rlen < 0) {
1624*d4a07e70Sfengbojiang #endif
1625144c6bcdSlogwang 		switch (errno) {
1626144c6bcdSlogwang 		case EPERM:
1627144c6bcdSlogwang 			err(1, "writing to routing socket");
1628144c6bcdSlogwang 			break;
1629144c6bcdSlogwang 		case ESRCH:
1630144c6bcdSlogwang 			warnx("route has not been found");
1631144c6bcdSlogwang 			break;
1632144c6bcdSlogwang 		case EEXIST:
1633144c6bcdSlogwang 			/* Handled by newroute() */
1634144c6bcdSlogwang 			break;
1635144c6bcdSlogwang 		default:
1636144c6bcdSlogwang 			warn("writing to routing socket");
1637144c6bcdSlogwang 		}
1638144c6bcdSlogwang 		return (-1);
1639144c6bcdSlogwang 	}
1640144c6bcdSlogwang 	if (cmd == RTM_GET) {
1641*d4a07e70Sfengbojiang #ifndef FSTACK
164222ce4affSfengbojiang 		stop_read = 0;
164322ce4affSfengbojiang 		alarm(READ_TIMEOUT);
1644144c6bcdSlogwang 		do {
1645144c6bcdSlogwang 			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
164622ce4affSfengbojiang 		} while (l > 0 && stop_read == 0 &&
164722ce4affSfengbojiang 		    (rtm.rtm_type != RTM_GET || rtm.rtm_seq != rtm_seq ||
164822ce4affSfengbojiang 			rtm.rtm_pid != pid));
164922ce4affSfengbojiang 		if (stop_read != 0) {
165022ce4affSfengbojiang 			warnx("read from routing socket timed out");
165122ce4affSfengbojiang 			return (-1);
165222ce4affSfengbojiang 		} else
165322ce4affSfengbojiang 			alarm(0);
1654*d4a07e70Sfengbojiang #else
1655*d4a07e70Sfengbojiang 		l = rlen;
1656*d4a07e70Sfengbojiang #endif
1657144c6bcdSlogwang 		if (l < 0)
1658144c6bcdSlogwang 			warn("read from routing socket");
1659144c6bcdSlogwang 		else
1660144c6bcdSlogwang 			print_getmsg(&rtm, l, fib);
1661144c6bcdSlogwang 	}
1662144c6bcdSlogwang #undef rtm
1663144c6bcdSlogwang 	return (0);
1664144c6bcdSlogwang }
1665144c6bcdSlogwang 
1666144c6bcdSlogwang static const char *const msgtypes[] = {
1667144c6bcdSlogwang 	"",
1668144c6bcdSlogwang 	"RTM_ADD: Add Route",
1669144c6bcdSlogwang 	"RTM_DELETE: Delete Route",
1670144c6bcdSlogwang 	"RTM_CHANGE: Change Metrics or flags",
1671144c6bcdSlogwang 	"RTM_GET: Report Metrics",
1672144c6bcdSlogwang 	"RTM_LOSING: Kernel Suspects Partitioning",
1673144c6bcdSlogwang 	"RTM_REDIRECT: Told to use different route",
1674144c6bcdSlogwang 	"RTM_MISS: Lookup failed on this address",
1675144c6bcdSlogwang 	"RTM_LOCK: fix specified metrics",
1676144c6bcdSlogwang 	"RTM_OLDADD: caused by SIOCADDRT",
1677144c6bcdSlogwang 	"RTM_OLDDEL: caused by SIOCDELRT",
1678144c6bcdSlogwang 	"RTM_RESOLVE: Route created by cloning",
1679144c6bcdSlogwang 	"RTM_NEWADDR: address being added to iface",
1680144c6bcdSlogwang 	"RTM_DELADDR: address being removed from iface",
1681144c6bcdSlogwang 	"RTM_IFINFO: iface status change",
1682144c6bcdSlogwang 	"RTM_NEWMADDR: new multicast group membership on iface",
1683144c6bcdSlogwang 	"RTM_DELMADDR: multicast group membership removed from iface",
1684144c6bcdSlogwang 	"RTM_IFANNOUNCE: interface arrival/departure",
1685144c6bcdSlogwang 	"RTM_IEEE80211: IEEE 802.11 wireless event",
1686144c6bcdSlogwang };
1687144c6bcdSlogwang 
1688144c6bcdSlogwang static const char metricnames[] =
1689144c6bcdSlogwang     "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
1690144c6bcdSlogwang     "\1mtu";
1691144c6bcdSlogwang static const char routeflags[] =
1692144c6bcdSlogwang     "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
1693144c6bcdSlogwang     "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
1694144c6bcdSlogwang     "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
1695144c6bcdSlogwang     "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
1696144c6bcdSlogwang static const char ifnetflags[] =
1697144c6bcdSlogwang     "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1698144c6bcdSlogwang     "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1699144c6bcdSlogwang     "\017LINK2\020MULTICAST";
1700144c6bcdSlogwang static const char addrnames[] =
1701144c6bcdSlogwang     "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1702144c6bcdSlogwang 
1703144c6bcdSlogwang static const char errfmt[] =
1704144c6bcdSlogwang     "\n%s: truncated route message, only %zu bytes left\n";
1705144c6bcdSlogwang 
1706144c6bcdSlogwang static void
1707144c6bcdSlogwang print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
1708144c6bcdSlogwang {
1709144c6bcdSlogwang 	struct if_msghdr *ifm;
1710144c6bcdSlogwang 	struct ifa_msghdr *ifam;
1711144c6bcdSlogwang #ifdef RTM_NEWMADDR
1712144c6bcdSlogwang 	struct ifma_msghdr *ifmam;
1713144c6bcdSlogwang #endif
1714144c6bcdSlogwang 	struct if_announcemsghdr *ifan;
1715144c6bcdSlogwang 	const char *state;
1716144c6bcdSlogwang 
1717144c6bcdSlogwang 	if (verbose == 0)
1718144c6bcdSlogwang 		return;
1719144c6bcdSlogwang 	if (rtm->rtm_version != RTM_VERSION) {
1720144c6bcdSlogwang 		(void)printf("routing message version %d not understood\n",
1721144c6bcdSlogwang 		    rtm->rtm_version);
1722144c6bcdSlogwang 		return;
1723144c6bcdSlogwang 	}
1724144c6bcdSlogwang 	if (rtm->rtm_type < nitems(msgtypes))
1725144c6bcdSlogwang 		(void)printf("%s: ", msgtypes[rtm->rtm_type]);
1726144c6bcdSlogwang 	else
1727144c6bcdSlogwang 		(void)printf("unknown type %d: ", rtm->rtm_type);
1728144c6bcdSlogwang 	(void)printf("len %d, ", rtm->rtm_msglen);
1729144c6bcdSlogwang 
1730144c6bcdSlogwang #define	REQUIRE(x)	do {		\
1731144c6bcdSlogwang 	if (msglen < sizeof(x))		\
1732144c6bcdSlogwang 		goto badlen;		\
1733144c6bcdSlogwang 	else				\
1734144c6bcdSlogwang 		msglen -= sizeof(x);	\
1735144c6bcdSlogwang 	} while (0)
1736144c6bcdSlogwang 
1737144c6bcdSlogwang 	switch (rtm->rtm_type) {
1738144c6bcdSlogwang 	case RTM_IFINFO:
1739144c6bcdSlogwang 		REQUIRE(struct if_msghdr);
1740144c6bcdSlogwang 		ifm = (struct if_msghdr *)rtm;
1741144c6bcdSlogwang 		(void)printf("if# %d, ", ifm->ifm_index);
1742144c6bcdSlogwang 		switch (ifm->ifm_data.ifi_link_state) {
1743144c6bcdSlogwang 		case LINK_STATE_DOWN:
1744144c6bcdSlogwang 			state = "down";
1745144c6bcdSlogwang 			break;
1746144c6bcdSlogwang 		case LINK_STATE_UP:
1747144c6bcdSlogwang 			state = "up";
1748144c6bcdSlogwang 			break;
1749144c6bcdSlogwang 		default:
1750144c6bcdSlogwang 			state = "unknown";
1751144c6bcdSlogwang 			break;
1752144c6bcdSlogwang 		}
1753144c6bcdSlogwang 		(void)printf("link: %s, flags:", state);
1754144c6bcdSlogwang 		printb(ifm->ifm_flags, ifnetflags);
1755144c6bcdSlogwang 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen);
1756144c6bcdSlogwang 		break;
1757144c6bcdSlogwang 	case RTM_NEWADDR:
1758144c6bcdSlogwang 	case RTM_DELADDR:
1759144c6bcdSlogwang 		REQUIRE(struct ifa_msghdr);
1760144c6bcdSlogwang 		ifam = (struct ifa_msghdr *)rtm;
1761144c6bcdSlogwang 		(void)printf("metric %d, flags:", ifam->ifam_metric);
1762144c6bcdSlogwang 		printb(ifam->ifam_flags, routeflags);
1763144c6bcdSlogwang 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen);
1764144c6bcdSlogwang 		break;
1765144c6bcdSlogwang #ifdef RTM_NEWMADDR
1766144c6bcdSlogwang 	case RTM_NEWMADDR:
1767144c6bcdSlogwang 	case RTM_DELMADDR:
1768144c6bcdSlogwang 		REQUIRE(struct ifma_msghdr);
1769144c6bcdSlogwang 		ifmam = (struct ifma_msghdr *)rtm;
1770144c6bcdSlogwang 		pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen);
1771144c6bcdSlogwang 		break;
1772144c6bcdSlogwang #endif
1773144c6bcdSlogwang 	case RTM_IFANNOUNCE:
1774144c6bcdSlogwang 		REQUIRE(struct if_announcemsghdr);
1775144c6bcdSlogwang 		ifan = (struct if_announcemsghdr *)rtm;
1776144c6bcdSlogwang 		(void)printf("if# %d, what: ", ifan->ifan_index);
1777144c6bcdSlogwang 		switch (ifan->ifan_what) {
1778144c6bcdSlogwang 		case IFAN_ARRIVAL:
1779144c6bcdSlogwang 			(void)printf("arrival");
1780144c6bcdSlogwang 			break;
1781144c6bcdSlogwang 		case IFAN_DEPARTURE:
1782144c6bcdSlogwang 			printf("departure");
1783144c6bcdSlogwang 			break;
1784144c6bcdSlogwang 		default:
1785144c6bcdSlogwang 			printf("#%d", ifan->ifan_what);
1786144c6bcdSlogwang 			break;
1787144c6bcdSlogwang 		}
1788144c6bcdSlogwang 		printf("\n");
1789144c6bcdSlogwang 		fflush(stdout);
1790144c6bcdSlogwang 		break;
1791144c6bcdSlogwang 
1792144c6bcdSlogwang 	default:
179322ce4affSfengbojiang 		if (rtm->rtm_type <= RTM_RESOLVE) {
1794144c6bcdSlogwang 			printf("pid: %ld, seq %d, errno %d, flags:",
1795144c6bcdSlogwang 			    (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1796144c6bcdSlogwang 			printb(rtm->rtm_flags, routeflags);
1797144c6bcdSlogwang 			pmsg_common(rtm, msglen);
179822ce4affSfengbojiang 		} else
179922ce4affSfengbojiang 			printf("type: %u, len: %zu\n", rtm->rtm_type, msglen);
1800144c6bcdSlogwang 	}
1801144c6bcdSlogwang 
1802144c6bcdSlogwang 	return;
1803144c6bcdSlogwang 
1804144c6bcdSlogwang badlen:
1805144c6bcdSlogwang 	(void)printf(errfmt, __func__, msglen);
1806144c6bcdSlogwang #undef	REQUIRE
1807144c6bcdSlogwang }
1808144c6bcdSlogwang 
1809144c6bcdSlogwang static void
1810144c6bcdSlogwang print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
1811144c6bcdSlogwang {
1812144c6bcdSlogwang 	struct sockaddr *sp[RTAX_MAX];
1813144c6bcdSlogwang 	struct timespec ts;
1814144c6bcdSlogwang 	char *cp;
1815144c6bcdSlogwang 	int i;
1816144c6bcdSlogwang 
1817144c6bcdSlogwang 	memset(sp, 0, sizeof(sp));
1818144c6bcdSlogwang 	(void)printf("   route to: %s\n",
1819144c6bcdSlogwang 	    routename((struct sockaddr *)&so[RTAX_DST]));
1820144c6bcdSlogwang 	if (rtm->rtm_version != RTM_VERSION) {
1821144c6bcdSlogwang 		warnx("routing message version %d not understood",
1822144c6bcdSlogwang 		     rtm->rtm_version);
1823144c6bcdSlogwang 		return;
1824144c6bcdSlogwang 	}
1825144c6bcdSlogwang 	if (rtm->rtm_msglen > msglen) {
1826144c6bcdSlogwang 		warnx("message length mismatch, in packet %d, returned %d",
1827144c6bcdSlogwang 		      rtm->rtm_msglen, msglen);
1828144c6bcdSlogwang 		return;
1829144c6bcdSlogwang 	}
1830144c6bcdSlogwang 	if (rtm->rtm_errno)  {
1831144c6bcdSlogwang 		errno = rtm->rtm_errno;
1832144c6bcdSlogwang 		warn("message indicates error %d", errno);
1833144c6bcdSlogwang 		return;
1834144c6bcdSlogwang 	}
1835144c6bcdSlogwang 	cp = ((char *)(rtm + 1));
1836144c6bcdSlogwang 	for (i = 0; i < RTAX_MAX; i++)
1837144c6bcdSlogwang 		if (rtm->rtm_addrs & (1 << i)) {
1838144c6bcdSlogwang 			sp[i] = (struct sockaddr *)cp;
1839144c6bcdSlogwang 			cp += SA_SIZE((struct sockaddr *)cp);
1840144c6bcdSlogwang 		}
1841144c6bcdSlogwang 	if ((rtm->rtm_addrs & RTA_IFP) &&
1842144c6bcdSlogwang 	    (sp[RTAX_IFP]->sa_family != AF_LINK ||
1843144c6bcdSlogwang 	     ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0))
1844144c6bcdSlogwang 			sp[RTAX_IFP] = NULL;
1845144c6bcdSlogwang 	if (sp[RTAX_DST])
1846144c6bcdSlogwang 		(void)printf("destination: %s\n", routename(sp[RTAX_DST]));
1847144c6bcdSlogwang 	if (sp[RTAX_NETMASK])
1848144c6bcdSlogwang 		(void)printf("       mask: %s\n", routename(sp[RTAX_NETMASK]));
1849144c6bcdSlogwang 	if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY))
1850144c6bcdSlogwang 		(void)printf("    gateway: %s\n", routename(sp[RTAX_GATEWAY]));
1851144c6bcdSlogwang 	if (fib >= 0)
1852144c6bcdSlogwang 		(void)printf("        fib: %u\n", (unsigned int)fib);
1853144c6bcdSlogwang 	if (sp[RTAX_IFP])
1854144c6bcdSlogwang 		(void)printf("  interface: %.*s\n",
1855144c6bcdSlogwang 		    ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen,
1856144c6bcdSlogwang 		    ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data);
1857144c6bcdSlogwang 	(void)printf("      flags: ");
1858144c6bcdSlogwang 	printb(rtm->rtm_flags, routeflags);
1859144c6bcdSlogwang 
1860144c6bcdSlogwang #define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1861144c6bcdSlogwang #define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1862144c6bcdSlogwang 	printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe",
1863144c6bcdSlogwang 	    "sendpipe", "ssthresh", "rtt,msec", "mtu   ", "weight", "expire");
1864144c6bcdSlogwang 	printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1865144c6bcdSlogwang 	printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1866144c6bcdSlogwang 	printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1867144c6bcdSlogwang 	printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1868144c6bcdSlogwang 	printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1869144c6bcdSlogwang 	printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
1870144c6bcdSlogwang 	if (rtm->rtm_rmx.rmx_expire > 0)
1871144c6bcdSlogwang 		clock_gettime(CLOCK_REALTIME_FAST, &ts);
1872144c6bcdSlogwang 	else
1873144c6bcdSlogwang 		ts.tv_sec = 0;
1874144c6bcdSlogwang 	printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec),
1875144c6bcdSlogwang 	    lock(EXPIRE));
1876144c6bcdSlogwang #undef lock
1877144c6bcdSlogwang #undef msec
1878144c6bcdSlogwang #define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1879144c6bcdSlogwang 	if (verbose)
1880144c6bcdSlogwang 		pmsg_common(rtm, msglen);
1881144c6bcdSlogwang 	else if (rtm->rtm_addrs &~ RTA_IGN) {
1882144c6bcdSlogwang 		(void)printf("sockaddrs: ");
1883144c6bcdSlogwang 		printb(rtm->rtm_addrs, addrnames);
1884144c6bcdSlogwang 		putchar('\n');
1885144c6bcdSlogwang 	}
1886144c6bcdSlogwang #undef	RTA_IGN
1887144c6bcdSlogwang }
1888144c6bcdSlogwang 
1889144c6bcdSlogwang static void
1890144c6bcdSlogwang pmsg_common(struct rt_msghdr *rtm, size_t msglen)
1891144c6bcdSlogwang {
1892144c6bcdSlogwang 
1893144c6bcdSlogwang 	(void)printf("\nlocks: ");
1894144c6bcdSlogwang 	printb(rtm->rtm_rmx.rmx_locks, metricnames);
1895144c6bcdSlogwang 	(void)printf(" inits: ");
1896144c6bcdSlogwang 	printb(rtm->rtm_inits, metricnames);
1897144c6bcdSlogwang 	if (msglen > sizeof(struct rt_msghdr))
1898144c6bcdSlogwang 		pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs,
1899144c6bcdSlogwang 		    msglen - sizeof(struct rt_msghdr));
1900144c6bcdSlogwang 	else
1901144c6bcdSlogwang 		(void)fflush(stdout);
1902144c6bcdSlogwang }
1903144c6bcdSlogwang 
1904144c6bcdSlogwang static void
1905144c6bcdSlogwang pmsg_addrs(char *cp, int addrs, size_t len)
1906144c6bcdSlogwang {
1907144c6bcdSlogwang 	struct sockaddr *sa;
1908144c6bcdSlogwang 	int i;
1909144c6bcdSlogwang 
1910144c6bcdSlogwang 	if (addrs == 0) {
1911144c6bcdSlogwang 		(void)putchar('\n');
1912144c6bcdSlogwang 		return;
1913144c6bcdSlogwang 	}
1914144c6bcdSlogwang 	(void)printf("\nsockaddrs: ");
1915144c6bcdSlogwang 	printb(addrs, addrnames);
1916144c6bcdSlogwang 	putchar('\n');
1917144c6bcdSlogwang 	for (i = 0; i < RTAX_MAX; i++)
1918144c6bcdSlogwang 		if (addrs & (1 << i)) {
1919144c6bcdSlogwang 			sa = (struct sockaddr *)cp;
1920144c6bcdSlogwang 			if (len == 0 || len < SA_SIZE(sa)) {
1921144c6bcdSlogwang 				(void)printf(errfmt, __func__, len);
1922144c6bcdSlogwang 				break;
1923144c6bcdSlogwang 			}
1924144c6bcdSlogwang 			(void)printf(" %s", routename(sa));
1925144c6bcdSlogwang 			len -= SA_SIZE(sa);
1926144c6bcdSlogwang 			cp += SA_SIZE(sa);
1927144c6bcdSlogwang 		}
1928144c6bcdSlogwang 	(void)putchar('\n');
1929144c6bcdSlogwang 	(void)fflush(stdout);
1930144c6bcdSlogwang }
1931144c6bcdSlogwang 
1932144c6bcdSlogwang static void
1933144c6bcdSlogwang printb(int b, const char *str)
1934144c6bcdSlogwang {
1935144c6bcdSlogwang 	int i;
1936144c6bcdSlogwang 	int gotsome = 0;
1937144c6bcdSlogwang 
1938144c6bcdSlogwang 	if (b == 0)
1939144c6bcdSlogwang 		return;
1940144c6bcdSlogwang 	while ((i = *str++) != 0) {
1941144c6bcdSlogwang 		if (b & (1 << (i-1))) {
1942144c6bcdSlogwang 			if (gotsome == 0)
1943144c6bcdSlogwang 				i = '<';
1944144c6bcdSlogwang 			else
1945144c6bcdSlogwang 				i = ',';
1946144c6bcdSlogwang 			putchar(i);
1947144c6bcdSlogwang 			gotsome = 1;
1948144c6bcdSlogwang 			for (; (i = *str) > 32; str++)
1949144c6bcdSlogwang 				putchar(i);
1950144c6bcdSlogwang 		} else
1951144c6bcdSlogwang 			while (*str > 32)
1952144c6bcdSlogwang 				str++;
1953144c6bcdSlogwang 	}
1954144c6bcdSlogwang 	if (gotsome)
1955144c6bcdSlogwang 		putchar('>');
1956144c6bcdSlogwang }
1957144c6bcdSlogwang 
1958144c6bcdSlogwang int
1959144c6bcdSlogwang keyword(const char *cp)
1960144c6bcdSlogwang {
1961144c6bcdSlogwang 	const struct keytab *kt = keywords;
1962144c6bcdSlogwang 
1963144c6bcdSlogwang 	while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0)
1964144c6bcdSlogwang 		kt++;
1965144c6bcdSlogwang 	return (kt->kt_i);
1966144c6bcdSlogwang }
1967144c6bcdSlogwang 
1968144c6bcdSlogwang static void
1969144c6bcdSlogwang sodump(struct sockaddr *sa, const char *which)
1970144c6bcdSlogwang {
1971144c6bcdSlogwang #ifdef INET6
1972144c6bcdSlogwang 	char nbuf[INET6_ADDRSTRLEN];
1973144c6bcdSlogwang #endif
1974144c6bcdSlogwang 
1975144c6bcdSlogwang 	switch (sa->sa_family) {
1976144c6bcdSlogwang 	case AF_LINK:
1977144c6bcdSlogwang 		(void)printf("%s: link %s; ", which,
1978144c6bcdSlogwang 		    link_ntoa((struct sockaddr_dl *)(void *)sa));
1979144c6bcdSlogwang 		break;
1980144c6bcdSlogwang #ifdef INET
1981144c6bcdSlogwang 	case AF_INET:
1982144c6bcdSlogwang 		(void)printf("%s: inet %s; ", which,
1983144c6bcdSlogwang 		    inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr));
1984144c6bcdSlogwang 		break;
1985144c6bcdSlogwang #endif
1986144c6bcdSlogwang #ifdef INET6
1987144c6bcdSlogwang 	case AF_INET6:
1988*d4a07e70Sfengbojiang #ifndef FSTACK
1989144c6bcdSlogwang 		(void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family,
1990*d4a07e70Sfengbojiang #else
1991*d4a07e70Sfengbojiang 		(void)printf("%s: inet6 %s; ", which, inet_ntop(AF_INET6_LINUX,
1992*d4a07e70Sfengbojiang #endif
1993144c6bcdSlogwang 		    &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf,
1994144c6bcdSlogwang 		    sizeof(nbuf)));
1995144c6bcdSlogwang 		break;
1996144c6bcdSlogwang #endif
1997144c6bcdSlogwang 	}
1998144c6bcdSlogwang 	(void)fflush(stdout);
1999144c6bcdSlogwang }
2000144c6bcdSlogwang 
2001144c6bcdSlogwang /* States*/
2002144c6bcdSlogwang #define VIRGIN	0
2003144c6bcdSlogwang #define GOTONE	1
2004144c6bcdSlogwang #define GOTTWO	2
2005144c6bcdSlogwang /* Inputs */
2006144c6bcdSlogwang #define	DIGIT	(4*0)
2007144c6bcdSlogwang #define	END	(4*1)
2008144c6bcdSlogwang #define DELIM	(4*2)
2009144c6bcdSlogwang 
2010144c6bcdSlogwang static void
2011144c6bcdSlogwang sockaddr(char *addr, struct sockaddr *sa, size_t size)
2012144c6bcdSlogwang {
2013144c6bcdSlogwang 	char *cp = (char *)sa;
2014144c6bcdSlogwang 	char *cplim = cp + size;
2015144c6bcdSlogwang 	int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
2016144c6bcdSlogwang 
2017144c6bcdSlogwang 	memset(cp, 0, size);
2018144c6bcdSlogwang 	cp++;
2019144c6bcdSlogwang 	do {
2020144c6bcdSlogwang 		if ((*addr >= '0') && (*addr <= '9')) {
2021144c6bcdSlogwang 			new = *addr - '0';
2022144c6bcdSlogwang 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2023144c6bcdSlogwang 			new = *addr - 'a' + 10;
2024144c6bcdSlogwang 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2025144c6bcdSlogwang 			new = *addr - 'A' + 10;
2026144c6bcdSlogwang 		} else if (*addr == '\0')
2027144c6bcdSlogwang 			state |= END;
2028144c6bcdSlogwang 		else
2029144c6bcdSlogwang 			state |= DELIM;
2030144c6bcdSlogwang 		addr++;
2031144c6bcdSlogwang 		switch (state /* | INPUT */) {
2032144c6bcdSlogwang 		case GOTTWO | DIGIT:
2033144c6bcdSlogwang 			*cp++ = byte; /*FALLTHROUGH*/
2034144c6bcdSlogwang 		case VIRGIN | DIGIT:
2035144c6bcdSlogwang 			state = GOTONE; byte = new; continue;
2036144c6bcdSlogwang 		case GOTONE | DIGIT:
2037144c6bcdSlogwang 			state = GOTTWO; byte = new + (byte << 4); continue;
2038144c6bcdSlogwang 		default: /* | DELIM */
2039144c6bcdSlogwang 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
2040144c6bcdSlogwang 		case GOTONE | END:
2041144c6bcdSlogwang 		case GOTTWO | END:
2042144c6bcdSlogwang 			*cp++ = byte; /* FALLTHROUGH */
2043144c6bcdSlogwang 		case VIRGIN | END:
2044144c6bcdSlogwang 			break;
2045144c6bcdSlogwang 		}
2046144c6bcdSlogwang 		break;
2047144c6bcdSlogwang 	} while (cp < cplim);
2048144c6bcdSlogwang 	sa->sa_len = cp - (char *)sa;
2049144c6bcdSlogwang }
2050