All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oshi.driver.unix.NetStat Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020-2022 The OSHI Project Contributors
 * SPDX-License-Identifier: MIT
 */
package oshi.driver.unix;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import oshi.annotation.concurrent.ThreadSafe;
import oshi.software.os.InternetProtocolStats.IPConnection;
import oshi.software.os.InternetProtocolStats.TcpState;
import oshi.software.os.InternetProtocolStats.TcpStats;
import oshi.software.os.InternetProtocolStats.UdpStats;
import oshi.util.ExecutingCommand;
import oshi.util.ParseUtil;
import oshi.util.tuples.Pair;

/**
 * Utility to query TCP connections
 */
@ThreadSafe
public final class NetStat {

    private NetStat() {
    }

    /**
     * Query netstat to obtain number of established TCP connections
     *
     * @return A pair with number of established IPv4 and IPv6 connections
     */
    public static Pair queryTcpnetstat() {
        long tcp4 = 0L;
        long tcp6 = 0L;
        List activeConns = ExecutingCommand.runNative("netstat -n -p tcp");
        for (String s : activeConns) {
            if (s.endsWith("ESTABLISHED")) {
                if (s.startsWith("tcp4")) {
                    tcp4++;
                } else if (s.startsWith("tcp6")) {
                    tcp6++;
                }
            }
        }
        return new Pair<>(tcp4, tcp6);
    }

    /**
     * Query netstat to all TCP and UDP connections
     *
     * @return A list of TCP and UDP connections
     */
    public static List queryNetstat() {
        List connections = new ArrayList<>();
        List activeConns = ExecutingCommand.runNative("netstat -n");
        for (String s : activeConns) {
            String[] split = null;
            if (s.startsWith("tcp") || s.startsWith("udp")) {
                split = ParseUtil.whitespaces.split(s);
                if (split.length >= 5) {
                    String state = (split.length == 6) ? split[5] : null;
                    // Substitution if required
                    if ("SYN_RCVD".equals(state)) {
                        state = "SYN_RECV";
                    }
                    String type = split[0];
                    Pair local = parseIP(split[3]);
                    Pair foreign = parseIP(split[4]);
                    connections.add(new IPConnection(type, local.getA(), local.getB(), foreign.getA(), foreign.getB(),
                            state == null ? TcpState.NONE : TcpState.valueOf(state),
                            ParseUtil.parseIntOrDefault(split[2], 0), ParseUtil.parseIntOrDefault(split[1], 0), -1));
                }
            }
        }
        return connections;
    }

    private static Pair parseIP(String s) {
        // 73.169.134.6.9599 to 73.169.134.6 port 9599
        // or
        // 2001:558:600a:a5.123 to 2001:558:600a:a5 port 123
        int portPos = s.lastIndexOf('.');
        if (portPos > 0 && s.length() > portPos) {
            int port = ParseUtil.parseIntOrDefault(s.substring(portPos + 1), 0);
            String ip = s.substring(0, portPos);
            try {
                // Try to parse existing IP
                return new Pair<>(InetAddress.getByName(ip).getAddress(), port);
            } catch (UnknownHostException e) {
                try {
                    // Try again with trailing ::
                    if (ip.endsWith(":") && ip.contains("::")) {
                        ip = ip + "0";
                    } else if (ip.endsWith(":") || ip.contains("::")) {
                        ip = ip + ":0";
                    } else {
                        ip = ip + "::0";
                    }
                    return new Pair<>(InetAddress.getByName(ip).getAddress(), port);
                } catch (UnknownHostException e2) {
                    return new Pair<>(new byte[0], port);
                }
            }
        }
        return new Pair<>(new byte[0], 0);
    }

    /**
     * Gets TCP stats via {@code netstat -s}. Used for Linux and OpenBSD formats
     *
     * @param netstatStr The command string
     * @return The statistics
     */
    public static TcpStats queryTcpStats(String netstatStr) {
        long connectionsEstablished = 0;
        long connectionsActive = 0;
        long connectionsPassive = 0;
        long connectionFailures = 0;
        long connectionsReset = 0;
        long segmentsSent = 0;
        long segmentsReceived = 0;
        long segmentsRetransmitted = 0;
        long inErrors = 0;
        long outResets = 0;
        List netstat = ExecutingCommand.runNative(netstatStr);
        for (String s : netstat) {
            String[] split = s.trim().split(" ", 2);
            if (split.length == 2) {
                switch (split[1]) {
                case "connections established":
                case "connection established (including accepts)":
                case "connections established (including accepts)":
                    connectionsEstablished = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "active connection openings":
                    connectionsActive = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "passive connection openings":
                    connectionsPassive = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "failed connection attempts":
                case "bad connection attempts":
                    connectionFailures = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "connection resets received":
                case "dropped due to RST":
                    connectionsReset = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "segments sent out":
                case "packet sent":
                case "packets sent":
                    segmentsSent = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "segments received":
                case "packet received":
                case "packets received":
                    segmentsReceived = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "segments retransmitted":
                    segmentsRetransmitted = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "bad segments received":
                case "discarded for bad checksum":
                case "discarded for bad checksums":
                case "discarded for bad header offset field":
                case "discarded for bad header offset fields":
                case "discarded because packet too short":
                case "discarded for missing IPsec protection":
                    inErrors += ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "resets sent":
                    outResets = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                default:
                    // handle special case variable strings
                    if (split[1].contains("retransmitted") && split[1].contains("data packet")) {
                        segmentsRetransmitted += ParseUtil.parseLongOrDefault(split[0], 0L);
                    }
                    break;
                }

            }

        }
        return new TcpStats(connectionsEstablished, connectionsActive, connectionsPassive, connectionFailures,
                connectionsReset, segmentsSent, segmentsReceived, segmentsRetransmitted, inErrors, outResets);
    }

    /**
     * Gets UDP stats via {@code netstat -s}. Used for Linux and OpenBSD formats
     *
     * @param netstatStr The command string
     * @return The statistics
     */
    public static UdpStats queryUdpStats(String netstatStr) {
        long datagramsSent = 0;
        long datagramsReceived = 0;
        long datagramsNoPort = 0;
        long datagramsReceivedErrors = 0;
        List netstat = ExecutingCommand.runNative(netstatStr);
        for (String s : netstat) {
            String[] split = s.trim().split(" ", 2);
            if (split.length == 2) {
                switch (split[1]) {
                case "packets sent":
                case "datagram output":
                case "datagrams output":
                    datagramsSent = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "packets received":
                case "datagram received":
                case "datagrams received":
                    datagramsReceived = ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "packets to unknown port received":
                case "dropped due to no socket":
                case "broadcast/multicast datagram dropped due to no socket":
                case "broadcast/multicast datagrams dropped due to no socket":
                    datagramsNoPort += ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                case "packet receive errors":
                case "with incomplete header":
                case "with bad data length field":
                case "with bad checksum":
                case "woth no checksum":
                    datagramsReceivedErrors += ParseUtil.parseLongOrDefault(split[0], 0L);
                    break;
                default:
                    break;
                }
            }
        }
        return new UdpStats(datagramsSent, datagramsReceived, datagramsNoPort, datagramsReceivedErrors);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy