1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1988, 1993
5 * Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #ifndef lint
33 static char const copyright[] =
34 "@(#) Copyright (c) 1983, 1988, 1993\n\
35 Regents of the University of California. All rights reserved.\n";
36 #endif /* not lint */
37
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
41 #endif /* not lint */
42 #endif
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/file.h>
49 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/sysctl.h>
53
54 #include <netinet/in.h>
55
56 #ifdef NETGRAPH
57 #include <netgraph/ng_socket.h>
58 #endif
59
60 #include <ctype.h>
61 #include <err.h>
62 #include <errno.h>
63 #include <kvm.h>
64 #include <limits.h>
65 #include <netdb.h>
66 #include <nlist.h>
67 #include <paths.h>
68 #include <stdint.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <stdbool.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include "netstat.h"
75 #include "nl_defs.h"
76 #include <libxo/xo.h>
77
78 static struct protox {
79 int pr_index; /* index into nlist of cb head */
80 int pr_sindex; /* index into nlist of stat block */
81 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
82 void (*pr_cblocks)(u_long, const char *, int, int);
83 /* control blocks printing routine */
84 void (*pr_stats)(u_long, const char *, int, int);
85 /* statistics printing routine */
86 void (*pr_istats)(char *); /* per/if statistics printing routine */
87 const char *pr_name; /* well-known name */
88 int pr_usesysctl; /* non-zero if we use sysctl, not kvm */
89 int pr_protocol;
90 } protox[] = {
91 { N_TCBINFO, N_TCPSTAT, 1, protopr,
92 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
93 { N_UDBINFO, N_UDPSTAT, 1, protopr,
94 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
95 #ifdef SCTP
96 { -1, N_SCTPSTAT, 1, sctp_protopr,
97 sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP },
98 #endif
99 #ifdef SDP
100 { -1, -1, 1, protopr,
101 NULL, NULL, "sdp", 1, IPPROTO_TCP },
102 #endif
103 { N_DIVCBINFO, -1, 1, protopr,
104 NULL, NULL, "divert", 1, IPPROTO_DIVERT },
105 { N_RIPCBINFO, N_IPSTAT, 1, protopr,
106 ip_stats, NULL, "ip", 1, IPPROTO_RAW },
107 { N_RIPCBINFO, N_ICMPSTAT, 1, protopr,
108 icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP },
109 { N_RIPCBINFO, N_IGMPSTAT, 1, protopr,
110 igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP },
111 #ifdef IPSEC
112 { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */
113 ipsec_stats, NULL, "ipsec", 1, 0},
114 { -1, N_AHSTAT, 1, NULL,
115 ah_stats, NULL, "ah", 1, 0},
116 { -1, N_ESPSTAT, 1, NULL,
117 esp_stats, NULL, "esp", 1, 0},
118 { -1, N_IPCOMPSTAT, 1, NULL,
119 ipcomp_stats, NULL, "ipcomp", 1, 0},
120 #endif
121 { N_RIPCBINFO, N_PIMSTAT, 1, protopr,
122 pim_stats, NULL, "pim", 1, IPPROTO_PIM },
123 { -1, N_CARPSTATS, 1, NULL,
124 carp_stats, NULL, "carp", 1, 0 },
125 #ifdef PF
126 { -1, N_PFSYNCSTATS, 1, NULL,
127 pfsync_stats, NULL, "pfsync", 1, 0 },
128 #endif
129 { -1, N_ARPSTAT, 1, NULL,
130 arp_stats, NULL, "arp", 1, 0 },
131 { -1, -1, 0, NULL,
132 NULL, NULL, NULL, 0, 0 }
133 };
134
135 #ifdef INET6
136 static struct protox ip6protox[] = {
137 { N_TCBINFO, N_TCPSTAT, 1, protopr,
138 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
139 { N_UDBINFO, N_UDPSTAT, 1, protopr,
140 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
141 { N_RIPCBINFO, N_IP6STAT, 1, protopr,
142 ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW },
143 { N_RIPCBINFO, N_ICMP6STAT, 1, protopr,
144 icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 },
145 #ifdef SDP
146 { -1, -1, 1, protopr,
147 NULL, NULL, "sdp", 1, IPPROTO_TCP },
148 #endif
149 #ifdef IPSEC
150 { -1, N_IPSEC6STAT, 1, NULL,
151 ipsec_stats, NULL, "ipsec6", 1, 0 },
152 #endif
153 #ifdef notyet
154 { -1, N_PIM6STAT, 1, NULL,
155 pim6_stats, NULL, "pim6", 1, 0 },
156 #endif
157 { -1, N_RIP6STAT, 1, NULL,
158 rip6_stats, NULL, "rip6", 1, 0 },
159 { -1, -1, 0, NULL,
160 NULL, NULL, NULL, 0, 0 }
161 };
162 #endif /*INET6*/
163
164 #ifdef IPSEC
165 static struct protox pfkeyprotox[] = {
166 { -1, N_PFKEYSTAT, 1, NULL,
167 pfkey_stats, NULL, "pfkey", 0, 0 },
168 { -1, -1, 0, NULL,
169 NULL, NULL, NULL, 0, 0 }
170 };
171 #endif
172
173 #ifdef NETGRAPH
174 static struct protox netgraphprotox[] = {
175 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
176 NULL, NULL, "ctrl", 0, 0 },
177 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
178 NULL, NULL, "data", 0, 0 },
179 { -1, -1, 0, NULL,
180 NULL, NULL, NULL, 0, 0 }
181 };
182 #endif
183
184 static struct protox *protoprotox[] = {
185 protox,
186 #ifdef INET6
187 ip6protox,
188 #endif
189 #ifdef IPSEC
190 pfkeyprotox,
191 #endif
192 NULL };
193
194 static void printproto(struct protox *, const char *, bool *);
195 static void usage(void);
196 static struct protox *name2protox(const char *);
197 static struct protox *knownname(const char *);
198
199 static int kresolve_list(struct nlist *_nl);
200
201 static kvm_t *kvmd;
202 static char *nlistf = NULL, *memf = NULL;
203
204 int Aflag; /* show addresses of protocol control block */
205 int aflag; /* show all sockets (including servers) */
206 static int Bflag; /* show information about bpf consumers */
207 int bflag; /* show i/f total bytes in/out */
208 int dflag; /* show i/f dropped packets */
209 int gflag; /* show group (multicast) routing or stats */
210 int hflag; /* show counters in human readable format */
211 int iflag; /* show interfaces */
212 int Lflag; /* show size of listen queues */
213 int mflag; /* show memory stats */
214 int noutputs = 0; /* how much outputs before we exit */
215 int numeric_addr; /* show addresses numerically */
216 int numeric_port; /* show ports numerically */
217 int Pflag; /* show TCP log ID */
218 static int pflag; /* show given protocol */
219 static int Qflag; /* show netisr information */
220 int rflag; /* show routing tables (or routing stats) */
221 int Rflag; /* show flow / RSS statistics */
222 int sflag; /* show protocol statistics */
223 int Wflag; /* wide display */
224 int Tflag; /* TCP Information */
225 int xflag; /* extra information, includes all socket buffer info */
226 int zflag; /* zero stats */
227
228 int interval; /* repeat interval for i/f stats */
229
230 char *interface; /* desired i/f for stats, or NULL for all i/fs */
231 int unit; /* unit number for above */
232
233 static int af; /* address family */
234 int live; /* true if we are examining a live system */
235
236 int
main(int argc,char * argv[])237 main(int argc, char *argv[])
238 {
239 struct protox *tp = NULL; /* for printing cblocks & stats */
240 int ch;
241 int fib = -1;
242 char *endptr;
243 bool first = true;
244
245 af = AF_UNSPEC;
246
247 argc = xo_parse_args(argc, argv);
248 if (argc < 0)
249 exit(EXIT_FAILURE);
250
251 while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:nPp:Qq:RrSTsuWw:xz"))
252 != -1)
253 switch(ch) {
254 case '4':
255 #ifdef INET
256 af = AF_INET;
257 #else
258 errx(1, "IPv4 support is not compiled in");
259 #endif
260 break;
261 case '6':
262 #ifdef INET6
263 af = AF_INET6;
264 #else
265 errx(1, "IPv6 support is not compiled in");
266 #endif
267 break;
268 case 'A':
269 Aflag = 1;
270 break;
271 case 'a':
272 aflag = 1;
273 break;
274 case 'B':
275 Bflag = 1;
276 break;
277 case 'b':
278 bflag = 1;
279 break;
280 case 'd':
281 dflag = 1;
282 break;
283 case 'F':
284 fib = strtol(optarg, &endptr, 0);
285 if (*endptr != '\0' ||
286 (fib == 0 && (errno == EINVAL || errno == ERANGE)))
287 xo_errx(1, "%s: invalid fib", optarg);
288 break;
289 case 'f':
290 if (strcmp(optarg, "inet") == 0)
291 af = AF_INET;
292 #ifdef INET6
293 else if (strcmp(optarg, "inet6") == 0)
294 af = AF_INET6;
295 #endif
296 #ifdef IPSEC
297 else if (strcmp(optarg, "pfkey") == 0)
298 af = PF_KEY;
299 #endif
300 else if (strcmp(optarg, "unix") == 0 ||
301 strcmp(optarg, "local") == 0)
302 af = AF_UNIX;
303 #ifdef NETGRAPH
304 else if (strcmp(optarg, "ng") == 0
305 || strcmp(optarg, "netgraph") == 0)
306 af = AF_NETGRAPH;
307 #endif
308 else if (strcmp(optarg, "link") == 0)
309 af = AF_LINK;
310 else {
311 xo_errx(1, "%s: unknown address family",
312 optarg);
313 }
314 break;
315 case 'g':
316 gflag = 1;
317 break;
318 case 'h':
319 hflag = 1;
320 break;
321 case 'I': {
322 char *cp;
323
324 iflag = 1;
325 for (cp = interface = optarg; isalpha(*cp); cp++)
326 continue;
327 unit = atoi(cp);
328 break;
329 }
330 case 'i':
331 iflag = 1;
332 break;
333 case 'L':
334 Lflag = 1;
335 break;
336 case 'M':
337 memf = optarg;
338 break;
339 case 'm':
340 mflag = 1;
341 break;
342 case 'N':
343 nlistf = optarg;
344 break;
345 case 'n':
346 numeric_addr = numeric_port = 1;
347 break;
348 case 'P':
349 Pflag = 1;
350 break;
351 case 'p':
352 if ((tp = name2protox(optarg)) == NULL) {
353 xo_errx(1, "%s: unknown or uninstrumented "
354 "protocol", optarg);
355 }
356 pflag = 1;
357 break;
358 case 'Q':
359 Qflag = 1;
360 break;
361 case 'q':
362 noutputs = atoi(optarg);
363 if (noutputs != 0)
364 noutputs++;
365 break;
366 case 'r':
367 rflag = 1;
368 break;
369 case 'R':
370 Rflag = 1;
371 break;
372 case 's':
373 ++sflag;
374 break;
375 case 'S':
376 numeric_addr = 1;
377 break;
378 case 'u':
379 af = AF_UNIX;
380 break;
381 case 'W':
382 case 'l':
383 Wflag = 1;
384 break;
385 case 'w':
386 interval = atoi(optarg);
387 iflag = 1;
388 break;
389 case 'T':
390 Tflag = 1;
391 break;
392 case 'x':
393 xflag = 1;
394 break;
395 case 'z':
396 zflag = 1;
397 break;
398 case '?':
399 default:
400 usage();
401 }
402 argv += optind;
403 argc -= optind;
404
405 #define BACKWARD_COMPATIBILITY
406 #ifdef BACKWARD_COMPATIBILITY
407 if (*argv) {
408 if (isdigit(**argv)) {
409 interval = atoi(*argv);
410 if (interval <= 0)
411 usage();
412 ++argv;
413 iflag = 1;
414 }
415 if (*argv) {
416 nlistf = *argv;
417 if (*++argv)
418 memf = *argv;
419 }
420 }
421 #endif
422
423 /*
424 * Discard setgid privileges if not the running kernel so that bad
425 * guys can't print interesting stuff from kernel memory.
426 */
427 live = (nlistf == NULL && memf == NULL);
428 if (!live) {
429 if (setgid(getgid()) != 0)
430 xo_err(-1, "setgid");
431 /* Load all necessary kvm symbols */
432 kresolve_list(nl);
433 }
434
435 if (xflag && Tflag)
436 xo_errx(1, "-x and -T are incompatible, pick one.");
437
438 if (Bflag) {
439 if (!live)
440 usage();
441 bpf_stats(interface);
442 xo_finish();
443 exit(0);
444 }
445 if (mflag) {
446 if (!live) {
447 if (kread(0, NULL, 0) == 0)
448 mbpr(kvmd, nl[N_SFSTAT].n_value);
449 } else
450 mbpr(NULL, 0);
451 xo_finish();
452 exit(0);
453 }
454 if (Qflag) {
455 if (!live) {
456 if (kread(0, NULL, 0) == 0)
457 netisr_stats();
458 } else
459 netisr_stats();
460 xo_finish();
461 exit(0);
462 }
463 #if 0
464 /*
465 * Keep file descriptors open to avoid overhead
466 * of open/close on each call to get* routines.
467 */
468 sethostent(1);
469 setnetent(1);
470 #else
471 /*
472 * This does not make sense any more with DNS being default over
473 * the files. Doing a setXXXXent(1) causes a tcp connection to be
474 * used for the queries, which is slower.
475 */
476 #endif
477 if (iflag && !sflag) {
478 xo_open_container("statistics");
479 intpr(NULL, af);
480 xo_close_container("statistics");
481 xo_finish();
482 exit(0);
483 }
484 if (rflag) {
485 xo_open_container("statistics");
486 if (sflag) {
487 rt_stats();
488 } else
489 routepr(fib, af);
490 xo_close_container("statistics");
491 xo_finish();
492 exit(0);
493 }
494
495 if (gflag) {
496 xo_open_container("statistics");
497 if (sflag) {
498 if (af == AF_INET || af == AF_UNSPEC)
499 mrt_stats();
500 #ifdef INET6
501 if (af == AF_INET6 || af == AF_UNSPEC)
502 mrt6_stats();
503 #endif
504 } else {
505 if (af == AF_INET || af == AF_UNSPEC)
506 mroutepr();
507 #ifdef INET6
508 if (af == AF_INET6 || af == AF_UNSPEC)
509 mroute6pr();
510 #endif
511 }
512 xo_close_container("statistics");
513 xo_finish();
514 exit(0);
515 }
516
517 if (tp) {
518 xo_open_container("statistics");
519 printproto(tp, tp->pr_name, &first);
520 if (!first)
521 xo_close_list("socket");
522 xo_close_container("statistics");
523 xo_finish();
524 exit(0);
525 }
526
527 xo_open_container("statistics");
528 if (af == AF_INET || af == AF_UNSPEC)
529 for (tp = protox; tp->pr_name; tp++)
530 printproto(tp, tp->pr_name, &first);
531 #ifdef INET6
532 if (af == AF_INET6 || af == AF_UNSPEC)
533 for (tp = ip6protox; tp->pr_name; tp++)
534 printproto(tp, tp->pr_name, &first);
535 #endif /*INET6*/
536 #ifdef IPSEC
537 if (af == PF_KEY || af == AF_UNSPEC)
538 for (tp = pfkeyprotox; tp->pr_name; tp++)
539 printproto(tp, tp->pr_name, &first);
540 #endif /*IPSEC*/
541 #ifdef NETGRAPH
542 if (af == AF_NETGRAPH || af == AF_UNSPEC)
543 for (tp = netgraphprotox; tp->pr_name; tp++)
544 printproto(tp, tp->pr_name, &first);
545 #endif /* NETGRAPH */
546 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
547 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
548 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
549 nl[N_UNP_SPHEAD].n_value, &first);
550
551 if (!first)
552 xo_close_list("socket");
553 xo_close_container("statistics");
554 xo_finish();
555 exit(0);
556 }
557
558 static int
fetch_stats_internal(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn,int zero)559 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
560 size_t len, kreadfn_t kreadfn, int zero)
561 {
562 int error;
563
564 if (live) {
565 memset(stats, 0, len);
566 if (zero)
567 error = sysctlbyname(sysctlname, NULL, NULL, stats,
568 len);
569 else
570 error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
571 if (error == -1 && errno != ENOENT)
572 xo_warn("sysctl %s", sysctlname);
573 } else {
574 if (off == 0)
575 return (1);
576 error = kreadfn(off, stats, len);
577 }
578 return (error);
579 }
580
581 int
fetch_stats(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)582 fetch_stats(const char *sysctlname, u_long off, void *stats,
583 size_t len, kreadfn_t kreadfn)
584 {
585
586 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
587 zflag));
588 }
589
590 int
fetch_stats_ro(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)591 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
592 size_t len, kreadfn_t kreadfn)
593 {
594
595 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
596 }
597
598 /*
599 * Print out protocol statistics or control blocks (per sflag).
600 * If the interface was not specifically requested, and the symbol
601 * is not in the namelist, ignore this one.
602 */
603 static void
printproto(struct protox * tp,const char * name,bool * first)604 printproto(struct protox *tp, const char *name, bool *first)
605 {
606 void (*pr)(u_long, const char *, int, int);
607 u_long off;
608 bool doingdblocks = false;
609
610 if (sflag) {
611 if (iflag) {
612 if (tp->pr_istats)
613 intpr(tp->pr_istats, af);
614 else if (pflag)
615 xo_message("%s: no per-interface stats routine",
616 tp->pr_name);
617 return;
618 } else {
619 pr = tp->pr_stats;
620 if (!pr) {
621 if (pflag)
622 xo_message("%s: no stats routine",
623 tp->pr_name);
624 return;
625 }
626 if (tp->pr_usesysctl && live)
627 off = 0;
628 else if (tp->pr_sindex < 0) {
629 if (pflag)
630 xo_message("%s: stats routine doesn't "
631 "work on cores", tp->pr_name);
632 return;
633 } else
634 off = nl[tp->pr_sindex].n_value;
635 }
636 } else {
637 doingdblocks = true;
638 pr = tp->pr_cblocks;
639 if (!pr) {
640 if (pflag)
641 xo_message("%s: no PCB routine", tp->pr_name);
642 return;
643 }
644 if (tp->pr_usesysctl && live)
645 off = 0;
646 else if (tp->pr_index < 0) {
647 if (pflag)
648 xo_message("%s: PCB routine doesn't work on "
649 "cores", tp->pr_name);
650 return;
651 } else
652 off = nl[tp->pr_index].n_value;
653 }
654 if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
655 af != AF_UNSPEC)) {
656 if (doingdblocks && *first) {
657 xo_open_list("socket");
658 *first = false;
659 }
660
661 (*pr)(off, name, af, tp->pr_protocol);
662 }
663 }
664
665 static int
kvmd_init(void)666 kvmd_init(void)
667 {
668 char errbuf[_POSIX2_LINE_MAX];
669
670 if (kvmd != NULL)
671 return (0);
672
673 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
674 if (setgid(getgid()) != 0)
675 xo_err(-1, "setgid");
676
677 if (kvmd == NULL) {
678 xo_warnx("kvm not available: %s", errbuf);
679 return (-1);
680 }
681
682 return (0);
683 }
684
685 /*
686 * Resolve symbol list, return 0 on success.
687 */
688 static int
kresolve_list(struct nlist * _nl)689 kresolve_list(struct nlist *_nl)
690 {
691
692 if ((kvmd == NULL) && (kvmd_init() != 0))
693 return (-1);
694
695 if (_nl[0].n_type != 0)
696 return (0);
697
698 if (kvm_nlist(kvmd, _nl) < 0) {
699 if (nlistf)
700 xo_errx(1, "%s: kvm_nlist: %s", nlistf,
701 kvm_geterr(kvmd));
702 else
703 xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
704 }
705
706 return (0);
707 }
708
709 /*
710 * Wrapper of kvm_dpcpu_setcpu().
711 */
712 void
kset_dpcpu(u_int cpuid)713 kset_dpcpu(u_int cpuid)
714 {
715
716 if ((kvmd == NULL) && (kvmd_init() != 0))
717 xo_errx(-1, "%s: kvm is not available", __func__);
718
719 if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
720 xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
721 cpuid, kvm_geterr(kvmd));
722 return;
723 }
724
725 /*
726 * Read kernel memory, return 0 on success.
727 */
728 int
kread(u_long addr,void * buf,size_t size)729 kread(u_long addr, void *buf, size_t size)
730 {
731
732 if (kvmd_init() < 0)
733 return (-1);
734
735 if (!buf)
736 return (0);
737 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
738 xo_warnx("%s", kvm_geterr(kvmd));
739 return (-1);
740 }
741 return (0);
742 }
743
744 /*
745 * Read single counter(9).
746 */
747 uint64_t
kread_counter(u_long addr)748 kread_counter(u_long addr)
749 {
750
751 if (kvmd_init() < 0)
752 return (-1);
753
754 return (kvm_counter_u64_fetch(kvmd, addr));
755 }
756
757 /*
758 * Read an array of N counters in kernel memory into array of N uint64_t's.
759 */
760 int
kread_counters(u_long addr,void * buf,size_t size)761 kread_counters(u_long addr, void *buf, size_t size)
762 {
763 uint64_t *c;
764 u_long *counters;
765 size_t i, n;
766
767 if (kvmd_init() < 0)
768 return (-1);
769
770 if (size % sizeof(uint64_t) != 0) {
771 xo_warnx("kread_counters: invalid counter set size");
772 return (-1);
773 }
774
775 n = size / sizeof(uint64_t);
776 if ((counters = malloc(n * sizeof(u_long))) == NULL)
777 xo_err(-1, "malloc");
778 if (kread(addr, counters, n * sizeof(u_long)) < 0) {
779 free(counters);
780 return (-1);
781 }
782
783 c = buf;
784 for (i = 0; i < n; i++)
785 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
786
787 free(counters);
788 return (0);
789 }
790
791 const char *
plural(uintmax_t n)792 plural(uintmax_t n)
793 {
794 return (n != 1 ? "s" : "");
795 }
796
797 const char *
plurales(uintmax_t n)798 plurales(uintmax_t n)
799 {
800 return (n != 1 ? "es" : "");
801 }
802
803 const char *
pluralies(uintmax_t n)804 pluralies(uintmax_t n)
805 {
806 return (n != 1 ? "ies" : "y");
807 }
808
809 /*
810 * Find the protox for the given "well-known" name.
811 */
812 static struct protox *
knownname(const char * name)813 knownname(const char *name)
814 {
815 struct protox **tpp, *tp;
816
817 for (tpp = protoprotox; *tpp; tpp++)
818 for (tp = *tpp; tp->pr_name; tp++)
819 if (strcmp(tp->pr_name, name) == 0)
820 return (tp);
821 return (NULL);
822 }
823
824 /*
825 * Find the protox corresponding to name.
826 */
827 static struct protox *
name2protox(const char * name)828 name2protox(const char *name)
829 {
830 struct protox *tp;
831 char **alias; /* alias from p->aliases */
832 struct protoent *p;
833
834 /*
835 * Try to find the name in the list of "well-known" names. If that
836 * fails, check if name is an alias for an Internet protocol.
837 */
838 if ((tp = knownname(name)) != NULL)
839 return (tp);
840
841 setprotoent(1); /* make protocol lookup cheaper */
842 while ((p = getprotoent()) != NULL) {
843 /* assert: name not same as p->name */
844 for (alias = p->p_aliases; *alias; alias++)
845 if (strcmp(name, *alias) == 0) {
846 endprotoent();
847 return (knownname(p->p_name));
848 }
849 }
850 endprotoent();
851 return (NULL);
852 }
853
854 static void
usage(void)855 usage(void)
856 {
857 (void)xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
858 "usage: netstat [-46AaLnRSTWx] [-f protocol_family | -p protocol]\n"
859 " [-M core] [-N system]",
860 " netstat -i | -I interface [-46abdhnW] [-f address_family]\n"
861 " [-M core] [-N system]",
862 " netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n"
863 " [-q howmany]",
864 " netstat -s [-46sz] [-f protocol_family | -p protocol]\n"
865 " [-M core] [-N system]",
866 " netstat -i | -I interface -s [-46s]\n"
867 " [-f protocol_family | -p protocol] [-M core] [-N system]",
868 " netstat -m [-M core] [-N system]",
869 " netstat -B [-z] [-I interface]",
870 " netstat -r [-46AnW] [-F fibnum] [-f address_family]\n"
871 " [-M core] [-N system]",
872 " netstat -rs [-s] [-M core] [-N system]",
873 " netstat -g [-46W] [-f address_family] [-M core] [-N system]",
874 " netstat -gs [-46s] [-f address_family] [-M core] [-N system]",
875 " netstat -Q");
876 xo_finish();
877 exit(1);
878 }
879