]>
Commit | Line | Data |
---|---|---|
b7080c8e | 1 | /* |
d9520f62 | 2 | * Copyright (c) 2008-2017 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 */ | |
e0b07f2d | 171 | #define WID_RT_IFA(af) 18 /* width of source column */ |
9c859447 | 172 | #define WID_IF(af) 7 /* width of netif column */ |
7ba0088d A |
173 | #else |
174 | #define WID_DST(af) \ | |
2b484d24 | 175 | ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18) |
7ba0088d | 176 | #define WID_GW(af) \ |
2b484d24 | 177 | ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18) |
e0b07f2d A |
178 | #define WID_RT_IFA(af) \ |
179 | ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18) | |
9c859447 | 180 | #define WID_IF(af) ((af) == AF_INET6 ? 8 : 7) |
7ba0088d | 181 | #endif /*INET6*/ |
b7080c8e A |
182 | |
183 | /* | |
184 | * Print header for routing table columns. | |
185 | */ | |
186 | void | |
7ba0088d | 187 | pr_rthdr(int af) |
b7080c8e | 188 | { |
e0b07f2d | 189 | if (lflag) { |
213b8c4f | 190 | if (lflag > 2) |
e0b07f2d A |
191 | printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s " |
192 | "%10s %10s %8s %8s %8s\n", | |
193 | WID_DST(af), WID_DST(af), "Destination", | |
194 | WID_GW(af), WID_GW(af), "Gateway", | |
195 | WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA", | |
196 | "Flags", "Refs", "Use", "Mtu", | |
197 | WID_IF(af), WID_IF(af), "Netif", "Expire", | |
198 | "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh"); | |
213b8c4f | 199 | else if (lflag > 1) |
e0b07f2d A |
200 | printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s " |
201 | "%10s %10s\n", | |
7ba0088d A |
202 | WID_DST(af), WID_DST(af), "Destination", |
203 | WID_GW(af), WID_GW(af), "Gateway", | |
e0b07f2d | 204 | WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA", |
7ba0088d | 205 | "Flags", "Refs", "Use", "Mtu", |
e0b07f2d A |
206 | WID_IF(af), WID_IF(af), "Netif", "Expire", |
207 | "rtt(ms)", "rttvar(ms)"); | |
7ba0088d | 208 | else |
e0b07f2d | 209 | printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n", |
7ba0088d A |
210 | WID_DST(af), WID_DST(af), "Destination", |
211 | WID_GW(af), WID_GW(af), "Gateway", | |
e0b07f2d A |
212 | WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA", |
213 | "Flags", "Refs", "Use", "Mtu", | |
7ba0088d | 214 | WID_IF(af), WID_IF(af), "Netif", "Expire"); |
e0b07f2d A |
215 | } else { |
216 | printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n", | |
7ba0088d A |
217 | WID_DST(af), WID_DST(af), "Destination", |
218 | WID_GW(af), WID_GW(af), "Gateway", | |
e0b07f2d A |
219 | "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire"); |
220 | } | |
213b8c4f | 221 | } |
b7080c8e | 222 | |
9dc66a05 A |
223 | /* |
224 | * Print routing tables. | |
225 | */ | |
226 | void | |
227 | routepr(void) | |
b7080c8e A |
228 | { |
229 | size_t needed; | |
230 | int mib[6]; | |
231 | char *buf, *next, *lim; | |
9c859447 | 232 | struct rt_msghdr2 *rtm; |
b7080c8e | 233 | |
9dc66a05 A |
234 | printf("Routing tables\n"); |
235 | ||
b7080c8e A |
236 | mib[0] = CTL_NET; |
237 | mib[1] = PF_ROUTE; | |
238 | mib[2] = 0; | |
239 | mib[3] = 0; | |
2b484d24 | 240 | mib[4] = NET_RT_DUMP2; |
b7080c8e A |
241 | mib[5] = 0; |
242 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { | |
243 | err(1, "sysctl: net.route.0.0.dump estimate"); | |
244 | } | |
245 | ||
246 | if ((buf = malloc(needed)) == 0) { | |
247 | err(2, "malloc(%lu)", (unsigned long)needed); | |
248 | } | |
249 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { | |
250 | err(1, "sysctl: net.route.0.0.dump"); | |
251 | } | |
252 | lim = buf + needed; | |
253 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | |
2b484d24 | 254 | rtm = (struct rt_msghdr2 *)next; |
b7080c8e A |
255 | np_rtentry(rtm); |
256 | } | |
257 | } | |
258 | ||
259 | static void | |
2b484d24 | 260 | get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) |
b7080c8e | 261 | { |
2b484d24 A |
262 | int i; |
263 | ||
264 | for (i = 0; i < RTAX_MAX; i++) { | |
265 | if (addrs & (1 << i)) { | |
266 | rti_info[i] = sa; | |
267 | sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); | |
9c859447 | 268 | } else { |
2b484d24 A |
269 | rti_info[i] = NULL; |
270 | } | |
271 | } | |
9c859447 | 272 | } |
2b484d24 A |
273 | |
274 | static void | |
275 | np_rtentry(struct rt_msghdr2 *rtm) | |
276 | { | |
277 | struct sockaddr *sa = (struct sockaddr *)(rtm + 1); | |
278 | struct sockaddr *rti_info[RTAX_MAX]; | |
279 | static int old_fam; | |
280 | int fam = 0; | |
281 | u_short lastindex = 0xffff; | |
282 | static char ifname[IFNAMSIZ + 1]; | |
283 | sa_u addr, mask; | |
284 | ||
285 | /* | |
286 | * Don't print protocol-cloned routes unless -a. | |
287 | */ | |
9c859447 A |
288 | if ((rtm->rtm_flags & RTF_WASCLONED) && |
289 | (rtm->rtm_parentflags & RTF_PRCLONING) && | |
290 | !aflag) { | |
2b484d24 | 291 | return; |
b7080c8e | 292 | } |
2b484d24 | 293 | |
213b8c4f A |
294 | if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0) |
295 | return; | |
2b484d24 A |
296 | fam = sa->sa_family; |
297 | if (af != AF_UNSPEC && af != fam) | |
298 | return; | |
299 | if (fam != old_fam) { | |
300 | pr_family(fam); | |
301 | pr_rthdr(fam); | |
302 | old_fam = fam; | |
303 | } | |
304 | get_rtaddrs(rtm->rtm_addrs, sa, rti_info); | |
305 | bzero(&addr, sizeof(addr)); | |
306 | if ((rtm->rtm_addrs & RTA_DST)) | |
307 | bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len); | |
308 | bzero(&mask, sizeof(mask)); | |
309 | if ((rtm->rtm_addrs & RTA_NETMASK)) | |
310 | bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len); | |
311 | p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags, | |
312 | WID_DST(addr.u_sa.sa_family)); | |
313 | ||
314 | p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST, | |
315 | WID_GW(addr.u_sa.sa_family)); | |
e0b07f2d A |
316 | |
317 | if (lflag && (rtm->rtm_addrs & RTA_IFA)) { | |
318 | p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST, | |
319 | WID_RT_IFA(addr.u_sa.sa_family)); | |
320 | } | |
2b484d24 | 321 | |
9c859447 | 322 | p_flags(rtm->rtm_flags, "%-10.10s "); |
2b484d24 | 323 | |
e0b07f2d | 324 | if (lflag) { |
9c859447 | 325 | printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use); |
e0b07f2d A |
326 | if (rtm->rtm_rmx.rmx_mtu != 0) |
327 | printf("%6u ", rtm->rtm_rmx.rmx_mtu); | |
328 | else | |
329 | printf("%6s ", ""); | |
b7080c8e | 330 | } |
e0b07f2d | 331 | |
2b484d24 A |
332 | if (rtm->rtm_index != lastindex) { |
333 | if_indextoname(rtm->rtm_index, ifname); | |
334 | lastindex = rtm->rtm_index; | |
335 | } | |
336 | printf("%*.*s", WID_IF(addr.u_sa.sa_family), | |
337 | WID_IF(addr.u_sa.sa_family), ifname); | |
338 | ||
339 | if (rtm->rtm_rmx.rmx_expire) { | |
340 | time_t expire_time; | |
341 | ||
342 | if ((expire_time = | |
343 | rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0) | |
344 | printf(" %6d", (int)expire_time); | |
213b8c4f A |
345 | else |
346 | printf(" %6s", "!"); | |
347 | } else { | |
348 | printf(" %6s", ""); | |
349 | } | |
350 | if (lflag > 1) { | |
351 | if (rtm->rtm_rmx.rmx_rtt != 0) | |
352 | printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000, | |
353 | rtm->rtm_rmx.rmx_rtt % 1000); | |
354 | else | |
355 | printf(" %10s", ""); | |
356 | if (rtm->rtm_rmx.rmx_rttvar != 0) | |
357 | printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000, | |
358 | rtm->rtm_rmx.rmx_rttvar % 1000); | |
359 | else | |
360 | printf(" %10s", ""); | |
361 | if (lflag > 2) { | |
362 | if (rtm->rtm_rmx.rmx_recvpipe != 0) | |
363 | printf(" %8u", rtm->rtm_rmx.rmx_recvpipe); | |
364 | else | |
365 | printf(" %8s", ""); | |
366 | if (rtm->rtm_rmx.rmx_sendpipe != 0) | |
367 | printf(" %8u", rtm->rtm_rmx.rmx_sendpipe); | |
368 | else | |
369 | printf(" %8s", ""); | |
370 | if (rtm->rtm_rmx.rmx_ssthresh != 0) | |
371 | printf(" %8u", rtm->rtm_rmx.rmx_ssthresh); | |
372 | else | |
373 | printf(" %8s", ""); | |
374 | } | |
b7080c8e | 375 | } |
b7080c8e A |
376 | putchar('\n'); |
377 | } | |
378 | ||
379 | static void | |
7ba0088d | 380 | p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) |
b7080c8e A |
381 | { |
382 | char workbuf[128], *cplim; | |
9c859447 | 383 | char *cp = workbuf; |
b7080c8e A |
384 | |
385 | switch(sa->sa_family) { | |
9c859447 A |
386 | case AF_INET: { |
387 | struct sockaddr_in *sin = (struct sockaddr_in *)sa; | |
b7080c8e | 388 | |
7ba0088d A |
389 | if ((sin->sin_addr.s_addr == INADDR_ANY) && |
390 | mask && | |
9c859447 | 391 | (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0)) |
7ba0088d | 392 | cp = "default" ; |
b7080c8e A |
393 | else if (flags & RTF_HOST) |
394 | cp = routename(sin->sin_addr.s_addr); | |
395 | else if (mask) | |
396 | cp = netname(sin->sin_addr.s_addr, | |
9c859447 A |
397 | ntohl(((struct sockaddr_in *)mask)-> |
398 | sin_addr.s_addr)); | |
b7080c8e A |
399 | else |
400 | cp = netname(sin->sin_addr.s_addr, 0L); | |
401 | break; | |
402 | } | |
7ba0088d A |
403 | |
404 | #ifdef INET6 | |
9c859447 | 405 | case AF_INET6: { |
7ba0088d A |
406 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; |
407 | struct in6_addr *in6 = &sa6->sin6_addr; | |
408 | ||
409 | /* | |
410 | * XXX: This is a special workaround for KAME kernels. | |
411 | * sin6_scope_id field of SA should be set in the future. | |
412 | */ | |
413 | if (IN6_IS_ADDR_LINKLOCAL(in6) || | |
fdfd5971 | 414 | IN6_IS_ADDR_MC_NODELOCAL(in6) || |
7ba0088d A |
415 | IN6_IS_ADDR_MC_LINKLOCAL(in6)) { |
416 | /* XXX: override is ok? */ | |
417 | sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); | |
418 | *(u_short *)&in6->s6_addr[2] = 0; | |
419 | } | |
420 | ||
421 | if (flags & RTF_HOST) | |
422 | cp = routename6(sa6); | |
423 | else if (mask) | |
2b484d24 | 424 | cp = netname6(sa6, mask); |
9c859447 | 425 | else |
7ba0088d | 426 | cp = netname6(sa6, NULL); |
7ba0088d A |
427 | break; |
428 | } | |
429 | #endif /*INET6*/ | |
b7080c8e | 430 | |
9c859447 A |
431 | case AF_LINK: { |
432 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; | |
b7080c8e A |
433 | |
434 | if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && | |
9c859447 | 435 | sdl->sdl_slen == 0) { |
fdfd5971 | 436 | (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index); |
9c859447 | 437 | } else { |
b7080c8e A |
438 | switch (sdl->sdl_type) { |
439 | ||
9c859447 A |
440 | case IFT_ETHER: { |
441 | int i; | |
442 | u_char *lla = (u_char *)sdl->sdl_data + | |
b7080c8e A |
443 | sdl->sdl_nlen; |
444 | ||
445 | cplim = ""; | |
446 | for (i = 0; i < sdl->sdl_alen; i++, lla++) { | |
fdfd5971 | 447 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla); |
b7080c8e A |
448 | cplim = ":"; |
449 | } | |
450 | cp = workbuf; | |
451 | break; | |
452 | } | |
453 | ||
454 | default: | |
455 | cp = link_ntoa(sdl); | |
456 | break; | |
457 | } | |
9c859447 | 458 | } |
b7080c8e A |
459 | break; |
460 | } | |
461 | ||
9c859447 A |
462 | default: { |
463 | u_char *s = (u_char *)sa->sa_data, *slim; | |
b7080c8e A |
464 | |
465 | slim = sa->sa_len + (u_char *) sa; | |
466 | cplim = cp + sizeof(workbuf) - 6; | |
fdfd5971 | 467 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family); |
b7080c8e | 468 | while (s < slim && cp < cplim) { |
fdfd5971 | 469 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++); |
b7080c8e | 470 | if (s < slim) |
fdfd5971 | 471 | cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++); |
b7080c8e A |
472 | } |
473 | cp = workbuf; | |
474 | } | |
475 | } | |
9c859447 | 476 | if (width < 0 ) { |
b7080c8e | 477 | printf("%s ", cp); |
9c859447 | 478 | } else { |
b7080c8e A |
479 | if (nflag) |
480 | printf("%-*s ", width, cp); | |
481 | else | |
482 | printf("%-*.*s ", width, width, cp); | |
483 | } | |
484 | } | |
485 | ||
486 | static void | |
7ba0088d | 487 | p_flags(int f, char *format) |
b7080c8e A |
488 | { |
489 | char name[33], *flags; | |
9c859447 | 490 | struct bits *p = bits; |
b7080c8e A |
491 | |
492 | for (flags = name; p->b_mask; p++) | |
493 | if (p->b_mask & f) | |
494 | *flags++ = p->b_val; | |
495 | *flags = '\0'; | |
496 | printf(format, name); | |
497 | } | |
498 | ||
b7080c8e | 499 | char * |
9c859447 | 500 | routename(uint32_t in) |
b7080c8e | 501 | { |
9c859447 | 502 | char *cp; |
7ba0088d | 503 | static char line[MAXHOSTNAMELEN]; |
b7080c8e A |
504 | struct hostent *hp; |
505 | ||
506 | cp = 0; | |
507 | if (!nflag) { | |
508 | hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), | |
509 | AF_INET); | |
510 | if (hp) { | |
511 | cp = hp->h_name; | |
7ba0088d | 512 | //### trimdomain(cp, strlen(cp)); |
b7080c8e A |
513 | } |
514 | } | |
515 | if (cp) { | |
e0b07f2d | 516 | strlcpy(line, cp, sizeof(line)); |
b7080c8e A |
517 | } else { |
518 | #define C(x) ((x) & 0xff) | |
519 | in = ntohl(in); | |
fdfd5971 | 520 | snprintf(line, sizeof(line), "%u.%u.%u.%u", |
b7080c8e A |
521 | C(in >> 24), C(in >> 16), C(in >> 8), C(in)); |
522 | } | |
523 | return (line); | |
524 | } | |
525 | ||
9c859447 A |
526 | static uint32_t |
527 | forgemask(uint32_t a) | |
b7080c8e | 528 | { |
9c859447 | 529 | uint32_t m; |
b7080c8e A |
530 | |
531 | if (IN_CLASSA(a)) | |
532 | m = IN_CLASSA_NET; | |
533 | else if (IN_CLASSB(a)) | |
534 | m = IN_CLASSB_NET; | |
535 | else | |
536 | m = IN_CLASSC_NET; | |
537 | return (m); | |
538 | } | |
539 | ||
540 | static void | |
9c859447 | 541 | domask(char *dst, uint32_t addr, uint32_t mask) |
b7080c8e | 542 | { |
9c859447 | 543 | int b, i; |
b7080c8e A |
544 | |
545 | if (!mask || (forgemask(addr) == mask)) { | |
546 | *dst = '\0'; | |
547 | return; | |
548 | } | |
549 | i = 0; | |
550 | for (b = 0; b < 32; b++) | |
551 | if (mask & (1 << b)) { | |
9c859447 | 552 | int bb; |
b7080c8e A |
553 | |
554 | i = b; | |
555 | for (bb = b+1; bb < 32; bb++) | |
556 | if (!(mask & (1 << bb))) { | |
557 | i = -1; /* noncontig */ | |
558 | break; | |
559 | } | |
560 | break; | |
561 | } | |
562 | if (i == -1) | |
fdfd5971 | 563 | snprintf(dst, sizeof(dst), "&0x%x", mask); |
b7080c8e | 564 | else |
fdfd5971 | 565 | snprintf(dst, sizeof(dst), "/%d", 32-i); |
b7080c8e A |
566 | } |
567 | ||
568 | /* | |
569 | * Return the name of the network whose address is given. | |
570 | * The address is assumed to be that of a net or subnet, not a host. | |
571 | */ | |
572 | char * | |
9c859447 | 573 | netname(uint32_t in, uint32_t mask) |
b7080c8e A |
574 | { |
575 | char *cp = 0; | |
7ba0088d | 576 | static char line[MAXHOSTNAMELEN]; |
b7080c8e | 577 | struct netent *np = 0; |
9c859447 A |
578 | uint32_t net, omask, dmask; |
579 | uint32_t i; | |
b7080c8e A |
580 | |
581 | i = ntohl(in); | |
7ba0088d | 582 | dmask = forgemask(i); |
b7080c8e A |
583 | omask = mask; |
584 | if (!nflag && i) { | |
b7080c8e A |
585 | net = i & dmask; |
586 | if (!(np = getnetbyaddr(i, AF_INET)) && net != i) | |
587 | np = getnetbyaddr(net, AF_INET); | |
588 | if (np) { | |
589 | cp = np->n_name; | |
7ba0088d | 590 | //### trimdomain(cp, strlen(cp)); |
b7080c8e A |
591 | } |
592 | } | |
593 | if (cp) | |
e0b07f2d | 594 | strlcpy(line, cp, sizeof(line)); |
7ba0088d A |
595 | else { |
596 | switch (dmask) { | |
597 | case IN_CLASSA_NET: | |
598 | if ((i & IN_CLASSA_HOST) == 0) { | |
fdfd5971 | 599 | snprintf(line, sizeof(line), "%u", C(i >> 24)); |
7ba0088d A |
600 | break; |
601 | } | |
602 | /* FALLTHROUGH */ | |
603 | case IN_CLASSB_NET: | |
604 | if ((i & IN_CLASSB_HOST) == 0) { | |
fdfd5971 | 605 | snprintf(line, sizeof(line), "%u.%u", |
7ba0088d A |
606 | C(i >> 24), C(i >> 16)); |
607 | break; | |
608 | } | |
609 | /* FALLTHROUGH */ | |
610 | case IN_CLASSC_NET: | |
611 | if ((i & IN_CLASSC_HOST) == 0) { | |
fdfd5971 | 612 | snprintf(line, sizeof(line), "%u.%u.%u", |
7ba0088d A |
613 | C(i >> 24), C(i >> 16), C(i >> 8)); |
614 | break; | |
615 | } | |
616 | /* FALLTHROUGH */ | |
617 | default: | |
fdfd5971 | 618 | snprintf(line, sizeof(line), "%u.%u.%u.%u", |
7ba0088d A |
619 | C(i >> 24), C(i >> 16), C(i >> 8), C(i)); |
620 | break; | |
621 | } | |
622 | } | |
b7080c8e A |
623 | domask(line+strlen(line), i, omask); |
624 | return (line); | |
625 | } | |
626 | ||
7ba0088d A |
627 | #ifdef INET6 |
628 | char * | |
2b484d24 | 629 | netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam) |
7ba0088d A |
630 | { |
631 | static char line[MAXHOSTNAMELEN]; | |
7ba0088d A |
632 | u_char *lim; |
633 | int masklen, illegal = 0, flag = NI_WITHSCOPEID; | |
2b484d24 | 634 | struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0; |
7ba0088d | 635 | |
2b484d24 A |
636 | if (sam && sam->sa_len == 0) { |
637 | masklen = 0; | |
638 | } else if (mask) { | |
639 | u_char *p = (u_char *)mask; | |
7ba0088d A |
640 | for (masklen = 0, lim = p + 16; p < lim; p++) { |
641 | switch (*p) { | |
642 | case 0xff: | |
643 | masklen += 8; | |
644 | break; | |
645 | case 0xfe: | |
646 | masklen += 7; | |
647 | break; | |
648 | case 0xfc: | |
649 | masklen += 6; | |
650 | break; | |
651 | case 0xf8: | |
652 | masklen += 5; | |
653 | break; | |
654 | case 0xf0: | |
655 | masklen += 4; | |
656 | break; | |
657 | case 0xe0: | |
658 | masklen += 3; | |
659 | break; | |
660 | case 0xc0: | |
661 | masklen += 2; | |
662 | break; | |
663 | case 0x80: | |
664 | masklen += 1; | |
665 | break; | |
666 | case 0x00: | |
667 | break; | |
668 | default: | |
669 | illegal ++; | |
670 | break; | |
671 | } | |
672 | } | |
673 | if (illegal) | |
674 | fprintf(stderr, "illegal prefixlen\n"); | |
9c859447 | 675 | } else { |
7ba0088d | 676 | masklen = 128; |
9c859447 | 677 | } |
7ba0088d A |
678 | if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) |
679 | return("default"); | |
680 | ||
681 | if (nflag) | |
682 | flag |= NI_NUMERICHOST; | |
683 | getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), | |
684 | NULL, 0, flag); | |
685 | ||
686 | if (nflag) | |
fdfd5971 | 687 | snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen); |
7ba0088d A |
688 | |
689 | return line; | |
690 | } | |
691 | ||
692 | char * | |
693 | routename6(struct sockaddr_in6 *sa6) | |
694 | { | |
695 | static char line[MAXHOSTNAMELEN]; | |
696 | int flag = NI_WITHSCOPEID; | |
697 | /* use local variable for safety */ | |
ac2f15b3 | 698 | struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, }; |
7ba0088d A |
699 | |
700 | sa6_local.sin6_addr = sa6->sin6_addr; | |
701 | sa6_local.sin6_scope_id = sa6->sin6_scope_id; | |
702 | ||
703 | if (nflag) | |
704 | flag |= NI_NUMERICHOST; | |
705 | ||
706 | getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, | |
707 | line, sizeof(line), NULL, 0, flag); | |
708 | ||
709 | return line; | |
710 | } | |
711 | #endif /*INET6*/ | |
712 | ||
b7080c8e A |
713 | /* |
714 | * Print routing statistics | |
715 | */ | |
716 | void | |
2b484d24 | 717 | rt_stats(void) |
b7080c8e A |
718 | { |
719 | struct rtstat rtstat; | |
7ba0088d | 720 | int rttrash; |
2b484d24 A |
721 | int mib[6]; |
722 | size_t len; | |
b7080c8e | 723 | |
2b484d24 A |
724 | mib[0] = CTL_NET; |
725 | mib[1] = AF_ROUTE; | |
726 | mib[2] = 0; | |
727 | mib[3] = 0; | |
728 | mib[4] = NET_RT_STAT; | |
729 | mib[5] = 0; | |
730 | len = sizeof(struct rtstat); | |
731 | if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1) | |
b7080c8e | 732 | return; |
2b484d24 A |
733 | |
734 | mib[0] = CTL_NET; | |
735 | mib[1] = AF_ROUTE; | |
736 | mib[2] = 0; | |
737 | mib[3] = 0; | |
738 | mib[4] = NET_RT_TRASH; | |
739 | mib[5] = 0; | |
740 | len = sizeof(rttrash); | |
741 | if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1) | |
7ba0088d | 742 | return; |
2b484d24 | 743 | |
b7080c8e | 744 | printf("routing:\n"); |
b7080c8e | 745 | |
7ba0088d A |
746 | #define p(f, m) if (rtstat.f || sflag <= 1) \ |
747 | printf(m, rtstat.f, plural(rtstat.f)) | |
748 | ||
749 | p(rts_badredirect, "\t%u bad routing redirect%s\n"); | |
750 | p(rts_dynamic, "\t%u dynamically created route%s\n"); | |
751 | p(rts_newgateway, "\t%u new gateway%s due to redirects\n"); | |
752 | p(rts_unreach, "\t%u destination%s found unreachable\n"); | |
753 | p(rts_wildcard, "\t%u use%s of a wildcard route\n"); | |
d9520f62 A |
754 | p(rts_badrtgwroute, "\t%u lookup%s returned indirect " |
755 | "routes pointing to indirect gateway route\n"); | |
7ba0088d | 756 | #undef p |
b7080c8e | 757 | |
7ba0088d A |
758 | if (rttrash || sflag <= 1) |
759 | printf("\t%u route%s not in table but not freed\n", | |
760 | rttrash, plural(rttrash)); | |
761 | } | |
b7080c8e A |
762 | |
763 | void | |
7ba0088d | 764 | upHex(char *p0) |
b7080c8e | 765 | { |
9c859447 | 766 | char *p = p0; |
b7080c8e A |
767 | |
768 | for (; *p; p++) | |
769 | switch (*p) { | |
770 | ||
771 | case 'a': | |
772 | case 'b': | |
773 | case 'c': | |
774 | case 'd': | |
775 | case 'e': | |
776 | case 'f': | |
777 | *p += ('A' - 'a'); | |
778 | break; | |
779 | } | |
780 | } |