2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static char sccsid
[] = "From: @(#)route.c 8.3 (Berkeley) 3/9/94";
38 static const char rcsid
[] =
42 #include <sys/param.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
51 #include <net/route.h>
53 #include <netinet/in.h>
60 #include <sys/sysctl.h>
72 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
75 * Definitions for showing gateway flags.
86 { RTF_MODIFIED
, 'M' },
87 { RTF_DONE
, 'd' }, /* Completed -- for routing messages only */
88 { RTF_MASK
, 'm' }, /* Mask Present -- for routing messages only */
90 { RTF_XRESOLVE
, 'X' },
95 { RTF_WASCLONED
,'W' },
96 { RTF_PRCLONING
,'c' },
102 struct sockaddr u_sa
;
107 struct rtentry rtentry
;
108 struct radix_node rnode
;
109 struct radix_mask rmask
;
110 struct radix_node_head
*rt_tables
[AF_MAX
+1];
114 static struct sockaddr
*kgetsa
__P((struct sockaddr
*));
115 static void p_tree
__P((struct radix_node
*));
116 static void p_rtnode
__P(());
117 static void ntreestuff
__P(());
118 static void np_rtentry
__P((struct rt_msghdr
*));
119 static void p_sockaddr
__P((struct sockaddr
*, int, int));
120 static void p_flags
__P((int, char *));
121 static void p_rtentry
__P((struct rtentry
*));
124 * Print routing tables.
130 struct radix_node_head
*rnh
, head
;
133 printf("Routing tables\n");
136 if (Aflag
== 0 && NewTree
)
141 printf("rt_tables: symbol not in namelist\n");
145 kget(rtree
, rt_tables
);
146 for (i
= 0; i
<= AF_MAX
; i
++) {
147 if ((rnh
= rt_tables
[i
]) == 0)
150 if (i
== AF_UNSPEC
) {
151 if (Aflag
&& af
== 0) {
152 printf("Netmasks:\n");
153 p_tree(head
.rnh_treetop
);
155 } else if (af
== AF_UNSPEC
|| af
== i
) {
159 p_tree(head
.rnh_treetop
);
168 * Print address family header before a section of the routing table.
194 printf("\n%s:\n", afname
);
196 printf("\nProtocol Family %d:\n", af
);
199 /* column widths; each followed by one space */
200 #define WID_DST 16 /* width of destination column */
201 #define WID_GW 18 /* width of gateway column */
204 * Print header for routing table columns.
211 printf("%-8.8s ","Address");
212 printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
213 WID_DST
, WID_DST
, "Destination",
214 WID_GW
, WID_GW
, "Gateway",
215 "Flags", "Refs", "Use", "Netif", "Expire");
218 static struct sockaddr
*
220 register struct sockaddr
*dst
;
223 kget(dst
, pt_u
.u_sa
);
224 if (pt_u
.u_sa
.sa_len
> sizeof (pt_u
.u_sa
))
225 kread((u_long
)dst
, (char *)pt_u
.u_data
, pt_u
.u_sa
.sa_len
);
231 struct radix_node
*rn
;
236 if (rnode
.rn_b
< 0) {
238 printf("%-8.8x ", rn
);
239 if (rnode
.rn_flags
& RNF_ROOT
) {
241 printf("(root node)%s",
242 rnode
.rn_dupedkey
? " =>\n" : "\n");
243 } else if (do_rtent
) {
249 p_sockaddr(kgetsa((struct sockaddr
*)rnode
.rn_key
),
253 if (rn
= rnode
.rn_dupedkey
)
256 if (Aflag
&& do_rtent
) {
257 printf("%-8.8x ", rn
);
271 struct radix_mask
*rm
= rnode
.rn_mklist
;
273 if (rnode
.rn_b
< 0) {
276 p_sockaddr(kgetsa((struct sockaddr
*)rnode
.rn_mask
),
281 sprintf(nbuf
, "(%d)", rnode
.rn_b
);
282 printf("%6.6s %8.8x : %8.8x", nbuf
, rnode
.rn_l
, rnode
.rn_r
);
286 sprintf(nbuf
, " %d refs, ", rmask
.rm_refs
);
287 printf(" mk = %8.8x {(%d),%s",
288 rm
, -1 - rmask
.rm_b
, rmask
.rm_refs
? nbuf
: " ");
289 p_sockaddr(kgetsa((struct sockaddr
*)rmask
.rm_mask
), 0, -1);
291 if (rm
= rmask
.rm_mklist
)
303 char *buf
, *next
, *lim
;
304 register struct rt_msghdr
*rtm
;
310 mib
[4] = NET_RT_DUMP
;
312 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
313 err(1, "sysctl: net.route.0.0.dump estimate");
316 if ((buf
= malloc(needed
)) == 0) {
317 err(2, "malloc(%lu)", (unsigned long)needed
);
319 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
320 err(1, "sysctl: net.route.0.0.dump");
323 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
324 rtm
= (struct rt_msghdr
*)next
;
332 register struct rt_msghdr
*rtm
;
334 register struct sockaddr
*sa
= (struct sockaddr
*)(rtm
+ 1);
336 static int masks_done
, banner_printed
;
339 int af
= 0, interesting
= RTF_UP
| RTF_GATEWAY
| RTF_HOST
;
342 /* for the moment, netmasks are skipped over */
343 if (!banner_printed
) {
344 printf("Netmasks:\n");
347 if (masks_done
== 0) {
348 if (rtm
->rtm_addrs
!= RTA_DST
) {
359 if (rtm
->rtm_addrs
== RTA_DST
)
360 p_sockaddr(sa
, 0, 36);
362 p_sockaddr(sa
, rtm
->rtm_flags
, 16);
364 sa
->sa_len
= sizeof(long);
365 sa
= (struct sockaddr
*)(sa
->sa_len
+ (char *)sa
);
366 p_sockaddr(sa
, 0, 18);
368 p_flags(rtm
->rtm_flags
& interesting
, "%-6.6s ");
373 p_sockaddr(sa
, flags
, width
)
377 char workbuf
[128], *cplim
;
378 register char *cp
= workbuf
;
380 switch(sa
->sa_family
) {
383 register struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
385 cp
= (sin
->sin_addr
.s_addr
== 0) ? "default" :
386 ((flags
& RTF_HOST
) ?
387 routename(sin
->sin_addr
.s_addr
) :
388 netname(sin
->sin_addr
.s_addr
, 0L));
398 register struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)sa
;
400 if (sdl
->sdl_nlen
== 0 && sdl
->sdl_alen
== 0 &&
402 (void) sprintf(workbuf
, "link#%d", sdl
->sdl_index
);
403 else switch (sdl
->sdl_type
) {
407 register u_char
*lla
= (u_char
*)sdl
->sdl_data
+
411 for (i
= 0; i
< sdl
->sdl_alen
; i
++, lla
++) {
412 cp
+= sprintf(cp
, "%s%x", cplim
, *lla
);
427 register u_char
*s
= (u_char
*)sa
->sa_data
, *slim
;
429 slim
= sa
->sa_len
+ (u_char
*) sa
;
430 cplim
= cp
+ sizeof(workbuf
) - 6;
431 cp
+= sprintf(cp
, "(%d)", sa
->sa_family
);
432 while (s
< slim
&& cp
< cplim
) {
433 cp
+= sprintf(cp
, " %02x", *s
++);
435 cp
+= sprintf(cp
, "%02x", *s
++);
444 printf("%-*s ", width
, cp
);
446 printf("%-*.*s ", width
, width
, cp
);
455 char name
[33], *flags
;
456 register struct bits
*p
= bits
;
458 for (flags
= name
; p
->b_mask
; p
++)
462 printf(format
, name
);
467 register struct rtentry
*rt
;
469 static struct ifnet ifnet
, *lastif
;
470 static char name
[16];
471 static char prettyname
[9];
474 * Don't print protocol-cloned routes unless -a.
476 if(rt
->rt_parent
&& !aflag
)
479 p_sockaddr(kgetsa(rt_key(rt
)), rt
->rt_flags
, WID_DST
);
480 p_sockaddr(kgetsa(rt
->rt_gateway
), RTF_HOST
, WID_GW
);
481 p_flags(rt
->rt_flags
, "%-6.6s ");
482 printf("%6d %8d ", rt
->rt_refcnt
, rt
->rt_use
);
484 if (rt
->rt_ifp
!= lastif
) {
485 kget(rt
->rt_ifp
, ifnet
);
486 kread((u_long
)ifnet
.if_name
, name
, 16);
488 snprintf(prettyname
, sizeof prettyname
,
489 "%.6s%d", name
, ifnet
.if_unit
);
491 if(rt
->rt_rmx
.rmx_expire
) {
495 =rt
->rt_rmx
.rmx_expire
- time((time_t *)0)) > 0)
496 printf(" %8.8s %6d%s", prettyname
,
498 rt
->rt_nodes
[0].rn_dupedkey
? " =>" : "");
500 printf(" %8.8s%s", prettyname
,
501 rt
->rt_nodes
[0].rn_dupedkey
? " =>" : "");
513 static char line
[MAXHOSTNAMELEN
+ 1];
515 static char domain
[MAXHOSTNAMELEN
+ 1];
516 static int first
= 1;
520 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
521 (cp
= index(domain
, '.')))
522 (void) strcpy(domain
, cp
+ 1);
528 hp
= gethostbyaddr((char *)&in
, sizeof (struct in_addr
),
531 if ((cp
= index(hp
->h_name
, '.')) &&
532 !strcmp(cp
+ 1, domain
))
538 strncpy(line
, cp
, sizeof(line
) - 1);
540 #define C(x) ((x) & 0xff)
542 sprintf(line
, "%u.%u.%u.%u",
543 C(in
>> 24), C(in
>> 16), C(in
>> 8), C(in
));
549 * Return the name of the network whose address is given.
550 * The address is assumed to be that of a net or subnet, not a host.
557 static char line
[MAXHOSTNAMELEN
+ 1];
558 struct netent
*np
= 0;
567 mask
= IN_CLASSA_NET
;
569 } else if (IN_CLASSB(i
)) {
570 mask
= IN_CLASSB_NET
;
573 mask
= IN_CLASSC_NET
;
577 * If there are more bits than the standard mask
578 * would suggest, subnets must be in use.
579 * Guess at the subnet mask, assuming reasonable
580 * width subnet fields.
583 mask
= (long)mask
>> subnetshift
;
586 while ((mask
& 1) == 0)
587 mask
>>= 1, net
>>= 1;
588 np
= getnetbyaddr(net
, AF_INET
);
593 strncpy(line
, cp
, sizeof(line
) - 1);
594 else if ((i
& 0xffffff) == 0)
595 sprintf(line
, "%u", C(i
>> 24));
596 else if ((i
& 0xffff) == 0)
597 sprintf(line
, "%u.%u", C(i
>> 24) , C(i
>> 16));
598 else if ((i
& 0xff) == 0)
599 sprintf(line
, "%u.%u.%u", C(i
>> 24), C(i
>> 16), C(i
>> 8));
601 sprintf(line
, "%u.%u.%u.%u", C(i
>> 24),
602 C(i
>> 16), C(i
>> 8), C(i
));
607 * Print routing statistics
613 struct rtstat rtstat
;
616 printf("rtstat: symbol not in namelist\n");
619 kread(off
, (char *)&rtstat
, sizeof (rtstat
));
620 printf("routing:\n");
621 printf("\t%u bad routing redirect%s\n",
622 rtstat
.rts_badredirect
, plural(rtstat
.rts_badredirect
));
623 printf("\t%u dynamically created route%s\n",
624 rtstat
.rts_dynamic
, plural(rtstat
.rts_dynamic
));
625 printf("\t%u new gateway%s due to redirects\n",
626 rtstat
.rts_newgateway
, plural(rtstat
.rts_newgateway
));
627 printf("\t%u destination%s found unreachable\n",
628 rtstat
.rts_unreach
, plural(rtstat
.rts_unreach
));
629 printf("\t%u use%s of a wildcard route\n",
630 rtstat
.rts_wildcard
, plural(rtstat
.rts_wildcard
));
634 short ns_nullh
[] = {0,0,0};
635 short ns_bh
[] = {-1,-1,-1};
639 register struct sockaddr
*sa
;
641 register struct sockaddr_ns
*sns
= (struct sockaddr_ns
*)sa
;
643 union { union ns_net net_e
; u_long long_e
; } net
;
645 static char mybuf
[50], cport
[10], chost
[25];
647 register char *p
; register u_char
*q
;
649 work
= sns
->sns_addr
;
650 port
= ntohs(work
.x_port
);
652 net
.net_e
= work
.x_net
;
653 if (ns_nullhost(work
) && net
.long_e
== 0) {
655 sprintf(mybuf
, "*.%xH", port
);
658 sprintf(mybuf
, "*.*");
662 if (bcmp(ns_bh
, work
.x_host
.c_host
, 6) == 0) {
664 } else if (bcmp(ns_nullh
, work
.x_host
.c_host
, 6) == 0) {
667 q
= work
.x_host
.c_host
;
668 sprintf(chost
, "%02x%02x%02x%02x%02x%02xH",
669 q
[0], q
[1], q
[2], q
[3], q
[4], q
[5]);
670 for (p
= chost
; *p
== '0' && p
< chost
+ 12; p
++)
675 sprintf(cport
, ".%xH", htons(port
));
679 sprintf(mybuf
,"%xH.%s%s", ntohl(net
.long_e
), host
, cport
);
688 register struct sockaddr_ns
*sns
= (struct sockaddr_ns
*)sa
;
689 struct sockaddr_ns work
;
690 static union ns_net ns_zeronet
;
694 work
.sns_addr
.x_port
= 0;
695 work
.sns_addr
.x_net
= ns_zeronet
;
697 p
= ns_print((struct sockaddr
*)&work
);
698 if (strncmp("0H.", p
, 3) == 0) p
+= 3;
706 register char *p
= p0
;
707 for (; *p
; p
++) switch (*p
) {
709 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':