• ss.c


    linux下 ss -i 可显示rto.

    how to display tcp rto

    http://linuxaleph.blogspot.com/2013/07/how-to-display-tcp-rto.html

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