]> git.cameronkatri.com Git - apple_cmds.git/blob - network_cmds/netstat.tproj/route.c
943e3c8ffa4b95b669448d24027ce230f74fbafb
[apple_cmds.git] / network_cmds / netstat.tproj / route.c
1 /*
2 * Copyright (c) 2008-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1983, 1988, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61 #include <stdint.h>
62 #include <sys/param.h>
63 #include <sys/socket.h>
64 #include <sys/time.h>
65 #include <sys/errno.h>
66
67 #include <net/if.h>
68 #include <net/if_var.h>
69 #include <net/if_dl.h>
70 #include <net/if_types.h>
71 #include <net/route.h>
72 #include <net/radix.h>
73
74 #include <netinet/in.h>
75
76 #include <sys/sysctl.h>
77
78 #include <arpa/inet.h>
79 #include <netdb.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <err.h>
85 #include <time.h>
86 #include "netstat.h"
87
88 /* alignment constraint for routing socket */
89 #define ROUNDUP(a) \
90 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
91 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
92
93 /*
94 * Definitions for showing gateway flags.
95 */
96 struct bits {
97 uint32_t b_mask;
98 char b_val;
99 } bits[] = {
100 { RTF_UP, 'U' },
101 { RTF_GATEWAY, 'G' },
102 { RTF_HOST, 'H' },
103 { RTF_REJECT, 'R' },
104 { RTF_DYNAMIC, 'D' },
105 { RTF_MODIFIED, 'M' },
106 { RTF_MULTICAST,'m' },
107 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
108 { RTF_CLONING, 'C' },
109 { RTF_XRESOLVE, 'X' },
110 { RTF_LLINFO, 'L' },
111 { RTF_STATIC, 'S' },
112 { RTF_PROTO1, '1' },
113 { RTF_PROTO2, '2' },
114 { RTF_WASCLONED,'W' },
115 { RTF_PRCLONING,'c' },
116 { RTF_PROTO3, '3' },
117 { RTF_BLACKHOLE,'B' },
118 { RTF_BROADCAST,'b' },
119 { RTF_IFSCOPE, 'I' },
120 { RTF_IFREF, 'i' },
121 { RTF_PROXY, 'Y' },
122 { RTF_ROUTER, 'r' },
123 { 0 }
124 };
125
126 typedef union {
127 uint32_t dummy; /* Helps align structure. */
128 struct sockaddr u_sa;
129 u_short u_data[128];
130 } sa_u;
131
132 static void np_rtentry __P((struct rt_msghdr2 *));
133 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
134 static void p_flags __P((int, char *));
135 static uint32_t forgemask __P((uint32_t));
136 static void domask __P((char *, uint32_t, uint32_t));
137
138 /*
139 * Print address family header before a section of the routing table.
140 */
141 void
142 pr_family(int af)
143 {
144 char *afname;
145
146 switch (af) {
147 case AF_INET:
148 afname = "Internet";
149 break;
150 #ifdef INET6
151 case AF_INET6:
152 afname = "Internet6";
153 break;
154 #endif /*INET6*/
155 case AF_IPX:
156 afname = "IPX";
157 break;
158 default:
159 afname = NULL;
160 break;
161 }
162 if (afname)
163 printf("\n%s:\n", afname);
164 else
165 printf("\nProtocol Family %d:\n", af);
166 }
167
168 /* column widths; each followed by one space */
169 #ifndef INET6
170 #define WID_DST(af) 18 /* width of destination column */
171 #define WID_GW(af) 18 /* width of gateway column */
172 #define WID_RT_IFA(af) 18 /* width of source column */
173 #define WID_IF(af) 7 /* width of netif column */
174 #else
175 #define WID_DST(af) \
176 ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
177 #define WID_GW(af) \
178 ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
179 #define WID_RT_IFA(af) \
180 ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18)
181 #define WID_IF(af) ((af) == AF_INET6 ? 8 : 7)
182 #endif /*INET6*/
183
184 /*
185 * Print header for routing table columns.
186 */
187 void
188 pr_rthdr(int af)
189 {
190 if (lflag) {
191 if (lflag > 2)
192 printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
193 "%10s %10s %8s %8s %8s\n",
194 WID_DST(af), WID_DST(af), "Destination",
195 WID_GW(af), WID_GW(af), "Gateway",
196 WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
197 "Flags", "Refs", "Use", "Mtu",
198 WID_IF(af), WID_IF(af), "Netif", "Expire",
199 "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh");
200 else if (lflag > 1)
201 printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
202 "%10s %10s\n",
203 WID_DST(af), WID_DST(af), "Destination",
204 WID_GW(af), WID_GW(af), "Gateway",
205 WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
206 "Flags", "Refs", "Use", "Mtu",
207 WID_IF(af), WID_IF(af), "Netif", "Expire",
208 "rtt(ms)", "rttvar(ms)");
209 else
210 printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n",
211 WID_DST(af), WID_DST(af), "Destination",
212 WID_GW(af), WID_GW(af), "Gateway",
213 WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
214 "Flags", "Refs", "Use", "Mtu",
215 WID_IF(af), WID_IF(af), "Netif", "Expire");
216 } else {
217 printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n",
218 WID_DST(af), WID_DST(af), "Destination",
219 WID_GW(af), WID_GW(af), "Gateway",
220 "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire");
221 }
222 }
223
224 /*
225 * Print routing tables.
226 */
227 void
228 routepr(void)
229 {
230 size_t extra_space;
231 size_t needed;
232 int mib[6];
233 char *buf, *next, *lim;
234 struct rt_msghdr2 *rtm;
235 int try = 1;
236
237 printf("Routing tables\n");
238
239 again:
240 mib[0] = CTL_NET;
241 mib[1] = PF_ROUTE;
242 mib[2] = 0;
243 mib[3] = 0;
244 mib[4] = NET_RT_DUMP2;
245 mib[5] = 0;
246 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
247 err(1, "sysctl: net.route.0.0.dump estimate");
248 }
249 /* allocate extra space in case the table grows */
250 extra_space = needed / 2;
251 if (needed <= (SIZE_MAX - extra_space)) {
252 needed += extra_space;
253 }
254 if ((buf = malloc(needed)) == 0) {
255 err(2, "malloc(%lu)", (unsigned long)needed);
256 }
257 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
258 #define MAX_TRIES 10
259 if (errno == ENOMEM && try < MAX_TRIES) {
260 /* the buffer we provided was too small, try again */
261 free(buf);
262 try++;
263 goto again;
264 }
265 err(1, "sysctl: net.route.0.0.dump");
266 }
267 lim = buf + needed;
268 for (next = buf; next < lim; next += rtm->rtm_msglen) {
269 rtm = (struct rt_msghdr2 *)next;
270 np_rtentry(rtm);
271 }
272 }
273
274 static void
275 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
276 {
277 int i;
278
279 for (i = 0; i < RTAX_MAX; i++) {
280 if (addrs & (1 << i)) {
281 rti_info[i] = sa;
282 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
283 } else {
284 rti_info[i] = NULL;
285 }
286 }
287 }
288
289 static void
290 np_rtentry(struct rt_msghdr2 *rtm)
291 {
292 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
293 struct sockaddr *rti_info[RTAX_MAX];
294 static int old_fam;
295 int fam = 0;
296 u_short lastindex = 0xffff;
297 static char ifname[IFNAMSIZ + 1];
298 sa_u addr, mask;
299
300 /*
301 * Don't print protocol-cloned routes unless -a.
302 */
303 if ((rtm->rtm_flags & RTF_WASCLONED) &&
304 (rtm->rtm_parentflags & RTF_PRCLONING) &&
305 !aflag) {
306 return;
307 }
308
309 if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0)
310 return;
311 fam = sa->sa_family;
312 if (af != AF_UNSPEC && af != fam)
313 return;
314 if (fam != old_fam) {
315 pr_family(fam);
316 pr_rthdr(fam);
317 old_fam = fam;
318 }
319 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
320 bzero(&addr, sizeof(addr));
321 if ((rtm->rtm_addrs & RTA_DST))
322 bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
323 bzero(&mask, sizeof(mask));
324 if ((rtm->rtm_addrs & RTA_NETMASK))
325 bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
326 p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
327 WID_DST(addr.u_sa.sa_family));
328
329 p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
330 WID_GW(addr.u_sa.sa_family));
331
332 if (lflag && (rtm->rtm_addrs & RTA_IFA)) {
333 p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST,
334 WID_RT_IFA(addr.u_sa.sa_family));
335 }
336
337 p_flags(rtm->rtm_flags, "%-10.10s ");
338
339 if (lflag) {
340 printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use);
341 if (rtm->rtm_rmx.rmx_mtu != 0)
342 printf("%6u ", rtm->rtm_rmx.rmx_mtu);
343 else
344 printf("%6s ", "");
345 }
346
347 if (rtm->rtm_index != lastindex) {
348 if_indextoname(rtm->rtm_index, ifname);
349 lastindex = rtm->rtm_index;
350 }
351 printf("%*.*s", WID_IF(addr.u_sa.sa_family),
352 WID_IF(addr.u_sa.sa_family), ifname);
353
354 if (rtm->rtm_rmx.rmx_expire) {
355 time_t expire_time;
356
357 if ((expire_time =
358 rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
359 printf(" %6d", (int)expire_time);
360 else
361 printf(" %6s", "!");
362 } else {
363 printf(" %6s", "");
364 }
365 if (lflag > 1) {
366 if (rtm->rtm_rmx.rmx_rtt != 0)
367 printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000,
368 rtm->rtm_rmx.rmx_rtt % 1000);
369 else
370 printf(" %10s", "");
371 if (rtm->rtm_rmx.rmx_rttvar != 0)
372 printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000,
373 rtm->rtm_rmx.rmx_rttvar % 1000);
374 else
375 printf(" %10s", "");
376 if (lflag > 2) {
377 if (rtm->rtm_rmx.rmx_recvpipe != 0)
378 printf(" %8u", rtm->rtm_rmx.rmx_recvpipe);
379 else
380 printf(" %8s", "");
381 if (rtm->rtm_rmx.rmx_sendpipe != 0)
382 printf(" %8u", rtm->rtm_rmx.rmx_sendpipe);
383 else
384 printf(" %8s", "");
385 if (rtm->rtm_rmx.rmx_ssthresh != 0)
386 printf(" %8u", rtm->rtm_rmx.rmx_ssthresh);
387 else
388 printf(" %8s", "");
389 }
390 }
391 putchar('\n');
392 }
393
394 static void
395 p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
396 {
397 char workbuf[128], *cplim;
398 char *cp = workbuf;
399
400 switch(sa->sa_family) {
401 case AF_INET: {
402 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
403
404 if ((sin->sin_addr.s_addr == INADDR_ANY) &&
405 mask &&
406 (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0))
407 cp = "default" ;
408 else if (flags & RTF_HOST)
409 cp = routename(sin->sin_addr.s_addr);
410 else if (mask)
411 cp = netname(sin->sin_addr.s_addr,
412 ntohl(((struct sockaddr_in *)mask)->
413 sin_addr.s_addr));
414 else
415 cp = netname(sin->sin_addr.s_addr, 0L);
416 break;
417 }
418
419 #ifdef INET6
420 case AF_INET6: {
421 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
422 struct in6_addr *in6 = &sa6->sin6_addr;
423
424 /*
425 * XXX: This is a special workaround for KAME kernels.
426 * sin6_scope_id field of SA should be set in the future.
427 */
428 if (IN6_IS_ADDR_LINKLOCAL(in6) ||
429 IN6_IS_ADDR_MC_NODELOCAL(in6) ||
430 IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
431 /* XXX: override is ok? */
432 sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
433 *(u_short *)&in6->s6_addr[2] = 0;
434 }
435
436 if (flags & RTF_HOST)
437 cp = routename6(sa6);
438 else if (mask)
439 cp = netname6(sa6, mask);
440 else
441 cp = netname6(sa6, NULL);
442 break;
443 }
444 #endif /*INET6*/
445
446 case AF_LINK: {
447 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
448
449 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
450 sdl->sdl_slen == 0) {
451 (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index);
452 } else {
453 switch (sdl->sdl_type) {
454
455 case IFT_ETHER: {
456 int i;
457 u_char *lla = (u_char *)sdl->sdl_data +
458 sdl->sdl_nlen;
459
460 cplim = "";
461 for (i = 0; i < sdl->sdl_alen; i++, lla++) {
462 cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla);
463 cplim = ":";
464 }
465 cp = workbuf;
466 break;
467 }
468
469 default:
470 cp = link_ntoa(sdl);
471 break;
472 }
473 }
474 break;
475 }
476
477 default: {
478 u_char *s = (u_char *)sa->sa_data, *slim;
479
480 slim = sa->sa_len + (u_char *) sa;
481 cplim = cp + sizeof(workbuf) - 6;
482 cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family);
483 while (s < slim && cp < cplim) {
484 cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++);
485 if (s < slim)
486 cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++);
487 }
488 cp = workbuf;
489 }
490 }
491 if (width < 0 ) {
492 printf("%s ", cp);
493 } else {
494 if (nflag)
495 printf("%-*s ", width, cp);
496 else
497 printf("%-*.*s ", width, width, cp);
498 }
499 }
500
501 static void
502 p_flags(int f, char *format)
503 {
504 char name[33], *flags;
505 struct bits *p = bits;
506
507 for (flags = name; p->b_mask; p++)
508 if (p->b_mask & f)
509 *flags++ = p->b_val;
510 *flags = '\0';
511 printf(format, name);
512 }
513
514 char *
515 routename(uint32_t in)
516 {
517 char *cp;
518 static char line[MAXHOSTNAMELEN];
519 struct hostent *hp;
520
521 cp = 0;
522 if (!nflag) {
523 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
524 AF_INET);
525 if (hp) {
526 cp = hp->h_name;
527 //### trimdomain(cp, strlen(cp));
528 }
529 }
530 if (cp) {
531 strlcpy(line, cp, sizeof(line));
532 } else {
533 #define C(x) ((x) & 0xff)
534 in = ntohl(in);
535 snprintf(line, sizeof(line), "%u.%u.%u.%u",
536 C(in >> 24), C(in >> 16), C(in >> 8), C(in));
537 }
538 return (line);
539 }
540
541 static uint32_t
542 forgemask(uint32_t a)
543 {
544 uint32_t m;
545
546 if (IN_CLASSA(a))
547 m = IN_CLASSA_NET;
548 else if (IN_CLASSB(a))
549 m = IN_CLASSB_NET;
550 else
551 m = IN_CLASSC_NET;
552 return (m);
553 }
554
555 static void
556 domask(char *dst, uint32_t addr, uint32_t mask)
557 {
558 int b, i;
559
560 if (!mask || (forgemask(addr) == mask)) {
561 *dst = '\0';
562 return;
563 }
564 i = 0;
565 for (b = 0; b < 32; b++)
566 if (mask & (1 << b)) {
567 int bb;
568
569 i = b;
570 for (bb = b+1; bb < 32; bb++)
571 if (!(mask & (1 << bb))) {
572 i = -1; /* noncontig */
573 break;
574 }
575 break;
576 }
577 if (i == -1)
578 snprintf(dst, sizeof(dst), "&0x%x", mask);
579 else
580 snprintf(dst, sizeof(dst), "/%d", 32-i);
581 }
582
583 /*
584 * Return the name of the network whose address is given.
585 * The address is assumed to be that of a net or subnet, not a host.
586 */
587 char *
588 netname(uint32_t in, uint32_t mask)
589 {
590 char *cp = 0;
591 static char line[MAXHOSTNAMELEN];
592 struct netent *np = 0;
593 uint32_t net, omask, dmask;
594 uint32_t i;
595
596 i = ntohl(in);
597 dmask = forgemask(i);
598 omask = mask;
599 if (!nflag && i) {
600 net = i & dmask;
601 if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
602 np = getnetbyaddr(net, AF_INET);
603 if (np) {
604 cp = np->n_name;
605 //### trimdomain(cp, strlen(cp));
606 }
607 }
608 if (cp)
609 strlcpy(line, cp, sizeof(line));
610 else {
611 switch (dmask) {
612 case IN_CLASSA_NET:
613 if ((i & IN_CLASSA_HOST) == 0) {
614 snprintf(line, sizeof(line), "%u", C(i >> 24));
615 break;
616 }
617 /* FALLTHROUGH */
618 case IN_CLASSB_NET:
619 if ((i & IN_CLASSB_HOST) == 0) {
620 snprintf(line, sizeof(line), "%u.%u",
621 C(i >> 24), C(i >> 16));
622 break;
623 }
624 /* FALLTHROUGH */
625 case IN_CLASSC_NET:
626 if ((i & IN_CLASSC_HOST) == 0) {
627 snprintf(line, sizeof(line), "%u.%u.%u",
628 C(i >> 24), C(i >> 16), C(i >> 8));
629 break;
630 }
631 /* FALLTHROUGH */
632 default:
633 snprintf(line, sizeof(line), "%u.%u.%u.%u",
634 C(i >> 24), C(i >> 16), C(i >> 8), C(i));
635 break;
636 }
637 }
638 domask(line+strlen(line), i, omask);
639 return (line);
640 }
641
642 #ifdef INET6
643 char *
644 netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
645 {
646 static char line[MAXHOSTNAMELEN];
647 u_char *lim;
648 int masklen, illegal = 0, flag = NI_WITHSCOPEID;
649 struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
650
651 if (sam && sam->sa_len == 0) {
652 masklen = 0;
653 } else if (mask) {
654 u_char *p = (u_char *)mask;
655 for (masklen = 0, lim = p + 16; p < lim; p++) {
656 switch (*p) {
657 case 0xff:
658 masklen += 8;
659 break;
660 case 0xfe:
661 masklen += 7;
662 break;
663 case 0xfc:
664 masklen += 6;
665 break;
666 case 0xf8:
667 masklen += 5;
668 break;
669 case 0xf0:
670 masklen += 4;
671 break;
672 case 0xe0:
673 masklen += 3;
674 break;
675 case 0xc0:
676 masklen += 2;
677 break;
678 case 0x80:
679 masklen += 1;
680 break;
681 case 0x00:
682 break;
683 default:
684 illegal ++;
685 break;
686 }
687 }
688 if (illegal)
689 fprintf(stderr, "illegal prefixlen\n");
690 } else {
691 masklen = 128;
692 }
693 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
694 return("default");
695
696 if (nflag)
697 flag |= NI_NUMERICHOST;
698 getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
699 NULL, 0, flag);
700
701 if (nflag)
702 snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen);
703
704 return line;
705 }
706
707 char *
708 routename6(struct sockaddr_in6 *sa6)
709 {
710 static char line[MAXHOSTNAMELEN];
711 int flag = NI_WITHSCOPEID;
712 /* use local variable for safety */
713 struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
714
715 sa6_local.sin6_addr = sa6->sin6_addr;
716 sa6_local.sin6_scope_id = sa6->sin6_scope_id;
717
718 if (nflag)
719 flag |= NI_NUMERICHOST;
720
721 getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
722 line, sizeof(line), NULL, 0, flag);
723
724 return line;
725 }
726 #endif /*INET6*/
727
728 /*
729 * Print routing statistics
730 */
731 void
732 rt_stats(void)
733 {
734 struct rtstat rtstat;
735 int rttrash;
736 int mib[6];
737 size_t len;
738
739 mib[0] = CTL_NET;
740 mib[1] = AF_ROUTE;
741 mib[2] = 0;
742 mib[3] = 0;
743 mib[4] = NET_RT_STAT;
744 mib[5] = 0;
745 len = sizeof(struct rtstat);
746 if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
747 return;
748
749 mib[0] = CTL_NET;
750 mib[1] = AF_ROUTE;
751 mib[2] = 0;
752 mib[3] = 0;
753 mib[4] = NET_RT_TRASH;
754 mib[5] = 0;
755 len = sizeof(rttrash);
756 if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
757 return;
758
759 printf("routing:\n");
760
761 #define p(f, m) if (rtstat.f || sflag <= 1) \
762 printf(m, rtstat.f, plural(rtstat.f))
763
764 p(rts_badredirect, "\t%u bad routing redirect%s\n");
765 p(rts_dynamic, "\t%u dynamically created route%s\n");
766 p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
767 p(rts_unreach, "\t%u destination%s found unreachable\n");
768 p(rts_wildcard, "\t%u use%s of a wildcard route\n");
769 p(rts_badrtgwroute, "\t%u lookup%s returned indirect "
770 "routes pointing to indirect gateway route\n");
771 #undef p
772
773 if (rttrash || sflag <= 1)
774 printf("\t%u route%s not in table but not freed\n",
775 rttrash, plural(rttrash));
776 }
777
778 void
779 upHex(char *p0)
780 {
781 char *p = p0;
782
783 for (; *p; p++)
784 switch (*p) {
785
786 case 'a':
787 case 'b':
788 case 'c':
789 case 'd':
790 case 'e':
791 case 'f':
792 *p += ('A' - 'a');
793 break;
794 }
795 }