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