Class NetStat


  • public class NetStat
    extends java.lang.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 Detail

      • LOGGER

        private static final org.slf4j.Logger LOGGER
      • LSOF_WARNING_EMITTED

        private static final java.util.concurrent.atomic.AtomicBoolean LSOF_WARNING_EMITTED
      • POWERSHELL_NETSTAT_COMMAND

        private static final java.lang.String[] POWERSHELL_NETSTAT_COMMAND
      • SUDO_PREFIX

        private static final java.lang.String[] SUDO_PREFIX
      • LSOF_COMMAND

        private static final java.lang.String[] LSOF_COMMAND
      • NETTOP_COMMAND

        private static final java.lang.String[] NETTOP_COMMAND
      • TCP4_ENDPOINT_PATTERN

        private static final java.util.regex.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 java.util.regex.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 Detail

      • NetStat

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

      • info

        public static java.util.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:
        java.lang.RuntimeException - if the busy port information cannot be obtained
      • info

        public static java.util.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:
        java.lang.IllegalArgumentException - if port is not a valid port number
        java.lang.RuntimeException - if the busy port information cannot be obtained
      • main

        public static void main​(java.lang.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​(java.lang.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 java.util.List<NetStat.BusyPort> parseLsof​(java.util.stream.Stream<java.lang.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,
                                                                      java.lang.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 java.net.InetSocketAddress parseLsofEndpoint​(NetStat.BusyPort.IPVersion ipVersion,
                                                                    java.lang.String endpoint)
      • parseNetTop

        private static java.util.List<NetStat.BusyPort> parseNetTop​(java.util.stream.Stream<java.lang.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,
                                                   java.lang.String line,
                                                   java.util.regex.Pattern endpointPattern,
                                                   java.util.function.Function<java.lang.String,​java.lang.String> endpointHostMapper)