1 /* 2 * ss.c "sockstat", socket statistics 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 #include <syslog.h> 16 #include <fcntl.h> 17 #include <sys/ioctl.h> 18 #include <sys/socket.h> 19 #include <sys/uio.h> 20 #include <netinet/in.h> 21 #include <string.h> 22 #include <errno.h> 23 #include <netdb.h> 24 #include <arpa/inet.h> 25 #include <resolv.h> 26 #include <dirent.h> 27 #include <fnmatch.h> 28 #include <getopt.h> 29 30 #include "utils.h" 31 #include "rt_names.h" 32 #include "ll_map.h" 33 #include "libnetlink.h" 34 #include "SNAPSHOT.h" 35 36 #include <netinet/tcp.h> 37 #include <linux/inet_diag.h> 38 39 int resolve_hosts = 0; 40 int resolve_services = 1; 41 int preferred_family = AF_UNSPEC; 42 int show_options = 0; 43 int show_details = 0; 44 int show_users = 0; 45 int show_mem = 0; 46 int show_tcpinfo = 0; 47 48 int netid_width; 49 int state_width; 50 int addrp_width; 51 int addr_width; 52 int serv_width; 53 int screen_width; 54 55 static const char *TCP_PROTO = "tcp"; 56 static const char *UDP_PROTO = "udp"; 57 static const char *RAW_PROTO = "raw"; 58 static const char *dg_proto = NULL; 59 60 enum 61 { 62 TCP_DB, 63 DCCP_DB, 64 UDP_DB, 65 RAW_DB, 66 UNIX_DG_DB, 67 UNIX_ST_DB, 68 PACKET_DG_DB, 69 PACKET_R_DB, 70 NETLINK_DB, 71 MAX_DB 72 }; 73 74 #define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB)) 75 #define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)) 76 #define ALL_DB ((1<<MAX_DB)-1) 77 78 enum { 79 SS_UNKNOWN, 80 SS_ESTABLISHED, 81 SS_SYN_SENT, 82 SS_SYN_RECV, 83 SS_FIN_WAIT1, 84 SS_FIN_WAIT2, 85 SS_TIME_WAIT, 86 SS_CLOSE, 87 SS_CLOSE_WAIT, 88 SS_LAST_ACK, 89 SS_LISTEN, 90 SS_CLOSING, 91 SS_MAX 92 }; 93 94 #define SS_ALL ((1<<SS_MAX)-1) 95 96 #include "ssfilter.h" 97 98 struct filter 99 { 100 int dbs; 101 int states; 102 int families; 103 struct ssfilter *f; 104 }; 105 106 struct filter default_filter = { 107 .dbs = (1<<TCP_DB), 108 .states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)), 109 .families= (1<<AF_INET)|(1<<AF_INET6), 110 }; 111 112 struct filter current_filter; 113 114 static FILE *generic_proc_open(const char *env, const char *name) 115 { 116 const char *p = getenv(env); 117 char store[128]; 118 119 if (!p) { 120 p = getenv("PROC_ROOT") ? : "/proc"; 121 snprintf(store, sizeof(store)-1, "%s/%s", p, name); 122 p = store; 123 } 124 125 return fopen(p, "r"); 126 } 127 128 static FILE *net_tcp_open(void) 129 { 130 return generic_proc_open("PROC_NET_TCP", "net/tcp"); 131 } 132 133 static FILE *net_tcp6_open(void) 134 { 135 return generic_proc_open("PROC_NET_TCP6", "net/tcp6"); 136 } 137 138 static FILE *net_udp_open(void) 139 { 140 return generic_proc_open("PROC_NET_UDP", "net/udp"); 141 } 142 143 static FILE *net_udp6_open(void) 144 { 145 return generic_proc_open("PROC_NET_UDP6", "net/udp6"); 146 } 147 148 static FILE *net_raw_open(void) 149 { 150 return generic_proc_open("PROC_NET_RAW", "net/raw"); 151 } 152 153 static FILE *net_raw6_open(void) 154 { 155 return generic_proc_open("PROC_NET_RAW6", "net/raw6"); 156 } 157 158 static FILE *net_unix_open(void) 159 { 160 return generic_proc_open("PROC_NET_UNIX", "net/unix"); 161 } 162 163 static FILE *net_packet_open(void) 164 { 165 return generic_proc_open("PROC_NET_PACKET", "net/packet"); 166 } 167 168 static FILE *net_netlink_open(void) 169 { 170 return generic_proc_open("PROC_NET_NETLINK", "net/netlink"); 171 } 172 173 static FILE *slabinfo_open(void) 174 { 175 return generic_proc_open("PROC_SLABINFO", "slabinfo"); 176 } 177 178 static FILE *net_sockstat_open(void) 179 { 180 return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat"); 181 } 182 183 static FILE *net_sockstat6_open(void) 184 { 185 return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6"); 186 } 187 188 static FILE *net_snmp_open(void) 189 { 190 return generic_proc_open("PROC_NET_SNMP", "net/snmp"); 191 } 192 193 static FILE *ephemeral_ports_open(void) 194 { 195 return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range"); 196 } 197 198 int find_users(unsigned ino, char *buf, int buflen) 199 { 200 char pattern[64]; 201 int pattern_len; 202 char *ptr = buf; 203 char name[1024]; 204 DIR *dir; 205 struct dirent *d; 206 int cnt = 0; 207 int nameoff; 208 209 if (!ino) 210 return 0; 211 212 sprintf(pattern, "socket:[%u]", ino); 213 pattern_len = strlen(pattern); 214 215 strncpy(name, getenv("PROC_ROOT") ? : "/proc/", sizeof(name)/2); 216 name[sizeof(name)/2] = 0; 217 if (strlen(name) == 0 || 218 name[strlen(name)-1] != '/') 219 strcat(name, "/"); 220 nameoff = strlen(name); 221 if ((dir = opendir(name)) == NULL) 222 return 0; 223 224 while ((d = readdir(dir)) != NULL) { 225 DIR *dir1; 226 struct dirent *d1; 227 int pid; 228 int pos; 229 char crap; 230 char process[16]; 231 232 if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1) 233 continue; 234 235 sprintf(name+nameoff, "%d/fd/", pid); 236 pos = strlen(name); 237 if ((dir1 = opendir(name)) == NULL) 238 continue; 239 240 process[0] = 0; 241 242 while ((d1 = readdir(dir1)) != NULL) { 243 int fd, n; 244 char lnk[64]; 245 246 if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1) 247 continue; 248 249 sprintf(name+pos, "%d", fd); 250 n = readlink(name, lnk, sizeof(lnk)-1); 251 if (n != pattern_len || 252 memcmp(lnk, pattern, n)) 253 continue; 254 255 if (ptr-buf >= buflen-1) 256 break; 257 258 if (process[0] == 0) { 259 char tmp[1024]; 260 FILE *fp; 261 snprintf(tmp, sizeof(tmp), "%s/%d/stat", 262 getenv("PROC_ROOT") ? : "/proc", pid); 263 if ((fp = fopen(tmp, "r")) != NULL) { 264 fscanf(fp, "%*d (%[^)])", process); 265 fclose(fp); 266 } 267 } 268 269 snprintf(ptr, buflen-(ptr-buf), "(\"%s\",%d,%d),", process, pid, fd); 270 ptr += strlen(ptr); 271 cnt++; 272 } 273 closedir(dir1); 274 } 275 closedir(dir); 276 if (ptr != buf) 277 ptr[-1] = 0; 278 return cnt; 279 } 280 281 282 /* Get stats from slab */ 283 284 struct slabstat 285 { 286 int socks; 287 int tcp_ports; 288 int tcp_tws; 289 int tcp_syns; 290 int skbs; 291 }; 292 293 struct slabstat slabstat; 294 295 static const char *slabstat_ids[] = 296 { 297 "sock", 298 "tcp_bind_bucket", 299 "tcp_tw_bucket", 300 "tcp_open_request", 301 "skbuff_head_cache", 302 }; 303 304 int get_slabstat(struct slabstat *s) 305 { 306 char buf[256]; 307 FILE *fp; 308 int cnt; 309 310 memset(s, 0, sizeof(*s)); 311 312 fp = slabinfo_open(); 313 if (!fp) 314 return -1; 315 316 cnt = sizeof(*s)/sizeof(int); 317 318 fgets(buf, sizeof(buf), fp); 319 while(fgets(buf, sizeof(buf), fp) != NULL) { 320 int i; 321 for (i=0; i<sizeof(slabstat_ids)/sizeof(slabstat_ids[0]); i++) { 322 if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) { 323 sscanf(buf, "%*s%d", ((int *)s) + i); 324 cnt--; 325 break; 326 } 327 } 328 if (cnt <= 0) 329 break; 330 } 331 332 fclose(fp); 333 return 0; 334 } 335 336 static const char *sstate_name[] = { 337 "UNKNOWN", 338 [TCP_ESTABLISHED] = "ESTAB", 339 [TCP_SYN_SENT] = "SYN-SENT", 340 [TCP_SYN_RECV] = "SYN-RECV", 341 [TCP_FIN_WAIT1] = "FIN-WAIT-1", 342 [TCP_FIN_WAIT2] = "FIN-WAIT-2", 343 [TCP_TIME_WAIT] = "TIME-WAIT", 344 [TCP_CLOSE] = "UNCONN", 345 [TCP_CLOSE_WAIT] = "CLOSE-WAIT", 346 [TCP_LAST_ACK] = "LAST-ACK", 347 [TCP_LISTEN] = "LISTEN", 348 [TCP_CLOSING] = "CLOSING", 349 }; 350 351 static const char *sstate_namel[] = { 352 "UNKNOWN", 353 [TCP_ESTABLISHED] = "established", 354 [TCP_SYN_SENT] = "syn-sent", 355 [TCP_SYN_RECV] = "syn-recv", 356 [TCP_FIN_WAIT1] = "fin-wait-1", 357 [TCP_FIN_WAIT2] = "fin-wait-2", 358 [TCP_TIME_WAIT] = "time-wait", 359 [TCP_CLOSE] = "unconnected", 360 [TCP_CLOSE_WAIT] = "close-wait", 361 [TCP_LAST_ACK] = "last-ack", 362 [TCP_LISTEN] = "listening", 363 [TCP_CLOSING] = "closing", 364 }; 365 366 struct tcpstat 367 { 368 inet_prefix local; 369 inet_prefix remote; 370 int lport; 371 int rport; 372 int state; 373 int rq, wq; 374 int timer; 375 int timeout; 376 int retrs; 377 unsigned ino; 378 int probes; 379 unsigned uid; 380 int refcnt; 381 unsigned long long sk; 382 int rto, ato, qack, cwnd, ssthresh; 383 }; 384 385 static const char *tmr_name[] = { 386 "off", 387 "on", 388 "keepalive", 389 "timewait", 390 "persist", 391 "unknown" 392 }; 393 394 const char *print_ms_timer(int timeout) 395 { 396 static char buf[64]; 397 int secs, msecs, minutes; 398 if (timeout < 0) 399 timeout = 0; 400 secs = timeout/1000; 401 minutes = secs/60; 402 secs = secs%60; 403 msecs = timeout%1000; 404 buf[0] = 0; 405 if (minutes) { 406 msecs = 0; 407 snprintf(buf, sizeof(buf)-16, "%dmin", minutes); 408 if (minutes > 9) 409 secs = 0; 410 } 411 if (secs) { 412 if (secs > 9) 413 msecs = 0; 414 sprintf(buf+strlen(buf), "%d%s", secs, msecs ? "." : "sec"); 415 } 416 if (msecs) 417 sprintf(buf+strlen(buf), "%03dms", msecs); 418 return buf; 419 } 420 421 const char *print_hz_timer(int timeout) 422 { 423 int hz = get_user_hz(); 424 return print_ms_timer(((timeout*1000) + hz-1)/hz); 425 } 426 427 struct scache 428 { 429 struct scache *next; 430 int port; 431 char *name; 432 const char *proto; 433 }; 434 435 struct scache *rlist; 436 437 void init_service_resolver(void) 438 { 439 char buf[128]; 440 FILE *fp = popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r"); 441 if (fp) { 442 fgets(buf, sizeof(buf), fp); 443 while (fgets(buf, sizeof(buf), fp) != NULL) { 444 unsigned int progn, port; 445 char proto[128], prog[128]; 446 if (sscanf(buf, "%u %*d %s %u %s", &progn, proto, 447 &port, prog+4) == 4) { 448 struct scache *c = malloc(sizeof(*c)); 449 if (c) { 450 c->port = port; 451 memcpy(prog, "rpc.", 4); 452 c->name = strdup(prog); 453 if (strcmp(proto, TCP_PROTO) == 0) 454 c->proto = TCP_PROTO; 455 else if (strcmp(proto, UDP_PROTO) == 0) 456 c->proto = UDP_PROTO; 457 else 458 c->proto = NULL; 459 c->next = rlist; 460 rlist = c; 461 } 462 } 463 } 464 } 465 } 466 467 static int ip_local_port_min, ip_local_port_max; 468 469 /* Even do not try default linux ephemeral port ranges: 470 * default /etc/services contains so much of useless crap 471 * wouldbe "allocated" to this area that resolution 472 * is really harmful. I shrug each time when seeing 473 * "socks" or "cfinger" in dumps. 474 */ 475 static int is_ephemeral(int port) 476 { 477 if (!ip_local_port_min) { 478 FILE *f = ephemeral_ports_open(); 479 if (f) { 480 fscanf(f, "%d %d", 481 &ip_local_port_min, &ip_local_port_max); 482 fclose(f); 483 } else { 484 ip_local_port_min = 1024; 485 ip_local_port_max = 4999; 486 } 487 } 488 489 return (port >= ip_local_port_min && port<= ip_local_port_max); 490 } 491 492 493 const char *__resolve_service(int port) 494 { 495 struct scache *c; 496 497 for (c = rlist; c; c = c->next) { 498 if (c->port == port && c->proto == dg_proto) 499 return c->name; 500 } 501 502 if (!is_ephemeral(port)) { 503 static int notfirst; 504 struct servent *se; 505 if (!notfirst) { 506 setservent(1); 507 notfirst = 1; 508 } 509 se = getservbyport(htons(port), dg_proto); 510 if (se) 511 return se->s_name; 512 } 513 514 return NULL; 515 } 516 517 518 const char *resolve_service(int port) 519 { 520 static char buf[128]; 521 static struct scache cache[256]; 522 523 if (port == 0) { 524 buf[0] = '*'; 525 buf[1] = 0; 526 return buf; 527 } 528 529 if (resolve_services) { 530 if (dg_proto == RAW_PROTO) { 531 return inet_proto_n2a(port, buf, sizeof(buf)); 532 } else { 533 struct scache *c; 534 const char *res; 535 int hash = (port^(((unsigned long)dg_proto)>>2))&255; 536 537 for (c = &cache[hash]; c; c = c->next) { 538 if (c->port == port && 539 c->proto == dg_proto) { 540 if (c->name) 541 return c->name; 542 goto do_numeric; 543 } 544 } 545 546 if ((res = __resolve_service(port)) != NULL) { 547 if ((c = malloc(sizeof(*c))) == NULL) 548 goto do_numeric; 549 } else { 550 c = &cache[hash]; 551 if (c->name) 552 free(c->name); 553 } 554 c->port = port; 555 c->name = NULL; 556 c->proto = dg_proto; 557 if (res) { 558 c->name = strdup(res); 559 c->next = cache[hash].next; 560 cache[hash].next = c; 561 } 562 if (c->name) 563 return c->name; 564 } 565 } 566 567 do_numeric: 568 sprintf(buf, "%u", port); 569 return buf; 570 } 571 572 void formatted_print(const inet_prefix *a, int port) 573 { 574 char buf[1024]; 575 const char *ap = buf; 576 int est_len; 577 578 est_len = addr_width; 579 580 if (a->family == AF_INET) { 581 if (a->data[0] == 0) { 582 buf[0] = '*'; 583 buf[1] = 0; 584 } else { 585 ap = format_host(AF_INET, 4, a->data, buf, sizeof(buf)); 586 } 587 } else { 588 ap = format_host(a->family, 16, a->data, buf, sizeof(buf)); 589 est_len = strlen(ap); 590 if (est_len <= addr_width) 591 est_len = addr_width; 592 else 593 est_len = addr_width + ((est_len-addr_width+3)/4)*4; 594 } 595 printf("%*s:%-*s ", est_len, ap, serv_width, resolve_service(port)); 596 } 597 598 struct aafilter 599 { 600 inet_prefix addr; 601 int port; 602 struct aafilter *next; 603 }; 604 605 int inet2_addr_match(const inet_prefix *a, const inet_prefix *p, int plen) 606 { 607 if (!inet_addr_match(a, p, plen)) 608 return 0; 609 610 /* Cursed "v4 mapped" addresses: v4 mapped socket matches 611 * pure IPv4 rule, but v4-mapped rule selects only v4-mapped 612 * sockets. Fair? */ 613 if (p->family == AF_INET && a->family == AF_INET6) { 614 if (a->data[0] == 0 && a->data[1] == 0 && 615 a->data[2] == htonl(0xffff)) { 616 inet_prefix tmp = *a; 617 tmp.data[0] = a->data[3]; 618 return inet_addr_match(&tmp, p, plen); 619 } 620 } 621 return 1; 622 } 623 624 int unix_match(const inet_prefix *a, const inet_prefix *p) 625 { 626 char *addr, *pattern; 627 memcpy(&addr, a->data, sizeof(addr)); 628 memcpy(&pattern, p->data, sizeof(pattern)); 629 if (pattern == NULL) 630 return 1; 631 if (addr == NULL) 632 addr = ""; 633 return !fnmatch(pattern, addr, 0); 634 } 635 636 int run_ssfilter(struct ssfilter *f, struct tcpstat *s) 637 { 638 switch (f->type) { 639 case SSF_S_AUTO: 640 { 641 static int low, high=65535; 642 643 if (s->local.family == AF_UNIX) { 644 char *p; 645 memcpy(&p, s->local.data, sizeof(p)); 646 return p == NULL || (p[0] == '@' && strlen(p) == 6 && 647 strspn(p+1, "0123456789abcdef") == 5); 648 } 649 if (s->local.family == AF_PACKET) 650 return s->lport == 0 && s->local.data == 0; 651 if (s->local.family == AF_NETLINK) 652 return s->lport < 0; 653 654 if (!low) { 655 FILE *fp = ephemeral_ports_open(); 656 if (fp) { 657 fscanf(fp, "%d%d", &low, &high); 658 fclose(fp); 659 } 660 } 661 return s->lport >= low && s->lport <= high; 662 } 663 case SSF_DCOND: 664 { 665 struct aafilter *a = (void*)f->pred; 666 if (a->addr.family == AF_UNIX) 667 return unix_match(&s->remote, &a->addr); 668 if (a->port != -1 && a->port != s->rport) 669 return 0; 670 if (a->addr.bitlen) { 671 do { 672 if (!inet2_addr_match(&s->remote, &a->addr, a->addr.bitlen)) 673 return 1; 674 } while ((a = a->next) != NULL); 675 return 0; 676 } 677 return 1; 678 } 679 case SSF_SCOND: 680 { 681 struct aafilter *a = (void*)f->pred; 682 if (a->addr.family == AF_UNIX) 683 return unix_match(&s->local, &a->addr); 684 if (a->port != -1 && a->port != s->lport) 685 return 0; 686 if (a->addr.bitlen) { 687 do { 688 if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen)) 689 return 1; 690 } while ((a = a->next) != NULL); 691 return 0; 692 } 693 return 1; 694 } 695 case SSF_D_GE: 696 { 697 struct aafilter *a = (void*)f->pred; 698 return s->rport >= a->port; 699 } 700 case SSF_D_LE: 701 { 702 struct aafilter *a = (void*)f->pred; 703 return s->rport <= a->port; 704 } 705 case SSF_S_GE: 706 { 707 struct aafilter *a = (void*)f->pred; 708 return s->lport >= a->port; 709 } 710 case SSF_S_LE: 711 { 712 struct aafilter *a = (void*)f->pred; 713 return s->lport <= a->port; 714 } 715 716 /* Yup. It is recursion. Sorry. */ 717 case SSF_AND: 718 return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s); 719 case SSF_OR: 720 return run_ssfilter(f->pred, s) || run_ssfilter(f->post, s); 721 case SSF_NOT: 722 return !run_ssfilter(f->pred, s); 723 default: 724 abort(); 725 } 726 } 727 728 /* Relocate external jumps by reloc. */ 729 static void ssfilter_patch(char *a, int len, int reloc) 730 { 731 while (len > 0) { 732 struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)a; 733 if (op->no == len+4) 734 op->no += reloc; 735 len -= op->yes; 736 a += op->yes; 737 } 738 if (len < 0) 739 abort(); 740 } 741 742 static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) 743 { 744 switch (f->type) { 745 case SSF_S_AUTO: 746 { 747 if (!(*bytecode=malloc(4))) abort(); 748 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 }; 749 return 8; 750 } 751 case SSF_DCOND: 752 case SSF_SCOND: 753 { 754 struct aafilter *a = (void*)f->pred; 755 struct aafilter *b; 756 char *ptr; 757 int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND); 758 int len = 0; 759 760 for (b=a; b; b=b->next) { 761 len += 4 + sizeof(struct inet_diag_hostcond); 762 if (a->addr.family == AF_INET6) 763 len += 16; 764 else 765 len += 4; 766 if (b->next) 767 len += 4; 768 } 769 if (!(ptr = malloc(len))) abort(); 770 *bytecode = ptr; 771 for (b=a; b; b=b->next) { 772 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr; 773 int alen = (a->addr.family == AF_INET6 ? 16 : 4); 774 int oplen = alen + 4 + sizeof(struct inet_diag_hostcond); 775 struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(ptr+4); 776 777 *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 }; 778 cond->family = a->addr.family; 779 cond->port = a->port; 780 cond->prefix_len = a->addr.bitlen; 781 memcpy(cond->addr, a->addr.data, alen); 782 ptr += oplen; 783 if (b->next) { 784 op = (struct inet_diag_bc_op *)ptr; 785 *op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)}; 786 ptr += 4; 787 } 788 } 789 return ptr - *bytecode; 790 } 791 case SSF_D_GE: 792 { 793 struct aafilter *x = (void*)f->pred; 794 if (!(*bytecode=malloc(8))) abort(); 795 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 }; 796 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; 797 return 8; 798 } 799 case SSF_D_LE: 800 { 801 struct aafilter *x = (void*)f->pred; 802 if (!(*bytecode=malloc(8))) abort(); 803 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 }; 804 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; 805 return 8; 806 } 807 case SSF_S_GE: 808 { 809 struct aafilter *x = (void*)f->pred; 810 if (!(*bytecode=malloc(8))) abort(); 811 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 }; 812 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; 813 return 8; 814 } 815 case SSF_S_LE: 816 { 817 struct aafilter *x = (void*)f->pred; 818 if (!(*bytecode=malloc(8))) abort(); 819 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 }; 820 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; 821 return 8; 822 } 823 824 case SSF_AND: 825 { 826 char *a1, *a2, *a, l1, l2; 827 l1 = ssfilter_bytecompile(f->pred, &a1); 828 l2 = ssfilter_bytecompile(f->post, &a2); 829 if (!(a = malloc(l1+l2))) abort(); 830 memcpy(a, a1, l1); 831 memcpy(a+l1, a2, l2); 832 free(a1); free(a2); 833 ssfilter_patch(a, l1, l2); 834 *bytecode = a; 835 return l1+l2; 836 } 837 case SSF_OR: 838 { 839 char *a1, *a2, *a, l1, l2; 840 l1 = ssfilter_bytecompile(f->pred, &a1); 841 l2 = ssfilter_bytecompile(f->post, &a2); 842 if (!(a = malloc(l1+l2+4))) abort(); 843 memcpy(a, a1, l1); 844 memcpy(a+l1+4, a2, l2); 845 free(a1); free(a2); 846 *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 }; 847 *bytecode = a; 848 return l1+l2+4; 849 } 850 case SSF_NOT: 851 { 852 char *a1, *a, l1; 853 l1 = ssfilter_bytecompile(f->pred, &a1); 854 if (!(a = malloc(l1+4))) abort(); 855 memcpy(a, a1, l1); 856 free(a1); 857 *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 }; 858 *bytecode = a; 859 return l1+4; 860 } 861 default: 862 abort(); 863 } 864 } 865 866 static int remember_he(struct aafilter *a, struct hostent *he) 867 { 868 char **ptr = he->h_addr_list; 869 int cnt = 0; 870 int len; 871 872 if (he->h_addrtype == AF_INET) 873 len = 4; 874 else if (he->h_addrtype == AF_INET6) 875 len = 16; 876 else 877 return 0; 878 879 while (*ptr) { 880 struct aafilter *b = a; 881 if (a->addr.bitlen) { 882 if ((b = malloc(sizeof(*b))) == NULL) 883 return cnt; 884 *b = *a; 885 b->next = a->next; 886 a->next = b; 887 } 888 memcpy(b->addr.data, *ptr, len); 889 b->addr.bytelen = len; 890 b->addr.bitlen = len*8; 891 b->addr.family = he->h_addrtype; 892 ptr++; 893 cnt++; 894 } 895 return cnt; 896 } 897 898 static int get_dns_host(struct aafilter *a, const char *addr, int fam) 899 { 900 static int notfirst; 901 int cnt = 0; 902 struct hostent *he; 903 904 a->addr.bitlen = 0; 905 if (!notfirst) { 906 sethostent(1); 907 notfirst = 1; 908 } 909 he = gethostbyname2(addr, fam == AF_UNSPEC ? AF_INET : fam); 910 if (he) 911 cnt = remember_he(a, he); 912 if (fam == AF_UNSPEC) { 913 he = gethostbyname2(addr, AF_INET6); 914 if (he) 915 cnt += remember_he(a, he); 916 } 917 return !cnt; 918 } 919 920 static int xll_initted = 0; 921 922 static void xll_init(void) 923 { 924 struct rtnl_handle rth; 925 rtnl_open(&rth, 0); 926 ll_init_map(&rth); 927 rtnl_close(&rth); 928 xll_initted = 1; 929 } 930 931 static const char *xll_index_to_name(int index) 932 { 933 if (!xll_initted) 934 xll_init(); 935 return ll_index_to_name(index); 936 } 937 938 static int xll_name_to_index(const char *dev) 939 { 940 if (!xll_initted) 941 xll_init(); 942 return ll_name_to_index(dev); 943 } 944 945 void *parse_hostcond(char *addr) 946 { 947 char *port = NULL; 948 struct aafilter a; 949 struct aafilter *res; 950 int fam = preferred_family; 951 952 memset(&a, 0, sizeof(a)); 953 a.port = -1; 954 955 if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) { 956 char *p; 957 a.addr.family = AF_UNIX; 958 if (strncmp(addr, "unix:", 5) == 0) 959 addr+=5; 960 p = strdup(addr); 961 a.addr.bitlen = 8*strlen(p); 962 memcpy(a.addr.data, &p, sizeof(p)); 963 goto out; 964 } 965 966 if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) { 967 a.addr.family = AF_PACKET; 968 a.addr.bitlen = 0; 969 if (strncmp(addr, "link:", 5) == 0) 970 addr+=5; 971 port = strchr(addr, ':'); 972 if (port) { 973 *port = 0; 974 if (port[1] && strcmp(port+1, "*")) { 975 if (get_integer(&a.port, port+1, 0)) { 976 if ((a.port = xll_name_to_index(port+1)) <= 0) 977 return NULL; 978 } 979 } 980 } 981 if (addr[0] && strcmp(addr, "*")) { 982 unsigned short tmp; 983 a.addr.bitlen = 32; 984 if (ll_proto_a2n(&tmp, addr)) 985 return NULL; 986 a.addr.data[0] = ntohs(tmp); 987 } 988 goto out; 989 } 990 991 if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) { 992 a.addr.family = AF_NETLINK; 993 a.addr.bitlen = 0; 994 if (strncmp(addr, "netlink:", 8) == 0) 995 addr+=8; 996 port = strchr(addr, ':'); 997 if (port) { 998 *port = 0; 999 if (port[1] && strcmp(port+1, "*")) { 1000 if (get_integer(&a.port, port+1, 0)) { 1001 if (strcmp(port+1, "kernel") == 0) 1002 a.port = 0; 1003 else 1004 return NULL; 1005 } 1006 } 1007 } 1008 if (addr[0] && strcmp(addr, "*")) { 1009 a.addr.bitlen = 32; 1010 if (get_u32(a.addr.data, addr, 0)) { 1011 if (strcmp(addr, "rtnl") == 0) 1012 a.addr.data[0] = 0; 1013 else if (strcmp(addr, "fw") == 0) 1014 a.addr.data[0] = 3; 1015 else if (strcmp(addr, "tcpdiag") == 0) 1016 a.addr.data[0] = 4; 1017 else 1018 return NULL; 1019 } 1020 } 1021 goto out; 1022 } 1023 1024 if (strncmp(addr, "inet:", 5) == 0) { 1025 addr += 5; 1026 fam = AF_INET; 1027 } else if (strncmp(addr, "inet6:", 6) == 0) { 1028 addr += 6; 1029 fam = AF_INET6; 1030 } 1031 1032 /* URL-like literal [] */ 1033 if (addr[0] == '[') { 1034 addr++; 1035 if ((port = strchr(addr, ']')) == NULL) 1036 return NULL; 1037 *port++ = 0; 1038 } else if (addr[0] == '*') { 1039 port = addr+1; 1040 } else { 1041 port = strrchr(strchr(addr, '/') ? : addr, ':'); 1042 } 1043 if (port && *port) { 1044 if (*port != ':') 1045 return NULL; 1046 *port++ = 0; 1047 if (*port && *port != '*') { 1048 if (get_integer(&a.port, port, 0)) { 1049 struct servent *se1 = NULL; 1050 struct servent *se2 = NULL; 1051 if (current_filter.dbs&(1<<UDP_DB)) 1052 se1 = getservbyname(port, UDP_PROTO); 1053 if (current_filter.dbs&(1<<TCP_DB)) 1054 se2 = getservbyname(port, TCP_PROTO); 1055 if (se1 && se2 && se1->s_port != se2->s_port) { 1056 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port); 1057 return NULL; 1058 } 1059 if (!se1) 1060 se1 = se2; 1061 if (se1) { 1062 a.port = ntohs(se1->s_port); 1063 } else { 1064 struct scache *s; 1065 for (s = rlist; s; s = s->next) { 1066 if ((s->proto == UDP_PROTO && 1067 (current_filter.dbs&(1<<UDP_DB))) || 1068 (s->proto == TCP_PROTO && 1069 (current_filter.dbs&(1<<TCP_DB)))) { 1070 if (s->name && strcmp(s->name, port) == 0) { 1071 if (a.port > 0 && a.port != s->port) { 1072 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port); 1073 return NULL; 1074 } 1075 a.port = s->port; 1076 } 1077 } 1078 } 1079 if (a.port <= 0) { 1080 fprintf(stderr, "Error: \"%s\" does not look like a port.\n", port); 1081 return NULL; 1082 } 1083 } 1084 } 1085 } 1086 } 1087 if (addr && *addr && *addr != '*') { 1088 if (get_prefix_1(&a.addr, addr, fam)) { 1089 if (get_dns_host(&a, addr, fam)) { 1090 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr); 1091 return NULL; 1092 } 1093 } 1094 } 1095 1096 out: 1097 res = malloc(sizeof(*res)); 1098 if (res) 1099 memcpy(res, &a, sizeof(a)); 1100 return res; 1101 } 1102 1103 static int tcp_show_line(char *line, const struct filter *f, int family) 1104 { 1105 struct tcpstat s; 1106 char *loc, *rem, *data; 1107 char opt[256]; 1108 int n; 1109 char *p; 1110 1111 if ((p = strchr(line, ':')) == NULL) 1112 return -1; 1113 loc = p+2; 1114 1115 if ((p = strchr(loc, ':')) == NULL) 1116 return -1; 1117 p[5] = 0; 1118 rem = p+6; 1119 1120 if ((p = strchr(rem, ':')) == NULL) 1121 return -1; 1122 p[5] = 0; 1123 data = p+6; 1124 1125 do { 1126 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0'); 1127 1128 if (!(f->states & (1<<state))) 1129 return 0; 1130 } while (0); 1131 1132 s.local.family = s.remote.family = family; 1133 if (family == AF_INET) { 1134 sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport); 1135 sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport); 1136 s.local.bytelen = s.remote.bytelen = 4; 1137 } else { 1138 sscanf(loc, "%08x%08x%08x%08x:%x", 1139 s.local.data, 1140 s.local.data+1, 1141 s.local.data+2, 1142 s.local.data+3, 1143 &s.lport); 1144 sscanf(rem, "%08x%08x%08x%08x:%x", 1145 s.remote.data, 1146 s.remote.data+1, 1147 s.remote.data+2, 1148 s.remote.data+3, 1149 &s.rport); 1150 s.local.bytelen = s.remote.bytelen = 16; 1151 } 1152 1153 if (f->f && run_ssfilter(f->f, &s) == 0) 1154 return 0; 1155 1156 opt[0] = 0; 1157 n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n", 1158 &s.state, &s.wq, &s.rq, 1159 &s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino, 1160 &s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack, 1161 &s.cwnd, &s.ssthresh, opt); 1162 1163 if (n < 17) 1164 opt[0] = 0; 1165 1166 if (n < 12) { 1167 s.rto = 0; 1168 s.cwnd = 2; 1169 s.ssthresh = -1; 1170 s.ato = s.qack = 0; 1171 } 1172 1173 if (netid_width) 1174 printf("%-*s ", netid_width, "tcp"); 1175 if (state_width) 1176 printf("%-*s ", state_width, sstate_name[s.state]); 1177 1178 printf("%-6d %-6d ", s.rq, s.wq); 1179 1180 formatted_print(&s.local, s.lport); 1181 formatted_print(&s.remote, s.rport); 1182 1183 if (show_options) { 1184 if (s.timer) { 1185 if (s.timer > 4) 1186 s.timer = 5; 1187 printf(" timer:(%s,%s,%d)", 1188 tmr_name[s.timer], 1189 print_hz_timer(s.timeout), 1190 s.timer != 1 ? s.probes : s.retrs); 1191 } 1192 } 1193 if (show_tcpinfo) { 1194 int hz = get_user_hz(); 1195 if (s.rto && s.rto != 3*hz) 1196 printf(" rto:%g", (double)s.rto/hz); 1197 if (s.ato) 1198 printf(" ato:%g", (double)s.ato/hz); 1199 if (s.cwnd != 2) 1200 printf(" cwnd:%d", s.cwnd); 1201 if (s.ssthresh != -1) 1202 printf(" ssthresh:%d", s.ssthresh); 1203 if (s.qack/2) 1204 printf(" qack:%d", s.qack/2); 1205 if (s.qack&1) 1206 printf(" bidir"); 1207 } 1208 if (show_users) { 1209 char ubuf[4096]; 1210 if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0) 1211 printf(" users:(%s)", ubuf); 1212 } 1213 if (show_details) { 1214 if (s.uid) 1215 printf(" uid:%u", (unsigned)s.uid); 1216 printf(" ino:%u", s.ino); 1217 printf(" sk:%llx", s.sk); 1218 if (opt[0]) 1219 printf(" opt:\"%s\"", opt); 1220 } 1221 printf("\n"); 1222 1223 return 0; 1224 } 1225 1226 static int generic_record_read(FILE *fp, 1227 int (*worker)(char*, const struct filter *, int), 1228 const struct filter *f, int fam) 1229 { 1230 char line[256]; 1231 1232 /* skip header */ 1233 if (fgets(line, sizeof(line), fp) == NULL) 1234 goto outerr; 1235 1236 while (fgets(line, sizeof(line), fp) != NULL) { 1237 int n = strlen(line); 1238 if (n == 0 || line[n-1] != '\n') { 1239 errno = -EINVAL; 1240 return -1; 1241 } 1242 line[n-1] = 0; 1243 1244 if (worker(line, f, fam) < 0) 1245 return 0; 1246 } 1247 outerr: 1248 1249 return ferror(fp) ? -1 : 0; 1250 } 1251 1252 static char *sprint_bw(char *buf, double bw) 1253 { 1254 if (bw > 1000000.) 1255 sprintf(buf,"%.1fM", bw / 1000000.); 1256 else if (bw > 1000.) 1257 sprintf(buf,"%.1fK", bw / 1000.); 1258 else 1259 sprintf(buf, "%g", bw); 1260 1261 return buf; 1262 } 1263 1264 static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r) 1265 { 1266 struct rtattr * tb[INET_DIAG_MAX+1]; 1267 char b1[64]; 1268 double rtt = 0; 1269 1270 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1), 1271 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); 1272 1273 if (tb[INET_DIAG_MEMINFO]) { 1274 const struct inet_diag_meminfo *minfo 1275 = RTA_DATA(tb[INET_DIAG_MEMINFO]); 1276 printf(" mem:(r%u,w%u,f%u,t%u)", 1277 minfo->idiag_rmem, 1278 minfo->idiag_wmem, 1279 minfo->idiag_fmem, 1280 minfo->idiag_tmem); 1281 } 1282 1283 if (tb[INET_DIAG_INFO]) { 1284 struct tcp_info *info; 1285 int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]); 1286 1287 /* workaround for older kernels with less fields */ 1288 if (len < sizeof(*info)) { 1289 info = alloca(sizeof(*info)); 1290 memset(info, 0, sizeof(*info)); 1291 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len); 1292 } else 1293 info = RTA_DATA(tb[INET_DIAG_INFO]); 1294 1295 if (show_options) { 1296 if (info->tcpi_options & TCPI_OPT_TIMESTAMPS) 1297 printf(" ts"); 1298 if (info->tcpi_options & TCPI_OPT_SACK) 1299 printf(" sack"); 1300 if (info->tcpi_options & TCPI_OPT_ECN) 1301 printf(" ecn"); 1302 } 1303 1304 if (tb[INET_DIAG_CONG]) 1305 printf(" %s", (char *) RTA_DATA(tb[INET_DIAG_CONG])); 1306 1307 if (info->tcpi_options & TCPI_OPT_WSCALE) 1308 printf(" wscale:%d,%d", info->tcpi_snd_wscale, 1309 info->tcpi_rcv_wscale); 1310 if (info->tcpi_rto && info->tcpi_rto != 3000000) 1311 printf(" rto:%g", (double)info->tcpi_rto/1000); 1312 if (info->tcpi_rtt) 1313 printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000, 1314 (double)info->tcpi_rttvar/1000); 1315 if (info->tcpi_ato) 1316 printf(" ato:%g", (double)info->tcpi_ato/1000); 1317 if (info->tcpi_snd_cwnd != 2) 1318 printf(" cwnd:%d", info->tcpi_snd_cwnd); 1319 if (info->tcpi_snd_ssthresh < 0xFFFF) 1320 printf(" ssthresh:%d", info->tcpi_snd_ssthresh); 1321 1322 rtt = (double) info->tcpi_rtt; 1323 if (tb[INET_DIAG_VEGASINFO]) { 1324 const struct tcpvegas_info *vinfo 1325 = RTA_DATA(tb[INET_DIAG_VEGASINFO]); 1326 1327 if (vinfo->tcpv_enabled && 1328 vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff) 1329 rtt = vinfo->tcpv_rtt; 1330 } 1331 1332 if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) { 1333 printf(" send %sbps", 1334 sprint_bw(b1, (double) info->tcpi_snd_cwnd * 1335 (double) info->tcpi_snd_mss * 8000000. 1336 / rtt)); 1337 } 1338 1339 if (info->tcpi_rcv_rtt) 1340 printf(" rcv_rtt:%g", (double) info->tcpi_rcv_rtt/1000); 1341 if (info->tcpi_rcv_space) 1342 printf(" rcv_space:%d", info->tcpi_rcv_space); 1343 1344 } 1345 } 1346 1347 static int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f) 1348 { 1349 struct inet_diag_msg *r = NLMSG_DATA(nlh); 1350 struct tcpstat s; 1351 1352 s.state = r->idiag_state; 1353 s.local.family = s.remote.family = r->idiag_family; 1354 s.lport = ntohs(r->id.idiag_sport); 1355 s.rport = ntohs(r->id.idiag_dport); 1356 if (s.local.family == AF_INET) { 1357 s.local.bytelen = s.remote.bytelen = 4; 1358 } else { 1359 s.local.bytelen = s.remote.bytelen = 16; 1360 } 1361 memcpy(s.local.data, r->id.idiag_src, s.local.bytelen); 1362 memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen); 1363 1364 if (f && f->f && run_ssfilter(f->f, &s) == 0) 1365 return 0; 1366 1367 if (netid_width) 1368 printf("%-*s ", netid_width, "tcp"); 1369 if (state_width) 1370 printf("%-*s ", state_width, sstate_name[s.state]); 1371 1372 printf("%-6d %-6d ", r->idiag_rqueue, r->idiag_wqueue); 1373 1374 formatted_print(&s.local, s.lport); 1375 formatted_print(&s.remote, s.rport); 1376 1377 if (show_options) { 1378 if (r->idiag_timer) { 1379 if (r->idiag_timer > 4) 1380 r->idiag_timer = 5; 1381 printf(" timer:(%s,%s,%d)", 1382 tmr_name[r->idiag_timer], 1383 print_ms_timer(r->idiag_expires), 1384 r->idiag_retrans); 1385 } 1386 } 1387 if (show_users) { 1388 char ubuf[4096]; 1389 if (find_users(r->idiag_inode, ubuf, sizeof(ubuf)) > 0) 1390 printf(" users:(%s)", ubuf); 1391 } 1392 if (show_details) { 1393 if (r->idiag_uid) 1394 printf(" uid:%u", (unsigned)r->idiag_uid); 1395 printf(" ino:%u", r->idiag_inode); 1396 printf(" sk:"); 1397 if (r->id.idiag_cookie[1] != 0) 1398 printf("%08x", r->id.idiag_cookie[1]); 1399 printf("%08x", r->id.idiag_cookie[0]); 1400 } 1401 if (show_mem || show_tcpinfo) { 1402 printf("\n\t"); 1403 tcp_show_info(nlh, r); 1404 } 1405 1406 printf("\n"); 1407 1408 return 0; 1409 } 1410 1411 static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype) 1412 { 1413 int fd; 1414 struct sockaddr_nl nladdr; 1415 struct { 1416 struct nlmsghdr nlh; 1417 struct inet_diag_req r; 1418 } req; 1419 char *bc = NULL; 1420 int bclen; 1421 struct msghdr msg; 1422 struct rtattr rta; 1423 char buf[8192]; 1424 struct iovec iov[3]; 1425 1426 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0) 1427 return -1; 1428 1429 memset(&nladdr, 0, sizeof(nladdr)); 1430 nladdr.nl_family = AF_NETLINK; 1431 1432 req.nlh.nlmsg_len = sizeof(req); 1433 req.nlh.nlmsg_type = socktype; 1434 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; 1435 req.nlh.nlmsg_pid = 0; 1436 req.nlh.nlmsg_seq = 123456; 1437 memset(&req.r, 0, sizeof(req.r)); 1438 req.r.idiag_family = AF_INET; 1439 req.r.idiag_states = f->states; 1440 if (show_mem) 1441 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1)); 1442 1443 if (show_tcpinfo) { 1444 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1)); 1445 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1)); 1446 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1)); 1447 } 1448 1449 iov[0] = (struct iovec){ 1450 .iov_base = &req, 1451 .iov_len = sizeof(req) 1452 }; 1453 if (f->f) { 1454 bclen = ssfilter_bytecompile(f->f, &bc); 1455 rta.rta_type = INET_DIAG_REQ_BYTECODE; 1456 rta.rta_len = RTA_LENGTH(bclen); 1457 iov[1] = (struct iovec){ &rta, sizeof(rta) }; 1458 iov[2] = (struct iovec){ bc, bclen }; 1459 req.nlh.nlmsg_len += RTA_LENGTH(bclen); 1460 } 1461 1462 msg = (struct msghdr) { 1463 .msg_name = (void*)&nladdr, 1464 .msg_namelen = sizeof(nladdr), 1465 .msg_iov = iov, 1466 .msg_iovlen = f->f ? 3 : 1, 1467 }; 1468 1469 if (sendmsg(fd, &msg, 0) < 0) 1470 return -1; 1471 1472 iov[0] = (struct iovec){ 1473 .iov_base = buf, 1474 .iov_len = sizeof(buf) 1475 }; 1476 1477 while (1) { 1478 int status; 1479 struct nlmsghdr *h; 1480 1481 msg = (struct msghdr) { 1482 (void*)&nladdr, sizeof(nladdr), 1483 iov, 1, 1484 NULL, 0, 1485 0 1486 }; 1487 1488 status = recvmsg(fd, &msg, 0); 1489 1490 if (status < 0) { 1491 if (errno == EINTR) 1492 continue; 1493 perror("OVERRUN"); 1494 continue; 1495 } 1496 if (status == 0) { 1497 fprintf(stderr, "EOF on netlink\n"); 1498 return 0; 1499 } 1500 1501 if (dump_fp) 1502 fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp); 1503 1504 h = (struct nlmsghdr*)buf; 1505 while (NLMSG_OK(h, status)) { 1506 int err; 1507 struct inet_diag_msg *r = NLMSG_DATA(h); 1508 1509 if (/*h->nlmsg_pid != rth->local.nl_pid ||*/ 1510 h->nlmsg_seq != 123456) 1511 goto skip_it; 1512 1513 if (h->nlmsg_type == NLMSG_DONE) 1514 return 0; 1515 if (h->nlmsg_type == NLMSG_ERROR) { 1516 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 1517 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 1518 fprintf(stderr, "ERROR truncated\n"); 1519 } else { 1520 errno = -err->error; 1521 perror("TCPDIAG answers"); 1522 } 1523 return 0; 1524 } 1525 if (!dump_fp) { 1526 if (!(f->families & (1<<r->idiag_family))) { 1527 h = NLMSG_NEXT(h, status); 1528 continue; 1529 } 1530 err = tcp_show_sock(h, NULL); 1531 if (err < 0) 1532 return err; 1533 } 1534 1535 skip_it: 1536 h = NLMSG_NEXT(h, status); 1537 } 1538 if (msg.msg_flags & MSG_TRUNC) { 1539 fprintf(stderr, "Message truncated\n"); 1540 continue; 1541 } 1542 if (status) { 1543 fprintf(stderr, "!!!Remnant of size %d\n", status); 1544 exit(1); 1545 } 1546 } 1547 return 0; 1548 } 1549 1550 static int tcp_show_netlink_file(struct filter *f) 1551 { 1552 FILE *fp; 1553 char buf[8192]; 1554 1555 if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) { 1556 perror("fopen($TCPDIAG_FILE)"); 1557 return -1; 1558 } 1559 1560 while (1) { 1561 int status, err; 1562 struct nlmsghdr *h = (struct nlmsghdr*)buf; 1563 1564 status = fread(buf, 1, sizeof(*h), fp); 1565 if (status < 0) { 1566 perror("Reading header from $TCPDIAG_FILE"); 1567 return -1; 1568 } 1569 if (status != sizeof(*h)) { 1570 perror("Unexpected EOF reading $TCPDIAG_FILE"); 1571 return -1; 1572 } 1573 1574 status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp); 1575 1576 if (status < 0) { 1577 perror("Reading $TCPDIAG_FILE"); 1578 return -1; 1579 } 1580 if (status + sizeof(*h) < h->nlmsg_len) { 1581 perror("Unexpected EOF reading $TCPDIAG_FILE"); 1582 return -1; 1583 } 1584 1585 /* The only legal exit point */ 1586 if (h->nlmsg_type == NLMSG_DONE) 1587 return 0; 1588 1589 if (h->nlmsg_type == NLMSG_ERROR) { 1590 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 1591 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 1592 fprintf(stderr, "ERROR truncated\n"); 1593 } else { 1594 errno = -err->error; 1595 perror("TCPDIAG answered"); 1596 } 1597 return -1; 1598 } 1599 1600 err = tcp_show_sock(h, f); 1601 if (err < 0) 1602 return err; 1603 } 1604 } 1605 1606 static int tcp_show(struct filter *f, int socktype) 1607 { 1608 FILE *fp = NULL; 1609 char *buf = NULL; 1610 int bufsize = 64*1024; 1611 1612 dg_proto = TCP_PROTO; 1613 1614 if (getenv("TCPDIAG_FILE")) 1615 return tcp_show_netlink_file(f); 1616 1617 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT") 1618 && tcp_show_netlink(f, NULL, socktype) == 0) 1619 return 0; 1620 1621 /* Sigh... We have to parse /proc/net/tcp... */ 1622 1623 1624 /* Estimate amount of sockets and try to allocate 1625 * huge buffer to read all the table at one read. 1626 * Limit it by 16MB though. The assumption is: as soon as 1627 * kernel was able to hold information about N connections, 1628 * it is able to give us some memory for snapshot. 1629 */ 1630 if (1) { 1631 int guess = slabstat.socks+slabstat.tcp_syns; 1632 if (f->states&(1<<SS_TIME_WAIT)) 1633 guess += slabstat.tcp_tws; 1634 if (guess > (16*1024*1024)/128) 1635 guess = (16*1024*1024)/128; 1636 guess *= 128; 1637 if (guess > bufsize) 1638 bufsize = guess; 1639 } 1640 while (bufsize >= 64*1024) { 1641 if ((buf = malloc(bufsize)) != NULL) 1642 break; 1643 bufsize /= 2; 1644 } 1645 if (buf == NULL) { 1646 errno = ENOMEM; 1647 return -1; 1648 } 1649 1650 if (f->families & (1<<AF_INET)) { 1651 if ((fp = net_tcp_open()) == NULL) 1652 goto outerr; 1653 1654 setbuffer(fp, buf, bufsize); 1655 if (generic_record_read(fp, tcp_show_line, f, AF_INET)) 1656 goto outerr; 1657 fclose(fp); 1658 } 1659 1660 if ((f->families & (1<<AF_INET6)) && 1661 (fp = net_tcp6_open()) != NULL) { 1662 setbuffer(fp, buf, bufsize); 1663 if (generic_record_read(fp, tcp_show_line, f, AF_INET6)) 1664 goto outerr; 1665 fclose(fp); 1666 } 1667 1668 free(buf); 1669 return 0; 1670 1671 outerr: 1672 do { 1673 int saved_errno = errno; 1674 if (buf) 1675 free(buf); 1676 if (fp) 1677 fclose(fp); 1678 errno = saved_errno; 1679 return -1; 1680 } while (0); 1681 } 1682 1683 1684 int dgram_show_line(char *line, const struct filter *f, int family) 1685 { 1686 struct tcpstat s; 1687 char *loc, *rem, *data; 1688 char opt[256]; 1689 int n; 1690 char *p; 1691 1692 if ((p = strchr(line, ':')) == NULL) 1693 return -1; 1694 loc = p+2; 1695 1696 if ((p = strchr(loc, ':')) == NULL) 1697 return -1; 1698 p[5] = 0; 1699 rem = p+6; 1700 1701 if ((p = strchr(rem, ':')) == NULL) 1702 return -1; 1703 p[5] = 0; 1704 data = p+6; 1705 1706 do { 1707 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0'); 1708 1709 if (!(f->states & (1<<state))) 1710 return 0; 1711 } while (0); 1712 1713 s.local.family = s.remote.family = family; 1714 if (family == AF_INET) { 1715 sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport); 1716 sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport); 1717 s.local.bytelen = s.remote.bytelen = 4; 1718 } else { 1719 sscanf(loc, "%08x%08x%08x%08x:%x", 1720 s.local.data, 1721 s.local.data+1, 1722 s.local.data+2, 1723 s.local.data+3, 1724 &s.lport); 1725 sscanf(rem, "%08x%08x%08x%08x:%x", 1726 s.remote.data, 1727 s.remote.data+1, 1728 s.remote.data+2, 1729 s.remote.data+3, 1730 &s.rport); 1731 s.local.bytelen = s.remote.bytelen = 16; 1732 } 1733 1734 if (f->f && run_ssfilter(f->f, &s) == 0) 1735 return 0; 1736 1737 opt[0] = 0; 1738 n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n", 1739 &s.state, &s.wq, &s.rq, 1740 &s.uid, &s.ino, 1741 &s.refcnt, &s.sk, opt); 1742 1743 if (n < 9) 1744 opt[0] = 0; 1745 1746 if (netid_width) 1747 printf("%-*s ", netid_width, dg_proto); 1748 if (state_width) 1749 printf("%-*s ", state_width, sstate_name[s.state]); 1750 1751 printf("%-6d %-6d ", s.rq, s.wq); 1752 1753 formatted_print(&s.local, s.lport); 1754 formatted_print(&s.remote, s.rport); 1755 1756 if (show_users) { 1757 char ubuf[4096]; 1758 if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0) 1759 printf(" users:(%s)", ubuf); 1760 } 1761 1762 if (show_details) { 1763 if (s.uid) 1764 printf(" uid=%u", (unsigned)s.uid); 1765 printf(" ino=%u", s.ino); 1766 printf(" sk=%llx", s.sk); 1767 if (opt[0]) 1768 printf(" opt:\"%s\"", opt); 1769 } 1770 printf("\n"); 1771 1772 return 0; 1773 } 1774 1775 1776 int udp_show(struct filter *f) 1777 { 1778 FILE *fp = NULL; 1779 1780 dg_proto = UDP_PROTO; 1781 1782 if (f->families&(1<<AF_INET)) { 1783 if ((fp = net_udp_open()) == NULL) 1784 goto outerr; 1785 if (generic_record_read(fp, dgram_show_line, f, AF_INET)) 1786 goto outerr; 1787 fclose(fp); 1788 } 1789 1790 if ((f->families&(1<<AF_INET6)) && 1791 (fp = net_udp6_open()) != NULL) { 1792 if (generic_record_read(fp, dgram_show_line, f, AF_INET6)) 1793 goto outerr; 1794 fclose(fp); 1795 } 1796 return 0; 1797 1798 outerr: 1799 do { 1800 int saved_errno = errno; 1801 if (fp) 1802 fclose(fp); 1803 errno = saved_errno; 1804 return -1; 1805 } while (0); 1806 } 1807 1808 int raw_show(struct filter *f) 1809 { 1810 FILE *fp = NULL; 1811 1812 dg_proto = RAW_PROTO; 1813 1814 if (f->families&(1<<AF_INET)) { 1815 if ((fp = net_raw_open()) == NULL) 1816 goto outerr; 1817 if (generic_record_read(fp, dgram_show_line, f, AF_INET)) 1818 goto outerr; 1819 fclose(fp); 1820 } 1821 1822 if ((f->families&(1<<AF_INET6)) && 1823 (fp = net_raw6_open()) != NULL) { 1824 if (generic_record_read(fp, dgram_show_line, f, AF_INET6)) 1825 goto outerr; 1826 fclose(fp); 1827 } 1828 return 0; 1829 1830 outerr: 1831 do { 1832 int saved_errno = errno; 1833 if (fp) 1834 fclose(fp); 1835 errno = saved_errno; 1836 return -1; 1837 } while (0); 1838 } 1839 1840 1841 struct unixstat 1842 { 1843 struct unixstat *next; 1844 int ino; 1845 int peer; 1846 int rq; 1847 int wq; 1848 int state; 1849 int type; 1850 char *name; 1851 }; 1852 1853 1854 1855 int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT, 1856 SS_ESTABLISHED, SS_CLOSING }; 1857 1858 1859 #define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct unixstat)) 1860 1861 void unix_list_free(struct unixstat *list) 1862 { 1863 while (list) { 1864 struct unixstat *s = list; 1865 list = list->next; 1866 if (s->name) 1867 free(s->name); 1868 free(s); 1869 } 1870 } 1871 1872 void unix_list_print(struct unixstat *list, struct filter *f) 1873 { 1874 struct unixstat *s; 1875 char *peer; 1876 1877 for (s = list; s; s = s->next) { 1878 if (!(f->states & (1<<s->state))) 1879 continue; 1880 if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB))) 1881 continue; 1882 if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB))) 1883 continue; 1884 1885 peer = "*"; 1886 if (s->peer) { 1887 struct unixstat *p; 1888 for (p = list; p; p = p->next) { 1889 if (s->peer == p->ino) 1890 break; 1891 } 1892 if (!p) { 1893 peer = "?"; 1894 } else { 1895 peer = p->name ? : "*"; 1896 } 1897 } 1898 1899 if (f->f) { 1900 struct tcpstat tst; 1901 tst.local.family = AF_UNIX; 1902 tst.remote.family = AF_UNIX; 1903 memcpy(tst.local.data, &s->name, sizeof(s->name)); 1904 if (strcmp(peer, "*") == 0) 1905 memset(tst.remote.data, 0, sizeof(peer)); 1906 else 1907 memcpy(tst.remote.data, &peer, sizeof(peer)); 1908 if (run_ssfilter(f->f, &tst) == 0) 1909 continue; 1910 } 1911 1912 if (netid_width) 1913 printf("%-*s ", netid_width, 1914 s->type == SOCK_STREAM ? "u_str" : "u_dgr"); 1915 if (state_width) 1916 printf("%-*s ", state_width, sstate_name[s->state]); 1917 printf("%-6d %-6d ", s->rq, s->wq); 1918 printf("%*s %-*d %*s %-*d", 1919 addr_width, s->name ? : "*", serv_width, s->ino, 1920 addr_width, peer, serv_width, s->peer); 1921 if (show_users) { 1922 char ubuf[4096]; 1923 if (find_users(s->ino, ubuf, sizeof(ubuf)) > 0) 1924 printf(" users:(%s)", ubuf); 1925 } 1926 printf("\n"); 1927 } 1928 } 1929 1930 int unix_show(struct filter *f) 1931 { 1932 FILE *fp; 1933 char buf[256]; 1934 char name[128]; 1935 int newformat = 0; 1936 int cnt; 1937 struct unixstat *list = NULL; 1938 1939 if ((fp = net_unix_open()) == NULL) 1940 return -1; 1941 fgets(buf, sizeof(buf)-1, fp); 1942 1943 if (memcmp(buf, "Peer", 4) == 0) 1944 newformat = 1; 1945 cnt = 0; 1946 1947 while (fgets(buf, sizeof(buf)-1, fp)) { 1948 struct unixstat *u, **insp; 1949 int flags; 1950 1951 if (!(u = malloc(sizeof(*u)))) 1952 break; 1953 u->name = NULL; 1954 1955 if (sscanf(buf, "%x: %x %x %x %x %x %d %s", 1956 &u->peer, &u->rq, &u->wq, &flags, &u->type, 1957 &u->state, &u->ino, name) < 8) 1958 name[0] = 0; 1959 1960 if (flags&(1<<16)) { 1961 u->state = SS_LISTEN; 1962 } else { 1963 u->state = unix_state_map[u->state-1]; 1964 if (u->type == SOCK_DGRAM && 1965 u->state == SS_CLOSE && 1966 u->peer) 1967 u->state = SS_ESTABLISHED; 1968 } 1969 1970 if (!newformat) { 1971 u->peer = 0; 1972 u->rq = 0; 1973 u->wq = 0; 1974 } 1975 1976 insp = &list; 1977 while (*insp) { 1978 if (u->type < (*insp)->type || 1979 (u->type == (*insp)->type && 1980 u->ino < (*insp)->ino)) 1981 break; 1982 insp = &(*insp)->next; 1983 } 1984 u->next = *insp; 1985 *insp = u; 1986 1987 if (name[0]) { 1988 if ((u->name = malloc(strlen(name)+1)) == NULL) 1989 break; 1990 strcpy(u->name, name); 1991 } 1992 if (++cnt > MAX_UNIX_REMEMBER) { 1993 unix_list_print(list, f); 1994 unix_list_free(list); 1995 list = NULL; 1996 cnt = 0; 1997 } 1998 } 1999 2000 if (list) { 2001 unix_list_print(list, f); 2002 unix_list_free(list); 2003 list = NULL; 2004 cnt = 0; 2005 } 2006 2007 return 0; 2008 } 2009 2010 2011 int packet_show(struct filter *f) 2012 { 2013 FILE *fp; 2014 char buf[256]; 2015 int type; 2016 int prot; 2017 int iface; 2018 int state; 2019 int rq; 2020 int uid; 2021 int ino; 2022 unsigned long long sk; 2023 2024 if (!(f->states & (1<<SS_CLOSE))) 2025 return 0; 2026 2027 if ((fp = net_packet_open()) == NULL) 2028 return -1; 2029 fgets(buf, sizeof(buf)-1, fp); 2030 2031 while (fgets(buf, sizeof(buf)-1, fp)) { 2032 sscanf(buf, "%llx %*d %d %x %d %d %u %u %u", 2033 &sk, 2034 &type, &prot, &iface, &state, 2035 &rq, &uid, &ino); 2036 2037 if (type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB))) 2038 continue; 2039 if (type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB))) 2040 continue; 2041 if (f->f) { 2042 struct tcpstat tst; 2043 tst.local.family = AF_PACKET; 2044 tst.remote.family = AF_PACKET; 2045 tst.rport = 0; 2046 tst.lport = iface; 2047 tst.local.data[0] = prot; 2048 tst.remote.data[0] = 0; 2049 if (run_ssfilter(f->f, &tst) == 0) 2050 continue; 2051 } 2052 2053 if (netid_width) 2054 printf("%-*s ", netid_width, 2055 type == SOCK_RAW ? "p_raw" : "p_dgr"); 2056 if (state_width) 2057 printf("%-*s ", state_width, "UNCONN"); 2058 printf("%-6d %-6d ", rq, 0); 2059 if (prot == 3) { 2060 printf("%*s:", addr_width, "*"); 2061 } else { 2062 char tb[16]; 2063 printf("%*s:", addr_width, 2064 ll_proto_n2a(htons(prot), tb, sizeof(tb))); 2065 } 2066 if (iface == 0) { 2067 printf("%-*s ", serv_width, "*"); 2068 } else { 2069 printf("%-*s ", serv_width, xll_index_to_name(iface)); 2070 } 2071 printf("%*s*%-*s", 2072 addr_width, "", serv_width, ""); 2073 2074 if (show_users) { 2075 char ubuf[4096]; 2076 if (find_users(ino, ubuf, sizeof(ubuf)) > 0) 2077 printf(" users:(%s)", ubuf); 2078 } 2079 if (show_details) { 2080 printf(" ino=%u uid=%u sk=%llx", ino, uid, sk); 2081 } 2082 printf("\n"); 2083 } 2084 2085 return 0; 2086 } 2087 2088 int netlink_show(struct filter *f) 2089 { 2090 FILE *fp; 2091 char buf[256]; 2092 int prot, pid; 2093 unsigned groups; 2094 int rq, wq, rc; 2095 unsigned long long sk, cb; 2096 2097 if (!(f->states & (1<<SS_CLOSE))) 2098 return 0; 2099 2100 if ((fp = net_netlink_open()) == NULL) 2101 return -1; 2102 fgets(buf, sizeof(buf)-1, fp); 2103 2104 while (fgets(buf, sizeof(buf)-1, fp)) { 2105 sscanf(buf, "%llx %d %d %x %d %d %llx %d", 2106 &sk, 2107 &prot, &pid, &groups, &rq, &wq, &cb, &rc); 2108 2109 if (f->f) { 2110 struct tcpstat tst; 2111 tst.local.family = AF_NETLINK; 2112 tst.remote.family = AF_NETLINK; 2113 tst.rport = -1; 2114 tst.lport = pid; 2115 tst.local.data[0] = prot; 2116 tst.remote.data[0] = 0; 2117 if (run_ssfilter(f->f, &tst) == 0) 2118 continue; 2119 } 2120 2121 if (netid_width) 2122 printf("%-*s ", netid_width, "nl"); 2123 if (state_width) 2124 printf("%-*s ", state_width, "UNCONN"); 2125 printf("%-6d %-6d ", rq, wq); 2126 if (resolve_services && prot == 0) 2127 printf("%*s:", addr_width, "rtnl"); 2128 else if (resolve_services && prot == 3) 2129 printf("%*s:", addr_width, "fw"); 2130 else if (resolve_services && prot == 4) 2131 printf("%*s:", addr_width, "tcpdiag"); 2132 else 2133 printf("%*d:", addr_width, prot); 2134 if (pid == -1) { 2135 printf("%-*s ", serv_width, "*"); 2136 } else if (resolve_services) { 2137 int done = 0; 2138 if (!pid) { 2139 done = 1; 2140 printf("%-*s ", serv_width, "kernel"); 2141 } else if (pid > 0) { 2142 char procname[64]; 2143 FILE *fp; 2144 sprintf(procname, "%s/%d/stat", 2145 getenv("PROC_ROOT") ? : "/proc", pid); 2146 if ((fp = fopen(procname, "r")) != NULL) { 2147 if (fscanf(fp, "%*d (%[^)])", procname) == 1) { 2148 sprintf(procname+strlen(procname), "/%d", pid); 2149 printf("%-*s ", serv_width, procname); 2150 done = 1; 2151 } 2152 fclose(fp); 2153 } 2154 } 2155 if (!done) 2156 printf("%-*d ", serv_width, pid); 2157 } else { 2158 printf("%-*d ", serv_width, pid); 2159 } 2160 printf("%*s*%-*s", 2161 addr_width, "", serv_width, ""); 2162 2163 if (show_details) { 2164 printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups); 2165 } 2166 printf("\n"); 2167 } 2168 2169 return 0; 2170 } 2171 2172 struct snmpstat 2173 { 2174 int tcp_estab; 2175 }; 2176 2177 int get_snmp_int(char *proto, char *key, int *result) 2178 { 2179 char buf[1024]; 2180 FILE *fp; 2181 int protolen = strlen(proto); 2182 int keylen = strlen(key); 2183 2184 *result = 0; 2185 2186 if ((fp = net_snmp_open()) == NULL) 2187 return -1; 2188 2189 while (fgets(buf, sizeof(buf), fp) != NULL) { 2190 char *p = buf; 2191 int pos = 0; 2192 if (memcmp(buf, proto, protolen)) 2193 continue; 2194 while ((p = strchr(p, ' ')) != NULL) { 2195 pos++; 2196 p++; 2197 if (memcmp(p, key, keylen) == 0 && 2198 (p[keylen] == ' ' || p[keylen] == '\n')) 2199 break; 2200 } 2201 if (fgets(buf, sizeof(buf), fp) == NULL) 2202 break; 2203 if (memcmp(buf, proto, protolen)) 2204 break; 2205 p = buf; 2206 while ((p = strchr(p, ' ')) != NULL) { 2207 p++; 2208 if (--pos == 0) { 2209 sscanf(p, "%d", result); 2210 fclose(fp); 2211 return 0; 2212 } 2213 } 2214 } 2215 2216 fclose(fp); 2217 errno = ESRCH; 2218 return -1; 2219 } 2220 2221 2222 /* Get stats from sockstat */ 2223 2224 struct sockstat 2225 { 2226 int socks; 2227 int tcp_mem; 2228 int tcp_total; 2229 int tcp_orphans; 2230 int tcp_tws; 2231 int tcp4_hashed; 2232 int udp4; 2233 int raw4; 2234 int frag4; 2235 int frag4_mem; 2236 int tcp6_hashed; 2237 int udp6; 2238 int raw6; 2239 int frag6; 2240 int frag6_mem; 2241 }; 2242 2243 static void get_sockstat_line(char *line, struct sockstat *s) 2244 { 2245 char id[256], rem[256]; 2246 2247 if (sscanf(line, "%[^ ] %[^\n]\n", id, rem) != 2) 2248 return; 2249 2250 if (strcmp(id, "sockets:") == 0) 2251 sscanf(rem, "%*s%d", &s->socks); 2252 else if (strcmp(id, "UDP:") == 0) 2253 sscanf(rem, "%*s%d", &s->udp4); 2254 else if (strcmp(id, "UDP6:") == 0) 2255 sscanf(rem, "%*s%d", &s->udp6); 2256 else if (strcmp(id, "RAW:") == 0) 2257 sscanf(rem, "%*s%d", &s->raw4); 2258 else if (strcmp(id, "RAW6:") == 0) 2259 sscanf(rem, "%*s%d", &s->raw6); 2260 else if (strcmp(id, "TCP6:") == 0) 2261 sscanf(rem, "%*s%d", &s->tcp6_hashed); 2262 else if (strcmp(id, "FRAG:") == 0) 2263 sscanf(rem, "%*s%d%*s%d", &s->frag4, &s->frag4_mem); 2264 else if (strcmp(id, "FRAG6:") == 0) 2265 sscanf(rem, "%*s%d%*s%d", &s->frag6, &s->frag6_mem); 2266 else if (strcmp(id, "TCP:") == 0) 2267 sscanf(rem, "%*s%d%*s%d%*s%d%*s%d%*s%d", 2268 &s->tcp4_hashed, 2269 &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem); 2270 } 2271 2272 int get_sockstat(struct sockstat *s) 2273 { 2274 char buf[256]; 2275 FILE *fp; 2276 2277 memset(s, 0, sizeof(*s)); 2278 2279 if ((fp = net_sockstat_open()) == NULL) 2280 return -1; 2281 while(fgets(buf, sizeof(buf), fp) != NULL) 2282 get_sockstat_line(buf, s); 2283 fclose(fp); 2284 2285 if ((fp = net_sockstat6_open()) == NULL) 2286 return 0; 2287 while(fgets(buf, sizeof(buf), fp) != NULL) 2288 get_sockstat_line(buf, s); 2289 fclose(fp); 2290 2291 return 0; 2292 } 2293 2294 int print_summary(void) 2295 { 2296 struct sockstat s; 2297 struct snmpstat sn; 2298 2299 if (get_sockstat(&s) < 0) 2300 perror("ss: get_sockstat"); 2301 if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0) 2302 perror("ss: get_snmpstat"); 2303 2304 printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks); 2305 2306 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n", 2307 s.tcp_total + slabstat.tcp_syns + s.tcp_tws, 2308 sn.tcp_estab, 2309 s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws), 2310 s.tcp_orphans, 2311 slabstat.tcp_syns, 2312 s.tcp_tws, slabstat.tcp_tws, 2313 slabstat.tcp_ports 2314 ); 2315 2316 printf("\n"); 2317 printf("Transport Total IP IPv6\n"); 2318 printf("* %-9d %-9s %-9s\n", slabstat.socks, "-", "-"); 2319 printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6); 2320 printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6); 2321 printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed); 2322 printf("INET %-9d %-9d %-9d\n", 2323 s.raw4+s.udp4+s.tcp4_hashed+ 2324 s.raw6+s.udp6+s.tcp6_hashed, 2325 s.raw4+s.udp4+s.tcp4_hashed, 2326 s.raw6+s.udp6+s.tcp6_hashed); 2327 printf("FRAG %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6); 2328 2329 printf("\n"); 2330 2331 return 0; 2332 } 2333 2334 static void _usage(FILE *dest) 2335 { 2336 fprintf(dest, 2337 "Usage: ss [ OPTIONS ]\n" 2338 " ss [ OPTIONS ] [ FILTER ]\n" 2339 " -h, --help this message\n" 2340 " -V, --version output version information\n" 2341 " -n, --numeric don't resolve service names\n" 2342 " -r, --resolve resolve host names\n" 2343 " -a, --all display all sockets\n" 2344 " -l, --listening display listening sockets\n" 2345 " -o, --options show timer information\n" 2346 " -e, --extended show detailed socket information\n" 2347 " -m, --memory show socket memory usage\n" 2348 " -p, --processes show process using socket\n" 2349 " -i, --info show internal TCP information\n" 2350 " -s, --summary show socket usage summary\n" 2351 "\n" 2352 " -4, --ipv4 display only IP version 4 sockets\n" 2353 " -6, --ipv6 display only IP version 6 sockets\n" 2354 " -0, --packet display PACKET sockets\n" 2355 " -t, --tcp display only TCP sockets\n" 2356 " -u, --udp display only UDP sockets\n" 2357 " -d, --dccp display only DCCP sockets\n" 2358 " -w, --raw display only RAW sockets\n" 2359 " -x, --unix display only Unix domain sockets\n" 2360 " -f, --family=FAMILY display sockets of type FAMILY\n" 2361 "\n" 2362 " -A, --query=QUERY\n" 2363 " QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n" 2364 "\n" 2365 " -F, --filter=FILE read filter information from FILE\n" 2366 " FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n" 2367 ); 2368 } 2369 2370 static void help(void) __attribute__((noreturn)); 2371 static void help(void) 2372 { 2373 _usage(stdout); 2374 exit(0); 2375 } 2376 2377 static void usage(void) __attribute__((noreturn)); 2378 static void usage(void) 2379 { 2380 _usage(stderr); 2381 exit(-1); 2382 } 2383 2384 2385 int scan_state(const char *state) 2386 { 2387 int i; 2388 if (strcasecmp(state, "close") == 0 || 2389 strcasecmp(state, "closed") == 0) 2390 return (1<<SS_CLOSE); 2391 if (strcasecmp(state, "syn-rcv") == 0) 2392 return (1<<SS_SYN_RECV); 2393 if (strcasecmp(state, "established") == 0) 2394 return (1<<SS_ESTABLISHED); 2395 if (strcasecmp(state, "all") == 0) 2396 return SS_ALL; 2397 if (strcasecmp(state, "connected") == 0) 2398 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)); 2399 if (strcasecmp(state, "synchronized") == 0) 2400 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)|(1<<SS_SYN_SENT)); 2401 if (strcasecmp(state, "bucket") == 0) 2402 return (1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT); 2403 if (strcasecmp(state, "big") == 0) 2404 return SS_ALL & ~((1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT)); 2405 for (i=0; i<SS_MAX; i++) { 2406 if (strcasecmp(state, sstate_namel[i]) == 0) 2407 return (1<<i); 2408 } 2409 return 0; 2410 } 2411 2412 static const struct option long_opts[] = { 2413 { "numeric", 0, 0, 'n' }, 2414 { "resolve", 0, 0, 'r' }, 2415 { "options", 0, 0, 'o' }, 2416 { "extended", 0, 0, 'e' }, 2417 { "memory", 0, 0, 'm' }, 2418 { "info", 0, 0, 'i' }, 2419 { "processes", 0, 0, 'p' }, 2420 { "dccp", 0, 0, 'd' }, 2421 { "tcp", 0, 0, 't' }, 2422 { "udp", 0, 0, 'u' }, 2423 { "raw", 0, 0, 'w' }, 2424 { "unix", 0, 0, 'x' }, 2425 { "all", 0, 0, 'a' }, 2426 { "listening", 0, 0, 'l' }, 2427 { "ipv4", 0, 0, '4' }, 2428 { "ipv6", 0, 0, '6' }, 2429 { "packet", 0, 0, '0' }, 2430 { "family", 1, 0, 'f' }, 2431 { "socket", 1, 0, 'A' }, 2432 { "summary", 0, 0, 's' }, 2433 { "diag", 0, 0, 'D' }, 2434 { "filter", 1, 0, 'F' }, 2435 { "version", 0, 0, 'V' }, 2436 { "help", 0, 0, 'h' }, 2437 { 0 } 2438 2439 }; 2440 2441 int main(int argc, char *argv[]) 2442 { 2443 int do_default = 1; 2444 int saw_states = 0; 2445 int saw_query = 0; 2446 int do_summary = 0; 2447 const char *dump_tcpdiag = NULL; 2448 FILE *filter_fp = NULL; 2449 int ch; 2450 2451 memset(¤t_filter, 0, sizeof(current_filter)); 2452 2453 current_filter.states = default_filter.states; 2454 2455 while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spf:miA:D:F:vV", 2456 long_opts, NULL)) != EOF) { 2457 switch(ch) { 2458 case 'n': 2459 resolve_services = 0; 2460 break; 2461 case 'r': 2462 resolve_hosts = 1; 2463 break; 2464 case 'o': 2465 show_options = 1; 2466 break; 2467 case 'e': 2468 show_options = 1; 2469 show_details++; 2470 break; 2471 case 'm': 2472 show_mem = 1; 2473 break; 2474 case 'i': 2475 show_tcpinfo = 1; 2476 break; 2477 case 'p': 2478 show_users++; 2479 break; 2480 case 'd': 2481 current_filter.dbs |= (1<<DCCP_DB); 2482 do_default = 0; 2483 break; 2484 case 't': 2485 current_filter.dbs |= (1<<TCP_DB); 2486 do_default = 0; 2487 break; 2488 case 'u': 2489 current_filter.dbs |= (1<<UDP_DB); 2490 do_default = 0; 2491 break; 2492 case 'w': 2493 current_filter.dbs |= (1<<RAW_DB); 2494 do_default = 0; 2495 break; 2496 case 'x': 2497 current_filter.dbs |= UNIX_DBM; 2498 do_default = 0; 2499 break; 2500 case 'a': 2501 current_filter.states = SS_ALL; 2502 break; 2503 case 'l': 2504 current_filter.states = (1<<SS_LISTEN); 2505 break; 2506 case '4': 2507 preferred_family = AF_INET; 2508 break; 2509 case '6': 2510 preferred_family = AF_INET6; 2511 break; 2512 case '0': 2513 preferred_family = AF_PACKET; 2514 break; 2515 case 'f': 2516 if (strcmp(optarg, "inet") == 0) 2517 preferred_family = AF_INET; 2518 else if (strcmp(optarg, "inet6") == 0) 2519 preferred_family = AF_INET6; 2520 else if (strcmp(optarg, "link") == 0) 2521 preferred_family = AF_PACKET; 2522 else if (strcmp(optarg, "unix") == 0) 2523 preferred_family = AF_UNIX; 2524 else if (strcmp(optarg, "netlink") == 0) 2525 preferred_family = AF_NETLINK; 2526 else if (strcmp(optarg, "help") == 0) 2527 help(); 2528 else { 2529 fprintf(stderr, "ss: \"%s\" is invalid family\n", optarg); 2530 usage(); 2531 } 2532 break; 2533 case 'A': 2534 { 2535 char *p, *p1; 2536 if (!saw_query) { 2537 current_filter.dbs = 0; 2538 saw_query = 1; 2539 do_default = 0; 2540 } 2541 p = p1 = optarg; 2542 do { 2543 if ((p1 = strchr(p, ',')) != NULL) 2544 *p1 = 0; 2545 if (strcmp(p, "all") == 0) { 2546 current_filter.dbs = ALL_DB; 2547 } else if (strcmp(p, "inet") == 0) { 2548 current_filter.dbs |= (1<<TCP_DB)|(1<<DCCP_DB)|(1<<UDP_DB)|(1<<RAW_DB); 2549 } else if (strcmp(p, "udp") == 0) { 2550 current_filter.dbs |= (1<<UDP_DB); 2551 } else if (strcmp(p, "dccp") == 0) { 2552 current_filter.dbs |= (1<<DCCP_DB); 2553 } else if (strcmp(p, "tcp") == 0) { 2554 current_filter.dbs |= (1<<TCP_DB); 2555 } else if (strcmp(p, "raw") == 0) { 2556 current_filter.dbs |= (1<<RAW_DB); 2557 } else if (strcmp(p, "unix") == 0) { 2558 current_filter.dbs |= UNIX_DBM; 2559 } else if (strcasecmp(p, "unix_stream") == 0 || 2560 strcmp(p, "u_str") == 0) { 2561 current_filter.dbs |= (1<<UNIX_ST_DB); 2562 } else if (strcasecmp(p, "unix_dgram") == 0 || 2563 strcmp(p, "u_dgr") == 0) { 2564 current_filter.dbs |= (1<<UNIX_DG_DB); 2565 } else if (strcmp(p, "packet") == 0) { 2566 current_filter.dbs |= PACKET_DBM; 2567 } else if (strcmp(p, "packet_raw") == 0 || 2568 strcmp(p, "p_raw") == 0) { 2569 current_filter.dbs |= (1<<PACKET_R_DB); 2570 } else if (strcmp(p, "packet_dgram") == 0 || 2571 strcmp(p, "p_dgr") == 0) { 2572 current_filter.dbs |= (1<<PACKET_DG_DB); 2573 } else if (strcmp(p, "netlink") == 0) { 2574 current_filter.dbs |= (1<<NETLINK_DB); 2575 } else { 2576 fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p); 2577 usage(); 2578 } 2579 p = p1 + 1; 2580 } while (p1); 2581 break; 2582 } 2583 case 's': 2584 do_summary = 1; 2585 break; 2586 case 'D': 2587 dump_tcpdiag = optarg; 2588 break; 2589 case 'F': 2590 if (filter_fp) { 2591 fprintf(stderr, "More than one filter file\n"); 2592 exit(-1); 2593 } 2594 if (optarg[0] == '-') 2595 filter_fp = stdin; 2596 else 2597 filter_fp = fopen(optarg, "r"); 2598 if (!filter_fp) { 2599 perror("fopen filter file"); 2600 exit(-1); 2601 } 2602 break; 2603 case 'v': 2604 case 'V': 2605 printf("ss utility, iproute2-ss%s\n", SNAPSHOT); 2606 exit(0); 2607 case 'h': 2608 case '?': 2609 help(); 2610 default: 2611 usage(); 2612 } 2613 } 2614 2615 argc -= optind; 2616 argv += optind; 2617 2618 get_slabstat(&slabstat); 2619 2620 if (do_summary) { 2621 print_summary(); 2622 if (do_default && argc == 0) 2623 exit(0); 2624 } 2625 2626 if (do_default) 2627 current_filter.dbs = default_filter.dbs; 2628 2629 if (preferred_family == AF_UNSPEC) { 2630 if (!(current_filter.dbs&~UNIX_DBM)) 2631 preferred_family = AF_UNIX; 2632 else if (!(current_filter.dbs&~PACKET_DBM)) 2633 preferred_family = AF_PACKET; 2634 else if (!(current_filter.dbs&~(1<<NETLINK_DB))) 2635 preferred_family = AF_NETLINK; 2636 } 2637 2638 if (preferred_family != AF_UNSPEC) { 2639 int mask2; 2640 if (preferred_family == AF_INET || 2641 preferred_family == AF_INET6) { 2642 mask2= current_filter.dbs; 2643 } else if (preferred_family == AF_PACKET) { 2644 mask2 = PACKET_DBM; 2645 } else if (preferred_family == AF_UNIX) { 2646 mask2 = UNIX_DBM; 2647 } else if (preferred_family == AF_NETLINK) { 2648 mask2 = (1<<NETLINK_DB); 2649 } else { 2650 mask2 = 0; 2651 } 2652 2653 if (do_default) 2654 current_filter.dbs = mask2; 2655 else 2656 current_filter.dbs &= mask2; 2657 current_filter.families = (1<<preferred_family); 2658 } else { 2659 if (!do_default) 2660 current_filter.families = ~0; 2661 else 2662 current_filter.families = default_filter.families; 2663 } 2664 if (current_filter.dbs == 0) { 2665 fprintf(stderr, "ss: no socket tables to show with such filter.\n"); 2666 exit(0); 2667 } 2668 if (current_filter.families == 0) { 2669 fprintf(stderr, "ss: no families to show with such filter.\n"); 2670 exit(0); 2671 } 2672 2673 if (resolve_services && resolve_hosts && 2674 (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)))) 2675 init_service_resolver(); 2676 2677 /* Now parse filter... */ 2678 if (argc == 0 && filter_fp) { 2679 if (ssfilter_parse(¤t_filter.f, 0, NULL, filter_fp)) 2680 usage(); 2681 } 2682 2683 while (argc > 0) { 2684 if (strcmp(*argv, "state") == 0) { 2685 NEXT_ARG(); 2686 if (!saw_states) 2687 current_filter.states = 0; 2688 current_filter.states |= scan_state(*argv); 2689 saw_states = 1; 2690 } else if (strcmp(*argv, "exclude") == 0 || 2691 strcmp(*argv, "excl") == 0) { 2692 NEXT_ARG(); 2693 if (!saw_states) 2694 current_filter.states = SS_ALL; 2695 current_filter.states &= ~scan_state(*argv); 2696 saw_states = 1; 2697 } else { 2698 if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp)) 2699 usage(); 2700 break; 2701 } 2702 argc--; argv++; 2703 } 2704 2705 if (current_filter.states == 0) { 2706 fprintf(stderr, "ss: no socket states to show with such filter.\n"); 2707 exit(0); 2708 } 2709 2710 if (dump_tcpdiag) { 2711 FILE *dump_fp = stdout; 2712 if (!(current_filter.dbs & (1<<TCP_DB))) { 2713 fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n"); 2714 exit(0); 2715 } 2716 if (dump_tcpdiag[0] != '-') { 2717 dump_fp = fopen(dump_tcpdiag, "w"); 2718 if (!dump_tcpdiag) { 2719 perror("fopen dump file"); 2720 exit(-1); 2721 } 2722 } 2723 tcp_show_netlink(¤t_filter, dump_fp, TCPDIAG_GETSOCK); 2724 fflush(dump_fp); 2725 exit(0); 2726 } 2727 2728 netid_width = 0; 2729 if (current_filter.dbs&(current_filter.dbs-1)) 2730 netid_width = 5; 2731 2732 state_width = 0; 2733 if (current_filter.states&(current_filter.states-1)) 2734 state_width = 10; 2735 2736 screen_width = 80; 2737 if (isatty(STDOUT_FILENO)) { 2738 struct winsize w; 2739 2740 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) { 2741 if (w.ws_col > 0) 2742 screen_width = w.ws_col; 2743 } 2744 } 2745 2746 addrp_width = screen_width; 2747 addrp_width -= netid_width+1; 2748 addrp_width -= state_width+1; 2749 addrp_width -= 14; 2750 2751 if (addrp_width&1) { 2752 if (netid_width) 2753 netid_width++; 2754 else if (state_width) 2755 state_width++; 2756 } 2757 2758 addrp_width /= 2; 2759 addrp_width--; 2760 2761 serv_width = resolve_services ? 7 : 5; 2762 2763 if (addrp_width < 15+serv_width+1) 2764 addrp_width = 15+serv_width+1; 2765 2766 addr_width = addrp_width - serv_width - 1; 2767 2768 if (netid_width) 2769 printf("%-*s ", netid_width, "Netid"); 2770 if (state_width) 2771 printf("%-*s ", state_width, "State"); 2772 printf("%-6s %-6s ", "Recv-Q", "Send-Q"); 2773 2774 printf("%*s:%-*s %*s:%-*s\n", 2775 addr_width, "Local Address", serv_width, "Port", 2776 addr_width, "Peer Address", serv_width, "Port"); 2777 2778 fflush(stdout); 2779 2780 if (current_filter.dbs & (1<<NETLINK_DB)) 2781 netlink_show(¤t_filter); 2782 if (current_filter.dbs & PACKET_DBM) 2783 packet_show(¤t_filter); 2784 if (current_filter.dbs & UNIX_DBM) 2785 unix_show(¤t_filter); 2786 if (current_filter.dbs & (1<<RAW_DB)) 2787 raw_show(¤t_filter); 2788 if (current_filter.dbs & (1<<UDP_DB)) 2789 udp_show(¤t_filter); 2790 if (current_filter.dbs & (1<<TCP_DB)) 2791 tcp_show(¤t_filter, TCPDIAG_GETSOCK); 2792 if (current_filter.dbs & (1<<DCCP_DB)) 2793 tcp_show(¤t_filter, DCCPDIAG_GETSOCK); 2794 return 0; 2795 } 2796