1/*- 2 * Copyright (c) 1998 Andrzej Bialecki 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 30/* 31 * Small replacement for netstat. Uses only sysctl(3) to get the info. 32 */ 33 34#include <sys/types.h> 35#include <sys/time.h> 36#include <sys/sysctl.h> 37#include <sys/socket.h> 38#include <sys/un.h> 39 40#include <net/if.h> 41#include <net/route.h> 42#include <net/if_dl.h> 43#include <netinet/in_systm.h> 44#include <netinet/in.h> 45#include <netinet/ip.h> 46#include <netinet/ip_icmp.h> 47#include <netinet/icmp_var.h> 48#include <netinet/ip_var.h> 49#include <netinet/tcp.h> 50#include <netinet/tcp_timer.h> 51#include <netinet/tcp_var.h> 52#include <netinet/udp.h> 53#include <netinet/udp_var.h> 54#include <arpa/inet.h> 55 56#include <err.h> 57#include <errno.h> 58#include <osreldate.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <unistd.h> 63 64char *progname; 65int iflag = 0; 66int lflag = 0; /* print cpu load info */ 67int rflag = 0; 68int sflag = 0; 69int pflag = 0; 70int wflag = 0; /* repeat every wait seconds */ 71int delta = 0 ; 72 73extern char *optarg; 74extern int optind; 75 76void print_load_stats(void); 77 78void 79usage() 80{ 81 fprintf(stderr, "\n%s [-nrsil] [-p proto] [-w wait]\n", progname); 82 fprintf(stderr, " proto: {ip|tcp|udp|icmp}\n\n"); 83} 84 85 86/* 87 * The following parts related to retrieving the routing table and 88 * interface information, were borrowed from R. Stevens' code examples 89 * accompanying his excellent book. Thanks! 90 */ 91char * 92sock_ntop(const struct sockaddr *sa, size_t salen) 93{ 94 char portstr[7]; 95 static char str[128]; /* Unix domain is largest */ 96 97 switch (sa->sa_family) { 98 case 255: { 99 int i = 0; 100 u_long mask; 101 u_int index = 1 << 31; 102 u_short new_mask = 0; 103 104 mask = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); 105 106 while (mask & index) { 107 new_mask++; 108 index >>= 1; 109 } 110 sprintf(str, "/%hu", new_mask); 111 return (str); 112 } 113 case AF_UNSPEC: 114 case AF_INET: { 115 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 116 117 if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) 118 == NULL) 119 return (NULL); 120 if (ntohs(sin->sin_port) != 0) { 121 snprintf(portstr, sizeof(portstr), ".%d", 122 ntohs(sin->sin_port)); 123 strcat(str, portstr); 124 } 125 if (strcmp(str, "0.0.0.0") == 0) 126 sprintf(str, "default"); 127 return (str); 128 } 129 130 case AF_UNIX: { 131 struct sockaddr_un *unp = (struct sockaddr_un *)sa; 132 133 /* 134 * OK to have no pathname bound to the socket: 135 * happens on every connect() unless client calls 136 * bind() first. 137 */ 138 if (unp->sun_path[0] == 0) 139 strcpy(str, "(no pathname bound)"); 140 else 141 snprintf(str, sizeof(str), "%s", unp->sun_path); 142 return (str); 143 } 144 145 case AF_LINK: { 146 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 147 148 if (sdl->sdl_nlen > 0) { 149 bcopy(&sdl->sdl_data[0], str, sdl->sdl_nlen); 150 str[sdl->sdl_nlen] = '\0'; 151 } else 152 snprintf(str, sizeof(str), "link#%d", sdl->sdl_index); 153 return (str); 154 } 155 156 default: 157 snprintf(str, sizeof(str), 158 "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, 159 salen); 160 return (str); 161 } 162 return (NULL); 163} 164 165char * 166Sock_ntop(const struct sockaddr *sa, size_t salen) 167{ 168 char *ptr; 169 170 if ((ptr = sock_ntop(sa, salen)) == NULL) 171 err(1, "sock_ntop error"); /* inet_ntop() sets errno */ 172 return (ptr); 173} 174 175 176#define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a)) 177 178#define NEXT_SA(ap) \ 179 ap=(struct sockaddr *) \ 180 ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\ 181 sizeof(u_long))) 182 183void 184get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 185{ 186 int i; 187 188 for (i = 0; i < RTAX_MAX; i++) { 189 if (addrs & (1 << i)) { 190 rti_info[i] = sa; 191 NEXT_SA(sa); 192 } else 193 rti_info[i] = NULL; 194 } 195} 196 197void 198get_flags(char *buf, int flags) 199{ 200 if (flags & 0x1) 201 strcat(buf, "U"); 202 if (flags & 0x2) 203 strcat(buf, "G"); 204 if (flags & 0x4) 205 strcat(buf, "H"); 206 if (flags & 0x8) 207 strcat(buf, "r"); 208 if (flags & 0x10) 209 strcat(buf, "d"); 210#ifdef NEVER 211 if (flags & 0x20) 212 strcat(buf, "mod,"); 213#endif /*NEVER*/ 214 if (flags & 0x100) 215 strcat(buf, "C"); 216 if (flags & 0x400) 217 strcat(buf, "L"); 218 if (flags & 0x800) 219 strcat(buf, "S"); 220 if (flags & 0x10000) 221 strcat(buf, "c"); 222 if (flags & 0x20000) 223 strcat(buf, "W"); 224#ifdef NEVER 225 if (flags & 0x200000) 226 strcat(buf, ",LOC"); 227#endif /*NEVER*/ 228 if (flags & 0x400000) 229 strcat(buf, "b"); 230#ifdef NEVER 231 if (flags & 0x800000) 232 strcat(buf, ",MCA"); 233#endif /*NEVER*/ 234} 235 236void 237print_routing(char *proto) 238{ 239 int mib[6]; 240 int i = 0; 241 int rt_len; 242 int if_len; 243 int if_num; 244 char *rt_buf; 245 char *if_buf; 246 char *next; 247 char *lim; 248 struct rt_msghdr *rtm; 249 struct if_msghdr *ifm; 250 struct if_msghdr **ifm_table; 251 struct ifa_msghdr *ifam; 252 struct sockaddr *sa; 253 struct sockaddr *sa1; 254 struct sockaddr *rti_info[RTAX_MAX]; 255 struct sockaddr **if_table; 256 struct rt_metrics rm; 257 char fbuf[50]; 258 259 /* keep a copy of statistics here for future use */ 260 static unsigned *base_stats = NULL ; 261 static unsigned base_len = 0 ; 262 263 /* Get the routing table */ 264 mib[0] = CTL_NET; 265 mib[1] = PF_ROUTE; 266 mib[2] = 0; 267 mib[3] = 0; 268 mib[4] = NET_RT_DUMP; 269 mib[5] = 0; 270 271 /*Estimate the size of table */ 272 if (sysctl(mib, 6, NULL, &rt_len, NULL, 0) == -1) { 273 perror("sysctl size"); 274 exit(-1); 275 } 276 if ((rt_buf = (char *)malloc(rt_len)) == NULL) { 277 perror("malloc"); 278 exit(-1); 279 } 280 281 /* Now get it. */ 282 if (sysctl(mib, 6, rt_buf, &rt_len, NULL, 0) == -1) { 283 perror("sysctl get"); 284 exit(-1); 285 } 286 287 /* Get the interfaces table */ 288 mib[0] = CTL_NET; 289 mib[1] = PF_ROUTE; 290 mib[2] = 0; 291 mib[3] = 0; 292 mib[4] = NET_RT_IFLIST; 293 mib[5] = 0; 294 295 /* Estimate the size of table */ 296 if (sysctl(mib, 6, NULL, &if_len, NULL, 0) == -1) { 297 perror("sysctl size"); 298 exit(-1); 299 } 300 if ((if_buf = (char *)malloc(if_len)) == NULL) { 301 perror("malloc"); 302 exit(-1); 303 } 304 305 /* Now get it. */ 306 if (sysctl(mib, 6, if_buf, &if_len, NULL, 0) == -1) { 307 perror("sysctl get"); 308 exit(-1); 309 } 310 lim = if_buf + if_len; 311 i = 0; 312 for (next = if_buf, i = 0; next < lim; next += ifm->ifm_msglen) { 313 ifm = (struct if_msghdr *)next; 314 i++; 315 } 316 if_num = i; 317 if_table = (struct sockaddr **)calloc(i, sizeof(struct sockaddr)); 318 ifm_table = (struct if_msghdr **)calloc(i, sizeof(struct if_msghdr)); 319 if (iflag) { 320 printf("\nInterface table:\n"); 321 printf("----------------\n"); 322 printf("Name Mtu Network Address " 323 "Ipkts Ierrs Opkts Oerrs Coll\n"); 324 } 325 /* scan the list and store base values */ 326 i = 0 ; 327 for (next = if_buf; next < lim; next += ifm->ifm_msglen) { 328 ifm = (struct if_msghdr *)next; 329 i++ ; 330 } 331 if (base_stats == NULL || i != base_len) { 332 base_stats = calloc(i*5, sizeof(unsigned)); 333 base_len = i ; 334 } 335 i = 0; 336 for (next = if_buf; next < lim; next += ifm->ifm_msglen) { 337 ifm = (struct if_msghdr *)next; 338 if_table[i] = (struct sockaddr *)(ifm + 1); 339 ifm_table[i] = ifm; 340 341 sa = if_table[i]; 342 if (iflag && sa->sa_family == AF_LINK) { 343 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 344 unsigned *bp = &base_stats[i*5]; 345 346 printf("%-4s %-5d <Link> ", 347 sock_ntop(if_table[i], if_table[i]->sa_len), 348 ifm->ifm_data.ifi_mtu); 349 if (sdl->sdl_alen == 6) { 350 unsigned char *p = 351 sdl->sdl_data + sdl->sdl_nlen; 352 printf("%02x:%02x:%02x:%02x:%02x:%02x ", 353 p[0], p[1], p[2], p[3], p[4], p[5]); 354 } else 355 printf(" "); 356 printf("%9d%6d%9d%6d%6d\n", 357 ifm->ifm_data.ifi_ipackets - bp[0], 358 ifm->ifm_data.ifi_ierrors - bp[1], 359 ifm->ifm_data.ifi_opackets - bp[2], 360 ifm->ifm_data.ifi_oerrors - bp[3], 361 ifm->ifm_data.ifi_collisions -bp[4]); 362 if (delta > 0) { 363 bp[0] = ifm->ifm_data.ifi_ipackets ; 364 bp[1] = ifm->ifm_data.ifi_ierrors ; 365 bp[2] = ifm->ifm_data.ifi_opackets ; 366 bp[3] = ifm->ifm_data.ifi_oerrors ; 367 bp[4] = ifm->ifm_data.ifi_collisions ; 368 } 369 } 370 i++; 371 } 372 if (!rflag) { 373 free(rt_buf); 374 free(if_buf); 375 free(if_table); 376 free(ifm_table); 377 return; 378 } 379 380 /* Now dump the routing table */ 381 printf("\nRouting table:\n"); 382 printf("--------------\n"); 383 printf 384 ("Destination Gateway Flags Netif Use\n"); 385 lim = rt_buf + rt_len; 386 for (next = rt_buf; next < lim; next += rtm->rtm_msglen) { 387 rtm = (struct rt_msghdr *)next; 388 sa = (struct sockaddr *)(rtm + 1); 389 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 390 if ((sa = rti_info[RTAX_DST]) != NULL) { 391 sprintf(fbuf, "%s", sock_ntop(sa, sa->sa_len)); 392 if (((sa1 = rti_info[RTAX_NETMASK]) != NULL) 393 && sa1->sa_family == 255) { 394 strcat(fbuf, sock_ntop(sa1, sa1->sa_len)); 395 } 396 printf("%-19s", fbuf); 397 } 398 if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { 399 printf("%-19s", sock_ntop(sa, sa->sa_len)); 400 } 401 memset(fbuf, 0, sizeof(fbuf)); 402 get_flags(fbuf, rtm->rtm_flags); 403 printf("%-10s", fbuf); 404 for (i = 0; i < if_num; i++) { 405 ifm = ifm_table[i]; 406 if ((ifm->ifm_index == rtm->rtm_index) && 407 (ifm->ifm_data.ifi_type > 0)) { 408 sa = if_table[i]; 409 break; 410 } 411 } 412 if (ifm->ifm_type == RTM_IFINFO) { 413 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 414 printf(" %s", Sock_ntop(sa, sa->sa_len)); 415 } else if (ifm->ifm_type == RTM_NEWADDR) { 416 ifam = 417 (struct ifa_msghdr *)ifm_table[rtm->rtm_index - 1]; 418 sa = (struct sockaddr *)(ifam + 1); 419 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 420 printf(" %s", Sock_ntop(sa, sa->sa_len)); 421 } 422 /* printf(" %u", rtm->rtm_use); */ 423 printf("\n"); 424 } 425 free(rt_buf); 426 free(if_buf); 427 free(if_table); 428 free(ifm_table); 429} 430 431void 432print_ip_stats(void) 433{ 434 int mib[4]; 435 int len; 436 struct ipstat s; 437 438 mib[0] = CTL_NET; 439 mib[1] = PF_INET; 440 mib[2] = IPPROTO_IP; 441#ifndef IPCTL_STATS 442 printf("sorry, ip stats not available\n"); 443 return -1; 444#else 445 mib[3] = IPCTL_STATS; 446 len = sizeof(struct ipstat); 447 if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { 448 perror("sysctl"); 449 return; 450 } 451 printf("\nIP statistics:\n"); 452 printf("--------------\n"); 453 printf(" %10lu total packets received\n", s.ips_total); 454 printf("* Packets ok:\n"); 455 printf(" %10lu fragments received\n", s.ips_fragments); 456 printf(" %10lu forwarded\n", s.ips_forward); 457#if __FreeBSD_version > 300001 458 printf(" %10lu fast forwarded\n", s.ips_fastforward); 459#endif 460 printf(" %10lu forwarded on same net (redirect)\n", 461 s.ips_redirectsent); 462 printf(" %10lu delivered to upper level\n", s.ips_delivered); 463 printf(" %10lu total ip packets generated here\n", s.ips_localout); 464 printf(" %10lu total packets reassembled ok\n", s.ips_reassembled); 465 printf(" %10lu total datagrams successfully fragmented\n", 466 s.ips_fragmented); 467 printf(" %10lu output fragments created\n", s.ips_ofragments); 468 printf(" %10lu total raw IP packets generated\n", s.ips_rawout); 469 printf("\n* Bad packets:\n"); 470 printf(" %10lu bad checksum\n", s.ips_badsum); 471 printf(" %10lu too short\n", s.ips_tooshort); 472 printf(" %10lu not enough data (too small)\n", s.ips_toosmall); 473 printf(" %10lu more data than declared in header\n", s.ips_badhlen); 474 printf(" %10lu less data than declared in header\n", s.ips_badlen); 475 printf(" %10lu fragments dropped (dups, no mbuf)\n", 476 s.ips_fragdropped); 477 printf(" %10lu fragments timed out in reassembly\n", 478 s.ips_fragtimeout); 479 printf(" %10lu received for unreachable dest.\n", s.ips_cantforward); 480 printf(" %10lu unknown or unsupported protocol\n", s.ips_noproto); 481 printf(" %10lu lost due to no bufs etc.\n", s.ips_odropped); 482 printf(" %10lu couldn't fragment (DF set, etc.)\n", s.ips_cantfrag); 483 printf(" %10lu error in IP options processing\n", s.ips_badoptions); 484 printf(" %10lu dropped due to no route\n", s.ips_noroute); 485 printf(" %10lu bad IP version\n", s.ips_badvers); 486 printf(" %10lu too long (more than max IP size)\n", s.ips_toolong); 487#if __FreeBSD_version > 300001 488 printf(" %10lu multicast for unregistered groups\n", s.ips_notmember); 489#endif 490#endif 491} 492 493void 494print_tcp_stats(void) 495{ 496 int mib[4]; 497 int len; 498 struct tcpstat s; 499 500 mib[0] = CTL_NET; 501 mib[1] = PF_INET; 502 mib[2] = IPPROTO_TCP; 503#ifndef TCPCTL_STATS 504 printf("sorry, tcp stats not available\n"); 505 return; 506#else 507 mib[3] = TCPCTL_STATS; 508 len = sizeof(struct tcpstat); 509 if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { 510 perror("sysctl"); 511 return; 512 } 513 printf("\nTCP statistics:\n"); 514 printf("---------------\n"); 515 printf("* Connections:\n"); 516 printf(" %10lu initiated\n", s.tcps_connattempt); 517 printf(" %10lu accepted\n", s.tcps_accepts); 518 printf(" %10lu established\n", s.tcps_connects); 519 printf(" %10lu dropped\n", s.tcps_drops); 520 printf(" %10lu embryonic connections dropped\n", s.tcps_conndrops); 521 printf(" %10lu closed (includes dropped)\n", s.tcps_closed); 522 printf(" %10lu segments where we tried to get RTT\n", 523 s.tcps_segstimed); 524 printf(" %10lu times RTT successfully updated\n", s.tcps_rttupdated); 525 printf(" %10lu delayed ACKs sent\n", s.tcps_delack); 526 printf(" %10lu dropped in rxmt timeout\n", s.tcps_timeoutdrop); 527 printf(" %10lu retrasmit timeouts\n", s.tcps_rexmttimeo); 528 printf(" %10lu persist timeouts\n", s.tcps_persisttimeo); 529 printf(" %10lu keepalive timeouts\n", s.tcps_keeptimeo); 530 printf(" %10lu keepalive probes sent\n", s.tcps_keepprobe); 531 printf(" %10lu dropped in keepalive\n", s.tcps_keepdrops); 532 533 printf("* Packets sent:\n"); 534 printf(" %10lu total packets sent\n", s.tcps_sndtotal); 535 printf(" %10lu data packets sent\n", s.tcps_sndpack); 536 printf(" %10lu data bytes sent\n", s.tcps_sndbyte); 537 printf(" %10lu data packets retransmitted\n", s.tcps_sndrexmitpack); 538 printf(" %10lu data bytes retransmitted\n", s.tcps_sndrexmitbyte); 539 printf(" %10lu ACK-only packets sent\n", s.tcps_sndacks); 540 printf(" %10lu window probes sent\n", s.tcps_sndprobe); 541 printf(" %10lu URG-only packets sent\n", s.tcps_sndurg); 542 printf(" %10lu window update-only packets sent\n", s.tcps_sndwinup); 543 printf(" %10lu control (SYN,FIN,RST) packets sent\n", s.tcps_sndctrl); 544 printf("* Packets received:\n"); 545 printf(" %10lu total packets received\n", s.tcps_rcvtotal); 546 printf(" %10lu packets in sequence\n", s.tcps_rcvpack); 547 printf(" %10lu bytes in sequence\n", s.tcps_rcvbyte); 548 printf(" %10lu packets with bad checksum\n", s.tcps_rcvbadsum); 549 printf(" %10lu packets with bad offset\n", s.tcps_rcvbadoff); 550 printf(" %10lu packets too short\n", s.tcps_rcvshort); 551 printf(" %10lu duplicate-only packets\n", s.tcps_rcvduppack); 552 printf(" %10lu duplicate-only bytes\n", s.tcps_rcvdupbyte); 553 printf(" %10lu packets with some duplicate data\n", 554 s.tcps_rcvpartduppack); 555 printf(" %10lu duplicate bytes in partially dup. packets\n", 556 s.tcps_rcvpartdupbyte); 557 printf(" %10lu out-of-order packets\n", s.tcps_rcvoopack); 558 printf(" %10lu out-of-order bytes\n", s.tcps_rcvoobyte); 559 printf(" %10lu packets with data after window\n", 560 s.tcps_rcvpackafterwin); 561 printf(" %10lu bytes received after window\n", 562 s.tcps_rcvbyteafterwin); 563 printf(" %10lu packets received after 'close'\n", 564 s.tcps_rcvafterclose); 565 printf(" %10lu window probe packets\n", s.tcps_rcvwinprobe); 566 printf(" %10lu duplicate ACKs\n", s.tcps_rcvdupack); 567 printf(" %10lu ACKs for unsent data\n", s.tcps_rcvacktoomuch); 568 printf(" %10lu ACK packets\n", s.tcps_rcvackpack); 569 printf(" %10lu bytes ACKed by received ACKs\n", s.tcps_rcvackbyte); 570 printf(" %10lu window update packets\n", s.tcps_rcvwinupd); 571 printf(" %10lu segments dropped due to PAWS\n", s.tcps_pawsdrop); 572 printf(" %10lu times header predict ok for ACKs\n", s.tcps_predack); 573 printf(" %10lu times header predict ok for data packets\n", 574 s.tcps_preddat); 575 printf(" %10lu PCB cache misses\n", s.tcps_pcbcachemiss); 576 printf(" %10lu times cached RTT in route updated\n", 577 s.tcps_cachedrtt); 578 printf(" %10lu times cached RTTVAR updated\n", s.tcps_cachedrttvar); 579 printf(" %10lu times ssthresh updated\n", s.tcps_cachedssthresh); 580 printf(" %10lu times RTT initialized from route\n", s.tcps_usedrtt); 581 printf(" %10lu times RTTVAR initialized from route\n", 582 s.tcps_usedrttvar); 583 printf(" %10lu times ssthresh initialized from route\n", 584 s.tcps_usedssthresh); 585 printf(" %10lu timeout in persist state\n", s.tcps_persistdrop); 586 printf(" %10lu bogus SYN, e.g. premature ACK\n", s.tcps_badsyn); 587 printf(" %10lu resends due to MTU discovery\n", s.tcps_mturesent); 588 printf(" %10lu listen queue overflows\n", s.tcps_listendrop); 589#endif 590} 591 592void 593print_udp_stats(void) 594{ 595 int mib[4]; 596 int len; 597 struct udpstat s; 598 599 mib[0] = CTL_NET; 600 mib[1] = PF_INET; 601 mib[2] = IPPROTO_UDP; 602 mib[3] = UDPCTL_STATS; 603 len = sizeof(struct udpstat); 604 if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { 605 perror("sysctl"); 606 return; 607 } 608 printf("\nUDP statistics:\n"); 609 printf("---------------\n"); 610 printf("* Packets received:\n"); 611 printf(" %10lu total input packets\n", s.udps_ipackets); 612 printf(" %10lu packets shorter than header (dropped)\n", 613 s.udps_hdrops); 614 printf(" %10lu bad checksum\n", s.udps_badsum); 615 printf(" %10lu data length larger than packet\n", s.udps_badlen); 616 printf(" %10lu no socket on specified port\n", s.udps_noport); 617 printf(" %10lu of above, arrived as broadcast\n", s.udps_noportbcast); 618 printf(" %10lu not delivered, input socket full\n", s.udps_fullsock); 619 printf(" %10lu packets missing PCB cache\n", s.udpps_pcbcachemiss); 620 printf(" %10lu packets not for hashed PCBs\n", s.udpps_pcbhashmiss); 621 printf("* Packets sent:\n"); 622 printf(" %10lu total output packets\n", s.udps_opackets); 623#if __FreeBSD_version > 300001 624 printf(" %10lu output packets on fast path\n", s.udps_fastout); 625#endif 626} 627 628char *icmp_names[] = { 629 "echo reply", 630 "#1", 631 "#2", 632 "destination unreachable", 633 "source quench", 634 "routing redirect", 635 "#6", 636 "#7", 637 "echo", 638 "router advertisement", 639 "router solicitation", 640 "time exceeded", 641 "parameter problem", 642 "time stamp", 643 "time stamp reply", 644 "information request", 645 "information request reply", 646 "address mask request", 647 "address mask reply", 648}; 649 650print_icmp_stats() 651{ 652 int mib[4]; 653 int len; 654 int i; 655 struct icmpstat s; 656 657 mib[0] = CTL_NET; 658 mib[1] = PF_INET; 659 mib[2] = IPPROTO_ICMP; 660 mib[3] = ICMPCTL_STATS; 661 len = sizeof(struct icmpstat); 662 if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { 663 perror("sysctl"); 664 return (-1); 665 } 666 printf("\nICMP statistics:\n"); 667 printf("----------------\n"); 668 printf("* Output histogram:\n"); 669 for (i = 0; i < (ICMP_MAXTYPE + 1); i++) { 670 if (s.icps_outhist[i] > 0) 671 printf("\t%10lu %s\n", 672 s.icps_outhist[i], icmp_names[i]); 673 } 674 printf("* Input histogram:\n"); 675 for (i = 0; i < (ICMP_MAXTYPE + 1); i++) { 676 if (s.icps_inhist[i] > 0) 677 printf("\t%10lu %s\n", 678 s.icps_inhist[i], icmp_names[i]); 679 } 680 printf("* Other stats:\n"); 681 printf(" %10lu calls to icmp_error\n", s.icps_error); 682 printf(" %10lu no error 'cuz old ip too short\n", s.icps_oldshort); 683 printf(" %10lu no error 'cuz old was icmp\n", s.icps_oldicmp); 684 685 printf(" %10lu icmp code out of range\n", s.icps_badcode); 686 printf(" %10lu packets shorter than min length\n", s.icps_tooshort); 687 printf(" %10lu bad checksum\n", s.icps_checksum); 688 printf(" %10lu calculated bound mismatch\n", s.icps_badlen); 689 printf(" %10lu number of responses\n", s.icps_reflect); 690 printf(" %10lu broad/multi-cast echo requests dropped\n", 691 s.icps_bmcastecho); 692 printf(" %10lu broad/multi-cast timestamp requests dropped\n", 693 s.icps_bmcasttstamp); 694} 695 696int 697stats(char *proto) 698{ 699 if (!sflag) 700 return 0; 701 if (pflag) { 702 if (proto == NULL) { 703 fprintf(stderr, "Option '-p' requires paramter.\n"); 704 usage(); 705 exit(-1); 706 } 707 if (strcmp(proto, "ip") == 0) 708 print_ip_stats(); 709 if (strcmp(proto, "icmp") == 0) 710 print_icmp_stats(); 711 if (strcmp(proto, "udp") == 0) 712 print_udp_stats(); 713 if (strcmp(proto, "tcp") == 0) 714 print_tcp_stats(); 715 return (0); 716 } 717 print_ip_stats(); 718 print_icmp_stats(); 719 print_udp_stats(); 720 print_tcp_stats(); 721 return (0); 722} 723 724int 725main(int argc, char *argv[]) 726{ 727 char c; 728 char *proto = NULL; 729 730 progname = argv[0]; 731 732 while ((c = getopt(argc, argv, "dilnrsp:w:")) != -1) { 733 switch (c) { 734 case 'd': /* print deltas in stats every w seconds */ 735 delta++ ; 736 break; 737 case 'w': 738 wflag = atoi(optarg); 739 break; 740 case 'n': /* ignored, just for compatibility with std netstat */ 741 break; 742 case 'r': 743 rflag++; 744 break; 745 case 'i': 746 iflag++; 747 break; 748 case 'l': 749 lflag++; 750 break; 751 case 's': 752 sflag++; 753 rflag = 0; 754 break; 755 case 'p': 756 pflag++; 757 sflag++; 758 proto = optarg; 759 break; 760 case '?': 761 default: 762 usage(); 763 exit(0); 764 break; 765 } 766 } 767 if (rflag == 0 && sflag == 0 && iflag == 0) 768 rflag = 1; 769 argc -= optind; 770 771 if (argc > 0) { 772 usage(); 773 exit(-1); 774 } 775 if (wflag) 776 printf("\033[H\033[J"); 777again: 778 if (wflag) { 779 struct timeval t; 780 781 gettimeofday(&t, NULL); 782 printf("\033[H%s", ctime(&t.tv_sec)); 783 } 784 print_routing(proto); 785 print_load_stats(); 786 stats(proto); 787 if (wflag) { 788 sleep(wflag); 789 goto again; 790 } 791 exit(0); 792} 793 794void 795print_load_stats(void) 796{ 797 static u_int32_t cp_time[5]; 798 u_int32_t new_cp_time[5]; 799 int l; 800 int shz; 801 static int stathz ; 802 803 if (!lflag || !wflag) 804 return; 805 l = sizeof(new_cp_time) ; 806 bzero(new_cp_time, l); 807 if (sysctlbyname("kern.cp_time", new_cp_time, &l, NULL, 0) < 0) { 808 warn("sysctl: retrieving cp_time length"); 809 return; 810 } 811 if (stathz == 0) { 812 struct clockinfo ci; 813 814 bzero (&ci, sizeof(ci)); 815 l = sizeof(ci) ; 816 if (sysctlbyname("kern.clockrate", &ci, &l, NULL, 0) < 0) { 817 warn("sysctl: retrieving clockinfo length"); 818 return; 819 } 820 stathz = ci.stathz ; 821 bcopy(new_cp_time, cp_time, sizeof(cp_time)); 822 } 823 shz = stathz * wflag ; 824 if (shz == 0) 825 shz = 1; 826#define X(i) ( (double)(new_cp_time[i] - cp_time[i])*100/shz ) 827 printf("\nUSER %5.2f%% NICE %5.2f%% SYS %5.2f%% " 828 "INTR %5.2f%% IDLE %5.2f%%\n", 829 X(0), X(1), X(2), X(3), X(4) ); 830 bcopy(new_cp_time, cp_time, sizeof(cp_time)); 831} 832