]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/main.c
e097bc665f41e1f580ff5af1e9822ff90b8312cc
[apple/network_cmds.git] / netstat.tproj / main.c
1 /*
2 * Copyright (c) 2008-2013 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 * 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 #ifndef lint
62 char const copyright[] =
63 "@(#) Copyright (c) 1983, 1988, 1993\n\
64 Regents of the University of California. All rights reserved.\n";
65 #endif /* not lint */
66
67 #include <sys/param.h>
68 #include <sys/file.h>
69 #include <sys/socket.h>
70
71 #include <netinet/in.h>
72 #include <net/pfkeyv2.h>
73
74 #include <ctype.h>
75 #include <err.h>
76 #include <errno.h>
77 #include <limits.h>
78 #include <netdb.h>
79 #include <nlist.h>
80 #include <paths.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <unistd.h>
85 #include "netstat.h"
86 #include <sys/types.h>
87 #include <sys/sysctl.h>
88
89 #ifdef __APPLE__
90 #include <TargetConditionals.h>
91 #endif
92
93 /*
94 * ----------------------------------------------------------------------------
95 * "THE BEER-WARE LICENSE" (Revision 42):
96 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
97 * can do whatever you want with this stuff. If we meet some day, and you think
98 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
99 * ----------------------------------------------------------------------------
100 *
101 * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
102 *
103 */
104
105 struct protox {
106 void (*pr_cblocks)(uint32_t, char *, int);
107 /* control blocks printing routine */
108 void (*pr_stats)(uint32_t, char *, int);
109 /* statistics printing routine */
110 void (*pr_istats)(char *); /* per/if statistics printing routine */
111 char *pr_name; /* well-known name */
112 int pr_protocol;
113 } protox[] = {
114 { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
115 { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
116 { protopr, NULL, NULL, "divert", IPPROTO_DIVERT },
117 { protopr, ip_stats, NULL, "ip", IPPROTO_RAW },
118 { protopr, icmp_stats, NULL, "icmp", IPPROTO_ICMP },
119 { protopr, igmp_stats, NULL, "igmp", IPPROTO_IGMP },
120 #ifdef IPSEC
121 { NULL, ipsec_stats, NULL, "ipsec", IPPROTO_ESP},
122 #endif
123 { NULL, arp_stats, NULL, "arp", 0 },
124 #if TARGET_OS_EMBEDDED
125 { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
126 #endif
127 { NULL, NULL, NULL, NULL, 0 }
128 };
129
130 #ifdef INET6
131 struct protox ip6protox[] = {
132 { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
133 { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
134 { protopr, ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
135 { protopr, icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
136 #ifdef IPSEC
137 { NULL, ipsec_stats, NULL, "ipsec6", IPPROTO_ESP },
138 #endif
139 #ifdef notyet
140 { NULL, pim6_stats, NULL, "pim6", 0 },
141 #endif
142 { NULL, rip6_stats, NULL, "rip6", IPPROTO_RAW },
143 #if TARGET_OS_EMBEDDED
144 { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
145 #endif
146 { NULL, NULL, NULL, NULL, 0 }
147 };
148 #endif /*INET6*/
149
150 #ifdef IPSEC
151 struct protox pfkeyprotox[] = {
152 { NULL, pfkey_stats, NULL, "pfkey", PF_KEY_V2 },
153 { NULL, NULL, NULL, NULL, 0 }
154 };
155 #endif
156
157 struct protox *protoprotox[] = {
158 protox,
159 #ifdef INET6
160 ip6protox,
161 #endif
162 #ifdef IPSEC
163 pfkeyprotox,
164 #endif
165 NULL
166 };
167
168 static void printproto (struct protox *, char *);
169 static void usage (void);
170 static struct protox *name2protox (char *);
171 static struct protox *knownname (char *);
172 #ifdef SRVCACHE
173 extern void _serv_cache_close();
174 #endif
175
176 int Aflag; /* show addresses of protocol control block */
177 int aflag; /* show all sockets (including servers) */
178 int bflag; /* show i/f total bytes in/out */
179 int cflag; /* show specific classq */
180 int dflag; /* show i/f dropped packets */
181 int Fflag; /* show i/f forwarded packets */
182 #if defined(__APPLE__)
183 int gflag; /* show group (multicast) routing or stats */
184 #endif
185 int iflag; /* show interfaces */
186 int lflag; /* show routing table with use and ref */
187 int Lflag; /* show size of listen queues */
188 int mflag; /* show memory stats */
189 int nflag; /* show addresses numerically */
190 static int pflag; /* show given protocol */
191 int prioflag = -1; /* show packet priority statistics */
192 int Rflag; /* show reachability information */
193 int rflag; /* show routing tables (or routing stats) */
194 int sflag; /* show protocol statistics */
195 int tflag; /* show i/f watchdog timers */
196 int vflag; /* more verbose */
197 int Wflag; /* wide display */
198 int qflag; /* classq stats display */
199 int Qflag; /* opportunistic polling stats display */
200 int xflag; /* show extended link-layer reachability information */
201
202 int cq = -1; /* send classq index (-1 for all) */
203 int interval; /* repeat interval for i/f stats */
204
205 char *interface; /* desired i/f for stats, or NULL for all i/fs */
206 int unit; /* unit number for above */
207
208 int af; /* address family */
209
210 int
211 main(argc, argv)
212 int argc;
213 char *argv[];
214 {
215 register struct protox *tp = NULL; /* for printing cblocks & stats */
216 int ch;
217
218 af = AF_UNSPEC;
219
220 while ((ch = getopt(argc, argv, "Aabc:dFf:gI:iLlmnP:p:qQrRstuvWw:x")) != -1)
221 switch(ch) {
222 case 'A':
223 Aflag = 1;
224 break;
225 case 'a':
226 aflag = 1;
227 break;
228 case 'b':
229 bflag = 1;
230 break;
231 case 'c':
232 cflag = 1;
233 cq = atoi(optarg);
234 break;
235 case 'd':
236 dflag = 1;
237 break;
238 case 'F':
239 Fflag = 1;
240 break;
241 case 'f':
242 if (strcmp(optarg, "ipx") == 0)
243 af = AF_IPX;
244 else if (strcmp(optarg, "inet") == 0)
245 af = AF_INET;
246 #ifdef INET6
247 else if (strcmp(optarg, "inet6") == 0)
248 af = AF_INET6;
249 #endif /*INET6*/
250 #ifdef INET6
251 else if (strcmp(optarg, "pfkey") == 0)
252 af = PF_KEY;
253 #endif /*INET6*/
254 else if (strcmp(optarg, "unix") == 0)
255 af = AF_UNIX;
256 else {
257 errx(1, "%s: unknown address family", optarg);
258 }
259 break;
260 #if defined(__APPLE__)
261 case 'g':
262 gflag = 1;
263 break;
264 #endif
265 case 'I': {
266 char *cp;
267
268 iflag = 1;
269 for (cp = interface = optarg; isalpha(*cp); cp++)
270 continue;
271 unit = atoi(cp);
272 break;
273 }
274 case 'i':
275 iflag = 1;
276 break;
277 case 'l':
278 lflag = 1;
279 break;
280 case 'L':
281 Lflag = 1;
282 break;
283 case 'm':
284 mflag++;
285 break;
286 case 'n':
287 nflag = 1;
288 break;
289 case 'P':
290 prioflag = atoi(optarg);
291 break;
292 case 'p':
293 if ((tp = name2protox(optarg)) == NULL) {
294 errx(1,
295 "%s: unknown or uninstrumented protocol",
296 optarg);
297 }
298 pflag = 1;
299 break;
300 case 'q':
301 qflag++;
302 break;
303 case 'Q':
304 Qflag++;
305 break;
306 case 'R':
307 Rflag = 1;
308 break;
309 case 'r':
310 rflag = 1;
311 break;
312 case 's':
313 ++sflag;
314 break;
315 case 't':
316 tflag = 1;
317 break;
318 case 'u':
319 af = AF_UNIX;
320 break;
321 case 'v':
322 vflag++;
323 break;
324 case 'W':
325 Wflag = 1;
326 break;
327 case 'w':
328 interval = atoi(optarg);
329 iflag = 1;
330 break;
331 case 'x':
332 xflag = 1;
333 Rflag = 1;
334 break;
335 case '?':
336 default:
337 usage();
338 }
339 argv += optind;
340 argc -= optind;
341
342 #define BACKWARD_COMPATIBILITY
343 #ifdef BACKWARD_COMPATIBILITY
344 if (*argv) {
345 if (isdigit(**argv)) {
346 interval = atoi(*argv);
347 if (interval <= 0)
348 usage();
349 ++argv;
350 iflag = 1;
351 }
352 }
353 #endif
354
355 if (mflag) {
356 mbpr();
357 exit(0);
358 }
359 if (iflag && !sflag && !gflag && !qflag && !Qflag) {
360 if (Rflag)
361 intpr_ri(NULL);
362 else
363 intpr(NULL);
364 exit(0);
365 }
366 if (rflag) {
367 if (sflag)
368 rt_stats();
369 else
370 routepr();
371 exit(0);
372 }
373 if (qflag || Qflag) {
374 if (interface == NULL) {
375 fprintf(stderr, "%s statistics option "
376 "requires interface name\n", qflag ? "Queue" :
377 "Polling");
378 } else if (qflag) {
379 aqstatpr();
380 } else {
381 rxpollstatpr();
382 }
383 exit(0);
384 }
385
386 #if defined(__APPLE__)
387 if (gflag) {
388 #if !TARGET_OS_EMBEDDED
389 if (sflag) {
390 if (af == AF_INET || af == AF_UNSPEC)
391 mrt_stats();
392 #ifdef INET6
393 if (af == AF_INET6 || af == AF_UNSPEC)
394 mrt6_stats();
395 #endif
396 } else {
397 if (af == AF_INET || af == AF_UNSPEC)
398 mroutepr();
399 #ifdef INET6
400 if (af == AF_INET6 || af == AF_UNSPEC)
401 mroute6pr();
402 #endif
403 }
404 #endif /* !TARGET_OS_EMBEDDED */
405 ifmalist_dump();
406 exit(0);
407 }
408 #endif
409
410 if (tp) {
411 printproto(tp, tp->pr_name);
412 exit(0);
413 }
414 if (af == AF_INET || af == AF_UNSPEC)
415 for (tp = protox; tp->pr_name; tp++)
416 printproto(tp, tp->pr_name);
417 #ifdef INET6
418 if (af == AF_INET6 || af == AF_UNSPEC)
419 for (tp = ip6protox; tp->pr_name; tp++)
420 printproto(tp, tp->pr_name);
421 #endif /*INET6*/
422 #ifdef IPSEC
423 if (af == PF_KEY || af == AF_UNSPEC)
424 for (tp = pfkeyprotox; tp->pr_name; tp++)
425 printproto(tp, tp->pr_name);
426 #endif /*IPSEC*/
427 if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
428 unixpr();
429 #ifdef SRVCACHE
430 _serv_cache_close();
431 #endif
432 exit(0);
433 }
434
435 /*
436 * Print out protocol statistics or control blocks (per sflag).
437 * If the interface was not specifically requested, and the symbol
438 * is not in the namelist, ignore this one.
439 */
440 static void
441 printproto(tp, name)
442 register struct protox *tp;
443 char *name;
444 {
445 void (*pr)(uint32_t, char *, int);
446 uint32_t off;
447
448 if (sflag) {
449 if (iflag && !pflag) {
450 if (tp->pr_istats)
451 intpr(tp->pr_istats);
452 else if (vflag)
453 printf("%s: no per-interface stats routine\n",
454 tp->pr_name);
455 return;
456 }
457 else {
458 pr = tp->pr_stats;
459 if (!pr) {
460 if (pflag && vflag)
461 printf("%s: no stats routine\n",
462 tp->pr_name);
463 return;
464 }
465 off = tp->pr_protocol;
466 }
467 } else {
468 pr = tp->pr_cblocks;
469 if (!pr) {
470 if (pflag && vflag)
471 printf("%s: no PCB routine\n", tp->pr_name);
472 return;
473 }
474 off = tp->pr_protocol;
475 }
476 if (pr != NULL) {
477 if (sflag && iflag && pflag)
478 intervalpr(pr, off, name, af);
479 else
480 (*pr)(off, name, af);
481 } else {
482 printf("### no stats for %s\n", name);
483 }
484 }
485
486 char *
487 plural(int n)
488 {
489 return (n != 1 ? "s" : "");
490 }
491
492 char *
493 plurales(int n)
494 {
495 return (n != 1 ? "es" : "");
496 }
497
498 char *
499 pluralies(int n)
500 {
501 return (n != 1 ? "ies" : "y");
502 }
503
504 /*
505 * Find the protox for the given "well-known" name.
506 */
507 static struct protox *
508 knownname(char *name)
509 {
510 struct protox **tpp, *tp;
511
512 for (tpp = protoprotox; *tpp; tpp++)
513 for (tp = *tpp; tp->pr_name; tp++)
514 if (strcmp(tp->pr_name, name) == 0)
515 return (tp);
516 return (NULL);
517 }
518
519 /*
520 * Find the protox corresponding to name.
521 */
522 static struct protox *
523 name2protox(char *name)
524 {
525 struct protox *tp;
526 char **alias; /* alias from p->aliases */
527 struct protoent *p;
528
529 /*
530 * Try to find the name in the list of "well-known" names. If that
531 * fails, check if name is an alias for an Internet protocol.
532 */
533 if ((tp = knownname(name)) != NULL)
534 return (tp);
535
536 setprotoent(1); /* make protocol lookup cheaper */
537 while ((p = getprotoent()) != NULL) {
538 /* assert: name not same as p->name */
539 for (alias = p->p_aliases; *alias; alias++)
540 if (strcmp(name, *alias) == 0) {
541 endprotoent();
542 return (knownname(p->p_name));
543 }
544 }
545 endprotoent();
546 return (NULL);
547 }
548
549 #define NETSTAT_USAGE "\
550 Usage: netstat [-AaLlnW] [-f address_family | -p protocol]\n\
551 netstat [-gilns] [-f address_family]\n\
552 netstat -i | -I interface [-w wait] [-abdgRt]\n\
553 netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
554 netstat -i | -I interface -s [-f address_family | -p protocol]\n\
555 netstat -m [-m]\n\
556 netstat -r [-Aaln] [-f address_family]\n\
557 netstat -rs [-s]\n\
558 "
559
560 static void
561 usage(void)
562 {
563 (void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
564 exit(1);
565 }
566
567 int
568 print_time(void)
569 {
570 time_t now;
571 struct tm tm;
572 int num_written = 0;
573
574 (void) time(&now);
575 (void) localtime_r(&now, &tm);
576
577 num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
578
579 return (num_written);
580 }
581