xref: /original-bsd/usr.bin/netstat/route.c (revision cd18b70b)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)route.c	5.11 (Berkeley) 87/08/29";
9 #endif
10 
11 #include <stdio.h>
12 #include <strings.h>
13 
14 #include <sys/param.h>
15 #include <sys/socket.h>
16 #include <sys/mbuf.h>
17 
18 #include <net/if.h>
19 #include <net/route.h>
20 #include <netinet/in.h>
21 
22 #include <netns/ns.h>
23 
24 #include <netdb.h>
25 
26 extern	int kmem;
27 extern	int nflag;
28 extern	char *routename(), *netname(), *ns_print(), *plural();
29 extern	char *malloc();
30 
31 /*
32  * Definitions for showing gateway flags.
33  */
34 struct bits {
35 	short	b_mask;
36 	char	b_val;
37 } bits[] = {
38 	{ RTF_UP,	'U' },
39 	{ RTF_GATEWAY,	'G' },
40 	{ RTF_HOST,	'H' },
41 	{ RTF_DYNAMIC,	'D' },
42 	{ RTF_MODIFIED,	'M' },
43 	{ 0 }
44 };
45 
46 /*
47  * Print routing tables.
48  */
49 routepr(hostaddr, netaddr, hashsizeaddr)
50 	off_t hostaddr, netaddr, hashsizeaddr;
51 {
52 	struct mbuf mb;
53 	register struct rtentry *rt;
54 	register struct mbuf *m;
55 	register struct bits *p;
56 	char name[16], *flags;
57 	struct mbuf **routehash;
58 	struct ifnet ifnet;
59 	int hashsize;
60 	int i, doinghost = 1;
61 
62 	if (hostaddr == 0) {
63 		printf("rthost: symbol not in namelist\n");
64 		return;
65 	}
66 	if (netaddr == 0) {
67 		printf("rtnet: symbol not in namelist\n");
68 		return;
69 	}
70 	if (hashsizeaddr == 0) {
71 		printf("rthashsize: symbol not in namelist\n");
72 		return;
73 	}
74 	klseek(kmem, hashsizeaddr, 0);
75 	read(kmem, (char *)&hashsize, sizeof (hashsize));
76 	routehash = (struct mbuf **)malloc( hashsize*sizeof (struct mbuf *) );
77 	klseek(kmem, hostaddr, 0);
78 	read(kmem, (char *)routehash, hashsize*sizeof (struct mbuf *));
79 	printf("Routing tables\n");
80 	printf("%-16.16s %-18.18s %-6.6s  %6.6s%8.8s  %s\n",
81 		"Destination", "Gateway",
82 		"Flags", "Refs", "Use", "Interface");
83 again:
84 	for (i = 0; i < hashsize; i++) {
85 		if (routehash[i] == 0)
86 			continue;
87 		m = routehash[i];
88 		while (m) {
89 			struct sockaddr_in *sin;
90 
91 			klseek(kmem, (off_t)m, 0);
92 			read(kmem, (char *)&mb, sizeof (mb));
93 			rt = mtod(&mb, struct rtentry *);
94 			if ((unsigned)rt < (unsigned)&mb ||
95 			    (unsigned)rt >= (unsigned)(&mb + 1)) {
96 				printf("???\n");
97 				return;
98 			}
99 
100 			switch(rt->rt_dst.sa_family) {
101 			case AF_INET:
102 				sin = (struct sockaddr_in *)&rt->rt_dst;
103 				printf("%-16.16s ",
104 				    (sin->sin_addr.s_addr == 0) ? "default" :
105 				    (rt->rt_flags & RTF_HOST) ?
106 				    routename(sin->sin_addr) :
107 					netname(sin->sin_addr, 0L));
108 				sin = (struct sockaddr_in *)&rt->rt_gateway;
109 				printf("%-18.18s ", routename(sin->sin_addr));
110 				break;
111 			case AF_NS:
112 				printf("%-16s ",
113 				    ns_print((struct sockaddr_ns *)&rt->rt_dst));
114 				printf("%-18s ",
115 				    ns_print((struct sockaddr_ns *)&rt->rt_gateway));
116 				break;
117 			default:
118 				{
119 				u_short *s = (u_short *)rt->rt_dst.sa_data;
120 				printf("(%d)%x %x %x %x %x %x %x ",
121 				    rt->rt_dst.sa_family,
122 				    s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
123 				s = (u_short *)rt->rt_gateway.sa_data;
124 				printf("(%d)%x %x %x %x %x %x %x ",
125 				    rt->rt_gateway.sa_family,
126 				    s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
127 				}
128 			}
129 			for (flags = name, p = bits; p->b_mask; p++)
130 				if (p->b_mask & rt->rt_flags)
131 					*flags++ = p->b_val;
132 			*flags = '\0';
133 			printf("%-6.6s %6d %8d ", name,
134 				rt->rt_refcnt, rt->rt_use);
135 			if (rt->rt_ifp == 0) {
136 				putchar('\n');
137 				m = mb.m_next;
138 				continue;
139 			}
140 			klseek(kmem, (off_t)rt->rt_ifp, 0);
141 			read(kmem, (char *)&ifnet, sizeof (ifnet));
142 			klseek(kmem, (off_t)ifnet.if_name, 0);
143 			read(kmem, name, 16);
144 			printf(" %s%d\n", name, ifnet.if_unit);
145 			m = mb.m_next;
146 		}
147 	}
148 	if (doinghost) {
149 		klseek(kmem, netaddr, 0);
150 		read(kmem, (char *)routehash, hashsize*sizeof (struct mbuf *));
151 		doinghost = 0;
152 		goto again;
153 	}
154 	free((char *)routehash);
155 }
156 
157 char *
158 routename(in)
159 	struct in_addr in;
160 {
161 	register char *cp;
162 	static char line[50];
163 	struct hostent *hp;
164 	static char domain[MAXHOSTNAMELEN + 1];
165 	static int first = 1;
166 	char *index();
167 
168 	if (first) {
169 		first = 0;
170 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
171 		    (cp = index(domain, '.')))
172 			(void) strcpy(domain, cp + 1);
173 		else
174 			domain[0] = 0;
175 	}
176 	cp = 0;
177 	if (!nflag) {
178 		hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
179 			AF_INET);
180 		if (hp) {
181 			if ((cp = index(hp->h_name, '.')) &&
182 			    !strcmp(cp + 1, domain))
183 				*cp = 0;
184 			cp = hp->h_name;
185 		}
186 	}
187 	if (cp)
188 		strcpy(line, cp);
189 	else {
190 #define C(x)	((x) & 0xff)
191 		in.s_addr = ntohl(in.s_addr);
192 		sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
193 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
194 	}
195 	return (line);
196 }
197 
198 /*
199  * Return the name of the network whose address is given.
200  * The address is assumed to be that of a net or subnet, not a host.
201  */
202 char *
203 netname(in, mask)
204 	struct in_addr in;
205 	u_long mask;
206 {
207 	char *cp = 0;
208 	static char line[50];
209 	struct netent *np = 0;
210 	u_long net;
211 	register i;
212 	int subnetshift;
213 
214 	i = ntohl(in.s_addr);
215 	if (!nflag && i) {
216 		if (mask == 0) {
217 			if (IN_CLASSA(i)) {
218 				mask = IN_CLASSA_NET;
219 				subnetshift = 8;
220 			} else if (IN_CLASSB(i)) {
221 				mask = IN_CLASSB_NET;
222 				subnetshift = 8;
223 			} else {
224 				mask = IN_CLASSC_NET;
225 				subnetshift = 4;
226 			}
227 			/*
228 			 * If there are more bits than the standard mask
229 			 * would suggest, subnets must be in use.
230 			 * Guess at the subnet mask, assuming reasonable
231 			 * width subnet fields.
232 			 */
233 			while (i &~ mask)
234 				mask = (long)mask >> subnetshift;
235 		}
236 		net = i & mask;
237 		while ((mask & 1) == 0)
238 			mask >>= 1, net >>= 1;
239 		np = getnetbyaddr(net, AF_INET);
240 		if (np)
241 			cp = np->n_name;
242 	}
243 	if (cp)
244 		strcpy(line, cp);
245 	else if ((i & 0xffffff) == 0)
246 		sprintf(line, "%u", C(i >> 24));
247 	else if ((i & 0xffff) == 0)
248 		sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16));
249 	else if ((i & 0xff) == 0)
250 		sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8));
251 	else
252 		sprintf(line, "%u.%u.%u.%u", C(i >> 24),
253 			C(i >> 16), C(i >> 8), C(i));
254 	return (line);
255 }
256 
257 /*
258  * Print routing statistics
259  */
260 rt_stats(off)
261 	off_t off;
262 {
263 	struct rtstat rtstat;
264 
265 	if (off == 0) {
266 		printf("rtstat: symbol not in namelist\n");
267 		return;
268 	}
269 	klseek(kmem, off, 0);
270 	read(kmem, (char *)&rtstat, sizeof (rtstat));
271 	printf("routing:\n");
272 	printf("\t%u bad routing redirect%s\n",
273 		rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
274 	printf("\t%u dynamically created route%s\n",
275 		rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
276 	printf("\t%u new gateway%s due to redirects\n",
277 		rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
278 	printf("\t%u destination%s found unreachable\n",
279 		rtstat.rts_unreach, plural(rtstat.rts_unreach));
280 	printf("\t%u use%s of a wildcard route\n",
281 		rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
282 }
283 short ns_nullh[] = {0,0,0};
284 short ns_bh[] = {-1,-1,-1};
285 
286 char *
287 ns_print(sns)
288 struct sockaddr_ns *sns;
289 {
290 	struct ns_addr work;
291 	union { union ns_net net_e; u_long long_e; } net;
292 	u_short port;
293 	static char mybuf[50], cport[10], chost[25];
294 	char *host = "";
295 	register char *p; register u_char *q;
296 
297 	work = sns->sns_addr;
298 	port = ntohs(work.x_port);
299 	work.x_port = 0;
300 	net.net_e  = work.x_net;
301 	if (ns_nullhost(work) && net.long_e == 0) {
302 		if (port ) {
303 			sprintf(mybuf, "*.%xH", port);
304 			upHex(mybuf);
305 		} else
306 			sprintf(mybuf, "*.*");
307 		return (mybuf);
308 	}
309 
310 	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
311 		host = "any";
312 	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
313 		host = "*";
314 	} else {
315 		q = work.x_host.c_host;
316 		sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
317 			q[0], q[1], q[2], q[3], q[4], q[5]);
318 		for (p = chost; *p == '0' && p < chost + 12; p++);
319 		host = p;
320 	}
321 	if (port)
322 		sprintf(cport, ".%xH", htons(port));
323 	else
324 		*cport = 0;
325 
326 	sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
327 	upHex(mybuf);
328 	return(mybuf);
329 }
330 
331 char *
332 ns_phost(sns)
333 struct sockaddr_ns *sns;
334 {
335 	struct sockaddr_ns work;
336 	static union ns_net ns_zeronet;
337 	char *p;
338 
339 	work = *sns;
340 	work.sns_addr.x_port = 0;
341 	work.sns_addr.x_net = ns_zeronet;
342 
343 	p = ns_print(&work);
344 	if (strncmp("0H.", p, 3) == 0) p += 3;
345 	return(p);
346 }
347 upHex(p0)
348 char *p0;
349 {
350 	register char *p = p0;
351 	for (; *p; p++) switch (*p) {
352 
353 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
354 		*p += ('A' - 'a');
355 	}
356 }
357