[Toybox] [PATCH] Decode netlink sockets in lsof.

enh enh at google.com
Wed Sep 16 22:42:15 PDT 2015


this time with patch!

On Wed, Sep 16, 2015 at 9:45 PM, enh <enh at google.com> wrote:
> Decode netlink sockets in lsof.
>
> Refactor the /proc/net parsing so this only adds 7 lines overall.
>
> Also clear the DEVICE field for sockets and fix alignment for long
> usernames (until someone implements the two-pass output that measures
> columns).
>
> --
> Elliott Hughes - http://who/enh - http://jessies.org/~enh/
> Android native code/tools questions? Mail me/drop by/add me as a reviewer.



-- 
Elliott Hughes - http://who/enh - http://jessies.org/~enh/
Android native code/tools questions? Mail me/drop by/add me as a reviewer.
-------------- next part --------------
diff --git a/toys/pending/lsof.c b/toys/pending/lsof.c
index ac38fdd..18013f7 100644
--- a/toys/pending/lsof.c
+++ b/toys/pending/lsof.c
@@ -72,7 +72,7 @@ static void print_header()
   char* names[] = {
     "COMMAND", "PID", "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME"
   };
-  printf("%-9s %5s %10s %4s   %7s %18s %9s %10s %s\n", names[0], names[1],
+  printf("%-9s %5s %10.10s %4s   %7s %18s %9s %10s %s\n", names[0], names[1],
          names[2], names[3], names[4], names[5], names[6], names[7], names[8]);
   TT.shown_header = 1;
 }
@@ -88,7 +88,7 @@ static void print_info(void *data)
       printf("%d\n", (TT.last_shown_pid = fi->pi.pid));
   } else {
     if (!TT.shown_header) print_header();
-    printf("%-9s %5d %10s %4s%c%c %7s %18s %9s %10s %s\n",
+    printf("%-9s %5d %10.10s %4s%c%c %7s %18s %9s %10s %s\n",
            fi->pi.cmd, fi->pi.pid, fi->pi.user,
            fi->fd, fi->rw, fi->locks, fi->type, fi->device, fi->size_off,
            fi->node, fi->name);
@@ -129,9 +129,11 @@ static char *chomp(char *s)
   return s;
 }
 
-static int find_unix_socket(struct file_info *fi, long sought_inode)
+static int scan_proc_net_file(char *path, int family, char type,
+    void (*fn)(char *, int, char, struct file_info *, long),
+    struct file_info *fi, long sought_inode)
 {
-  FILE *fp = fopen("/proc/net/unix", "r");
+  FILE *fp = fopen(path, "r");
   char *line = NULL;
   size_t line_length = 0;
 
@@ -140,19 +142,8 @@ static int find_unix_socket(struct file_info *fi, long sought_inode)
   if (!getline(&line, &line_length, fp)) return 0; // Skip header.
 
   while (getline(&line, &line_length, fp) > 0) {
-    long inode;
-    int path_pos;
-
-    if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n",
-               &inode, &path_pos) >= 1) {
-      if (inode == sought_inode) {
-        char *name = chomp(line + path_pos);
-
-        strcpy(fi->type, "unix");
-        fi->name = strdup(*name ? name : "socket");
-        break;
-      }
-    }
+    fn(line, family, type, fi, sought_inode);
+    if (fi->name != 0) break;
   }
 
   free(line);
@@ -161,87 +152,102 @@ static int find_unix_socket(struct file_info *fi, long sought_inode)
   return fi->name != 0;
 }
 
-// Matches lines in either /proc/net/tcp or /proc/net/tcp6, depending on 'af'.
-static int ip_match(int af, char* line, struct in6_addr* l, int* l_port,
-                    struct in6_addr* r, int* r_port, int* state, long* inode)
+static void match_unix(char *line, int af, char type, struct file_info *fi,
+                       long sought_inode)
 {
-  if (af == AF_INET) {
-    return sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
-                  &(l->s6_addr32[0]), l_port, &(r->s6_addr32[0]), r_port,
-                  state, inode) == 6;
-  } else {
-    return sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
-                  "%*x:%*x %*X:%*X %*X %*d %*d %ld",
-                  &(l->s6_addr32[0]), &(l->s6_addr32[1]), &(l->s6_addr32[2]),
-                  &(l->s6_addr32[3]), l_port, &(r->s6_addr32[0]),
-                  &(r->s6_addr32[1]), &(r->s6_addr32[2]), &(r->s6_addr32[3]),
-                  r_port, state, inode) == 12;
+  long inode;
+  int path_pos;
+
+  if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1 &&
+        inode == sought_inode) {
+    char *name = chomp(line + path_pos);
+
+    strcpy(fi->type, "unix");
+    fi->name = strdup(*name ? name : "socket");
   }
 }
 
-static int find_ip_socket(struct file_info *fi, const char *path,
-                          int af, int type, long sought_inode)
+static void match_netlink(char *line, int af, char type, struct file_info *fi,
+                          long sought_inode)
+{
+  unsigned state;
+  long inode;
+  char *netlink_states[] = {
+    "ROUTE", "UNUSED", "USERSOCK", "FIREWALL", "SOCK_DIAG", "NFLOG", "XFRM",
+    "SELINUX", "ISCSI", "AUDIT", "FIB_LOOKUP", "CONNECTOR", "NETFILTER",
+    "IP6_FW", "DNRTMSG", "KOBJECT_UEVENT", "GENERIC", "DM", "SCSITRANSPORT",
+    "ENCRYPTFS", "RDMA", "CRYPTO"
+  };
+
+  if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu",
+             &state, &inode) < 2 || inode != sought_inode) {
+    return;
+  }
+
+  strcpy(fi->type, "netlink");
+  fi->name =
+      strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?");
+}
+
+static void match_ip(char *line, int af, char type, struct file_info *fi,
+                     long sought_inode)
 {
-  FILE *fp = fopen(path, "r");
-  char *line = NULL;
-  size_t line_length = 0;
   char *tcp_states[] = {
     "UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2",
     "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING"
   };
+  char local_ip[INET6_ADDRSTRLEN] = {0};
+  char remote_ip[INET6_ADDRSTRLEN] = {0};
+  struct in6_addr local, remote;
+  int local_port, remote_port, state;
+  long inode;
+  int ok;
 
-  if (!fp) return 0;
-
-  if (!getline(&line, &line_length, fp)) return 0; // Skip header.
-
-  while (getline(&line, &line_length, fp) > 0) {
-    struct in6_addr local, remote;
-    int local_port, remote_port, state;
-    long inode;
-
-    if (ip_match(af, line, &local, &local_port, &remote, &remote_port,
-                  &state, &inode)) {
-      if (inode == sought_inode) {
-        char local_ip[INET6_ADDRSTRLEN] = {0};
-        char remote_ip[INET6_ADDRSTRLEN] = {0};
-
-        strcpy(fi->type, af == AF_INET ? "IPv4" : "IPv6");
-        inet_ntop(af, &local, local_ip, sizeof(local_ip));
-        inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
-        if (type == SOCK_STREAM) {
-          if (state < 0 || state > TCP_CLOSING) state = 0;
-          fi->name = xmprintf(af == AF_INET ?
-                              "TCP %s:%d->%s:%d (%s)" :
-                              "TCP [%s]:%d->[%s]:%d (%s)",
-                              local_ip, local_port, remote_ip, remote_port,
-                              tcp_states[state]);
-        } else {
-          fi->name = xmprintf(af == AF_INET ?
-                              "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
-                              type == SOCK_DGRAM ? "UDP" : "RAW",
-                              local_ip, local_port, remote_ip, remote_port);
-        }
-        break;
-      }
-    }
+  if (af == 4) {
+    ok = sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
+                &(local.s6_addr32[0]), &local_port,
+                &(remote.s6_addr32[0]), &remote_port,
+                &state, &inode) == 6;
+  } else {
+    ok = sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
+                "%*x:%*x %*X:%*X %*X %*d %*d %ld",
+                &(local.s6_addr32[0]), &(local.s6_addr32[1]),
+                &(local.s6_addr32[2]), &(local.s6_addr32[3]),
+                &local_port,
+                &(remote.s6_addr32[0]), &(remote.s6_addr32[1]),
+                &(remote.s6_addr32[2]), &(remote.s6_addr32[3]),
+                &remote_port, &state, &inode) == 12;
+  }
+  if (!ok || inode != sought_inode) return;
+
+  strcpy(fi->type, af == 4 ? "IPv4" : "IPv6");
+  inet_ntop(af, &local, local_ip, sizeof(local_ip));
+  inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
+  if (type == 't') {
+    if (state < 0 || state > TCP_CLOSING) state = 0;
+    fi->name = xmprintf(af == 4 ?
+                        "TCP %s:%d->%s:%d (%s)" :
+                        "TCP [%s]:%d->[%s]:%d (%s)",
+                        local_ip, local_port, remote_ip, remote_port,
+                        tcp_states[state]);
+  } else {
+    fi->name = xmprintf(af == 4 ? "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
+                        type == 'u' ? "UDP" : "RAW",
+                        local_ip, local_port, remote_ip, remote_port);
   }
-
-  free(line);
-  fclose(fp);
-
-  return fi->name != 0;
 }
 
 static int find_socket(struct file_info *fi, long inode)
 {
-  // TODO: other protocols (netlink).
-  return find_unix_socket(fi, inode) ||
-         find_ip_socket(fi, "/proc/net/tcp", AF_INET, SOCK_STREAM, inode) ||
-         find_ip_socket(fi, "/proc/net/tcp6", AF_INET6, SOCK_STREAM, inode) ||
-         find_ip_socket(fi, "/proc/net/udp", AF_INET, SOCK_DGRAM, inode) ||
-         find_ip_socket(fi, "/proc/net/udp6", AF_INET6, SOCK_DGRAM, inode) ||
-         find_ip_socket(fi, "/proc/net/raw", AF_INET, SOCK_RAW, inode) ||
-         find_ip_socket(fi, "/proc/net/raw6", AF_INET6, SOCK_RAW, inode);
+  // TODO: other protocols (packet).
+  return scan_proc_net_file("/proc/net/tcp", 4, 't', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/tcp6", 6, 't', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/udp", 4, 'u', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/udp6", 6, 'u', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/raw", 4, 'r', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/raw6", 6, 'r', match_ip, fi, inode) ||
+    scan_proc_net_file("/proc/net/unix", 0, 0, match_unix, fi, inode) ||
+    scan_proc_net_file("/proc/net/netlink", 0, 0, match_netlink, fi, inode);
 }
 
 static void fill_stat(struct file_info *fi, const char* path)
@@ -269,8 +275,9 @@ static void fill_stat(struct file_info *fi, const char* path)
 
   // Fill DEVICE.
   dev = (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) ? sb.st_rdev : sb.st_dev;
-  snprintf(fi->device, sizeof(fi->device), "%ld,%ld",
-           (long)major(dev), (long)minor(dev));
+  if (!S_ISSOCK(sb.st_mode))
+    snprintf(fi->device, sizeof(fi->device), "%ld,%ld",
+             (long)major(dev), (long)minor(dev));
 
   // Fill SIZE/OFF.
   if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))


More information about the Toybox mailing list