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: stable/12/usr.bin/netstat/main.c 367015 2020-10-24 17:47:43Z rscheff $");
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 cflag; /* show TCP congestion control stack */
209 int Cflag; /* show congestion control algo and vars */
210 int dflag; /* show i/f dropped packets */
211 int gflag; /* show group (multicast) routing or stats */
212 int hflag; /* show counters in human readable format */
213 int iflag; /* show interfaces */
214 int Lflag; /* show size of listen queues */
215 int mflag; /* show memory stats */
216 int noutputs = 0; /* how much outputs before we exit */
217 int numeric_addr; /* show addresses numerically */
218 int numeric_port; /* show ports numerically */
219 int Pflag; /* show TCP log ID */
220 static int pflag; /* show given protocol */
221 static int Qflag; /* show netisr information */
222 int rflag; /* show routing tables (or routing stats) */
223 int Rflag; /* show flow / RSS statistics */
224 int sflag; /* show protocol statistics */
225 int Wflag; /* wide display */
226 int Tflag; /* TCP Information */
227 int xflag; /* extra information, includes all socket buffer info */
228 int zflag; /* zero stats */
229
230 int interval; /* repeat interval for i/f stats */
231
232 char *interface; /* desired i/f for stats, or NULL for all i/fs */
233 int unit; /* unit number for above */
234
235 static int af; /* address family */
236 int live; /* true if we are examining a live system */
237
238 int
main(int argc,char * argv[])239 main(int argc, char *argv[])
240 {
241 struct protox *tp = NULL; /* for printing cblocks & stats */
242 int ch;
243 int fib = -1;
244 char *endptr;
245 bool first = true;
246
247 af = AF_UNSPEC;
248
249 argc = xo_parse_args(argc, argv);
250 if (argc < 0)
251 exit(EXIT_FAILURE);
252
253 while ((ch = getopt(argc, argv, "46AaBbCcdF:f:ghI:iLlM:mN:nPp:Qq:RrSTsuWw:xz"))
254 != -1)
255 switch(ch) {
256 case '4':
257 #ifdef INET
258 af = AF_INET;
259 #else
260 errx(1, "IPv4 support is not compiled in");
261 #endif
262 break;
263 case '6':
264 #ifdef INET6
265 af = AF_INET6;
266 #else
267 errx(1, "IPv6 support is not compiled in");
268 #endif
269 break;
270 case 'A':
271 Aflag = 1;
272 break;
273 case 'a':
274 aflag = 1;
275 break;
276 case 'B':
277 Bflag = 1;
278 break;
279 case 'b':
280 bflag = 1;
281 break;
282 case 'c':
283 cflag = 1;
284 break;
285 case 'C':
286 Cflag = 1;
287 break;
288 case 'd':
289 dflag = 1;
290 break;
291 case 'F':
292 fib = strtol(optarg, &endptr, 0);
293 if (*endptr != '\0' ||
294 (fib == 0 && (errno == EINVAL || errno == ERANGE)))
295 xo_errx(1, "%s: invalid fib", optarg);
296 break;
297 case 'f':
298 if (strcmp(optarg, "inet") == 0)
299 af = AF_INET;
300 #ifdef INET6
301 else if (strcmp(optarg, "inet6") == 0)
302 af = AF_INET6;
303 #endif
304 #ifdef IPSEC
305 else if (strcmp(optarg, "pfkey") == 0)
306 af = PF_KEY;
307 #endif
308 else if (strcmp(optarg, "unix") == 0 ||
309 strcmp(optarg, "local") == 0)
310 af = AF_UNIX;
311 #ifdef NETGRAPH
312 else if (strcmp(optarg, "ng") == 0
313 || strcmp(optarg, "netgraph") == 0)
314 af = AF_NETGRAPH;
315 #endif
316 else if (strcmp(optarg, "link") == 0)
317 af = AF_LINK;
318 else {
319 xo_errx(1, "%s: unknown address family",
320 optarg);
321 }
322 break;
323 case 'g':
324 gflag = 1;
325 break;
326 case 'h':
327 hflag = 1;
328 break;
329 case 'I': {
330 char *cp;
331
332 iflag = 1;
333 for (cp = interface = optarg; isalpha(*cp); cp++)
334 continue;
335 unit = atoi(cp);
336 break;
337 }
338 case 'i':
339 iflag = 1;
340 break;
341 case 'L':
342 Lflag = 1;
343 break;
344 case 'M':
345 memf = optarg;
346 break;
347 case 'm':
348 mflag = 1;
349 break;
350 case 'N':
351 nlistf = optarg;
352 break;
353 case 'n':
354 numeric_addr = numeric_port = 1;
355 break;
356 case 'P':
357 Pflag = 1;
358 break;
359 case 'p':
360 if ((tp = name2protox(optarg)) == NULL) {
361 xo_errx(1, "%s: unknown or uninstrumented "
362 "protocol", optarg);
363 }
364 pflag = 1;
365 break;
366 case 'Q':
367 Qflag = 1;
368 break;
369 case 'q':
370 noutputs = atoi(optarg);
371 if (noutputs != 0)
372 noutputs++;
373 break;
374 case 'r':
375 rflag = 1;
376 break;
377 case 'R':
378 Rflag = 1;
379 break;
380 case 's':
381 ++sflag;
382 break;
383 case 'S':
384 numeric_addr = 1;
385 break;
386 case 'u':
387 af = AF_UNIX;
388 break;
389 case 'W':
390 case 'l':
391 Wflag = 1;
392 break;
393 case 'w':
394 interval = atoi(optarg);
395 iflag = 1;
396 break;
397 case 'T':
398 Tflag = 1;
399 break;
400 case 'x':
401 xflag = 1;
402 break;
403 case 'z':
404 zflag = 1;
405 break;
406 case '?':
407 default:
408 usage();
409 }
410 argv += optind;
411 argc -= optind;
412
413 #define BACKWARD_COMPATIBILITY
414 #ifdef BACKWARD_COMPATIBILITY
415 if (*argv) {
416 if (isdigit(**argv)) {
417 interval = atoi(*argv);
418 if (interval <= 0)
419 usage();
420 ++argv;
421 iflag = 1;
422 }
423 if (*argv) {
424 nlistf = *argv;
425 if (*++argv)
426 memf = *argv;
427 }
428 }
429 #endif
430
431 /*
432 * Discard setgid privileges if not the running kernel so that bad
433 * guys can't print interesting stuff from kernel memory.
434 */
435 live = (nlistf == NULL && memf == NULL);
436 if (!live) {
437 if (setgid(getgid()) != 0)
438 xo_err(-1, "setgid");
439 /* Load all necessary kvm symbols */
440 kresolve_list(nl);
441 }
442
443 if (xflag && Tflag)
444 xo_errx(1, "-x and -T are incompatible, pick one.");
445
446 if (Bflag) {
447 if (!live)
448 usage();
449 bpf_stats(interface);
450 xo_finish();
451 exit(0);
452 }
453 if (mflag) {
454 if (!live) {
455 if (kread(0, NULL, 0) == 0)
456 mbpr(kvmd, nl[N_SFSTAT].n_value);
457 } else
458 mbpr(NULL, 0);
459 xo_finish();
460 exit(0);
461 }
462 if (Qflag) {
463 if (!live) {
464 if (kread(0, NULL, 0) == 0)
465 netisr_stats();
466 } else
467 netisr_stats();
468 xo_finish();
469 exit(0);
470 }
471 #if 0
472 /*
473 * Keep file descriptors open to avoid overhead
474 * of open/close on each call to get* routines.
475 */
476 sethostent(1);
477 setnetent(1);
478 #else
479 /*
480 * This does not make sense any more with DNS being default over
481 * the files. Doing a setXXXXent(1) causes a tcp connection to be
482 * used for the queries, which is slower.
483 */
484 #endif
485 if (iflag && !sflag) {
486 xo_open_container("statistics");
487 intpr(NULL, af);
488 xo_close_container("statistics");
489 xo_finish();
490 exit(0);
491 }
492 if (rflag) {
493 xo_open_container("statistics");
494 if (sflag) {
495 if (live) {
496 kresolve_list(nl);
497 }
498 rt_stats();
499 } else
500 routepr(fib, af);
501 xo_close_container("statistics");
502 xo_finish();
503 exit(0);
504 }
505
506 if (gflag) {
507 xo_open_container("statistics");
508 if (sflag) {
509 if (af == AF_INET || af == AF_UNSPEC)
510 mrt_stats();
511 #ifdef INET6
512 if (af == AF_INET6 || af == AF_UNSPEC)
513 mrt6_stats();
514 #endif
515 } else {
516 if (af == AF_INET || af == AF_UNSPEC)
517 mroutepr();
518 #ifdef INET6
519 if (af == AF_INET6 || af == AF_UNSPEC)
520 mroute6pr();
521 #endif
522 }
523 xo_close_container("statistics");
524 xo_finish();
525 exit(0);
526 }
527
528 if (tp) {
529 xo_open_container("statistics");
530 printproto(tp, tp->pr_name, &first);
531 if (!first)
532 xo_close_list("socket");
533 xo_close_container("statistics");
534 xo_finish();
535 exit(0);
536 }
537
538 xo_open_container("statistics");
539 if (af == AF_INET || af == AF_UNSPEC)
540 for (tp = protox; tp->pr_name; tp++)
541 printproto(tp, tp->pr_name, &first);
542 #ifdef INET6
543 if (af == AF_INET6 || af == AF_UNSPEC)
544 for (tp = ip6protox; tp->pr_name; tp++)
545 printproto(tp, tp->pr_name, &first);
546 #endif /*INET6*/
547 #ifdef IPSEC
548 if (af == PF_KEY || af == AF_UNSPEC)
549 for (tp = pfkeyprotox; tp->pr_name; tp++)
550 printproto(tp, tp->pr_name, &first);
551 #endif /*IPSEC*/
552 #ifdef NETGRAPH
553 if (af == AF_NETGRAPH || af == AF_UNSPEC)
554 for (tp = netgraphprotox; tp->pr_name; tp++)
555 printproto(tp, tp->pr_name, &first);
556 #endif /* NETGRAPH */
557 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
558 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
559 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
560 nl[N_UNP_SPHEAD].n_value, &first);
561
562 if (!first)
563 xo_close_list("socket");
564 xo_close_container("statistics");
565 xo_finish();
566 exit(0);
567 }
568
569 static int
fetch_stats_internal(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn,int zero)570 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
571 size_t len, kreadfn_t kreadfn, int zero)
572 {
573 int error;
574
575 if (live) {
576 memset(stats, 0, len);
577 if (zero)
578 error = sysctlbyname(sysctlname, NULL, NULL, stats,
579 len);
580 else
581 error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
582 if (error == -1 && errno != ENOENT)
583 xo_warn("sysctl %s", sysctlname);
584 } else {
585 if (off == 0)
586 return (1);
587 error = kreadfn(off, stats, len);
588 }
589 return (error);
590 }
591
592 int
fetch_stats(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)593 fetch_stats(const char *sysctlname, u_long off, void *stats,
594 size_t len, kreadfn_t kreadfn)
595 {
596
597 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
598 zflag));
599 }
600
601 int
fetch_stats_ro(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)602 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
603 size_t len, kreadfn_t kreadfn)
604 {
605
606 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
607 }
608
609 /*
610 * Print out protocol statistics or control blocks (per sflag).
611 * If the interface was not specifically requested, and the symbol
612 * is not in the namelist, ignore this one.
613 */
614 static void
printproto(struct protox * tp,const char * name,bool * first)615 printproto(struct protox *tp, const char *name, bool *first)
616 {
617 void (*pr)(u_long, const char *, int, int);
618 u_long off;
619 bool doingdblocks = false;
620
621 if (sflag) {
622 if (iflag) {
623 if (tp->pr_istats)
624 intpr(tp->pr_istats, af);
625 else if (pflag)
626 xo_message("%s: no per-interface stats routine",
627 tp->pr_name);
628 return;
629 } else {
630 pr = tp->pr_stats;
631 if (!pr) {
632 if (pflag)
633 xo_message("%s: no stats routine",
634 tp->pr_name);
635 return;
636 }
637 if (tp->pr_usesysctl && live)
638 off = 0;
639 else if (tp->pr_sindex < 0) {
640 if (pflag)
641 xo_message("%s: stats routine doesn't "
642 "work on cores", tp->pr_name);
643 return;
644 } else
645 off = nl[tp->pr_sindex].n_value;
646 }
647 } else {
648 doingdblocks = true;
649 pr = tp->pr_cblocks;
650 if (!pr) {
651 if (pflag)
652 xo_message("%s: no PCB routine", tp->pr_name);
653 return;
654 }
655 if (tp->pr_usesysctl && live)
656 off = 0;
657 else if (tp->pr_index < 0) {
658 if (pflag)
659 xo_message("%s: PCB routine doesn't work on "
660 "cores", tp->pr_name);
661 return;
662 } else
663 off = nl[tp->pr_index].n_value;
664 }
665 if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
666 af != AF_UNSPEC)) {
667 if (doingdblocks && *first) {
668 xo_open_list("socket");
669 *first = false;
670 }
671
672 (*pr)(off, name, af, tp->pr_protocol);
673 }
674 }
675
676 static int
kvmd_init(void)677 kvmd_init(void)
678 {
679 char errbuf[_POSIX2_LINE_MAX];
680
681 if (kvmd != NULL)
682 return (0);
683
684 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
685 if (setgid(getgid()) != 0)
686 xo_err(-1, "setgid");
687
688 if (kvmd == NULL) {
689 xo_warnx("kvm not available: %s", errbuf);
690 return (-1);
691 }
692
693 return (0);
694 }
695
696 /*
697 * Resolve symbol list, return 0 on success.
698 */
699 static int
kresolve_list(struct nlist * _nl)700 kresolve_list(struct nlist *_nl)
701 {
702
703 if ((kvmd == NULL) && (kvmd_init() != 0))
704 return (-1);
705
706 if (_nl[0].n_type != 0)
707 return (0);
708
709 if (kvm_nlist(kvmd, _nl) < 0) {
710 if (nlistf)
711 xo_errx(1, "%s: kvm_nlist: %s", nlistf,
712 kvm_geterr(kvmd));
713 else
714 xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
715 }
716
717 return (0);
718 }
719
720 /*
721 * Wrapper of kvm_dpcpu_setcpu().
722 */
723 void
kset_dpcpu(u_int cpuid)724 kset_dpcpu(u_int cpuid)
725 {
726
727 if ((kvmd == NULL) && (kvmd_init() != 0))
728 xo_errx(-1, "%s: kvm is not available", __func__);
729
730 if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
731 xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
732 cpuid, kvm_geterr(kvmd));
733 return;
734 }
735
736 /*
737 * Read kernel memory, return 0 on success.
738 */
739 int
kread(u_long addr,void * buf,size_t size)740 kread(u_long addr, void *buf, size_t size)
741 {
742
743 if (kvmd_init() < 0)
744 return (-1);
745
746 if (!buf)
747 return (0);
748 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
749 xo_warnx("%s", kvm_geterr(kvmd));
750 return (-1);
751 }
752 return (0);
753 }
754
755 /*
756 * Read single counter(9).
757 */
758 uint64_t
kread_counter(u_long addr)759 kread_counter(u_long addr)
760 {
761
762 if (kvmd_init() < 0)
763 return (-1);
764
765 return (kvm_counter_u64_fetch(kvmd, addr));
766 }
767
768 /*
769 * Read an array of N counters in kernel memory into array of N uint64_t's.
770 */
771 int
kread_counters(u_long addr,void * buf,size_t size)772 kread_counters(u_long addr, void *buf, size_t size)
773 {
774 uint64_t *c;
775 u_long *counters;
776 size_t i, n;
777
778 if (kvmd_init() < 0)
779 return (-1);
780
781 if (size % sizeof(uint64_t) != 0) {
782 xo_warnx("kread_counters: invalid counter set size");
783 return (-1);
784 }
785
786 n = size / sizeof(uint64_t);
787 if ((counters = malloc(n * sizeof(u_long))) == NULL)
788 xo_err(-1, "malloc");
789 if (kread(addr, counters, n * sizeof(u_long)) < 0) {
790 free(counters);
791 return (-1);
792 }
793
794 c = buf;
795 for (i = 0; i < n; i++)
796 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
797
798 free(counters);
799 return (0);
800 }
801
802 const char *
plural(uintmax_t n)803 plural(uintmax_t n)
804 {
805 return (n != 1 ? "s" : "");
806 }
807
808 const char *
plurales(uintmax_t n)809 plurales(uintmax_t n)
810 {
811 return (n != 1 ? "es" : "");
812 }
813
814 const char *
pluralies(uintmax_t n)815 pluralies(uintmax_t n)
816 {
817 return (n != 1 ? "ies" : "y");
818 }
819
820 /*
821 * Find the protox for the given "well-known" name.
822 */
823 static struct protox *
knownname(const char * name)824 knownname(const char *name)
825 {
826 struct protox **tpp, *tp;
827
828 for (tpp = protoprotox; *tpp; tpp++)
829 for (tp = *tpp; tp->pr_name; tp++)
830 if (strcmp(tp->pr_name, name) == 0)
831 return (tp);
832 return (NULL);
833 }
834
835 /*
836 * Find the protox corresponding to name.
837 */
838 static struct protox *
name2protox(const char * name)839 name2protox(const char *name)
840 {
841 struct protox *tp;
842 char **alias; /* alias from p->aliases */
843 struct protoent *p;
844
845 /*
846 * Try to find the name in the list of "well-known" names. If that
847 * fails, check if name is an alias for an Internet protocol.
848 */
849 if ((tp = knownname(name)) != NULL)
850 return (tp);
851
852 setprotoent(1); /* make protocol lookup cheaper */
853 while ((p = getprotoent()) != NULL) {
854 /* assert: name not same as p->name */
855 for (alias = p->p_aliases; *alias; alias++)
856 if (strcmp(name, *alias) == 0) {
857 endprotoent();
858 return (knownname(p->p_name));
859 }
860 }
861 endprotoent();
862 return (NULL);
863 }
864
865 static void
usage(void)866 usage(void)
867 {
868 (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",
869 "usage: netstat [-46AaCcLnRSTWx] [-f protocol_family | -p protocol]\n"
870 " [-M core] [-N system]",
871 " netstat -i | -I interface [-46abdhnW] [-f address_family]\n"
872 " [-M core] [-N system]",
873 " netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n"
874 " [-q howmany]",
875 " netstat -s [-46sz] [-f protocol_family | -p protocol]\n"
876 " [-M core] [-N system]",
877 " netstat -i | -I interface -s [-46s]\n"
878 " [-f protocol_family | -p protocol] [-M core] [-N system]",
879 " netstat -m [-M core] [-N system]",
880 " netstat -B [-z] [-I interface]",
881 " netstat -r [-46AnW] [-F fibnum] [-f address_family]\n"
882 " [-M core] [-N system]",
883 " netstat -rs [-s] [-M core] [-N system]",
884 " netstat -g [-46W] [-f address_family] [-M core] [-N system]",
885 " netstat -gs [-46s] [-f address_family] [-M core] [-N system]",
886 " netstat -Q");
887 xo_finish();
888 exit(1);
889 }
890