我正在尝试执行以下操作:
但是,以下几点给我带来了麻烦:
PacketCapture.lookupDevices()
,它返回Windows的NPF驱动程序设备路径列表(例如\Device\NPF_{39966C4C-3728-4368-AE92-1D36ACAF6634}
)和相当平淡的显示字符串(例如Microsoft
),以及没有其他信息。所以我不能用它来构建UI界面列表。NetworkInterface.getNetworkInterfaces()
提供系统上的接口列表,其中包含UI所需的所有信息,但NetworkInterface
不提供NDF驱动程序设备路径,仅提供显示名称和设备名称,例如“net5”,“lo”等。PacketCapture#open()
只接受设备路径。同时启动而非环回的NetworkInterface
列表对应于jpcap返回的设备列表,尽管它们的顺序不同。
所以,我在NetworkInterface
中找不到任何可以传递给PacketCapture#open()
的内容,而且我不知道如何从{{1}返回的设备路径中获取适当的UI信息}}。 PacketCapture#lookupDevices()
不接受PacketCapture
。因此,我被困住了。
我没有在Linux上试过这个。我怀疑该问题是Windows独有的,其中NetworkInterface#getName()
与NetworkInterface#getName()
识别的设备路径不对应。
如何从PacketCapture#open()
获取jpcap打开设备所需的信息(或者相反,给定设备路径获取NetworkInterface
),或者是否有另一种方法可以请允许我直接从jpcap获取每个设备的良好显示名称和IP地址?
Windows'注册表:我一直在进行一些挖掘工作,至少在注册表中找到了有关NPF设备的信息。给定一个jpcap设备路径,并使用one of the techniques here或本机库,一个不错的适配器名称(相当于那些NetworkInterface
返回)和当前的IP地址可以从注册表获得,如下所示: / p>
NetworkInterface
)。留下花括号并调用 。{39966C4C-3728-4368-AE92-1D36ACAF6634}
包含设备的当前IP地址以及其他一些配置信息。HKLM\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\<guid>
包含类似的信息。HKLM\SYSTEM\CurrentControlSet\services\<guid>\Parameters\Tcpip
中搜索子项的所有子项。如果找到包含值为&lt; guid&gt; 的键HKLM\SYSTEM\CurrentControlSet\Control\Class\
的子项,那么其余的键将包含驱动程序信息 - 好的显示名称,供应商信息等我不知道IPv6因素如何进入上面(有一些注册表区域有一个单独的Tcpip6信息块)。我也不知道这些密钥在Windows 7之外是否相同,但我怀疑它们是。如果没有更好的答案,我将使用示例代码将上述内容转换为答案。我仍在寻找更直接(理想的平台无关和无注册表)方式。
答案 0 :(得分:3)
我至少在注册表中找到了有关NPF设备的信息,并且正在将我的问题的最后一点扩展到答案。
给定一个jpcap设备路径,一个不错的适配器名称(相当于那些NetworkInterface
返回),并且可以从注册表获取当前的IP地址,如下所示:
39966C4C-3728-4368-AE92-1D36ACAF6634
)。HKLM\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\{<guid>}
包含设备的当前IP地址以及其他一些配置信息。HKLM\SYSTEM\CurrentControlSet\Control\Class\
中搜索子项的所有子项。如果找到包含值为{em> {&lt; guid&gt;} 的密钥NetCfgInstanceId
的子项,则其余的密钥将包含驱动程序信息 - 良好的显示名称,供应商信息等等。先决条件:
WinRegistry
。您可以从那里复制并粘贴它。的问题:
java.util.prefs.WindowsPreferences
(因此WinRegistry
)只能读取字符串键,而不能读取整数。因此,下面的代码无法可靠地确定是否启用了DHCP。作为一个黑客,使用的逻辑是检查静态IP /掩码,如果是空白,则回退到DHCP IP /掩码(值在注册表中单独存储)。代码如下。完整代码,包括WinRegistry(下面没有),也是available on github。根据SO CC attribution-sharealike license使用是免费的。
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 https://stackoverflow.com/a/6163701/616460. 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's 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's 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's IP address.
* @return Interface's 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's subnet mask.
* @return Interface's 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
希望这很有帮助。欢迎改进。不使用注册表的更直接方式的更好建议也是受欢迎的。
答案 1 :(得分:0)
这是一个应该与平台无关的备用解决方案,尽管只提供了启动接口的信息。注册表解决方案是我的第一次尝试,它运行良好,但我相信这是一个更好的解决方案,只要不需要有关 down 接口的信息。
PacketCapture
可以在给定设备字符串的情况下提供网络地址和子网掩码(虽然它是实例方法,但不是静态方法)。对于PacketCapture.lookupDevices()
中的每个设备字符串:PacketCapture
实例获取网络地址和掩码(捕获不需要打开)。NetworkInterface.getNetworkInterfaces()
返回的所有网络接口,找到一个地址位于同一网络上的网络地址和jpcap为设备返回的掩码。NetworkInterface
(可能)对应于设备字符串。先决条件:
的问题:
代码如下。在SO CC attribution-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)
我没有像其他解决方案那样使输出变得漂亮。请注意,“虚拟wifi微型端口适配器”(第一个)具有空NetworkInterface
,因为它未启动,因此无法找到匹配项(不存在IP地址和网络地址)。