Getting interface name / address (or NetworkInterface mapping in) jpcap device path

I am trying to do the following:

  • Display a list of human-readable names of network interfaces and their IP addresses for the user.
  • Run the jpcap package capture on the interface that the user selects.

However, the following points give me problems:

  • jpcap only provides PacketCapture.lookupDevices()that returns a list of the HPP Windows' device driver paths to interfaces (for example, \Device\NPF_{39966C4C-3728-4368-AE92-1D36ACAF6634}) and a fairly soft display line (for example, Microsoft), and no other information. Therefore, I cannot use it to create a list of interface interfaces.
  • NetworkInterface.getNetworkInterfaces()provides a list of interfaces in the system with all the information I need for the user interface, but NetworkInterfacedoes not provide the device path of the NDF device, only the display names and device names, such as "net5", "lo", etc.
  • jpcap PacketCapture#open()only accepts device paths.

The list NetworkInterface, which are both up and not loopback, correspond to the list of devices returned by jpcap, although they are not in the same order.

So, I can’t find anything in NetworkInterfacethat can be passed in PacketCapture#open(), and I don’t know how to get the information corresponding to the UI from the device paths returned PacketCapture#lookupDevices(). PacketCapturedoes not accept NetworkInterface#getName(). So I'm stuck.

Linux. , Windows, NetworkInterface#getName() , PacketCapture#open().

, jpcap NetworkInterface ( ) - NetworkInterface ), , IP- jpcap?


Windows: , , NPF . jpcap , ( , NetworkInterface) IP- :

  • GUID (, {39966C4C-3728-4368-AE92-1D36ACAF6634} ). .
  • HKLM\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\<guid> IP- , .
  • HKLM\SYSTEM\CurrentControlSet\services\<guid>\Parameters\Tcpip .
  • HKLM\SYSTEM\CurrentControlSet\Control\Class\. , NetCfgInstanceId, <guid> , - , ..

, IPv6 ( Tcpip6). , Windows 7, , . , . ( ) .

+4
2

, NetworkInterface

, , , . , , , , .

  • PacketCapture ( , ). PacketCapture.lookupDevices():
  • PacketCapture ( ).
  • , NetworkInterface.getNetworkInterfaces(), , , , , , jpcap .
  • , NetworkInterface () .

:

:

  • , , , .
  • . jpcap SourceForge, -, , . , .
  • , , , .

. SO CC--sharealike license. , github.

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import net.sourceforge.jpcap.capture.CaptureDeviceLookupException;
import net.sourceforge.jpcap.capture.PacketCapture;

public class JpcapInterfaceInfo {


    /**
     * Get a list of interface information for all devices returned by jpcap.
     * @param capture An instance of PacketCapture to use for getting network address and mask info. If null,
     *                a new instance will be created.
     * @return List of information.
     * @throws CaptureDeviceLookupException
     */
    public static List<InterfaceInfo> listInterfaces (PacketCapture capture) throws CaptureDeviceLookupException {

        if (capture == null)
            capture = new PacketCapture();

        List<InterfaceInfo> infos = new ArrayList<InterfaceInfo>();
        for (String device : PacketCapture.lookupDevices())
            infos.add(getInterfaceInfo(capture, device));

        return infos;

    }


    /**
     * Get a list of interface information for all devices returned by jpcap.
     * @return List of information.
     * @throws CaptureDeviceLookupException
     */
    public static List<InterfaceInfo> listInterfaces () throws CaptureDeviceLookupException {
        return listInterfaces(null);
    }




    /**
     * Utility to check if an interface address matches a jpcap network address and mask.
     * @param address An InetAddress to check.
     * @param jpcapAddr Network address.
     * @param jpcapMask Network mask.
     * @return True if address is an IPv4 address on the network given by jpcapAddr/jpcapMask,
     *         false otherwise.
     */
    private static boolean networkMatches (InetAddress address, int jpcapAddr, int jpcapMask) {

        if (!(address instanceof Inet4Address))
            return false;

        byte[] address4 = address.getAddress();
        if (address4.length != 4)
            return false;

        int addr = ByteBuffer.wrap(address4).order(ByteOrder.LITTLE_ENDIAN).getInt();        
        return ((addr & jpcapMask) == jpcapAddr);

    }


    /**
     * Get an InterfaceInfo that corresponds to the given jpcap device string. The interface must be
     * up in order to query info about it; if it is not then the NetworkInterface in the returned
     * InterfaceInfo will be null.
     * @param capture A PacketCapture instance used to get network address and mask info.
     * @param jpcapDeviceString String from PacketCapture.lookupDevices().
     * @return InterfaceInfo.
     */
    public static InterfaceInfo getInterfaceInfo (PacketCapture capture, String jpcapDeviceString) {

        InterfaceInfo info = null;
        String deviceName = jpcapDeviceString.replaceAll("\n.*", "").trim();

        try {

            int netAddress = capture.getNetwork(deviceName);
            int netMask = capture.getNetmask(deviceName);

            // go through all addresses of all interfaces and try to find a match.

            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
            while (e.hasMoreElements() && info == null) {
                NetworkInterface iface = e.nextElement();
                Enumeration<InetAddress> ae = iface.getInetAddresses();
                while (ae.hasMoreElements() && info == null) {
                    if (networkMatches(ae.nextElement(), netAddress, netMask))
                        info = new InterfaceInfo(iface, deviceName);
                }
            }

        } catch (Exception x) {

            System.err.println("While querying info for " + deviceName + ":");
            x.printStackTrace(System.err);

        }

        if (info == null)
            info = new InterfaceInfo(null, deviceName);

        return info;

    }


    /**
     * Information about a network interface for jpcap, which is basically just a NetworkInterface
     * with details, and the jpcap device name for use with PacketCapture.
     */
    public static class InterfaceInfo {

        private final NetworkInterface iface;
        private final String deviceName;

        InterfaceInfo (NetworkInterface iface, String deviceName) {
            this.iface = iface;
            this.deviceName = deviceName;
        }

        /**
         * Get NetworkInterface for this interface.
         * @return May return null if no matching NetworkInterface was found.
         */
        public final NetworkInterface getIface () {
            return iface;
        }

        /**
         * Get jpcap device name for this interface. This can be passed to PacketCapture.open().
         * @return Device name for interface.
         */
        public final String getDeviceName () {
            return deviceName;
        }

        @Override public final String toString () {
            return deviceName + " : " + iface;
        }

    }


}

:

import java.util.List;

import net.sourceforge.jpcap.capture.PacketCapture;

public class JpcapInterfaceInfoTest {

    public static void main (String[] args) throws Exception {

        // Info can be queried from jpcap device list.
        List<JpcapInterfaceInfo.InterfaceInfo> infos = JpcapInterfaceInfo.listInterfaces();

        // Info can be displayed.
        for (JpcapInterfaceInfo.InterfaceInfo info : infos)
            System.out.println(info);

        // Device names from InterfaceInfo can be passed directly to jpcap:
        JpcapInterfaceInfo.InterfaceInfo selected = infos.get(0);
        PacketCapture capture = new PacketCapture();
        capture.open(selected.getDeviceName(), true);

    }

}

( , ), :

\Device\NPF_{691D289D-7EE5-4BD8-B5C1-3C4729A852D5} : null
\Device\NPF_{39966C4C-3728-4368-AE92-1D36ACAF6634} : name:net5 (1x1 11b/g/n Wireless LAN PCI Express Half Mini Card Adapter)

, . , " - Wi-Fi" () NetworkInterface, , , (IP- ).

0

Windows

, , NPF , .

jpcap, ( , NetworkInterface), IP- :

  • GUID (, 39966C4C-3728-4368-AE92-1D36ACAF6634 ).
  • HKLM\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\{<guid>} IP- , .
  • HKLM\SYSTEM\CurrentControlSet\Control\Class\. , NetCfgInstanceId, {{lt; guid > }, - , ..

:

:

  • java.util.prefs.WindowsPreferences ( WinRegistry) , . , DHCP. IP/ , , IP/ DHCP ( ).
  • IP- REG_MULTI_SZ, , IPv6 (?). . IPv6 + IPv4.
  • Windows, Windows 7 (Windows 8, - ?).
  • , jpcap 0.01.16.
  • Linux/OSX .

. , WinRegistry ( ), github. SO CC-sharealike.

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Gets information about network interface given a jpcap device string, on Windows. Makes
 * use of WinRegistry class from /questions/24918/readwrite-to-windows-registry-using-java/181412#181412. This is tested
 * against jpcap 0.01.16, which is available for download at http://sourceforge.net/projects/jpcap/.
 * 
 * All getters return empty strings rather than null if the information is unavailable.
 * 
 * @author https://stackoverflow.com/users/616460/jason-c
 */
public class NetworkDeviceInfo {


    private static final int DRIVER_CLASS_ROOT = WinRegistry.HKEY_LOCAL_MACHINE;
    private static final String DRIVER_CLASS_PATH = "SYSTEM\\CurrentControlSet\\Control\\Class";
    private static final String NETCFG_INSTANCE_KEY = "NetCfgInstanceId";
    private static final int IFACE_ROOT = WinRegistry.HKEY_LOCAL_MACHINE;
    private static final String IFACE_PATH = "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces";


    private final String jpcapDeviceName;
    private final String jpcapDisplayName;
    private final String guid;
    private final String driverName;
    private final String driverVendor;
    private final String interfaceAddress;
    private final String interfaceSubnetMask;


    /**
     * Construct from a jpcap device string.
     * @param jpcapDeviceString Device string from jpcap. 
     * @throws IllegalArgumentException If the device string could not be parsed.
     * @throws UnsupportedOperationException If the Windows registry could not be read.
     */
    public NetworkDeviceInfo (String jpcapDeviceString) throws IllegalArgumentException, UnsupportedOperationException {

        // extract jpcap device and display name, and guid, from jpcap device string

        String[] jpcapParts = jpcapDeviceString.split("\n", 2);

        jpcapDeviceName = (jpcapParts.length > 0) ? jpcapParts[0].trim() : "";
        jpcapDisplayName = (jpcapParts.length > 1) ? jpcapParts[1].replaceAll("\n", " ").trim() : "";

        Matcher matcher = Pattern.compile("\\{(\\S*)\\}").matcher(jpcapDeviceName);
        guid = matcher.find() ? matcher.group(1) : null;
        if (guid == null)
            throw new IllegalArgumentException("Could not parse GUID from jpcap device name '" + jpcapDeviceName + "'");

        try {

            // search registry for driver details:
            // Search all subkeys of subkeys in HKLM\SYSTEM\CurrentControlSet\Control\Class\. If a subkey
            // is found that contains a key NetCfgInstanceId whose value is {guid}, then the rest of the keys 
            // there will contain driver info - the nice display name, vendor info, etc.

            String theDriverName = "";
            String theDriverVendor = "";

            for (String driverClassSubkey : WinRegistry.readStringSubKeys(DRIVER_CLASS_ROOT, DRIVER_CLASS_PATH)) {
                for (String driverSubkey : WinRegistry.readStringSubKeys(DRIVER_CLASS_ROOT, DRIVER_CLASS_PATH + "\\" + driverClassSubkey)) {
                    String path = DRIVER_CLASS_PATH + "\\" + driverClassSubkey + "\\" + driverSubkey;
                    String netCfgInstanceId = WinRegistry.readString(DRIVER_CLASS_ROOT, path, NETCFG_INSTANCE_KEY);
                    if (netCfgInstanceId != null && netCfgInstanceId.equalsIgnoreCase("{" + guid + "}")) {
                        theDriverName = trimOrDefault(WinRegistry.readString(DRIVER_CLASS_ROOT, path, "DriverDesc"), "");
                        theDriverVendor = trimOrDefault(WinRegistry.readString(DRIVER_CLASS_ROOT, path, "ProviderName"), "");
                        // other interesting keys: DriverVersion, DriverDate
                        break;
                    }
                }
                if (!theDriverName.isEmpty())
                    break;
            }

            driverName = trimOrDefault(theDriverName, jpcapDisplayName);
            driverVendor = trimOrDefault(theDriverVendor, "Unknown");

            // read tcp/ip configuration details (HKLM\SYSTEM\CCS\services\Tcpip\Parameters\Interfaces\{guid})
            // there is an integer key EnableDHCP, but java.util.prefs.WindowsPreferences (and therefore 
            // WinRegistry) supports reading string keys only, therefore we'll have to hack it to decide on
            // DHCP vs. static IP address and hope it correct.
            // also note the ip addresses are REG_MULTI_SZ, presumably to also hold ipv6 addresses. the results
            // here may not be quite correct, then. that why I'm leaving addresses as strings instead of 
            // converting them to InetAddresses.

            String ifPath = IFACE_PATH + "\\{" + guid + "}";
            String dhcpIp = trimOrDefault(WinRegistry.readString(IFACE_ROOT, ifPath, "DhcpIPAddress"), "");
            String dhcpMask = trimOrDefault(WinRegistry.readString(IFACE_ROOT, ifPath, "DhcpSubnetMask"), "");
            // if static set, use it, otherwise use dhcp
            interfaceAddress = trimOrDefault(WinRegistry.readString(IFACE_ROOT, ifPath, "IPAddress"), dhcpIp);
            interfaceSubnetMask = trimOrDefault(WinRegistry.readString(IFACE_ROOT, ifPath, "SubnetMask"), dhcpMask);

        } catch (Exception x) {
            throw new UnsupportedOperationException("Information could not be read from the Windows registry.", x);
        }


    }


    /**
     * @param str A string.
     * @param def A default string.
     * @return Returns def if str is null or empty (after trim), otherwise returns str, trimmed.
     */
    private final static String trimOrDefault (String str, String def) {
        str = (str == null) ? "" : str.trim();
        return str.isEmpty() ? def : str;
    }


    /**
     * Gets the jpcap device name, which can be passed to PacketCapture.
     * @return Device name from jpcap. Pass this string to PacketCapture to specify this device.
     */
    public final String getJpcapDeviceName () {
        return jpcapDeviceName;
    }


    /**
     * Gets the jpcap display name. Usually this is pretty bland.
     * @return Display name from jpcap.
     */
    public final String getJpcapDisplayName () {
        return jpcapDisplayName;
    }


    /**
     * Gets the interface GUID.
     * @return Interface GUID.
     */
    public final String getGuid () {
        return guid;
    }


    /**
     * Get a nice display name for the interface driver. Display this in GUIs.
     * @return Interface driver name.
     */
    public final String getDriverName () {
        return driverName;
    }


    /**
     * Get the interface driver vendor name. Could be displayed in GUIs.
     * @return Interface driver vendor name.
     */
    public final String getDriverVendor () {
        return driverVendor;
    }


    /**
     * Get the interface IP address.
     * @return Interface IP address.
     * @bug This may not be correct for interfaces with multiple IP addresses. For this reason, it is
     *      left as a raw string rather than being converted to an InetAddress.
     */
    public final String getInterfaceAddress () {
        return interfaceAddress;
    }


    /**
     * Get the interface subnet mask.
     * @return Interface subnet mask.
     * @bug Same issue as getInterfaceAddress(). 
     */
    public final String getInterfaceSubnetMask () {
        return interfaceSubnetMask;
    }


    /**
     * Get a display string, for debugging.
     * @return Display string, for debugging.
     */
    @Override public String toString () {
        return String.format("%s (%s) {%s} @ %s/%s", driverName, driverVendor, guid, interfaceAddress, interfaceSubnetMask);
    }


}

:

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.jpcap.capture.PacketCapture;

public class NetworkDeviceInfoTest {

    public static void main (String[] args) throws Exception {

        List<NetworkDeviceInfo> infos = new ArrayList<NetworkDeviceInfo>();

        // Info can be queried from jpcap device string.
        for (String jpcapDevice : PacketCapture.lookupDevices())
            infos.add(new NetworkDeviceInfo(jpcapDevice));

        // Info can be displayed.
        for (NetworkDeviceInfo info : infos) {
            System.out.println(info.getJpcapDeviceName() + ":");
            System.out.println("  Description:   " + info.getDriverName());
            System.out.println("  Vendor:        " + info.getDriverVendor());
            System.out.println("  Address:       " + info.getInterfaceAddress());
            System.out.println("  Subnet Mask:   " + info.getInterfaceSubnetMask());
            System.out.println("  jpcap Display: " + info.getJpcapDisplayName());
            System.out.println("  GUID:          " + info.getGuid());
        }

        // Device names from NetworkDeviceInfo can be passed directly to jpcap:
        NetworkDeviceInfo selected = infos.get(0);
        PacketCapture capture = new PacketCapture();
        capture.open(selected.getJpcapDeviceName(), true);

    }

}

, :

PacketCapture: loading native library jpcap.. ok
\Device\NPF_{691D289D-7EE5-4BD8-B5C1-3C4729A852D5}:
  Description:   Microsoft Virtual WiFi Miniport Adapter
  Vendor:        Microsoft
  Address:       0.0.0.0
  Subnet Mask:   255.0.0.0
  jpcap Display: Microsoft
  GUID:          691D289D-7EE5-4BD8-B5C1-3C4729A852D5
\Device\NPF_{39966C4C-3728-4368-AE92-1D36ACAF6634}:
  Description:   1x1 11b/g/n Wireless LAN PCI Express Half Mini Card Adapter
  Vendor:        Realtek Semiconductor Corp.
  Address:       192.168.1.23
  Subnet Mask:   255.255.255.0
  jpcap Display: Microsoft
  GUID:          39966C4C-3728-4368-AE92-1D36ACAF6634

, . . .

+3

All Articles