Class NetStat

java.lang.Object
org.terracotta.utilities.test.net.NetStat

public class NetStat extends Object
Produces a network status collection similar to that obtained using netstat. This class is intended for diagnostic purposes; elevated privileges may be required for full status collection.

Implementation Notes

  • For a Windows platform, powershell must be available via PATH.
  • For a Mac OS X platform, nettop and ps must be available via PATH.
  • For a Linux platform, lsof and ps must be available via PATH. For a complete port list, the effective user must be permitted to use sudo to execute the lsof command without a password.
  • Not all connections observed using netstat are shown by lsof -- see lsof FAQ item 3.29.
  • Field Details

    • LOGGER

      private static final org.slf4j.Logger LOGGER
    • LSOF_WARNING_EMITTED

      private static final AtomicBoolean LSOF_WARNING_EMITTED
    • POWERSHELL_NETSTAT_COMMAND

      private static final String[] POWERSHELL_NETSTAT_COMMAND
    • SUDO_PREFIX

      private static final String[] SUDO_PREFIX
    • LSOF_COMMAND

      private static final String[] LSOF_COMMAND
    • NETTOP_COMMAND

      private static final String[] NETTOP_COMMAND
    • TCP4_ENDPOINT_PATTERN

      private static final Pattern TCP4_ENDPOINT_PATTERN
      Pattern for parsing IPv4 endpoints expressed by nettop.
      Group 1
      IP Address
      Group 2
      Port
    • TCP6_ENDPOINT_PATTERN

      private static final Pattern TCP6_ENDPOINT_PATTERN
      Pattern for parsing IPv6 endpoints expressed by nettop.
      Group 1
      IP Address
      Group 2
      Port
      nettop separates the IP address and port with a period ('.'). The port can be a number or an asterisk ('*') when used as the undesignated target for a listening port.
  • Constructor Details

    • NetStat

      private NetStat()
      Private niladic constructor to prevent instantiation.
  • Method Details

    • info

      public static List<NetStat.BusyPort> info()
      Gets the list of busy ports on the current host.

      Note that individual ports may appear more than once in the returned list. Depending on the source, a port may be listed for both IPv4 and IPv6 uses; for some applications (e.g. sshd), a port may be shared among multiple processes.

      Returns:
      the list of NetStat.BusyPort instances representing the busy TCP ports
      Throws:
      RuntimeException - if the busy port information cannot be obtained
    • info

      public static List<NetStat.BusyPort> info(int port)
      Gets the list of busy ports associated with a single local port.

      Note that individual ports may appear more than once in the returned list. Depending on the source, a port may be listed for both IPv4 and IPv6 uses; for some applications (e.g. sshd), a port may be shared among multiple processes.

      Parameters:
      port - the target port
      Returns:
      the list of NetStat.BusyPort instances representing the busy TCP ports
      Throws:
      IllegalArgumentException - if port is not a valid port number
      RuntimeException - if the busy port information cannot be obtained
    • main

      public static void main(String[] args)
      Writes the list returned by info() to System.out.
      Parameters:
      args - zero or more port numbers to check
    • parseWindowsCsv

      private static NetStat.BusyPort parseWindowsCsv(String line)
      Parses a response line from POWERSHELL_NETSTAT_COMMAND.
      Parameters:
      line - a comma-separated-value line containing:
      Returns:
      a BusyPort instance formed from line
    • parseLsof

      private static List<NetStat.BusyPort> parseLsof(Stream<String> lines)
      Parses the output of LSOF_COMMAND.

      The F options are:

      p
      process id
      g
      process group id
      R
      parent process id
      c
      command
      L
      process login name
      f
      file descriptor (fd)
      t
      file's type (IPv6 | IPv4)
      P
      protocol name (TCP)
      n
      internet address pair
      T
      TCP information
      ST
      connection state
      QR
      receive queue size
      QS
      send queue size
      Input lines from the lsof command are structured for program consumption:
      • Fields within each line are separated by a NUL (\0)
      • Lines are grouped by process
        1. a line beginning with a p begins each process group
        2. each TCP ports used by the process is represented by a line beginning with an f
      • The value of the c (command) field is not the full command line; this value is applied as the BusyPort.shortCommand. This value is generally not sufficient to establish, diagnostically, what application is actually using a port -- all Java processes are listed simply as java.
      The following is a sample of the expected input from lsof:
      
          p1\0g1\0R0\0claunchd\0Lroot
          f21\0tIPv6\0PTCP\0n*:445\0TST=LISTEN\0TQR=0\0TQS=0
          f22\0tIPv4\0PTCP\0n*:445\0TST=LISTEN\0TQR=0\0TQS=0
          f24\0tIPv6\0PTCP\0n*:445\0TST=LISTEN\0TQR=0\0TQS=0
          f25\0tIPv4\0PTCP\0n*:445\0TST=LISTEN\0TQR=0\0TQS=0
          f35\0tIPv6\0PTCP\0n*:548\0TST=LISTEN\0TQR=0\0TQS=0
          f36\0tIPv4\0PTCP\0n*:548\0TST=LISTEN\0TQR=0\0TQS=0
          f37\0tIPv6\0PTCP\0n*:548\0TST=LISTEN\0TQR=0\0TQS=0
          f38\0tIPv4\0PTCP\0n*:548\0TST=LISTEN\0TQR=0\0TQS=0
          p121\0g121\0R1\0cUserEventAgent\0Lroot
          f71\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49177->[fe80:5::aede:48ff:fe33:4455]:59602\0TST=ESTABLISHED\0TQR=0\0TQS=0
          f91\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49178\0TST=LISTEN\0TQR=0\0TQS=0
          f94\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49179\0TST=LISTEN\0TQR=0\0TQS=0
          f102\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49180\0TST=LISTEN\0TQR=0\0TQS=0
          f103\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49181\0TST=LISTEN\0TQR=0\0TQS=0
          f104\0tIPv6\0PTCP\0n[fe80:5::aede:48ff:fe00:1122]:49182\0TST=LISTEN\0TQR=0\0TQS=0
          p22899\0g22706\0R22706\0cjava\0Lclifford
          f66\0tIPv6\0PTCP\0n127.0.0.1:14542\0TST=LISTENT\0QR=0T\0QS=0
          f67\0tIPv6\0PTCP\0n127.0.0.1:51880\0TST=LISTENT\0QR=0T\0QS=0
          f68\0tIPv6\0PTCP\0n127.0.0.1:54696->127.0.0.1:51828\0TST=ESTABLISHED\0TQR=0\0TQS=0
       
      Parameters:
      lines - a Stream delivering lines from the lsof command
      Returns:
      the list of busy ports
    • parseLsofEndpointPair

      private static NetStat.InetEndpointPair parseLsofEndpointPair(NetStat.BusyPort.IPVersion ipVersion, String endpointPair)
      Converts the TCP endpoint address pair obtained from the "name" field output from lsof into an InetSocketAddress. The endpoint pair is of the following form:
      <localHost>':'<localPort>['->'<remoteHost>':'<remotePort>]
      If the port is a listener port, the remote endpoint portion is omitted.

      From the man page for lsof:

      ...
      the local host name or IP number is followed by a colon (':'), the port, ``->'', and the two-part remote address; IP addresses may be reported as numbers or names, depending on the +|-M, -n, and -P options; colon-separated IPv6 numbers are enclosed in square brackets; IPv4 INADDR_ANY and IPv6 IN6_IS_ADDR_UNSPECIFIED addresses, and zero port numbers are represented by an asterisk ('*'); a UDP destination address may be followed by the amount of time elapsed since the last packet was sent to the destination; TCP, UDP and UDPLITE remote addresses may be followed by TCP/TPI information in parentheses - state (e.g., ``(ESTABLISHED)'', ``(Unbound)''), queue sizes, and window sizes (not all dialects) - in a fashion similar to what netstat(1) reports; see the -T option description or the description of the TCP/TPI field in OUTPUT FOR OTHER PROGRAMS for more information on state, queue size, and window size;
      Parameters:
      ipVersion - the IPVersion constant identifying the IP address type
      endpointPair - tbe value of the "name" field from a file descriptor describing a TCP port/connection
      Returns:
      an InetEndpointPair describing the connection/port
    • parseLsofEndpoint

      private static InetSocketAddress parseLsofEndpoint(NetStat.BusyPort.IPVersion ipVersion, String endpoint)
    • parseNetTop

      private static List<NetStat.BusyPort> parseNetTop(Stream<String> lines)
      Parses the output of NETTOP_COMMAND.

      The output begins with a header line which is dropped by this method. The remaining output is grouped:

      • each group begins with process line <processName>'.'<processId>',,'
      • following the process line, are one or more lines each of which describes a port used by that process; each of these lines is of the form: ['tcp6'|'tcp4'] <localEndpoint>'<->'<remoteEndpoint>','<tcpState>','
      • 'tcp4' endpoints are in the form [<ipAddress>|'*']':'[<port>|'*']
      • 'tcp6' endpoints are in the form [<ipv6Address>'%'<interface>'.'<port>|'*'.[<port>|'*']] note that the <ipv6Address> is not wrapped in square brackets
      The following is a sample of the expected input from nettop:
      
       launchd.1,,
       tcp6 *.445<->*.*,Listen,
       tcp4 *:445<->*:*,Listen,
       tcp6 *.548<->*.*,Listen,
       tcp4 *:548<->*:*,Listen,
       UserEventAgent.121,,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49177<->fe80::aede:48ff:fe33:4455%en11.59602,Established,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49178<->*.*,Listen,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49179<->*.*,Listen,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49180<->*.*,Listen,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49181<->*.*,Listen,
       tcp6 fe80::aede:48ff:fe00:1122%en11.49182<->*.*,Listen,
       ...
       idea.22706,,
       tcp4 127.0.0.1:51828<->localhost:51173,Established,
       tcp4 127.0.0.1:6942<->*:*,Listen,
       tcp4 127.0.0.1:63342<->*:*,Listen,
       tcp4 127.0.0.1:51828<->*:*,Listen,
       tcp4 127.0.0.1:52002<->*:*,Listen,
       tcp4 127.0.0.1:52002<->127.0.0.1:64042,Established,
       tcp4 127.0.0.1:51828<->127.0.0.1:51172,Established,
       java.22899,,
       tcp4 127.0.0.1:14542<->*:*,Listen,
       tcp4 127.0.0.1:51880<->*:*,Listen,
       tcp4 127.0.0.1:51173<->127.0.0.1:51828,Established,
       java.22900,,
       tcp4 127.0.0.1:4720<->*:*,Listen,
       tcp4 127.0.0.1:51884<->*:*,Listen,
       tcp4 127.0.0.1:51172<->127.0.0.1:51828,Established,
       
      Parameters:
      lines - a Stream delivering lines from the nettop command
      Returns:
      the list of busy ports
    • processNettopEndpoints

      private static void processNettopEndpoints(NetStat.BusyPort.IPVersion ipVersion, NetStat.BusyPort.Builder builder, String line, Pattern endpointPattern, Function<String,String> endpointHostMapper)