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