]>
Commit | Line | Data |
---|---|---|
b7080c8e | 1 | /* |
9dc66a05 | 2 | * Copyright (c) 2008-2012 Apple Inc. All rights reserved. |
9c859447 A |
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. | |
b7080c8e | 17 | * |
b7080c8e A |
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, | |
9c859447 A |
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@ | |
b7080c8e A |
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 | ||
9c859447 | 61 | #include <stdint.h> |
b7080c8e | 62 | #include <sys/param.h> |
b7080c8e A |
63 | #include <sys/socket.h> |
64 | #include <sys/time.h> | |
65 | ||
66 | #include <net/if.h> | |
67 | #include <net/if_var.h> | |
68 | #include <net/if_dl.h> | |
69 | #include <net/if_types.h> | |
70 | #include <net/route.h> | |
2b484d24 | 71 | #include <net/radix.h> |
b7080c8e A |
72 | |
73 | #include <netinet/in.h> | |
b7080c8e A |
74 | |
75 | #include <sys/sysctl.h> | |
76 | ||
7ba0088d | 77 | #include <arpa/inet.h> |
b7080c8e A |
78 | #include <netdb.h> |
79 | #include <stdio.h> | |
80 | #include <stdlib.h> | |
81 | #include <string.h> | |
82 | #include <unistd.h> | |
83 | #include <err.h> | |
84 | #include <time.h> | |
85 | #include "netstat.h" | |
86 | ||
7ba0088d A |
87 | /* alignment constraint for routing socket */ |
88 | #define ROUNDUP(a) \ | |
9c859447 | 89 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) |
7ba0088d A |
90 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |
91 | ||
b7080c8e A |
92 | /* |
93 | * Definitions for showing gateway flags. | |
94 | */ | |
95 | struct bits { | |
9c859447 | 96 | uint32_t b_mask; |
b7080c8e A |
97 | char b_val; |
98 | } bits[] = { | |
99 | { RTF_UP, 'U' }, | |
100 | { RTF_GATEWAY, 'G' }, | |
101 | { RTF_HOST, 'H' }, | |
102 | { RTF_REJECT, 'R' }, | |
103 | { RTF_DYNAMIC, 'D' }, | |
104 | { RTF_MODIFIED, 'M' }, | |
9c859447 | 105 | { RTF_MULTICAST,'m' }, |
b7080c8e A |
106 | { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ |
107 | { RTF_CLONING, 'C' }, | |
108 | { RTF_XRESOLVE, 'X' }, | |
109 | { RTF_LLINFO, 'L' }, | |
110 | { RTF_STATIC, 'S' }, | |
111 | { RTF_PROTO1, '1' }, | |
112 | { RTF_PROTO2, '2' }, | |
113 | { RTF_WASCLONED,'W' }, | |
114 | { RTF_PRCLONING,'c' }, | |
115 | { RTF_PROTO3, '3' }, | |
116 | { RTF_BLACKHOLE,'B' }, | |
117 | { RTF_BROADCAST,'b' }, | |
9c859447 | 118 | { RTF_IFSCOPE, 'I' }, |
7f5b2e89 | 119 | { RTF_IFREF, 'i' }, |
7af5ce03 A |
120 | { RTF_PROXY, 'Y' }, |
121 | { RTF_ROUTER, 'r' }, | |
b7080c8e A |
122 | { 0 } |
123 | }; | |
124 | ||
125 | typedef union { | |
9c859447 | 126 | uint32_t dummy; /* Helps align structure. */ |
b7080c8e A |
127 | struct sockaddr u_sa; |
128 | u_short u_data[128]; | |
129 | } sa_u; | |
130 | ||
2b484d24 | 131 | static void np_rtentry __P((struct rt_msghdr2 *)); |
b7080c8e A |
132 | static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int)); |
133 | static void p_flags __P((int, char *)); | |
9c859447 A |
134 | static uint32_t forgemask __P((uint32_t)); |
135 | static void domask __P((char *, uint32_t, uint32_t)); | |
b7080c8e | 136 | |
b7080c8e A |
137 | /* |
138 | * Print address family header before a section of the routing table. | |
139 | */ | |
140 | void | |
7ba0088d | 141 | pr_family(int af) |
b7080c8e A |
142 | { |
143 | char *afname; | |
144 | ||
145 | switch (af) { | |
146 | case AF_INET: | |
147 | afname = "Internet"; | |
148 | break; | |
7ba0088d A |
149 | #ifdef INET6 |
150 | case AF_INET6: | |
151 | afname = "Internet6"; | |
152 | break; | |
153 | #endif /*INET6*/ | |
b7080c8e A |
154 | case AF_IPX: |
155 | afname = "IPX"; | |
156 | break; | |
b7080c8e A |
157 | default: |
158 | afname = NULL; | |
159 | break; | |
160 | } | |
161 | if (afname) | |
162 | printf("\n%s:\n", afname); | |
163 | else | |
164 | printf("\nProtocol Family %d:\n", af); | |
165 | } | |
166 | ||
167 | /* column widths; each followed by one space */ | |
7ba0088d A |
168 | #ifndef INET6 |
169 | #define WID_DST(af) 18 /* width of destination column */ | |
170 | #define WID_GW(af) 18 /* width of gateway column */ | |
9c859447 | 171 | #define WID_IF(af) 7 /* width of netif column */ |
7ba0088d A |
172 | #else |
173 | #define WID_DST(af) \ | |
2b484d24 | 174 | ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18) |
7ba0088d | 175 | #define WID_GW(af) \ |
2b484d24 | 176 | ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18) |
9c859447 | 177 | #define WID_IF(af) ((af) == AF_INET6 ? 8 : 7) |
7ba0088d | 178 | #endif /*INET6*/ |
b7080c8e A |
179 | |
180 | /* | |
181 | * Print header for routing table columns. | |
182 | */ | |
183 | void | |
7ba0088d | 184 | pr_rthdr(int af) |
b7080c8e | 185 | { |
7ba0088d | 186 | |
b7080c8e A |
187 | if (Aflag) |
188 | printf("%-8.8s ","Address"); | |
7ba0088d A |
189 | if (af == AF_INET || lflag) |
190 | if (lflag) | |
9c859447 | 191 | printf("%-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n", |
7ba0088d A |
192 | WID_DST(af), WID_DST(af), "Destination", |
193 | WID_GW(af), WID_GW(af), "Gateway", | |
194 | "Flags", "Refs", "Use", "Mtu", | |
195 | WID_IF(af), WID_IF(af), "Netif", "Expire"); | |
196 | else | |
9c859447 | 197 | printf("%-*.*s %-*.*s %-10.10s %6.6s %8.8s %*.*s %6s\n", |
7ba0088d A |
198 | WID_DST(af), WID_DST(af), "Destination", |
199 | WID_GW(af), WID_GW(af), "Gateway", | |
200 | "Flags", "Refs", "Use", | |
201 | WID_IF(af), WID_IF(af), "Netif", "Expire"); | |
202 | else | |
9c859447 | 203 | printf("%-*.*s %-*.*s %-10.10s %8.8s %6s\n", |
7ba0088d A |
204 | WID_DST(af), WID_DST(af), "Destination", |
205 | WID_GW(af), WID_GW(af), "Gateway", | |
206 | "Flags", "Netif", "Expire"); | |
b7080c8e A |
207 | } |
208 | ||
9dc66a05 A |
209 | /* |
210 | * Print routing tables. | |
211 | */ | |
212 | void | |
213 | routepr(void) | |
b7080c8e A |
214 | { |
215 | size_t needed; | |
216 | int mib[6]; | |
217 | char *buf, *next, *lim; | |
9c859447 | 218 | struct rt_msghdr2 *rtm; |
b7080c8e | 219 | |
9dc66a05 A |
220 | printf("Routing tables\n"); |
221 | ||
b7080c8e A |
222 | mib[0] = CTL_NET; |
223 | mib[1] = PF_ROUTE; | |
224 | mib[2] = 0; | |
225 | mib[3] = 0; | |
2b484d24 | 226 | mib[4] = NET_RT_DUMP2; |
b7080c8e A |
227 | mib[5] = 0; |
228 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { | |
229 | err(1, "sysctl: net.route.0.0.dump estimate"); | |
230 | } | |
231 | ||
232 | if ((buf = malloc(needed)) == 0) { | |
233 | err(2, "malloc(%lu)", (unsigned long)needed); | |
234 | } | |
235 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { | |
236 | err(1, "sysctl: net.route.0.0.dump"); | |
237 | } | |
238 | lim = buf + needed; | |
239 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | |
2b484d24 | 240 | rtm = (struct rt_msghdr2 *)next; |
b7080c8e A |
241 | np_rtentry(rtm); |
242 | } | |
243 | } | |
244 | ||
245 | static void | |
2b484d24 | 246 | get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) |
b7080c8e | 247 | { |
2b484d24 A |
248 | int i; |
249 | ||
250 | for (i = 0; i < RTAX_MAX; i++) { | |
251 | if (addrs & (1 << i)) { | |
252 | rti_info[i] = sa; | |
253 | sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); | |
9c859447 | 254 | } else { |
2b484d24 A |
255 | rti_info[i] = NULL; |
256 | } | |
257 | } | |
9c859447 | 258 | } |
2b484d24 A |
259 | |
260 | static void | |
261 | np_rtentry(struct rt_msghdr2 *rtm) | |
262 | { | |
263 | struct sockaddr *sa = (struct sockaddr *)(rtm + 1); | |
264 | struct sockaddr *rti_info[RTAX_MAX]; | |
265 | static int old_fam; | |
266 | int fam = 0; | |
267 | u_short lastindex = 0xffff; | |
268 | static char ifname[IFNAMSIZ + 1]; | |
269 | sa_u addr, mask; | |
270 | ||
271 | /* | |
272 | * Don't print protocol-cloned routes unless -a. | |
273 | */ | |
9c859447 A |
274 | if ((rtm->rtm_flags & RTF_WASCLONED) && |
275 | (rtm->rtm_parentflags & RTF_PRCLONING) && | |
276 | !aflag) { | |
2b484d24 | 277 | return; |
b7080c8e | 278 | } |
2b484d24 A |
279 | |
280 | fam = sa->sa_family; | |
281 | if (af != AF_UNSPEC && af != fam) | |
282 | return; | |
283 | if (fam != old_fam) { | |
284 | pr_family(fam); | |
285 | pr_rthdr(fam); | |
286 | old_fam = fam; | |
287 | } | |
288 | get_rtaddrs(rtm->rtm_addrs, sa, rti_info); | |
289 | bzero(&addr, sizeof(addr)); | |
290 | if ((rtm->rtm_addrs & RTA_DST)) | |
291 | bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len); | |
292 | bzero(&mask, sizeof(mask)); | |
293 | if ((rtm->rtm_addrs & RTA_NETMASK)) | |
294 | bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len); | |
295 | p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags, | |
296 | WID_DST(addr.u_sa.sa_family)); | |
297 | ||
298 | p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST, | |
299 | WID_GW(addr.u_sa.sa_family)); | |
300 | ||
9c859447 | 301 | p_flags(rtm->rtm_flags, "%-10.10s "); |
2b484d24 A |
302 | |
303 | if (addr.u_sa.sa_family == AF_INET || lflag) { | |
9c859447 | 304 | printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use); |
2b484d24 A |
305 | if (lflag) { |
306 | if (rtm->rtm_rmx.rmx_mtu != 0) | |
b8dff150 | 307 | printf("%6u ", rtm->rtm_rmx.rmx_mtu); |
2b484d24 A |
308 | else |
309 | printf("%6s ", ""); | |
b7080c8e | 310 | } |
b7080c8e | 311 | } |
2b484d24 A |
312 | if (rtm->rtm_index != lastindex) { |
313 | if_indextoname(rtm->rtm_index, ifname); | |
314 | lastindex = rtm->rtm_index; | |
315 | } | |
316 | printf("%*.*s", WID_IF(addr.u_sa.sa_family), | |
317 | WID_IF(addr.u_sa.sa_family), ifname); | |
318 | ||
319 | if (rtm->rtm_rmx.rmx_expire) { | |
320 | time_t expire_time; | |
321 | ||
322 | if ((expire_time = | |
323 | rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0) | |
324 | printf(" %6d", (int)expire_time); | |
b7080c8e | 325 | } |
b7080c8e A |
326 | putchar('\n'); |
327 | } | |
328 | ||
329 | static void | |
7ba0088d | 330 | p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) |
b7080c8e A |
331 | { |
332 | char workbuf[128], *cplim; | |
9c859447 | 333 | char *cp = workbuf; |
b7080c8e A |
334 | |
335 | switch(sa->sa_family) { | |
9c859447 A |
336 | case AF_INET: { |
337 | struct sockaddr_in *sin = (struct sockaddr_in *)sa; | |
b7080c8e | 338 | |
7ba0088d A |
339 | if ((sin->sin_addr.s_addr == INADDR_ANY) && |
340 | mask && | |
9c859447 | 341 | (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0)) |
7ba0088d | 342 | cp = "default" ; |
b7080c8e A |
343 | else if (flags & RTF_HOST) |
344 | cp = routename(sin->sin_addr.s_addr); | |
345 | else if (mask) | |
346 | cp = netname(sin->sin_addr.s_addr, | |
9c859447 A |
347 | ntohl(((struct sockaddr_in *)mask)-> |
348 | sin_addr.s_addr)); | |
b7080c8e A |
349 | else |
350 | cp = netname(sin->sin_addr.s_addr, 0L); | |
351 | break; | |
352 | } | |
7ba0088d A |
353 | |
354 | #ifdef INET6 | |
9c859447 | 355 | case AF_INET6: { |
7ba0088d A |
356 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; |
357 | struct in6_addr *in6 = &sa6->sin6_addr; | |
358 | ||
359 | /* | |
360 | * XXX: This is a special workaround for KAME kernels. | |
361 | * sin6_scope_id field of SA should be set in the future. | |
362 | */ | |
363 | if (IN6_IS_ADDR_LINKLOCAL(in6) || | |
fdfd5971 | 364 | IN6_IS_ADDR_MC_NODELOCAL(in6) || |
7ba0088d A |
365 | IN6_IS_ADDR_MC_LINKLOCAL(in6)) { |
366 | /* XXX: override is ok? */ | |
367 | sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); | |
368 | *(u_short *)&in6->s6_addr[2] = 0; | |
369 | } | |
370 | ||
371 | if (flags & RTF_HOST) | |
372 | cp = routename6(sa6); | |
373 | else if (mask) | |
2b484d24 | 374 | cp = netname6(sa6, mask); |
9c859447 | 375 | else |
7ba0088d | 376 | cp = netname6(sa6, NULL); |
7ba0088d A |
377 | break; |
378 | } | |
379 | #endif /*INET6*/ | |
b7080c8e | 380 | |
9c859447 A |
381 | case AF_LINK: { |
382 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; | |
b7080c8e A |
383 | |
384 | if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && | |
9c859447 | 385 | sdl->sdl_slen == 0) { |
fdfd5971 | 386 | (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index); |
9c859447 | 387 | } else { |
b7080c8e A |
388 | switch (sdl->sdl_type) { |
389 | ||
9c859447 A |
390 | case IFT_ETHER: { |
391 | int i; | |
392 | u_char *lla = (u_char *)sdl->sdl_data + | |
b7080c8e A |
393 | sdl->sdl_nlen; |
394 | ||
395 | cplim = ""; | |
396 | for (i = 0; i < sdl->sdl_alen; i++, lla++) { | |
fdfd5971 | 397 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla); |
b7080c8e A |
398 | cplim = ":"; |
399 | } | |
400 | cp = workbuf; | |
401 | break; | |
402 | } | |
403 | ||
404 | default: | |
405 | cp = link_ntoa(sdl); | |
406 | break; | |
407 | } | |
9c859447 | 408 | } |
b7080c8e A |
409 | break; |
410 | } | |
411 | ||
9c859447 A |
412 | default: { |
413 | u_char *s = (u_char *)sa->sa_data, *slim; | |
b7080c8e A |
414 | |
415 | slim = sa->sa_len + (u_char *) sa; | |
416 | cplim = cp + sizeof(workbuf) - 6; | |
fdfd5971 | 417 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family); |
b7080c8e | 418 | while (s < slim && cp < cplim) { |
fdfd5971 | 419 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++); |
b7080c8e | 420 | if (s < slim) |
fdfd5971 | 421 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++); |
b7080c8e A |
422 | } |
423 | cp = workbuf; | |
424 | } | |
425 | } | |
9c859447 | 426 | if (width < 0 ) { |
b7080c8e | 427 | printf("%s ", cp); |
9c859447 | 428 | } else { |
b7080c8e A |
429 | if (nflag) |
430 | printf("%-*s ", width, cp); | |
431 | else | |
432 | printf("%-*.*s ", width, width, cp); | |
433 | } | |
434 | } | |
435 | ||
436 | static void | |
7ba0088d | 437 | p_flags(int f, char *format) |
b7080c8e A |
438 | { |
439 | char name[33], *flags; | |
9c859447 | 440 | struct bits *p = bits; |
b7080c8e A |
441 | |
442 | for (flags = name; p->b_mask; p++) | |
443 | if (p->b_mask & f) | |
444 | *flags++ = p->b_val; | |
445 | *flags = '\0'; | |
446 | printf(format, name); | |
447 | } | |
448 | ||
b7080c8e | 449 | char * |
9c859447 | 450 | routename(uint32_t in) |
b7080c8e | 451 | { |
9c859447 | 452 | char *cp; |
7ba0088d | 453 | static char line[MAXHOSTNAMELEN]; |
b7080c8e A |
454 | struct hostent *hp; |
455 | ||
456 | cp = 0; | |
457 | if (!nflag) { | |
458 | hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), | |
459 | AF_INET); | |
460 | if (hp) { | |
461 | cp = hp->h_name; | |
7ba0088d | 462 | //### trimdomain(cp, strlen(cp)); |
b7080c8e A |
463 | } |
464 | } | |
465 | if (cp) { | |
466 | strncpy(line, cp, sizeof(line) - 1); | |
467 | line[sizeof(line) - 1] = '\0'; | |
468 | } else { | |
469 | #define C(x) ((x) & 0xff) | |
470 | in = ntohl(in); | |
fdfd5971 | 471 | snprintf(line, sizeof(line), "%u.%u.%u.%u", |
b7080c8e A |
472 | C(in >> 24), C(in >> 16), C(in >> 8), C(in)); |
473 | } | |
474 | return (line); | |
475 | } | |
476 | ||
9c859447 A |
477 | static uint32_t |
478 | forgemask(uint32_t a) | |
b7080c8e | 479 | { |
9c859447 | 480 | uint32_t m; |
b7080c8e A |
481 | |
482 | if (IN_CLASSA(a)) | |
483 | m = IN_CLASSA_NET; | |
484 | else if (IN_CLASSB(a)) | |
485 | m = IN_CLASSB_NET; | |
486 | else | |
487 | m = IN_CLASSC_NET; | |
488 | return (m); | |
489 | } | |
490 | ||
491 | static void | |
9c859447 | 492 | domask(char *dst, uint32_t addr, uint32_t mask) |
b7080c8e | 493 | { |
9c859447 | 494 | int b, i; |
b7080c8e A |
495 | |
496 | if (!mask || (forgemask(addr) == mask)) { | |
497 | *dst = '\0'; | |
498 | return; | |
499 | } | |
500 | i = 0; | |
501 | for (b = 0; b < 32; b++) | |
502 | if (mask & (1 << b)) { | |
9c859447 | 503 | int bb; |
b7080c8e A |
504 | |
505 | i = b; | |
506 | for (bb = b+1; bb < 32; bb++) | |
507 | if (!(mask & (1 << bb))) { | |
508 | i = -1; /* noncontig */ | |
509 | break; | |
510 | } | |
511 | break; | |
512 | } | |
513 | if (i == -1) | |
fdfd5971 | 514 | snprintf(dst, sizeof(dst), "&0x%x", mask); |
b7080c8e | 515 | else |
fdfd5971 | 516 | snprintf(dst, sizeof(dst), "/%d", 32-i); |
b7080c8e A |
517 | } |
518 | ||
519 | /* | |
520 | * Return the name of the network whose address is given. | |
521 | * The address is assumed to be that of a net or subnet, not a host. | |
522 | */ | |
523 | char * | |
9c859447 | 524 | netname(uint32_t in, uint32_t mask) |
b7080c8e A |
525 | { |
526 | char *cp = 0; | |
7ba0088d | 527 | static char line[MAXHOSTNAMELEN]; |
b7080c8e | 528 | struct netent *np = 0; |
9c859447 A |
529 | uint32_t net, omask, dmask; |
530 | uint32_t i; | |
b7080c8e A |
531 | |
532 | i = ntohl(in); | |
7ba0088d | 533 | dmask = forgemask(i); |
b7080c8e A |
534 | omask = mask; |
535 | if (!nflag && i) { | |
b7080c8e A |
536 | net = i & dmask; |
537 | if (!(np = getnetbyaddr(i, AF_INET)) && net != i) | |
538 | np = getnetbyaddr(net, AF_INET); | |
539 | if (np) { | |
540 | cp = np->n_name; | |
7ba0088d | 541 | //### trimdomain(cp, strlen(cp)); |
b7080c8e A |
542 | } |
543 | } | |
544 | if (cp) | |
545 | strncpy(line, cp, sizeof(line) - 1); | |
7ba0088d A |
546 | else { |
547 | switch (dmask) { | |
548 | case IN_CLASSA_NET: | |
549 | if ((i & IN_CLASSA_HOST) == 0) { | |
fdfd5971 | 550 | snprintf(line, sizeof(line), "%u", C(i >> 24)); |
7ba0088d A |
551 | break; |
552 | } | |
553 | /* FALLTHROUGH */ | |
554 | case IN_CLASSB_NET: | |
555 | if ((i & IN_CLASSB_HOST) == 0) { | |
fdfd5971 | 556 | snprintf(line, sizeof(line), "%u.%u", |
7ba0088d A |
557 | C(i >> 24), C(i >> 16)); |
558 | break; | |
559 | } | |
560 | /* FALLTHROUGH */ | |
561 | case IN_CLASSC_NET: | |
562 | if ((i & IN_CLASSC_HOST) == 0) { | |
fdfd5971 | 563 | snprintf(line, sizeof(line), "%u.%u.%u", |
7ba0088d A |
564 | C(i >> 24), C(i >> 16), C(i >> 8)); |
565 | break; | |
566 | } | |
567 | /* FALLTHROUGH */ | |
568 | default: | |
fdfd5971 | 569 | snprintf(line, sizeof(line), "%u.%u.%u.%u", |
7ba0088d A |
570 | C(i >> 24), C(i >> 16), C(i >> 8), C(i)); |
571 | break; | |
572 | } | |
573 | } | |
b7080c8e A |
574 | domask(line+strlen(line), i, omask); |
575 | return (line); | |
576 | } | |
577 | ||
7ba0088d A |
578 | #ifdef INET6 |
579 | char * | |
2b484d24 | 580 | netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam) |
7ba0088d A |
581 | { |
582 | static char line[MAXHOSTNAMELEN]; | |
7ba0088d A |
583 | u_char *lim; |
584 | int masklen, illegal = 0, flag = NI_WITHSCOPEID; | |
2b484d24 | 585 | struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0; |
7ba0088d | 586 | |
2b484d24 A |
587 | if (sam && sam->sa_len == 0) { |
588 | masklen = 0; | |
589 | } else if (mask) { | |
590 | u_char *p = (u_char *)mask; | |
7ba0088d A |
591 | for (masklen = 0, lim = p + 16; p < lim; p++) { |
592 | switch (*p) { | |
593 | case 0xff: | |
594 | masklen += 8; | |
595 | break; | |
596 | case 0xfe: | |
597 | masklen += 7; | |
598 | break; | |
599 | case 0xfc: | |
600 | masklen += 6; | |
601 | break; | |
602 | case 0xf8: | |
603 | masklen += 5; | |
604 | break; | |
605 | case 0xf0: | |
606 | masklen += 4; | |
607 | break; | |
608 | case 0xe0: | |
609 | masklen += 3; | |
610 | break; | |
611 | case 0xc0: | |
612 | masklen += 2; | |
613 | break; | |
614 | case 0x80: | |
615 | masklen += 1; | |
616 | break; | |
617 | case 0x00: | |
618 | break; | |
619 | default: | |
620 | illegal ++; | |
621 | break; | |
622 | } | |
623 | } | |
624 | if (illegal) | |
625 | fprintf(stderr, "illegal prefixlen\n"); | |
9c859447 | 626 | } else { |
7ba0088d | 627 | masklen = 128; |
9c859447 | 628 | } |
7ba0088d A |
629 | if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) |
630 | return("default"); | |
631 | ||
632 | if (nflag) | |
633 | flag |= NI_NUMERICHOST; | |
634 | getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), | |
635 | NULL, 0, flag); | |
636 | ||
637 | if (nflag) | |
fdfd5971 | 638 | snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen); |
7ba0088d A |
639 | |
640 | return line; | |
641 | } | |
642 | ||
643 | char * | |
644 | routename6(struct sockaddr_in6 *sa6) | |
645 | { | |
646 | static char line[MAXHOSTNAMELEN]; | |
647 | int flag = NI_WITHSCOPEID; | |
648 | /* use local variable for safety */ | |
ac2f15b3 | 649 | struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, }; |
7ba0088d A |
650 | |
651 | sa6_local.sin6_addr = sa6->sin6_addr; | |
652 | sa6_local.sin6_scope_id = sa6->sin6_scope_id; | |
653 | ||
654 | if (nflag) | |
655 | flag |= NI_NUMERICHOST; | |
656 | ||
657 | getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, | |
658 | line, sizeof(line), NULL, 0, flag); | |
659 | ||
660 | return line; | |
661 | } | |
662 | #endif /*INET6*/ | |
663 | ||
b7080c8e A |
664 | /* |
665 | * Print routing statistics | |
666 | */ | |
667 | void | |
2b484d24 | 668 | rt_stats(void) |
b7080c8e A |
669 | { |
670 | struct rtstat rtstat; | |
7ba0088d | 671 | int rttrash; |
2b484d24 A |
672 | int mib[6]; |
673 | size_t len; | |
b7080c8e | 674 | |
2b484d24 A |
675 | mib[0] = CTL_NET; |
676 | mib[1] = AF_ROUTE; | |
677 | mib[2] = 0; | |
678 | mib[3] = 0; | |
679 | mib[4] = NET_RT_STAT; | |
680 | mib[5] = 0; | |
681 | len = sizeof(struct rtstat); | |
682 | if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1) | |
b7080c8e | 683 | return; |
2b484d24 A |
684 | |
685 | mib[0] = CTL_NET; | |
686 | mib[1] = AF_ROUTE; | |
687 | mib[2] = 0; | |
688 | mib[3] = 0; | |
689 | mib[4] = NET_RT_TRASH; | |
690 | mib[5] = 0; | |
691 | len = sizeof(rttrash); | |
692 | if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1) | |
7ba0088d | 693 | return; |
2b484d24 | 694 | |
b7080c8e | 695 | printf("routing:\n"); |
b7080c8e | 696 | |
7ba0088d A |
697 | #define p(f, m) if (rtstat.f || sflag <= 1) \ |
698 | printf(m, rtstat.f, plural(rtstat.f)) | |
699 | ||
700 | p(rts_badredirect, "\t%u bad routing redirect%s\n"); | |
701 | p(rts_dynamic, "\t%u dynamically created route%s\n"); | |
702 | p(rts_newgateway, "\t%u new gateway%s due to redirects\n"); | |
703 | p(rts_unreach, "\t%u destination%s found unreachable\n"); | |
704 | p(rts_wildcard, "\t%u use%s of a wildcard route\n"); | |
705 | #undef p | |
b7080c8e | 706 | |
7ba0088d A |
707 | if (rttrash || sflag <= 1) |
708 | printf("\t%u route%s not in table but not freed\n", | |
709 | rttrash, plural(rttrash)); | |
710 | } | |
b7080c8e A |
711 | |
712 | void | |
7ba0088d | 713 | upHex(char *p0) |
b7080c8e | 714 | { |
9c859447 | 715 | char *p = p0; |
b7080c8e A |
716 | |
717 | for (; *p; p++) | |
718 | switch (*p) { | |
719 | ||
720 | case 'a': | |
721 | case 'b': | |
722 | case 'c': | |
723 | case 'd': | |
724 | case 'e': | |
725 | case 'f': | |
726 | *p += ('A' - 'a'); | |
727 | break; | |
728 | } | |
729 | } |