]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/route.c
d087959213aae9780cd4c4e4ccdac2d4ec342ee4
[apple/network_cmds.git] / netstat.tproj / route.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1983, 1988, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56 #ifndef lint
57 #if 0
58 static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95";
59 #endif
60 static const char rcsid[] =
61 "$Id: route.c,v 1.7 2004/10/14 22:24:09 lindak Exp $";
62 #endif /* not lint */
63
64 #include <sys/param.h>
65 #include <sys/socket.h>
66 #include <sys/time.h>
67
68 #include <net/if.h>
69 #include <net/if_var.h>
70 #include <net/if_dl.h>
71 #include <net/if_types.h>
72 #include <net/route.h>
73 #include <net/radix.h>
74
75 #include <netinet/in.h>
76 #ifndef __APPLE__
77 #include <netipx/ipx.h>
78 #include <netatalk/at.h>
79 #include <netgraph/ng_socket.h>
80 #endif
81
82 #ifdef NS
83 #include <netns/ns.h>
84 #endif
85
86 #include <sys/sysctl.h>
87
88 #include <arpa/inet.h>
89 #ifndef __APPLE__
90 #include <libutil.h>
91 #endif
92 #include <netdb.h>
93 #include <stdio.h>
94 #include <stdlib.h>
95 #include <string.h>
96 #include <unistd.h>
97 #include <err.h>
98 #include <time.h>
99 #include "netstat.h"
100
101 #if 0
102 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
103 #endif
104
105 /* alignment constraint for routing socket */
106 #define ROUNDUP(a) \
107 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
108 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
109
110 /*
111 * Definitions for showing gateway flags.
112 */
113 struct bits {
114 u_long b_mask;
115 char b_val;
116 } bits[] = {
117 { RTF_UP, 'U' },
118 { RTF_GATEWAY, 'G' },
119 { RTF_HOST, 'H' },
120 { RTF_REJECT, 'R' },
121 { RTF_DYNAMIC, 'D' },
122 { RTF_MODIFIED, 'M' },
123 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
124 { RTF_CLONING, 'C' },
125 { RTF_XRESOLVE, 'X' },
126 { RTF_LLINFO, 'L' },
127 { RTF_STATIC, 'S' },
128 { RTF_PROTO1, '1' },
129 { RTF_PROTO2, '2' },
130 { RTF_WASCLONED,'W' },
131 { RTF_PRCLONING,'c' },
132 { RTF_PROTO3, '3' },
133 { RTF_BLACKHOLE,'B' },
134 { RTF_BROADCAST,'b' },
135 { 0 }
136 };
137
138 typedef union {
139 long dummy; /* Helps align structure. */
140 struct sockaddr u_sa;
141 u_short u_data[128];
142 } sa_u;
143
144 #if 0
145 static sa_u pt_u;
146 #endif
147
148 int do_rtent = 0;
149 struct rtentry rtentry;
150 struct radix_node rnode;
151 struct radix_mask rmask;
152 struct radix_node_head *rt_tables[AF_MAX+1];
153
154 #if 0
155 static struct sockaddr *kgetsa __P((struct sockaddr *));
156 static void p_tree __P((struct radix_node *));
157 static void p_rtnode __P((void));
158 static void p_rtentry __P((struct rtentry *));
159 #endif
160 static void ntreestuff __P((void));
161 static void np_rtentry __P((struct rt_msghdr2 *));
162 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
163 static void p_flags __P((int, char *));
164 static u_long forgemask __P((u_long));
165 static void domask __P((char *, u_long, u_long));
166
167 /*
168 * Print routing tables.
169 */
170 void
171 routepr(u_long rtree)
172 {
173 #if 0
174 struct radix_node_head *rnh, head;
175 int i;
176 #endif
177
178 printf("Routing tables\n");
179
180 if (dflag == 0)
181 ntreestuff();
182 else {
183 if (rtree == 0) {
184 printf("rt_tables: symbol not in namelist\n");
185 return;
186 }
187 #if 0
188 kget(rtree, rt_tables);
189 for (i = 0; i <= AF_MAX; i++) {
190 if ((rnh = rt_tables[i]) == 0)
191 continue;
192 kget(rnh, head);
193 if (i == AF_UNSPEC) {
194 if (Aflag && af == 0) {
195 printf("Netmasks:\n");
196 p_tree(head.rnh_treetop);
197 }
198 } else if (af == AF_UNSPEC || af == i) {
199 pr_family(i);
200 do_rtent = 1;
201 pr_rthdr(i);
202 p_tree(head.rnh_treetop);
203 }
204 }
205 #endif
206 }
207 }
208
209 /*
210 * Print address family header before a section of the routing table.
211 */
212 void
213 pr_family(int af)
214 {
215 char *afname;
216
217 switch (af) {
218 case AF_INET:
219 afname = "Internet";
220 break;
221 #ifdef INET6
222 case AF_INET6:
223 afname = "Internet6";
224 break;
225 #endif /*INET6*/
226 case AF_IPX:
227 afname = "IPX";
228 break;
229 #ifdef NS
230 case AF_NS:
231 afname = "XNS";
232 break;
233 #endif
234 #ifndef __APPLE__
235 case AF_ISO:
236 afname = "ISO";
237 break;
238 case AF_APPLETALK:
239 afname = "AppleTalk";
240 break;
241 case AF_CCITT:
242 afname = "X.25";
243 break;
244 case AF_NETGRAPH:
245 afname = "Netgraph";
246 break;
247 #endif
248 default:
249 afname = NULL;
250 break;
251 }
252 if (afname)
253 printf("\n%s:\n", afname);
254 else
255 printf("\nProtocol Family %d:\n", af);
256 }
257
258 /* column widths; each followed by one space */
259 #ifndef INET6
260 #define WID_DST(af) 18 /* width of destination column */
261 #define WID_GW(af) 18 /* width of gateway column */
262 #define WID_IF(af) 6 /* width of netif column */
263 #else
264 #define WID_DST(af) \
265 ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
266 #define WID_GW(af) \
267 ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
268 #define WID_IF(af) ((af) == AF_INET6 ? 8 : 6)
269 #endif /*INET6*/
270
271 /*
272 * Print header for routing table columns.
273 */
274 void
275 pr_rthdr(int af)
276 {
277
278 if (Aflag)
279 printf("%-8.8s ","Address");
280 if (af == AF_INET || lflag)
281 if (lflag)
282 printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %*.*s %6s\n",
283 WID_DST(af), WID_DST(af), "Destination",
284 WID_GW(af), WID_GW(af), "Gateway",
285 "Flags", "Refs", "Use", "Mtu",
286 WID_IF(af), WID_IF(af), "Netif", "Expire");
287 else
288 printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %*.*s %6s\n",
289 WID_DST(af), WID_DST(af), "Destination",
290 WID_GW(af), WID_GW(af), "Gateway",
291 "Flags", "Refs", "Use",
292 WID_IF(af), WID_IF(af), "Netif", "Expire");
293 else
294 printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n",
295 WID_DST(af), WID_DST(af), "Destination",
296 WID_GW(af), WID_GW(af), "Gateway",
297 "Flags", "Netif", "Expire");
298 }
299
300 #if 0
301 static struct sockaddr *
302 kgetsa(struct sockaddr *dst)
303 {
304
305 kget(dst, pt_u.u_sa);
306 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
307 kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
308 return (&pt_u.u_sa);
309 }
310
311 static void
312 p_tree(struct radix_node *rn)
313 {
314
315 again:
316 kget(rn, rnode);
317 if (rnode.rn_bit < 0) {
318 if (Aflag)
319 printf("%-8.8lx ", (u_long)rn);
320 if (rnode.rn_flags & RNF_ROOT) {
321 if (Aflag)
322 printf("(root node)%s",
323 rnode.rn_dupedkey ? " =>\n" : "\n");
324 } else if (do_rtent) {
325 kget(rn, rtentry);
326 p_rtentry(&rtentry);
327 if (Aflag)
328 p_rtnode();
329 } else {
330 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
331 NULL, 0, 44);
332 putchar('\n');
333 }
334 if ((rn = rnode.rn_dupedkey))
335 goto again;
336 } else {
337 if (Aflag && do_rtent) {
338 printf("%-8.8lx ", (u_long)rn);
339 p_rtnode();
340 }
341 rn = rnode.rn_right;
342 p_tree(rnode.rn_left);
343 p_tree(rn);
344 }
345 }
346
347 char nbuf[20];
348
349 static void
350 p_rtnode(void)
351 {
352 struct radix_mask *rm = rnode.rn_mklist;
353
354 if (rnode.rn_bit < 0) {
355 if (rnode.rn_mask) {
356 printf("\t mask ");
357 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
358 NULL, 0, -1);
359 } else if (rm == 0)
360 return;
361 } else {
362 sprintf(nbuf, "(%d)", rnode.rn_bit);
363 printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right);
364 }
365 while (rm) {
366 kget(rm, rmask);
367 sprintf(nbuf, " %d refs, ", rmask.rm_refs);
368 printf(" mk = %8.8lx {(%d),%s",
369 (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " ");
370 if (rmask.rm_flags & RNF_NORMAL) {
371 struct radix_node rnode_aux;
372 printf(" <normal>, ");
373 kget(rmask.rm_leaf, rnode_aux);
374 p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask),
375 NULL, 0, -1);
376 } else
377 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
378 NULL, 0, -1);
379 putchar('}');
380 if ((rm = rmask.rm_mklist))
381 printf(" ->");
382 }
383 putchar('\n');
384 }
385 #endif
386
387 static void
388 ntreestuff(void)
389 {
390 size_t needed;
391 int mib[6];
392 char *buf, *next, *lim;
393 register struct rt_msghdr2 *rtm;
394
395 mib[0] = CTL_NET;
396 mib[1] = PF_ROUTE;
397 mib[2] = 0;
398 mib[3] = 0;
399 mib[4] = NET_RT_DUMP2;
400 mib[5] = 0;
401 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
402 err(1, "sysctl: net.route.0.0.dump estimate");
403 }
404
405 if ((buf = malloc(needed)) == 0) {
406 err(2, "malloc(%lu)", (unsigned long)needed);
407 }
408 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
409 err(1, "sysctl: net.route.0.0.dump");
410 }
411 lim = buf + needed;
412 for (next = buf; next < lim; next += rtm->rtm_msglen) {
413 rtm = (struct rt_msghdr2 *)next;
414 np_rtentry(rtm);
415 }
416 }
417
418 static void
419 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
420 {
421 int i;
422
423 for (i = 0; i < RTAX_MAX; i++) {
424 if (addrs & (1 << i)) {
425 rti_info[i] = sa;
426 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
427 }
428 else
429 rti_info[i] = NULL;
430 }
431 }
432
433 static void
434 np_rtentry(struct rt_msghdr2 *rtm)
435 {
436 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
437 struct sockaddr *rti_info[RTAX_MAX];
438 static int old_fam;
439 int fam = 0;
440 u_short lastindex = 0xffff;
441 static char ifname[IFNAMSIZ + 1];
442 sa_u addr, mask;
443
444 /*
445 * Don't print protocol-cloned routes unless -a.
446 */
447 if ((rtm->rtm_flags & RTF_WASCLONED) && (rtm->rtm_parentflags & RTF_PRCLONING) && !aflag) {
448 return;
449 }
450
451 fam = sa->sa_family;
452 if (af != AF_UNSPEC && af != fam)
453 return;
454 if (fam != old_fam) {
455 pr_family(fam);
456 pr_rthdr(fam);
457 old_fam = fam;
458 }
459 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
460 bzero(&addr, sizeof(addr));
461 if ((rtm->rtm_addrs & RTA_DST))
462 bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
463 bzero(&mask, sizeof(mask));
464 if ((rtm->rtm_addrs & RTA_NETMASK))
465 bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
466 p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
467 WID_DST(addr.u_sa.sa_family));
468
469 p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
470 WID_GW(addr.u_sa.sa_family));
471
472 p_flags(rtm->rtm_flags, "%-6.6s ");
473
474 if (addr.u_sa.sa_family == AF_INET || lflag) {
475 printf("%6u %8d ", rtm->rtm_refcnt, rtm->rtm_use);
476 if (lflag) {
477 if (rtm->rtm_rmx.rmx_mtu != 0)
478 printf("%6lu ", rtm->rtm_rmx.rmx_mtu);
479 else
480 printf("%6s ", "");
481 }
482 }
483 if (rtm->rtm_index != lastindex) {
484 if_indextoname(rtm->rtm_index, ifname);
485 lastindex = rtm->rtm_index;
486 }
487 printf("%*.*s", WID_IF(addr.u_sa.sa_family),
488 WID_IF(addr.u_sa.sa_family), ifname);
489
490 if (rtm->rtm_rmx.rmx_expire) {
491 time_t expire_time;
492
493 if ((expire_time =
494 rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
495 printf(" %6d", (int)expire_time);
496 }
497 putchar('\n');
498 }
499
500 static void
501 p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
502 {
503 char workbuf[128], *cplim;
504 register char *cp = workbuf;
505
506 switch(sa->sa_family) {
507 case AF_INET:
508 {
509 register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
510
511 if ((sin->sin_addr.s_addr == INADDR_ANY) &&
512 mask &&
513 (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L ||
514 mask->sa_len == 0))
515 cp = "default" ;
516 else if (flags & RTF_HOST)
517 cp = routename(sin->sin_addr.s_addr);
518 else if (mask)
519 cp = netname(sin->sin_addr.s_addr,
520 ntohl(((struct sockaddr_in *)mask)
521 ->sin_addr.s_addr));
522 else
523 cp = netname(sin->sin_addr.s_addr, 0L);
524 break;
525 }
526
527 #ifdef INET6
528 case AF_INET6:
529 {
530 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
531 struct in6_addr *in6 = &sa6->sin6_addr;
532
533 /*
534 * XXX: This is a special workaround for KAME kernels.
535 * sin6_scope_id field of SA should be set in the future.
536 */
537 if (IN6_IS_ADDR_LINKLOCAL(in6) ||
538 IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
539 /* XXX: override is ok? */
540 sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
541 *(u_short *)&in6->s6_addr[2] = 0;
542 }
543
544 if (flags & RTF_HOST)
545 cp = routename6(sa6);
546 else if (mask)
547 cp = netname6(sa6, mask);
548 else {
549 cp = netname6(sa6, NULL);
550 }
551 break;
552 }
553 #endif /*INET6*/
554 #ifndef __APPLE__
555 case AF_IPX:
556 {
557 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
558 if (ipx_nullnet(satoipx_addr(work)))
559 cp = "default";
560 else
561 cp = ipx_print(sa);
562 break;
563 }
564 case AF_APPLETALK:
565 {
566 if (!(flags & RTF_HOST) && mask)
567 cp = atalk_print2(sa,mask,9);
568 else
569 cp = atalk_print(sa,11);
570 break;
571 }
572 case AF_NETGRAPH:
573 {
574 printf("%s", ((struct sockaddr_ng *)sa)->sg_data);
575 break;
576 }
577 #endif
578 #ifdef NS
579 case AF_NS:
580 cp = ns_print(sa);
581 break;
582 #endif
583
584 case AF_LINK:
585 {
586 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
587
588 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
589 sdl->sdl_slen == 0)
590 (void) sprintf(workbuf, "link#%d", sdl->sdl_index);
591 else
592 switch (sdl->sdl_type) {
593
594 case IFT_ETHER:
595 {
596 register int i;
597 register u_char *lla = (u_char *)sdl->sdl_data +
598 sdl->sdl_nlen;
599
600 cplim = "";
601 for (i = 0; i < sdl->sdl_alen; i++, lla++) {
602 cp += sprintf(cp, "%s%x", cplim, *lla);
603 cplim = ":";
604 }
605 cp = workbuf;
606 break;
607 }
608
609 default:
610 cp = link_ntoa(sdl);
611 break;
612 }
613 break;
614 }
615
616 default:
617 {
618 register u_char *s = (u_char *)sa->sa_data, *slim;
619
620 slim = sa->sa_len + (u_char *) sa;
621 cplim = cp + sizeof(workbuf) - 6;
622 cp += sprintf(cp, "(%d)", sa->sa_family);
623 while (s < slim && cp < cplim) {
624 cp += sprintf(cp, " %02x", *s++);
625 if (s < slim)
626 cp += sprintf(cp, "%02x", *s++);
627 }
628 cp = workbuf;
629 }
630 }
631 if (width < 0 )
632 printf("%s ", cp);
633 else {
634 if (nflag)
635 printf("%-*s ", width, cp);
636 else
637 printf("%-*.*s ", width, width, cp);
638 }
639 }
640
641 static void
642 p_flags(int f, char *format)
643 {
644 char name[33], *flags;
645 register struct bits *p = bits;
646
647 for (flags = name; p->b_mask; p++)
648 if (p->b_mask & f)
649 *flags++ = p->b_val;
650 *flags = '\0';
651 printf(format, name);
652 }
653
654 #if 0
655 static void
656 p_rtentry(struct rtentry *rt)
657 {
658 static struct ifnet ifnet, *lastif;
659 struct rtentry parent;
660 static char name[16];
661 static char prettyname[9];
662 struct sockaddr *sa;
663 sa_u addr, mask;
664
665 /*
666 * Don't print protocol-cloned routes unless -a.
667 */
668 if (rt->rt_flags & RTF_WASCLONED && !aflag) {
669 kget(rt->rt_parent, parent);
670 if (parent.rt_flags & RTF_PRCLONING)
671 return;
672 }
673
674 bzero(&addr, sizeof(addr));
675 if ((sa = kgetsa(rt_key(rt))))
676 bcopy(sa, &addr, sa->sa_len);
677 bzero(&mask, sizeof(mask));
678 if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
679 bcopy(sa, &mask, sa->sa_len);
680 p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags,
681 WID_DST(addr.u_sa.sa_family));
682 p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST,
683 WID_GW(addr.u_sa.sa_family));
684 p_flags(rt->rt_flags, "%-6.6s ");
685 if (addr.u_sa.sa_family == AF_INET || lflag) {
686 printf("%6u %8ld ", rt->rt_refcnt, rt->rt_use);
687 if (lflag) {
688 if (rt->rt_rmx.rmx_mtu != 0)
689 printf("%6lu ", rt->rt_rmx.rmx_mtu);
690 else
691 printf("%6s ", "");
692 }
693 }
694 if (rt->rt_ifp) {
695 if (rt->rt_ifp != lastif) {
696 kget(rt->rt_ifp, ifnet);
697 kread((u_long)ifnet.if_name, name, 16);
698 lastif = rt->rt_ifp;
699 snprintf(prettyname, sizeof prettyname,
700 "%s%d", name, ifnet.if_unit);
701 }
702 printf("%*.*s", WID_IF(addr.u_sa.sa_family),
703 WID_IF(addr.u_sa.sa_family), prettyname);
704 if (rt->rt_rmx.rmx_expire) {
705 time_t expire_time;
706
707 if ((expire_time =
708 rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
709 printf(" %6d", (int)expire_time);
710 }
711 if (rt->rt_nodes[0].rn_dupedkey)
712 printf(" =>");
713 }
714 putchar('\n');
715 }
716 #endif
717
718 char *
719 routename(u_long in)
720 {
721 register char *cp;
722 static char line[MAXHOSTNAMELEN];
723 struct hostent *hp;
724
725 cp = 0;
726 if (!nflag) {
727 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
728 AF_INET);
729 if (hp) {
730 cp = hp->h_name;
731 //### trimdomain(cp, strlen(cp));
732 }
733 }
734 if (cp) {
735 strncpy(line, cp, sizeof(line) - 1);
736 line[sizeof(line) - 1] = '\0';
737 } else {
738 #define C(x) ((x) & 0xff)
739 in = ntohl(in);
740 sprintf(line, "%lu.%lu.%lu.%lu",
741 C(in >> 24), C(in >> 16), C(in >> 8), C(in));
742 }
743 return (line);
744 }
745
746 static u_long
747 forgemask(u_long a)
748 {
749 u_long m;
750
751 if (IN_CLASSA(a))
752 m = IN_CLASSA_NET;
753 else if (IN_CLASSB(a))
754 m = IN_CLASSB_NET;
755 else
756 m = IN_CLASSC_NET;
757 return (m);
758 }
759
760 static void
761 domask(char *dst, u_long addr, u_long mask)
762 {
763 register int b, i;
764
765 if (!mask || (forgemask(addr) == mask)) {
766 *dst = '\0';
767 return;
768 }
769 i = 0;
770 for (b = 0; b < 32; b++)
771 if (mask & (1 << b)) {
772 register int bb;
773
774 i = b;
775 for (bb = b+1; bb < 32; bb++)
776 if (!(mask & (1 << bb))) {
777 i = -1; /* noncontig */
778 break;
779 }
780 break;
781 }
782 if (i == -1)
783 sprintf(dst, "&0x%lx", mask);
784 else
785 sprintf(dst, "/%d", 32-i);
786 }
787
788 /*
789 * Return the name of the network whose address is given.
790 * The address is assumed to be that of a net or subnet, not a host.
791 */
792 char *
793 netname(u_long in, u_long mask)
794 {
795 char *cp = 0;
796 static char line[MAXHOSTNAMELEN];
797 struct netent *np = 0;
798 u_long net, omask, dmask;
799 register u_long i;
800
801 i = ntohl(in);
802 dmask = forgemask(i);
803 omask = mask;
804 if (!nflag && i) {
805 net = i & dmask;
806 if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
807 np = getnetbyaddr(net, AF_INET);
808 if (np) {
809 cp = np->n_name;
810 //### trimdomain(cp, strlen(cp));
811 }
812 }
813 if (cp)
814 strncpy(line, cp, sizeof(line) - 1);
815 else {
816 switch (dmask) {
817 case IN_CLASSA_NET:
818 if ((i & IN_CLASSA_HOST) == 0) {
819 sprintf(line, "%lu", C(i >> 24));
820 break;
821 }
822 /* FALLTHROUGH */
823 case IN_CLASSB_NET:
824 if ((i & IN_CLASSB_HOST) == 0) {
825 sprintf(line, "%lu.%lu",
826 C(i >> 24), C(i >> 16));
827 break;
828 }
829 /* FALLTHROUGH */
830 case IN_CLASSC_NET:
831 if ((i & IN_CLASSC_HOST) == 0) {
832 sprintf(line, "%lu.%lu.%lu",
833 C(i >> 24), C(i >> 16), C(i >> 8));
834 break;
835 }
836 /* FALLTHROUGH */
837 default:
838 sprintf(line, "%lu.%lu.%lu.%lu",
839 C(i >> 24), C(i >> 16), C(i >> 8), C(i));
840 break;
841 }
842 }
843 domask(line+strlen(line), i, omask);
844 return (line);
845 }
846
847 #ifdef INET6
848 char *
849 netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
850 {
851 static char line[MAXHOSTNAMELEN];
852 u_char *lim;
853 int masklen, illegal = 0, flag = NI_WITHSCOPEID;
854 struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
855
856 if (sam && sam->sa_len == 0) {
857 masklen = 0;
858 } else if (mask) {
859 u_char *p = (u_char *)mask;
860 for (masklen = 0, lim = p + 16; p < lim; p++) {
861 switch (*p) {
862 case 0xff:
863 masklen += 8;
864 break;
865 case 0xfe:
866 masklen += 7;
867 break;
868 case 0xfc:
869 masklen += 6;
870 break;
871 case 0xf8:
872 masklen += 5;
873 break;
874 case 0xf0:
875 masklen += 4;
876 break;
877 case 0xe0:
878 masklen += 3;
879 break;
880 case 0xc0:
881 masklen += 2;
882 break;
883 case 0x80:
884 masklen += 1;
885 break;
886 case 0x00:
887 break;
888 default:
889 illegal ++;
890 break;
891 }
892 }
893 if (illegal)
894 fprintf(stderr, "illegal prefixlen\n");
895 }
896 else
897 masklen = 128;
898
899 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
900 return("default");
901
902 if (nflag)
903 flag |= NI_NUMERICHOST;
904 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
905 NULL, 0, flag);
906
907 if (nflag)
908 sprintf(&line[strlen(line)], "/%d", masklen);
909
910 return line;
911 }
912
913 char *
914 routename6(struct sockaddr_in6 *sa6)
915 {
916 static char line[MAXHOSTNAMELEN];
917 int flag = NI_WITHSCOPEID;
918 /* use local variable for safety */
919 struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
920
921 sa6_local.sin6_addr = sa6->sin6_addr;
922 sa6_local.sin6_scope_id = sa6->sin6_scope_id;
923
924 if (nflag)
925 flag |= NI_NUMERICHOST;
926
927 getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
928 line, sizeof(line), NULL, 0, flag);
929
930 return line;
931 }
932 #endif /*INET6*/
933
934 /*
935 * Print routing statistics
936 */
937 void
938 rt_stats(void)
939 {
940 struct rtstat rtstat;
941 int rttrash;
942 int mib[6];
943 size_t len;
944
945 mib[0] = CTL_NET;
946 mib[1] = AF_ROUTE;
947 mib[2] = 0;
948 mib[3] = 0;
949 mib[4] = NET_RT_STAT;
950 mib[5] = 0;
951 len = sizeof(struct rtstat);
952 if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
953 return;
954
955 mib[0] = CTL_NET;
956 mib[1] = AF_ROUTE;
957 mib[2] = 0;
958 mib[3] = 0;
959 mib[4] = NET_RT_TRASH;
960 mib[5] = 0;
961 len = sizeof(rttrash);
962 if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
963 return;
964
965 printf("routing:\n");
966
967 #define p(f, m) if (rtstat.f || sflag <= 1) \
968 printf(m, rtstat.f, plural(rtstat.f))
969
970 p(rts_badredirect, "\t%u bad routing redirect%s\n");
971 p(rts_dynamic, "\t%u dynamically created route%s\n");
972 p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
973 p(rts_unreach, "\t%u destination%s found unreachable\n");
974 p(rts_wildcard, "\t%u use%s of a wildcard route\n");
975 #undef p
976
977 if (rttrash || sflag <= 1)
978 printf("\t%u route%s not in table but not freed\n",
979 rttrash, plural(rttrash));
980 }
981 #ifndef __APPLE__
982 char *
983 ipx_print(struct sockaddr *sa)
984 {
985 u_short port;
986 struct servent *sp = 0;
987 char *net = "", *host = "";
988 register char *p;
989 register u_char *q;
990 struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
991 static char mybuf[50];
992 char cport[10], chost[15], cnet[15];
993
994 port = ntohs(work.x_port);
995
996 if (ipx_nullnet(work) && ipx_nullhost(work)) {
997
998 if (port) {
999 if (sp)
1000 sprintf(mybuf, "*.%s", sp->s_name);
1001 else
1002 sprintf(mybuf, "*.%x", port);
1003 } else
1004 sprintf(mybuf, "*.*");
1005
1006 return (mybuf);
1007 }
1008
1009 if (ipx_wildnet(work))
1010 net = "any";
1011 else if (ipx_nullnet(work))
1012 net = "*";
1013 else {
1014 q = work.x_net.c_net;
1015 sprintf(cnet, "%02x%02x%02x%02x",
1016 q[0], q[1], q[2], q[3]);
1017 for (p = cnet; *p == '0' && p < cnet + 8; p++)
1018 continue;
1019 net = p;
1020 }
1021
1022 if (ipx_wildhost(work))
1023 host = "any";
1024 else if (ipx_nullhost(work))
1025 host = "*";
1026 else {
1027 q = work.x_host.c_host;
1028 sprintf(chost, "%02x%02x%02x%02x%02x%02x",
1029 q[0], q[1], q[2], q[3], q[4], q[5]);
1030 for (p = chost; *p == '0' && p < chost + 12; p++)
1031 continue;
1032 host = p;
1033 }
1034
1035 if (port) {
1036 if (strcmp(host, "*") == 0)
1037 host = "";
1038 if (sp)
1039 snprintf(cport, sizeof(cport),
1040 "%s%s", *host ? "." : "", sp->s_name);
1041 else
1042 snprintf(cport, sizeof(cport),
1043 "%s%x", *host ? "." : "", port);
1044 } else
1045 *cport = 0;
1046
1047 snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport);
1048 return(mybuf);
1049 }
1050
1051 char *
1052 ipx_phost(struct sockaddr *sa)
1053 {
1054 register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
1055 struct sockaddr_ipx work;
1056 static union ipx_net ipx_zeronet;
1057 char *p;
1058 struct ipx_addr in;
1059
1060 work = *sipx;
1061 in = work.sipx_addr;
1062
1063 work.sipx_addr.x_port = 0;
1064 work.sipx_addr.x_net = ipx_zeronet;
1065 p = ipx_print((struct sockaddr *)&work);
1066 if (strncmp("*.", p, 2) == 0) p += 2;
1067
1068 return(p);
1069 }
1070 #endif
1071 #ifdef NS
1072 short ns_nullh[] = {0,0,0};
1073 short ns_bh[] = {-1,-1,-1};
1074
1075 char *
1076 ns_print(struct sockaddr *sa)
1077 {
1078 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
1079 struct ns_addr work;
1080 union { union ns_net net_e; u_long long_e; } net;
1081 u_short port;
1082 static char mybuf[50], cport[10], chost[25];
1083 char *host = "";
1084 register char *p; register u_char *q;
1085
1086 work = sns->sns_addr;
1087 port = ntohs(work.x_port);
1088 work.x_port = 0;
1089 net.net_e = work.x_net;
1090 if (ns_nullhost(work) && net.long_e == 0) {
1091 if (port ) {
1092 sprintf(mybuf, "*.%xH", port);
1093 upHex(mybuf);
1094 } else
1095 sprintf(mybuf, "*.*");
1096 return (mybuf);
1097 }
1098
1099 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
1100 host = "any";
1101 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
1102 host = "*";
1103 } else {
1104 q = work.x_host.c_host;
1105 sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
1106 q[0], q[1], q[2], q[3], q[4], q[5]);
1107 for (p = chost; *p == '0' && p < chost + 12; p++)
1108 continue;
1109 host = p;
1110 }
1111 if (port)
1112 sprintf(cport, ".%xH", htons(port));
1113 else
1114 *cport = 0;
1115
1116 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
1117 upHex(mybuf);
1118 return(mybuf);
1119 }
1120
1121 char *
1122 ns_phost(struct sockaddr *sa)
1123 {
1124 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
1125 struct sockaddr_ns work;
1126 static union ns_net ns_zeronet;
1127 char *p;
1128
1129 work = *sns;
1130 work.sns_addr.x_port = 0;
1131 work.sns_addr.x_net = ns_zeronet;
1132
1133 p = ns_print((struct sockaddr *)&work);
1134 if (strncmp("0H.", p, 3) == 0)
1135 p += 3;
1136 return(p);
1137 }
1138 #endif
1139
1140 void
1141 upHex(char *p0)
1142 {
1143 register char *p = p0;
1144
1145 for (; *p; p++)
1146 switch (*p) {
1147
1148 case 'a':
1149 case 'b':
1150 case 'c':
1151 case 'd':
1152 case 'e':
1153 case 'f':
1154 *p += ('A' - 'a');
1155 break;
1156 }
1157 }