commit 675fa2433141f8a66d81068adce4b6cb3d822006
Author: Administrator <2014539504@qq.com>
Date: Fri Aug 21 15:35:09 2026 +0800
Java FFM的TUN虚拟网卡封装
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..26c53d3
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..e0e1ee7
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ JavaTUN
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/JavaTUN.dll b/JavaTUN.dll
new file mode 100644
index 0000000..6174939
Binary files /dev/null and b/JavaTUN.dll differ
diff --git a/bin/one/papachi/tuntap4j/NetworkDevice$Type.class b/bin/one/papachi/tuntap4j/NetworkDevice$Type.class
new file mode 100644
index 0000000..5958e50
Binary files /dev/null and b/bin/one/papachi/tuntap4j/NetworkDevice$Type.class differ
diff --git a/bin/one/papachi/tuntap4j/NetworkDevice.class b/bin/one/papachi/tuntap4j/NetworkDevice.class
new file mode 100644
index 0000000..f04cffb
Binary files /dev/null and b/bin/one/papachi/tuntap4j/NetworkDevice.class differ
diff --git a/bin/one/papachi/tuntap4j/TapDevice.class b/bin/one/papachi/tuntap4j/TapDevice.class
new file mode 100644
index 0000000..14abf5b
Binary files /dev/null and b/bin/one/papachi/tuntap4j/TapDevice.class differ
diff --git a/bin/one/papachi/tuntap4j/TunDevice.class b/bin/one/papachi/tuntap4j/TunDevice.class
new file mode 100644
index 0000000..893f625
Binary files /dev/null and b/bin/one/papachi/tuntap4j/TunDevice.class differ
diff --git a/bin/one/papachi/tuntap4j/TunTap4j.class b/bin/one/papachi/tuntap4j/TunTap4j.class
new file mode 100644
index 0000000..b11ee25
Binary files /dev/null and b/bin/one/papachi/tuntap4j/TunTap4j.class differ
diff --git a/bin/one/papachi/tuntap4j/Utils$OperatingSystemFamily.class b/bin/one/papachi/tuntap4j/Utils$OperatingSystemFamily.class
new file mode 100644
index 0000000..270fd15
Binary files /dev/null and b/bin/one/papachi/tuntap4j/Utils$OperatingSystemFamily.class differ
diff --git a/bin/one/papachi/tuntap4j/Utils.class b/bin/one/papachi/tuntap4j/Utils.class
new file mode 100644
index 0000000..9483f8e
Binary files /dev/null and b/bin/one/papachi/tuntap4j/Utils.class differ
diff --git a/bin/org/kne/cloud/network/tun/App.class b/bin/org/kne/cloud/network/tun/App.class
new file mode 100644
index 0000000..5dba11f
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/App.class differ
diff --git a/bin/org/kne/cloud/network/tun/InetAddressRow.class b/bin/org/kne/cloud/network/tun/InetAddressRow.class
new file mode 100644
index 0000000..4a23ff8
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/InetAddressRow.class differ
diff --git a/bin/org/kne/cloud/network/tun/LinuxTUNChannel.class b/bin/org/kne/cloud/network/tun/LinuxTUNChannel.class
new file mode 100644
index 0000000..c1d7fa9
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/LinuxTUNChannel.class differ
diff --git a/bin/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.class b/bin/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.class
new file mode 100644
index 0000000..5c445d5
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.class differ
diff --git a/bin/org/kne/cloud/network/tun/TUNChannel.class b/bin/org/kne/cloud/network/tun/TUNChannel.class
new file mode 100644
index 0000000..a075fdc
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/TUNChannel.class differ
diff --git a/bin/org/kne/cloud/network/tun/TUNNetworkDevice.class b/bin/org/kne/cloud/network/tun/TUNNetworkDevice.class
new file mode 100644
index 0000000..8a65c23
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/TUNNetworkDevice.class differ
diff --git a/bin/org/kne/cloud/network/tun/TestTUN.class b/bin/org/kne/cloud/network/tun/TestTUN.class
new file mode 100644
index 0000000..8377b69
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/TestTUN.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsAPIException.class b/bin/org/kne/cloud/network/tun/WindowsAPIException.class
new file mode 100644
index 0000000..dd11a0c
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsAPIException.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsDNSManager$DnsInterfaceSettings.class b/bin/org/kne/cloud/network/tun/WindowsDNSManager$DnsInterfaceSettings.class
new file mode 100644
index 0000000..052a5fb
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsDNSManager$DnsInterfaceSettings.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsDNSManager.class b/bin/org/kne/cloud/network/tun/WindowsDNSManager.class
new file mode 100644
index 0000000..1b01ebf
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsDNSManager.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$AddressFamily.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$AddressFamily.class
new file mode 100644
index 0000000..18eb1cb
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$AddressFamily.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$DadState.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$DadState.class
new file mode 100644
index 0000000..190a767
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$DadState.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$PrefixOrigin.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$PrefixOrigin.class
new file mode 100644
index 0000000..7afaeb6
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$PrefixOrigin.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$SuffixOrigin.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$SuffixOrigin.class
new file mode 100644
index 0000000..a2a5708
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$SuffixOrigin.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$UnicastIPAddressRow.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$UnicastIPAddressRow.class
new file mode 100644
index 0000000..5061294
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager$UnicastIPAddressRow.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPAddressManager.class b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager.class
new file mode 100644
index 0000000..9e9e7c4
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPAddressManager.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$LinkLocalAddressBehavior.class b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$LinkLocalAddressBehavior.class
new file mode 100644
index 0000000..f0952b0
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$LinkLocalAddressBehavior.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$MibIpInterfaceRow.class b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$MibIpInterfaceRow.class
new file mode 100644
index 0000000..d77d8bb
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$MibIpInterfaceRow.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$RouterDiscoveryBehavior.class b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$RouterDiscoveryBehavior.class
new file mode 100644
index 0000000..e09bd8d
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager$RouterDiscoveryBehavior.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager.class b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager.class
new file mode 100644
index 0000000..c42d729
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsIPInterfaceManager.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$GUID.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$GUID.class
new file mode 100644
index 0000000..4df3938
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$GUID.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$LUID.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$LUID.class
new file mode 100644
index 0000000..2df4a30
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$LUID.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$WindowsAPIException.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$WindowsAPIException.class
new file mode 100644
index 0000000..972eeb0
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter$WindowsAPIException.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter.class
new file mode 100644
index 0000000..e8d18e3
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceConverter.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceManager$MibIfRow.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager$MibIfRow.class
new file mode 100644
index 0000000..0465063
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager$MibIfRow.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceManager.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager.class
new file mode 100644
index 0000000..fe05ef5
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2$MibIfRow.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2$MibIfRow.class
new file mode 100644
index 0000000..848ee13
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2$MibIfRow.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2.class b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2.class
new file mode 100644
index 0000000..20a538b
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsInterfaceManager2.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsTUNChannel.class b/bin/org/kne/cloud/network/tun/WindowsTUNChannel.class
new file mode 100644
index 0000000..3bf3e6f
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsTUNChannel.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class b/bin/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class
new file mode 100644
index 0000000..e9862bf
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class differ
diff --git a/bin/org/kne/cloud/network/tun/WindowsWaitHandle.class b/bin/org/kne/cloud/network/tun/WindowsWaitHandle.class
new file mode 100644
index 0000000..483c639
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WindowsWaitHandle.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$LoggerCallback.class b/bin/org/kne/cloud/network/tun/WintunDriver$LoggerCallback.class
new file mode 100644
index 0000000..342a86f
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$LoggerCallback.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$NativeHandle.class b/bin/org/kne/cloud/network/tun/WintunDriver$NativeHandle.class
new file mode 100644
index 0000000..90c3a2f
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$NativeHandle.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$Packet.class b/bin/org/kne/cloud/network/tun/WintunDriver$Packet.class
new file mode 100644
index 0000000..69b2fb6
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$Packet.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$SendPacket.class b/bin/org/kne/cloud/network/tun/WintunDriver$SendPacket.class
new file mode 100644
index 0000000..e23a6c0
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$SendPacket.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$WintunAdapterHandle.class b/bin/org/kne/cloud/network/tun/WintunDriver$WintunAdapterHandle.class
new file mode 100644
index 0000000..19fc53e
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$WintunAdapterHandle.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver$WintunSessionHandle.class b/bin/org/kne/cloud/network/tun/WintunDriver$WintunSessionHandle.class
new file mode 100644
index 0000000..32f7b34
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver$WintunSessionHandle.class differ
diff --git a/bin/org/kne/cloud/network/tun/WintunDriver.class b/bin/org/kne/cloud/network/tun/WintunDriver.class
new file mode 100644
index 0000000..fd3e847
Binary files /dev/null and b/bin/org/kne/cloud/network/tun/WintunDriver.class differ
diff --git a/bin/org/kne/util/SystemInfo.class b/bin/org/kne/util/SystemInfo.class
new file mode 100644
index 0000000..efbf811
Binary files /dev/null and b/bin/org/kne/util/SystemInfo.class differ
diff --git a/bin/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h b/bin/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h
new file mode 100644
index 0000000..bfc0e9b
--- /dev/null
+++ b/bin/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h
@@ -0,0 +1,125 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class org_kne_cloud_network_tun_WindowsTUNNetworkDevice */
+
+#ifndef _Included_org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+#define _Included_org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: loadDriver
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_loadDriver
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: unloadDriver
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_unloadDriver
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: openTUNDevice
+ * Signature: (Ljava/lang/String;Ljava/lang/String;JJ)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_openTUNDevice
+ (JNIEnv *, jobject, jstring, jstring, jlong, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: closeTUNDevice
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_closeTUNDevice
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: openSession
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_openSession
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: closeSession
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_closeSession
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: readAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_readAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: waitForReadAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_waitForReadAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: read0
+ * Signature: (JLjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_read0
+ (JNIEnv *, jobject, jlong, jobject);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: writeAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_writeAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: write0
+ * Signature: (JLjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_write0
+ (JNIEnv *, jobject, jlong, jobject);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: setTUNDeviceIPAddressV6
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_setTUNDeviceIPAddressV6
+ (JNIEnv *, jobject, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: getMTU0
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_getMTU0
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: setMTU0
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_setMTU0
+ (JNIEnv *, jobject, jlong, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/lib/pcap4j-core-1.8.2.jar b/lib/pcap4j-core-1.8.2.jar
new file mode 100644
index 0000000..9663471
Binary files /dev/null and b/lib/pcap4j-core-1.8.2.jar differ
diff --git a/lib/pcap4j-distribution-1.8.2-src.zip b/lib/pcap4j-distribution-1.8.2-src.zip
new file mode 100644
index 0000000..4002cc7
Binary files /dev/null and b/lib/pcap4j-distribution-1.8.2-src.zip differ
diff --git a/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar b/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar
new file mode 100644
index 0000000..7f13634
Binary files /dev/null and b/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar differ
diff --git a/lib/pcap4j-packetfactory-static-1.8.2.jar b/lib/pcap4j-packetfactory-static-1.8.2.jar
new file mode 100644
index 0000000..e5cf3ab
Binary files /dev/null and b/lib/pcap4j-packetfactory-static-1.8.2.jar differ
diff --git a/lib/pcap4j-packettest-1.8.2-tests.jar b/lib/pcap4j-packettest-1.8.2-tests.jar
new file mode 100644
index 0000000..ea12ea3
Binary files /dev/null and b/lib/pcap4j-packettest-1.8.2-tests.jar differ
diff --git a/lib/pcap4j-sample-1.8.2.jar b/lib/pcap4j-sample-1.8.2.jar
new file mode 100644
index 0000000..efc5b8a
Binary files /dev/null and b/lib/pcap4j-sample-1.8.2.jar differ
diff --git a/lib/slf4j-api-2.0.9-javadoc.jar b/lib/slf4j-api-2.0.9-javadoc.jar
new file mode 100644
index 0000000..17f14f3
Binary files /dev/null and b/lib/slf4j-api-2.0.9-javadoc.jar differ
diff --git a/lib/slf4j-api-2.0.9-sources.jar b/lib/slf4j-api-2.0.9-sources.jar
new file mode 100644
index 0000000..9a2a2dc
Binary files /dev/null and b/lib/slf4j-api-2.0.9-sources.jar differ
diff --git a/lib/slf4j-api-2.0.9-tests.jar b/lib/slf4j-api-2.0.9-tests.jar
new file mode 100644
index 0000000..2452fa4
Binary files /dev/null and b/lib/slf4j-api-2.0.9-tests.jar differ
diff --git a/lib/slf4j-api-2.0.9.jar b/lib/slf4j-api-2.0.9.jar
new file mode 100644
index 0000000..3796afe
Binary files /dev/null and b/lib/slf4j-api-2.0.9.jar differ
diff --git a/libtuntap4j.dylib b/libtuntap4j.dylib
new file mode 100644
index 0000000..1566452
Binary files /dev/null and b/libtuntap4j.dylib differ
diff --git a/libtuntap4j.so b/libtuntap4j.so
new file mode 100644
index 0000000..7f527e6
Binary files /dev/null and b/libtuntap4j.so differ
diff --git a/src/one/papachi/tuntap4j/NetworkDevice.java b/src/one/papachi/tuntap4j/NetworkDevice.java
new file mode 100644
index 0000000..3683dbd
--- /dev/null
+++ b/src/one/papachi/tuntap4j/NetworkDevice.java
@@ -0,0 +1,121 @@
+package one.papachi.tuntap4j;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.util.List;
+
+public abstract class NetworkDevice {
+ private static final String temporaryLibraryPath = System.getProperty(".");
+ //private static final String temporaryLibraryPath = System.getProperty("java.io.tmpdir");
+
+ static {
+ String library = Utils.getOperatingSystemFamily().getLibraryName();
+ /* File file = Paths.get(temporaryLibraryPath, library).toFile();
+ try (InputStream is = NetworkDevice.class.getResourceAsStream(library); OutputStream os = new FileOutputStream(file)) {
+ is.transferTo(os);
+ } catch (Exception e) {
+ }
+ System.load(file.getAbsolutePath());*/
+ File f=new File(library);
+ System.out.println(f.getAbsoluteFile());
+ System.load(f.getAbsolutePath());
+ }
+
+ enum Type {
+ TUN, TAP
+ }
+
+ protected final String deviceName;
+
+ protected final Type type;
+
+ protected long deviceHandle = -1;
+
+ protected NetworkDevice(String deviceName, Type type) {
+ this.deviceName = deviceName;
+ this.type = type;
+ }
+
+ public boolean isOpen() throws IOException {
+ return isOpen(deviceName, deviceHandle);
+ }
+
+ public void open() throws IOException {
+ deviceHandle = open(deviceName, type == Type.TAP);
+ }
+
+ public int read(ByteBuffer dst) throws IOException {
+ return read(deviceName, deviceHandle, dst);
+ }
+
+ public int write(ByteBuffer src) throws IOException {
+ return write(deviceName, deviceHandle, src);
+ }
+
+ public void close() throws IOException {
+ close(deviceName, deviceHandle);
+ }
+
+ public void setStatus(boolean isUp) throws IOException {
+ setStatus(deviceName, deviceHandle, isUp);
+ }
+
+ public String getIPAddress() throws IOException {
+ return getIPAddress(deviceName, deviceHandle);
+
+ }
+
+ public void setIPAddress(String address, String mask) throws IOException {
+ setIPAddress(deviceName, deviceHandle, address, mask);
+ }
+
+ public int getMTU() throws IOException {
+ return getMTU(deviceName, deviceHandle);
+ }
+
+ public void setMTU(int mtu) throws IOException {
+ setMTU(deviceName, deviceHandle, mtu);
+ }
+
+ public byte[] getMACAddress() throws IOException {
+ if (type == Type.TUN)
+ throw new UnsupportedOperationException("TUN device does not have MAC address");
+ return getMACAddress(deviceName, deviceHandle);
+ }
+
+ public void setMACAddress(byte[] macAddress) throws IOException {
+ if (type == Type.TUN)
+ throw new UnsupportedOperationException("TUN device does not have MAC address");
+ setMACAddress(deviceName, deviceHandle, macAddress);
+ }
+
+ protected static native boolean isOpen(String deviceName, long deviceHandle);
+
+ protected static native long open(String deviceName, boolean isTAP) throws IOException;
+
+ protected static native int read(String deviceName, long deviceHandle, ByteBuffer dst) throws IOException;
+
+ protected static native int write(String deviceName, long deviceHandle, ByteBuffer src) throws IOException;
+
+ protected static native void close(String deviceName, long deviceHandle) throws IOException;
+
+ protected static native void setStatus(String deviceName, long deviceHandle, boolean isUp) throws IOException;
+
+ protected static native String getIPAddress(String deviceName, long deviceHandle) throws IOException;
+
+ protected static native void setIPAddress(String deviceName, long deviceHandle, String address, String mask) throws IOException;
+
+ protected static native int getMTU(String deviceName, long deviceHandle) throws IOException;
+
+ protected static native void setMTU(String deviceName, long deviceHandle, int mtu) throws IOException;
+
+ protected static native byte[] getMACAddress(String deviceName, long deviceHandle) throws IOException;
+
+ protected static native void setMACAddress(String deviceName, long deviceHandle, byte[] macAddress) throws IOException;
+
+ protected static native List getAvailableTunDevices() throws IOException;
+
+ protected static native List getAvailableTapDevices() throws IOException;
+
+}
diff --git a/src/one/papachi/tuntap4j/TapDevice.java b/src/one/papachi/tuntap4j/TapDevice.java
new file mode 100644
index 0000000..52c3880
--- /dev/null
+++ b/src/one/papachi/tuntap4j/TapDevice.java
@@ -0,0 +1,9 @@
+package one.papachi.tuntap4j;
+
+public class TapDevice extends NetworkDevice {
+
+ public TapDevice(String deviceName) {
+ super(deviceName, Type.TAP);
+ }
+
+}
diff --git a/src/one/papachi/tuntap4j/TunDevice.java b/src/one/papachi/tuntap4j/TunDevice.java
new file mode 100644
index 0000000..084dca5
--- /dev/null
+++ b/src/one/papachi/tuntap4j/TunDevice.java
@@ -0,0 +1,8 @@
+package one.papachi.tuntap4j;
+
+public class TunDevice extends NetworkDevice {
+
+ public TunDevice(String deviceName) {
+ super(deviceName, Type.TUN);
+ }
+}
diff --git a/src/one/papachi/tuntap4j/TunTap4j.java b/src/one/papachi/tuntap4j/TunTap4j.java
new file mode 100644
index 0000000..6237adb
--- /dev/null
+++ b/src/one/papachi/tuntap4j/TunTap4j.java
@@ -0,0 +1,17 @@
+package one.papachi.tuntap4j;
+
+public class TunTap4j {
+
+ public static void main(String[] args) throws Exception {
+ TapDevice tapDevice = new TapDevice("tap0");
+ tapDevice.open();
+ System.out.println(tapDevice.isOpen());
+ tapDevice.setStatus(true);
+ System.out.println(tapDevice.getMTU());
+ System.out.println(tapDevice.getMACAddress());
+ tapDevice.setIPAddress("10.0.0.1", "255.0.0.0");
+ System.out.println(tapDevice.getIPAddress());
+ Thread.sleep(10000);
+ }
+
+}
diff --git a/src/one/papachi/tuntap4j/Utils.java b/src/one/papachi/tuntap4j/Utils.java
new file mode 100644
index 0000000..bc3d07b
--- /dev/null
+++ b/src/one/papachi/tuntap4j/Utils.java
@@ -0,0 +1,31 @@
+package one.papachi.tuntap4j;
+
+public class Utils {
+
+ enum OperatingSystemFamily {
+ WINDOWS("tuntap4j.dll"), LINUX("libtuntap4j.so"), MAC("libtuntap4j.dylib"), UNKNOWN(null);
+
+ private String libraryName;
+
+ private OperatingSystemFamily(String libraryName) {
+ this.libraryName = libraryName;
+ }
+
+ public String getLibraryName() {
+ return libraryName;
+ }
+ }
+
+ public static OperatingSystemFamily getOperatingSystemFamily() {
+ String osName = System.getProperty("os.name").toLowerCase();
+ if (osName.contains("win")) {
+ return OperatingSystemFamily.WINDOWS;
+ } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) {
+ return OperatingSystemFamily.LINUX;
+ } else if (osName.contains("mac")) {
+ return OperatingSystemFamily.MAC;
+ }
+ return OperatingSystemFamily.UNKNOWN;
+ }
+
+}
diff --git a/src/org/kne/cloud/network/tun/App.java b/src/org/kne/cloud/network/tun/App.java
new file mode 100644
index 0000000..a4f3d3a
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/App.java
@@ -0,0 +1,24 @@
+package org.kne.cloud.network.tun;
+import one.papachi.tuntap4j.TunDevice;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class App {
+
+ public static void main(String[] args) throws IOException {
+ String deviceName = "klalb0"; // it can be any name e.g. "mytun"
+ TunDevice device = new TunDevice(deviceName); // initialize a TUN device
+ device.open(); // open device for reading and writing
+ device.setStatus(true); // set device status to "up"
+ device.setIPAddress("10.0.0.0", "255.0.0.0"); // set IPv4 address and mask
+ int mtu = device.getMTU(); // get MTU of the device
+ ByteBuffer buffer = ByteBuffer.allocate(mtu); // allocate ByteBuffer to use in read operation (direct ByteBuffer is supported)
+ while (true) {
+ device.read(buffer.clear()); // read from the device into ByteBuffer
+ buffer.flip(); // prepare ByteBuffer for reading
+ // TODO process IP packet
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/InetAddressRow.java b/src/org/kne/cloud/network/tun/InetAddressRow.java
new file mode 100644
index 0000000..47a399d
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/InetAddressRow.java
@@ -0,0 +1,50 @@
+package org.kne.cloud.network.tun;
+
+import java.net.InetAddress;
+
+public class InetAddressRow {
+ private InetAddress address;
+ private int perfix;
+ public InetAddressRow(InetAddress address, int perfix) {
+ super();
+ this.address = address;
+ this.perfix = perfix;
+ }
+ public InetAddress getAddress() {
+ return address;
+ }
+ public int getPerfix() {
+ return perfix;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((address == null) ? 0 : address.hashCode());
+ result = prime * result + perfix;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ InetAddressRow other = (InetAddressRow) obj;
+ if (address == null) {
+ if (other.address != null)
+ return false;
+ } else if (!address.equals(other.address))
+ return false;
+ if (perfix != other.perfix)
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "InetAddressRow [address=" + address + ", perfix=" + perfix + "]";
+ }
+
+}
diff --git a/src/org/kne/cloud/network/tun/LinuxTUNChannel.java b/src/org/kne/cloud/network/tun/LinuxTUNChannel.java
new file mode 100644
index 0000000..ae704e2
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/LinuxTUNChannel.java
@@ -0,0 +1,37 @@
+package org.kne.cloud.network.tun;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import one.papachi.tuntap4j.TunDevice;
+
+public class LinuxTUNChannel implements TUNChannel {
+ private TunDevice device;
+ protected LinuxTUNChannel(TunDevice device) throws IOException{
+ this.device=device;
+ device.setStatus(true);
+ }
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ return device.write(src);
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return device.read(dst);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return device!=null;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if(device!=null) {
+ device=null;
+ device.setStatus(false);
+ }
+ }
+
+}
diff --git a/src/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.java b/src/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.java
new file mode 100644
index 0000000..d5aa6ce
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/LinuxTUNNetworkDevice.java
@@ -0,0 +1,113 @@
+package org.kne.cloud.network.tun;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.util.List;
+
+import one.papachi.tuntap4j.TunDevice;
+
+public class LinuxTUNNetworkDevice extends TUNNetworkDevice {
+ private TunDevice tun;
+ private String name;
+ public LinuxTUNNetworkDevice(String name, String type) throws IOException {
+ this.name=name;
+ tun=new TunDevice(name);
+ tun.open();
+ }
+
+ @Override
+ public boolean isOpen() {
+ try {
+ return tun.isOpen();
+ } catch (IOException e) {
+ try {
+ tun.close();
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if(channel!=null&&channel.isOpen()) {
+ channel.close();
+ channel=null;
+ }
+ TunDevice tund=tun;
+ tun=null;
+ if(tund!=null)
+ tund.close();
+ }
+ private LinuxTUNChannel channel;
+ @Override
+ public TUNChannel openSession() throws IOException {
+ if(channel==null) {
+ channel=new LinuxTUNChannel(tun);
+ }
+ return channel;
+ }
+
+ @Override
+ public List getIPAddress() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setIPAddress(List rows) throws IOException {
+ // TODO Auto-generated method stub
+ for(InetAddressRow row:rows) {
+ try {
+ Process proc=Runtime.getRuntime().exec(new String[] {"ip","addr","add",row.getAddress().getHostAddress()+"/"+row.getPerfix(),"dev",name});
+ Thread t=new Thread(()->{
+ BufferedReader br=new BufferedReader(proc.errorReader());
+ String str=null;
+ try {
+ while((str=br.readLine())!=null) {
+ System.out.println(str);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ });
+ t.start();
+ int rez=proc.waitFor();
+ if(rez!=0) {
+ throw new SocketException("set address failed!");
+ }
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public int getMTU() throws IOException {
+ return tun.getMTU();
+ }
+
+ @Override
+ public void setMTU(int mtu) throws IOException {
+ tun.setMTU(mtu);
+ }
+
+ @Override
+ public void setDNSAddress(List address) throws IOException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public List getDNSAddress() throws SocketException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/org/kne/cloud/network/tun/SystemInfo.class b/src/org/kne/cloud/network/tun/SystemInfo.class
new file mode 100644
index 0000000..3f2f40e
Binary files /dev/null and b/src/org/kne/cloud/network/tun/SystemInfo.class differ
diff --git a/src/org/kne/cloud/network/tun/TUNChannel.java b/src/org/kne/cloud/network/tun/TUNChannel.java
new file mode 100644
index 0000000..b911aa6
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/TUNChannel.java
@@ -0,0 +1,25 @@
+package org.kne.cloud.network.tun;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+import org.kne.cloud.network.tun.WintunDriver.WintunSessionHandle;
+
+public interface TUNChannel extends Channel, ReadableByteChannel, WritableByteChannel {
+
+ @Override
+ public int write(ByteBuffer src) throws IOException;
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException;
+
+ @Override
+ public boolean isOpen();
+
+ @Override
+ public void close() throws IOException;
+
+}
diff --git a/src/org/kne/cloud/network/tun/TUNNetworkDevice.class b/src/org/kne/cloud/network/tun/TUNNetworkDevice.class
new file mode 100644
index 0000000..f459cbb
Binary files /dev/null and b/src/org/kne/cloud/network/tun/TUNNetworkDevice.class differ
diff --git a/src/org/kne/cloud/network/tun/TUNNetworkDevice.java b/src/org/kne/cloud/network/tun/TUNNetworkDevice.java
new file mode 100644
index 0000000..f7fa773
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/TUNNetworkDevice.java
@@ -0,0 +1,56 @@
+package org.kne.cloud.network.tun;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.kne.util.SystemInfo;
+
+
+public abstract class TUNNetworkDevice implements Closeable,AutoCloseable{
+ private static final SystemInfo sysiInfo=new SystemInfo();
+ public static TUNNetworkDevice createDevice(String name,String type)throws IOException {
+ String osnamel=sysiInfo.getOsName().toLowerCase();
+ if(osnamel.contains("windows")) {
+ try {
+ return new WindowsTUNNetworkDevice(name,type);
+ }catch(UnsatisfiedLinkError err) {
+ throw new IOException("Load native driver failed!",err);
+ }
+ }else if(osnamel.contains("linux")) {
+ try {
+ return new LinuxTUNNetworkDevice(name,type);
+ }catch(UnsatisfiedLinkError err) {
+ throw new IOException("Load native driver failed!",err);
+ }
+ }else {
+ throw new UnsupportedOperationException("unsupport Operating System");
+ }
+ }
+
+ public abstract boolean isOpen() ;//判断是否开启
+
+ public abstract void close() throws IOException;//关闭网卡
+
+ public abstract TUNChannel openSession() throws IOException;//开启IO会话
+
+ public abstract List getIPAddress() throws IOException;//查询网卡IP和掩码
+
+ public abstract void setIPAddress(List rows) throws IOException;//设置网卡IP和掩码
+
+ public abstract int getMTU() throws IOException;//查询MTU
+
+ public abstract void setMTU(int mtu) throws IOException;//设置MTU
+
+ public abstract void setDNSAddress(List address) throws IOException ;//设置DNS服务器地址
+
+ public abstract List getDNSAddress()throws SocketException;
+
+}
diff --git a/src/org/kne/cloud/network/tun/TestTUN.java b/src/org/kne/cloud/network/tun/TestTUN.java
new file mode 100644
index 0000000..c5567ac
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/TestTUN.java
@@ -0,0 +1,106 @@
+package org.kne.cloud.network.tun;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class TestTUN {
+ public static void main(String[] args) throws IOException, InterruptedException {
+ TUNNetworkDevice tun = TUNNetworkDevice.createDevice("klalb1", "KLALB Decentralized SRv6 Network");
+ InetAddressRow row4=new InetAddressRow(InetAddress.getByName("2486::1111"),120);
+ InetAddressRow row6=new InetAddressRow(InetAddress.getByName("3.3.3.3"), 32);
+ tun.setIPAddress(List.of(row4,row6));
+ List alist=new ArrayList<>();
+ alist.add(InetAddress.getByName("2486:1::8888"));
+ alist.add(InetAddress.getByName("8.8.8.8"));
+ tun.setDNSAddress(alist );
+ System.out.println(tun.getDNSAddress());
+ //System.out.println(tun.getMTU());
+ tun.setMTU(9000);
+ TUNChannel channel=tun.openSession();
+ new Thread(() -> {
+ try {
+ Thread.sleep(1000000);
+ tun.close();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ new Thread(() -> {
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(9000);
+ while (true) {
+ long t2 = 0,t3=0;
+ long t=System.nanoTime();
+ channel.read(bb);
+ long t1=System.nanoTime();
+
+ bb.flip();
+ /*try {
+ long tc=System.nanoTime();
+ IpV6Packet ipp=IpV6Packet.newPacket(bb.array(), 0, bb.limit());
+ if(ipp.getHeader().getVersion().equals(IpVersion.IPV6)) {
+ Packet pl=ipp.getPayload();
+ if(pl instanceof IcmpV6CommonPacket) {
+ Packet req=pl.getPayload();
+ if(req instanceof IcmpV6EchoRequestPacket) {
+ //System.out.println("recv:");
+ //System.out.println(ipp+"\n");
+ IcmpV6EchoReplyPacket.Builder ibdr=new IcmpV6EchoReplyPacket.Builder();
+ ibdr.sequenceNumber(((IcmpV6EchoRequestPacket)req).getHeader().getSequenceNumber());
+ ibdr.identifier(((IcmpV6EchoRequestPacket)req).getHeader().getIdentifier());
+ ibdr.payloadBuilder(req.getPayload().getBuilder());
+ IcmpV6CommonPacket.Builder icbd=new IcmpV6CommonPacket.Builder();
+ icbd.type(IcmpV6Type.ECHO_REPLY);
+ icbd.code(IcmpV6Code.NO_CODE);
+ icbd.srcAddr(ipp.getHeader().getDstAddr());
+ icbd.dstAddr(ipp.getHeader().getSrcAddr());
+ icbd.correctChecksumAtBuild(true);
+ icbd.payloadBuilder(ibdr);
+ IpV6Packet.Builder ipv=new IpV6Packet.Builder();
+ ipv.srcAddr(ipp.getHeader().getDstAddr());
+ ipv.dstAddr(ipp.getHeader().getSrcAddr());
+ ipv.trafficClass(ipp.getHeader().getTrafficClass());
+ ipv.payloadBuilder(icbd);
+ ipv.version(IpVersion.IPV6);
+ ipv.flowLabel(IpV6SimpleFlowLabel.newInstance(0));
+ ipv.nextHeader(IpNumber.ICMPV6);
+ ipv.correctLengthAtBuild(true);
+ ipv.hopLimit((byte) 20);
+ //System.out.println("send:");
+ Packet resp=ipv.build();
+ //System.out.println(resp+"\n");
+ byte[]b=resp.getRawData();
+ ByteBuffer bbe=ByteBuffer.wrap(b);
+ t2=System.nanoTime();
+ channel.write(bbe);
+ t3=System.nanoTime();
+ System.out.println("writetime:"+(t3-t2));
+ System.out.println("decodetime:"+(t2-tc));
+ }
+ }
+ //IcmpV6EchoReplyPacket.Builder ib=new IcmpV6EchoReplyPacket.Builder();
+ //ib.sequenceNumber(0)
+ }
+
+
+ } catch (IllegalRawDataException e) {
+ e.printStackTrace();
+ }*/
+
+ System.out.println("readtime:"+(t1-t));
+ bb.clear();
+ }
+
+ } catch (IOException e) {
+ // TODO 自动生成的 catch 块
+ e.printStackTrace();
+ }
+ }).start();
+ }
+}
diff --git a/src/org/kne/cloud/network/tun/WindowsAPIException.java b/src/org/kne/cloud/network/tun/WindowsAPIException.java
new file mode 100644
index 0000000..510cc63
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsAPIException.java
@@ -0,0 +1,26 @@
+package org.kne.cloud.network.tun;
+ /**
+ * Windows API 异常
+ */
+ public class WindowsAPIException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -8395315684612977860L;
+ private final int errorCode;
+
+ public WindowsAPIException(String message, int errorCode) {
+ super(message + " (Error code: " + errorCode + ")");
+ this.errorCode = errorCode;
+ }
+
+ public WindowsAPIException(String message) {
+ super(message);
+ this.errorCode = 0;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+ }
+
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsDNSManager.java b/src/org/kne/cloud/network/tun/WindowsDNSManager.java
new file mode 100644
index 0000000..37dfb41
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsDNSManager.java
@@ -0,0 +1,492 @@
+package org.kne.cloud.network.tun;
+
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.nio.charset.Charset;
+import java.util.*;
+
+import org.kne.cloud.network.tun.WindowsInterfaceConverter.GUID;
+
+/**
+ * Windows DNS 设置管理类
+ * 支持获取、设置和修改网络接口的 DNS 配置
+ */
+public class WindowsDNSManager {
+
+ // 内存布局
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+
+ // DNS 设置常量
+ public static final int DNS_SETTINGS_VERSION1 = 0x0001;
+ public static final int DNS_INTERFACE_SETTINGS_VERSION1 = 0x0001;
+ public static final int DNS_INTERFACE_SETTINGS_VERSION2 = 0x0002;
+
+ // DNS 设置标志
+ public static final long DNS_SETTING_IPV6 = 0x0001L;
+ public static final long DNS_SETTING_NAMESERVER = 0x0002L;
+ public static final long DNS_SETTING_SEARCHLIST = 0x0004L;
+ public static final long DNS_SETTING_REGISTRATION_ENABLED = 0x0008L;
+ public static final long DNS_SETTING_REGISTER_ADAPTER_NAME = 0x0010L;
+ public static final long DNS_SETTING_DOMAIN = 0x0020L;
+ public static final long DNS_SETTING_HOSTNAME = 0x0040L;
+ public static final long DNS_SETTINGS_ENABLE_LLMNR = 0x0080L;
+ public static final long DNS_SETTINGS_QUERY_ADAPTER_NAME = 0x0100L;
+ public static final long DNS_SETTING_PROFILE_NAMESERVER = 0x0200L;
+ public static final long DNS_SETTING_DISABLE_UNCONSTRAINED_QUERIES = 0x0400L;
+ public static final long DNS_SETTING_SUPPLEMENTAL_SEARCH_LIST = 0x0800L;
+
+ // DNS_SETTINGS 结构体布局 (通用 DNS 设置)
+ public static final GroupLayout DNS_SETTINGS_LAYOUT = MemoryLayout.structLayout(
+ DWORD.withName("Version"), // ULONG Version
+ MemoryLayout.paddingLayout(4),
+ DWORD64.withName("Flags"), // ULONG64 Flags
+ POINTER.withName("Hostname"), // PWSTR Hostname
+ POINTER.withName("Domain"), // PWSTR Domain
+ POINTER.withName("SearchList") // PWSTR SearchList
+ );
+
+ // DNS_INTERFACE_SETTINGS 结构体布局 (接口特定 DNS 设置 V1)
+ public static final GroupLayout DNS_INTERFACE_SETTINGS_LAYOUT = MemoryLayout.structLayout(
+ DWORD.withName("Version"), // ULONG Version
+ MemoryLayout.paddingLayout(4),
+ DWORD64.withName("Flags"), // ULONG64 Flags
+ POINTER.withName("Domain"), // PWSTR Domain
+ POINTER.withName("NameServer"), // PWSTR NameServer
+ POINTER.withName("SearchList"), // PWSTR SearchList
+ DWORD.withName("RegistrationEnabled"), // ULONG RegistrationEnabled
+ DWORD.withName("RegisterAdapterName"), // ULONG RegisterAdapterName
+ DWORD.withName("EnableLLMNR"), // ULONG EnableLLMNR
+ DWORD.withName("QueryAdapterName"), // ULONG QueryAdapterName
+ POINTER.withName("ProfileNameServer") // PWSTR ProfileNameServer
+ );
+
+ // DNS_INTERFACE_SETTINGS_EX 结构体布局 (扩展版本)
+ public static final GroupLayout DNS_INTERFACE_SETTINGS_EX_LAYOUT = MemoryLayout.structLayout(
+ DNS_INTERFACE_SETTINGS_LAYOUT.withName("SettingsV1"),
+ DWORD.withName("DisableUnconstrainedQueries"), // ULONG DisableUnconstrainedQueries
+ MemoryLayout.paddingLayout(4),
+ POINTER.withName("SupplementalSearchList") // PWSTR SupplementalSearchList
+ );
+
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ // 方法句柄
+ private static final MethodHandle GET_INTERFACE_DNS_SETTINGS;
+ private static final MethodHandle FREE_INTERFACE_DNS_SETTINGS;
+ private static final MethodHandle SET_INTERFACE_DNS_SETTINGS;
+ private static final MethodHandle FREE_DNS_SETTINGS;
+ private static final MethodHandle GET_DNS_SETTINGS;
+
+ static {
+ try {
+ // 加载 dnsapi.dll
+ System.loadLibrary("dnsapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // GetInterfaceDnsSettings 函数
+ // DWORD GetInterfaceDnsSettings(GUID *Interface, DNS_INTERFACE_SETTINGS *Settings);
+ FunctionDescriptor getInterfaceDnsSettingsDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER, // Interface: GUID*
+ POINTER // Settings: DNS_INTERFACE_SETTINGS*
+ );
+
+ // SetInterfaceDnsSettings 函数
+ // DWORD SetInterfaceDnsSettings(GUID *Interface, DNS_INTERFACE_SETTINGS *Settings);
+ FunctionDescriptor setInterfaceDnsSettingsDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER, // Interface: GUID*
+ POINTER // Settings: DNS_INTERFACE_SETTINGS*
+ );
+
+ FunctionDescriptor freeInterfaceDnsSettingsDesc = FunctionDescriptor.ofVoid(
+ POINTER
+ );
+
+ // FreeDnsSettings 函数
+ // VOID FreeDnsSettings(DNS_SETTINGS *Settings);
+ FunctionDescriptor freeDnsSettingsDesc = FunctionDescriptor.ofVoid(
+ POINTER // Settings: DNS_SETTINGS*
+ );
+
+ // GetDnsSettings 函数
+ // DWORD GetDnsSettings(DNS_SETTINGS *Settings);
+ FunctionDescriptor getDnsSettingsDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // Settings: DNS_SETTINGS*
+ );
+
+ // 获取方法句柄
+ GET_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
+ LOOKUP.find("GetInterfaceDnsSettings").orElseThrow(),
+ getInterfaceDnsSettingsDesc
+ );
+
+ SET_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
+ LOOKUP.find("SetInterfaceDnsSettings").orElseThrow(),
+ setInterfaceDnsSettingsDesc
+ );
+
+ FREE_DNS_SETTINGS = LINKER.downcallHandle(
+ LOOKUP.find("FreeDnsSettings").orElseThrow(),
+ freeInterfaceDnsSettingsDesc
+ );
+
+ FREE_INTERFACE_DNS_SETTINGS = LINKER.downcallHandle(
+ LOOKUP.find("FreeInterfaceDnsSettings").orElseThrow(),
+ freeDnsSettingsDesc
+ );
+
+ GET_DNS_SETTINGS = LINKER.downcallHandle(
+ LOOKUP.find("GetDnsSettings").orElseThrow(),
+ getDnsSettingsDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows DNS manager", e);
+ }
+ }
+
+ /**
+ * DNS 设置信息类 (Java 对象版本)
+ */
+ public static class DnsInterfaceSettings {
+ private int version;
+ private long flags;
+ private String domain;
+ private List nameServers;
+ private List searchList;
+ private boolean registrationEnabled;
+ private boolean registerAdapterName;
+ private boolean enableLLMNR;
+ private boolean queryAdapterName;
+ private String profileNameServer;
+ private boolean disableUnconstrainedQueries;
+ private List supplementalSearchList;
+
+ public DnsInterfaceSettings() {
+ this.version = DNS_INTERFACE_SETTINGS_VERSION1;
+ this.flags = 0;
+ }
+
+ // Getters and Setters
+ public int getVersion() { return version; }
+ public void setVersion(int version) { this.version = version; }
+
+ public long getFlags() { return flags; }
+ public void setFlags(long flags) { this.flags = flags; }
+
+ public String getDomain() { return domain; }
+ public void setDomain(String domain) { this.domain = domain; }
+
+ public List getNameServers() { return nameServers; }
+ public void setNameServers(List nameServers) { this.nameServers = nameServers; }
+
+ public List getSearchList() { return searchList; }
+ public void setSearchList(List searchList) { this.searchList = searchList; }
+
+ public boolean isRegistrationEnabled() { return registrationEnabled; }
+ public void setRegistrationEnabled(boolean registrationEnabled) {
+ this.registrationEnabled = registrationEnabled;
+ }
+
+ public boolean isRegisterAdapterName() { return registerAdapterName; }
+ public void setRegisterAdapterName(boolean registerAdapterName) {
+ this.registerAdapterName = registerAdapterName;
+ }
+
+ public boolean isEnableLLMNR() { return enableLLMNR; }
+ public void setEnableLLMNR(boolean enableLLMNR) { this.enableLLMNR = enableLLMNR; }
+
+ public boolean isQueryAdapterName() { return queryAdapterName; }
+ public void setQueryAdapterName(boolean queryAdapterName) {
+ this.queryAdapterName = queryAdapterName;
+ }
+
+ public String getProfileNameServer() { return profileNameServer; }
+ public void setProfileNameServer(String profileNameServer) {
+ this.profileNameServer = profileNameServer;
+ }
+
+ public boolean isDisableUnconstrainedQueries() { return disableUnconstrainedQueries; }
+ public void setDisableUnconstrainedQueries(boolean disableUnconstrainedQueries) {
+ this.disableUnconstrainedQueries = disableUnconstrainedQueries;
+ }
+
+ public List getSupplementalSearchList() { return supplementalSearchList; }
+ public void setSupplementalSearchList(List supplementalSearchList) {
+ this.supplementalSearchList = supplementalSearchList;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DNS Interface Settings:\n");
+ sb.append(" Version: ").append(version).append("\n");
+ sb.append(" Flags: 0x").append(Long.toHexString(flags)).append("\n");
+ sb.append(" Domain: ").append(domain != null ? domain : "(null)").append("\n");
+ sb.append(" Name Servers: ").append(nameServers).append("\n");
+ sb.append(" Search List: ").append(searchList).append("\n");
+ sb.append(" Registration Enabled: ").append(registrationEnabled).append("\n");
+ sb.append(" Register Adapter Name: ").append(registerAdapterName).append("\n");
+ sb.append(" Enable LLMNR: ").append(enableLLMNR).append("\n");
+ sb.append(" Query Adapter Name: ").append(queryAdapterName).append("\n");
+ sb.append(" Profile Name Server: ").append(profileNameServer).append("\n");
+ sb.append(" Disable Unconstrained Queries: ").append(disableUnconstrainedQueries).append("\n");
+ sb.append(" Supplemental Search List: ").append(supplementalSearchList);
+ return sb.toString();
+ }
+ }
+
+ /**
+ * 从网卡获取 DNS 设置
+ * @param interfaceGuid 网卡的 GUID
+ * @return DNS 设置对象
+ */
+ public static DnsInterfaceSettings getInterfaceDnsSettings(GUID interfaceGuid,DnsInterfaceSettings oldSettings) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 创建 GUID 内存段
+ MemorySegment guidSegment = interfaceGuid.toMemorySegment( arena);
+
+ // 分配 DNS_INTERFACE_SETTINGS 结构体 (版本1)
+ MemorySegment dnsSettings = createDnsInterfaceSettingsMemory(oldSettings, arena);
+
+ // 设置版本
+ dnsSettings.set(DWORD, 0, DNS_INTERFACE_SETTINGS_VERSION1);
+
+ // 调用 GetInterfaceDnsSettings
+ int result = (int) GET_INTERFACE_DNS_SETTINGS.invokeExact(
+ guidSegment,
+ dnsSettings
+ );
+
+ if (result != 0) { // NO_ERROR = 0
+ throw new WindowsAPIException("GetInterfaceDnsSettings failed", result);
+ }
+ DnsInterfaceSettings resultv=parseDnsInterfaceSettings(dnsSettings, arena);
+ FREE_INTERFACE_DNS_SETTINGS.invokeExact(dnsSettings);
+ // 解析结构体为 Java 对象
+ return resultv;
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting interface DNS settings", e);
+ }
+ }
+
+ /**
+ * 应用 DNS 设置到网卡
+ * @param interfaceGuid 网卡的 GUID
+ * @param settings DNS 设置对象
+ * @return 操作结果 (0 = 成功)
+ */
+ public static void setInterfaceDnsSettings(GUID interfaceGuid, DnsInterfaceSettings settings) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 创建 GUID 内存段
+ MemorySegment guidSegment = interfaceGuid.toMemorySegment( arena);
+
+ // 创建 DNS_INTERFACE_SETTINGS 结构体
+ MemorySegment dnsSettings = createDnsInterfaceSettingsMemory(settings, arena);
+
+ // 调用 SetInterfaceDnsSettings
+ int result= (int) SET_INTERFACE_DNS_SETTINGS.invokeExact(
+ guidSegment,
+ dnsSettings
+ );
+
+ if (result != 0) { // NO_ERROR = 0
+ throw new WindowsAPIException("SetInterfaceDnsSettings failed", result);
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Error setting interface DNS settings", e);
+ }
+ }
+
+ /**
+ * 解析 DNS_INTERFACE_SETTINGS 结构体为 Java 对象
+ */
+ private static DnsInterfaceSettings parseDnsInterfaceSettings(MemorySegment dnsSettings, Arena arena) {
+ DnsInterfaceSettings settings = new DnsInterfaceSettings();
+
+ // 读取基本字段
+ int version = dnsSettings.get(DWORD, 0);
+ settings.setVersion(version);
+
+ long flags = dnsSettings.get(DWORD64, 8);
+ settings.setFlags(flags);
+
+ // 读取字符串字段
+ MemorySegment domainPtr = dnsSettings.get(POINTER, 16);
+ if (!domainPtr.equals(MemorySegment.NULL)) {
+ String domain = readWideString(domainPtr, arena);
+ settings.setDomain(domain);
+ }else {
+ settings.setDomain(null);
+ }
+
+ // 读取 NameServer (可能是多个服务器,用空格分隔)
+ MemorySegment nameServerPtr = dnsSettings.get(POINTER, 24);
+ if (!nameServerPtr.equals(MemorySegment.NULL)) {
+ String nameServerStr = readWideString(nameServerPtr, arena);
+ if (nameServerStr != null && !nameServerStr.isEmpty()) {
+ String[] servers = nameServerStr.split("\\s+");
+ settings.setNameServers(Arrays.asList(servers));
+ }
+ }else {
+ settings.setNameServers(null);
+ }
+
+ // 读取 SearchList (可能是多个域名,用空格分隔)
+ MemorySegment searchListPtr = dnsSettings.get(POINTER, 32);
+ if (!searchListPtr.equals(MemorySegment.NULL)) {
+ String searchListStr = readWideString(searchListPtr, arena);
+ if (searchListStr != null && !searchListStr.isEmpty()) {
+ String[] domains = searchListStr.split("\\s+");
+ settings.setSearchList(Arrays.asList(domains));
+ }
+ }else {
+ settings.setSearchList(null);
+ }
+
+ // 读取布尔值字段
+ int registrationEnabled = dnsSettings.get(DWORD, 40);
+ settings.setRegistrationEnabled(registrationEnabled != 0);
+
+ int registerAdapterName = dnsSettings.get(DWORD, 44);
+ settings.setRegisterAdapterName(registerAdapterName != 0);
+
+ int enableLLMNR = dnsSettings.get(DWORD, 48);
+ settings.setEnableLLMNR(enableLLMNR != 0);
+
+ int queryAdapterName = dnsSettings.get(DWORD, 52);
+ settings.setQueryAdapterName(queryAdapterName != 0);
+
+ // 读取 ProfileNameServer
+ MemorySegment profileNameServerPtr = dnsSettings.get(POINTER, 56);
+ if (!profileNameServerPtr.equals(MemorySegment.NULL)) {
+ String profileNameServer = readWideString(profileNameServerPtr, arena);
+ settings.setProfileNameServer(profileNameServer);
+ }else {
+ settings.setProfileNameServer(null);
+ }
+
+ return settings;
+ }
+
+ /**
+ * 创建 DNS_INTERFACE_SETTINGS 结构体的内存表示
+ */
+ private static MemorySegment createDnsInterfaceSettingsMemory(DnsInterfaceSettings settings, Arena arena) {
+ // 分配结构体内存
+ MemorySegment dnsSettings = arena.allocate(DNS_INTERFACE_SETTINGS_LAYOUT);
+
+ // 设置版本和标志
+ dnsSettings.set(DWORD, 0, settings.getVersion());
+ dnsSettings.set(DWORD64, 8, settings.getFlags());
+
+ // 设置 Domain
+ if (settings.getDomain() != null) {
+ MemorySegment domainStr = toWideString(settings.getDomain(), arena);
+ dnsSettings.set(POINTER, 16, domainStr);
+ } else {
+ dnsSettings.set(POINTER, 16, MemorySegment.NULL);
+ }
+
+ // 设置 NameServer (多个服务器用空格分隔)
+ if (settings.getNameServers()!=null) {
+ String nameServerStr = String.join(" ", settings.getNameServers());
+ MemorySegment nameServerSegment = toWideString(nameServerStr, arena);
+ dnsSettings.set(POINTER, 24, nameServerSegment);
+ } else {
+ dnsSettings.set(POINTER, 24, MemorySegment.NULL);
+ }
+
+ // 设置 SearchList (多个域名用空格分隔)
+ if (settings.getSearchList()!=null) {
+ String searchListStr = String.join(" ", settings.getSearchList());
+ MemorySegment searchListSegment = toWideString(searchListStr, arena);
+ dnsSettings.set(POINTER, 32, searchListSegment);
+ } else {
+ dnsSettings.set(POINTER, 32, MemorySegment.NULL);
+ }
+
+ // 设置布尔值字段
+ dnsSettings.set(DWORD, 40, settings.isRegistrationEnabled() ? 1 : 0);
+ dnsSettings.set(DWORD, 44, settings.isRegisterAdapterName() ? 1 : 0);
+ dnsSettings.set(DWORD, 48, settings.isEnableLLMNR() ? 1 : 0);
+ dnsSettings.set(DWORD, 52, settings.isQueryAdapterName() ? 1 : 0);
+
+ // 设置 ProfileNameServer
+ if (settings.getProfileNameServer() != null ) {
+ MemorySegment profileNameServerSegment = toWideString(settings.getProfileNameServer(), arena);
+ dnsSettings.set(POINTER, 56, profileNameServerSegment);
+ } else {
+ dnsSettings.set(POINTER, 56, MemorySegment.NULL);
+ }
+
+ return dnsSettings;
+ }
+
+
+
+
+
+
+
+
+ /**
+ * 将 Java String 转换为 Windows 宽字符串 (UTF-16 LE)
+ */
+ private static MemorySegment toWideString(String str, Arena arena) {
+ if (str == null ) {
+ return MemorySegment.NULL;
+ }
+
+ byte[] utf16Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
+ MemorySegment segment = arena.allocate(utf16Bytes.length + 2);
+ segment.copyFrom(MemorySegment.ofArray(utf16Bytes));
+
+ // 添加 null 终止符
+ segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length, (byte) 0);
+ segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length + 1, (byte) 0);
+
+ return segment;
+ }
+
+ /**
+ * 读取 Windows 宽字符串
+ */
+ private static String readWideString(MemorySegment strPtr, Arena arena) {
+ if (strPtr.equals(MemorySegment.NULL)) {
+ return null;
+ }
+ strPtr= strPtr.reinterpret(0xffffffffL);
+ //return strPtr.getString(0,Charset.forName("UTF-16"));
+ try {
+ // 计算字符串长度 (找到 null 终止符)
+ long length = 0;
+ while (true) {
+ short ch = strPtr.get(ValueLayout.JAVA_SHORT, length * 2);
+ if (ch == 0) {
+ break;
+ }
+ length++;
+ }
+
+ // 读取字符串数据
+ byte[] bytes = new byte[(int) (length * 2)];
+ MemorySegment.copy(strPtr, 0, MemorySegment.ofArray(bytes), 0, bytes.length);
+
+ return new String(bytes, java.nio.charset.StandardCharsets.UTF_16LE);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsIPAddressManager.java b/src/org/kne/cloud/network/tun/WindowsIPAddressManager.java
new file mode 100644
index 0000000..0756bed
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsIPAddressManager.java
@@ -0,0 +1,772 @@
+package org.kne.cloud.network.tun;
+
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.time.Instant;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Windows IP地址管理类 提供对MIB_UNICASTIPADDRESS_ROW和MIB_UNICASTIPADDRESS_TABLE的Java封装
+ */
+public class WindowsIPAddressManager {
+
+ // 内存布局定义
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+ public static final ValueLayout.OfBoolean BOOLEAN_LAYOUT = ValueLayout.JAVA_BOOLEAN;
+
+ // 常量定义
+ public static final int NO_ERROR = 0;
+ public static final int ERROR_NOT_FOUND = 1168;
+ public static final int ERROR_OBJECT_ALREADY_EXISTS = 5010;
+ public static final int NET_IFINDEX_UNSPECIFIED = 0;
+ public static final long NET_IFLUID_UNSPECIFIED = 0;
+
+ // SCOPE_ID 结构 (ULONG)
+ public static final GroupLayout SCOPE_ID_LAYOUT = MemoryLayout.structLayout(DWORD.withName("Value"));
+
+ // LARGE_INTEGER 结构 (64位有符号整数)
+ public static final GroupLayout LARGE_INTEGER_LAYOUT = MemoryLayout.structLayout(DWORD64.withName("QuadPart"));
+
+ // SOCKADDR_IN (IPv4地址)
+ public static final GroupLayout SOCKADDR_IN_LAYOUT = MemoryLayout.structLayout(WORD.withName("sin_family"), // ADDRESS_FAMILY
+ // (AF_INET
+ // = 2)
+ WORD.withName("sin_port"), // USHORT
+ MemoryLayout.sequenceLayout(4, BYTE).withName("sin_addr"), // IN_ADDR (4 bytes)
+ MemoryLayout.sequenceLayout(8, BYTE).withName("sin_zero") // 填充字节
+ );
+
+ // IN6_ADDR (IPv6地址,16字节)
+ public static final GroupLayout IN6_ADDR_LAYOUT = MemoryLayout
+ .structLayout(MemoryLayout.sequenceLayout(16, BYTE).withName("s6_bytes"));
+
+ // SOCKADDR_IN6 (IPv6地址结构)
+ public static final GroupLayout SOCKADDR_IN6_LAYOUT = MemoryLayout.structLayout(WORD.withName("sin6_family"), // ADDRESS_FAMILY
+ // (AF_INET6
+ // =
+ // 23)
+ WORD.withName("sin6_port"), // USHORT
+ DWORD.withName("sin6_flowinfo"), // ULONG
+ IN6_ADDR_LAYOUT.withName("sin6_addr"), DWORD.withName("sin6_scope_id") // ULONG
+ );
+
+ // SOCKADDR_INET 联合 (IPv4或IPv6地址)
+ public static final GroupLayout SOCKADDR_INET_LAYOUT = MemoryLayout.structLayout(MemoryLayout
+ .unionLayout(SOCKADDR_IN_LAYOUT.withName("Ipv4"), SOCKADDR_IN6_LAYOUT.withName("Ipv6")).withName("u"),
+ WORD.withName("si_family") // 地址族
+ );
+
+ // NET_LUID 结构 (64位网络接口标识符)
+ public static final GroupLayout NET_LUID_LAYOUT = MemoryLayout.structLayout(DWORD64.withName("Value"));
+
+ // MIB_UNICASTIPADDRESS_ROW 结构体布局
+ public static final GroupLayout MIB_UNICASTIPADDRESS_ROW_LAYOUT;
+
+ static {
+ // 动态构建结构体布局
+ MemoryLayout[] layouts = {
+ // 键结构
+ SOCKADDR_INET_LAYOUT.withName("Address"), MemoryLayout.paddingLayout(2),
+ NET_LUID_LAYOUT.withName("InterfaceLuid"), DWORD.withName("InterfaceIndex"),
+
+ // 读写字段
+ DWORD.withName("PrefixOrigin"), DWORD.withName("SuffixOrigin"), DWORD.withName("ValidLifetime"),
+ DWORD.withName("PreferredLifetime"), BYTE.withName("OnLinkPrefixLength"),
+ BOOLEAN_LAYOUT.withName("SkipAsSource"), MemoryLayout.paddingLayout(2),
+
+ // 只读字段
+ DWORD.withName("DadState"), SCOPE_ID_LAYOUT.withName("ScopeId"),
+ LARGE_INTEGER_LAYOUT.withName("CreationTimeStamp") };
+
+ MIB_UNICASTIPADDRESS_ROW_LAYOUT = MemoryLayout.structLayout(layouts);
+ }
+
+ // MIB_UNICASTIPADDRESS_TABLE 结构体布局
+ public static final GroupLayout MIB_UNICASTIPADDRESS_TABLE_LAYOUT = MemoryLayout
+ .structLayout(DWORD.withName("NumEntries"), MemoryLayout.paddingLayout(4), POINTER.withName("Table") // 指向MIB_UNICASTIPADDRESS_ROW数组的指针
+ );
+
+ // 前缀来源枚举
+ public enum PrefixOrigin {
+ IpPrefixOriginOther(0), IpPrefixOriginManual(1), IpPrefixOriginWellKnown(2), IpPrefixOriginDhcp(3),
+ IpPrefixOriginRouterAdvertisement(4), IpPrefixOriginUnchanged(1 << 4);
+
+ private final int value;
+
+ PrefixOrigin(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static PrefixOrigin fromValue(int value) {
+ return Arrays.stream(values()).filter(e -> e.value == value).findFirst().orElse(IpPrefixOriginOther);
+ }
+ }
+
+ // 后缀来源枚举
+ public enum SuffixOrigin {
+ IpSuffixOriginOther(0), IpSuffixOriginManual(1), IpSuffixOriginWellKnown(2), IpSuffixOriginDhcp(3),
+ IpSuffixOriginLinkLayerAddress(4), IpSuffixOriginRandom(5), IpSuffixOriginUnchanged(1 << 4);
+
+ private final int value;
+
+ SuffixOrigin(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static SuffixOrigin fromValue(int value) {
+ return Arrays.stream(values()).filter(e -> e.value == value).findFirst().orElse(IpSuffixOriginOther);
+ }
+ }
+
+ // DAD状态枚举
+ public enum DadState {
+ IpDadStateInvalid(0), IpDadStateTentative(1), IpDadStateDuplicate(2), IpDadStateDeprecated(3),
+ IpDadStatePreferred(4);
+
+ private final int value;
+
+ DadState(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static DadState fromValue(int value) {
+ return Arrays.stream(values()).filter(e -> e.value == value).findFirst().orElse(IpDadStateInvalid);
+ }
+ }
+
+ // 地址族枚举
+ public enum AddressFamily {
+ AF_UNSPEC(0), AF_INET(2), AF_INET6(23);
+
+ private final int value;
+
+ AddressFamily(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static AddressFamily fromValue(int value) {
+ return Arrays.stream(values()).filter(e -> e.value == value).findFirst().orElse(AF_UNSPEC);
+ }
+ }
+
+ // Native库加载
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ static {
+ try {
+ // 加载iphlpapi.dll
+ System.loadLibrary("iphlpapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+ } catch (UnsatisfiedLinkError e) {
+ throw new RuntimeException("Failed to load iphlpapi.dll", e);
+ }
+ }
+
+ // Native函数句柄
+ private static final MethodHandle GET_UNICAST_IP_ADDRESS_TABLE;
+ private static final MethodHandle INITIALIZE_UNICAST_IP_ADDRESS_ENTRY;
+ private static final MethodHandle CREATE_UNICAST_IP_ADDRESS_ENTRY;
+ private static final MethodHandle DELETE_UNICAST_IP_ADDRESS_ENTRY;
+ private static final MethodHandle GET_UNICAST_IP_ADDRESS_ENTRY;
+ private static final MethodHandle FREE_MIB_TABLE;
+
+ static {
+ try {
+ // 定义函数描述符
+
+ // DWORD GetUnicastIpAddressTable(
+ // ADDRESS_FAMILY Family,
+ // PMIB_UNICASTIPADDRESS_TABLE *Table
+ // );
+ FunctionDescriptor getUnicastIpAddressTableDesc = FunctionDescriptor.of(DWORD, // 返回值: DWORD
+ DWORD, // Family: ADDRESS_FAMILY
+ POINTER // Table: PMIB_UNICASTIPADDRESS_TABLE*
+ );
+
+ // VOID InitializeUnicastIpAddressEntry(
+ // PMIB_UNICASTIPADDRESS_ROW Row
+ // );
+ FunctionDescriptor initializeUnicastIpAddressEntryDesc = FunctionDescriptor.ofVoid(POINTER // Row:
+ // PMIB_UNICASTIPADDRESS_ROW
+ );
+
+ // DWORD CreateUnicastIpAddressEntry(
+ // const MIB_UNICASTIPADDRESS_ROW *Row
+ // );
+ FunctionDescriptor createUnicastIpAddressEntryDesc = FunctionDescriptor.of(DWORD, // 返回值: DWORD
+ POINTER // Row: const MIB_UNICASTIPADDRESS_ROW*
+ );
+
+ // DWORD DeleteUnicastIpAddressEntry(
+ // const MIB_UNICASTIPADDRESS_ROW *Row
+ // );
+ FunctionDescriptor deleteUnicastIpAddressEntryDesc = FunctionDescriptor.of(DWORD, // 返回值: DWORD
+ POINTER // Row: const MIB_UNICASTIPADDRESS_ROW*
+ );
+
+ // DWORD GetUnicastIpAddressEntry(
+ // PMIB_UNICASTIPADDRESS_ROW Row
+ // );
+ FunctionDescriptor getUnicastIpAddressEntryDesc = FunctionDescriptor.of(DWORD, // 返回值: DWORD
+ POINTER // Row: PMIB_UNICASTIPADDRESS_ROW
+ );
+
+ // VOID FreeMibTable(
+ // PVOID Memory
+ // );
+ FunctionDescriptor freeMibTableDesc = FunctionDescriptor.ofVoid(POINTER // Memory: PVOID
+ );
+
+ // 获取函数句柄
+ GET_UNICAST_IP_ADDRESS_TABLE = LINKER.downcallHandle(LOOKUP.find("GetUnicastIpAddressTable").orElseThrow(),
+ getUnicastIpAddressTableDesc);
+
+ INITIALIZE_UNICAST_IP_ADDRESS_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("InitializeUnicastIpAddressEntry").orElseThrow(), initializeUnicastIpAddressEntryDesc);
+
+ CREATE_UNICAST_IP_ADDRESS_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("CreateUnicastIpAddressEntry").orElseThrow(), createUnicastIpAddressEntryDesc);
+
+ DELETE_UNICAST_IP_ADDRESS_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("DeleteUnicastIpAddressEntry").orElseThrow(), deleteUnicastIpAddressEntryDesc);
+
+ GET_UNICAST_IP_ADDRESS_ENTRY = LINKER.downcallHandle(LOOKUP.find("GetUnicastIpAddressEntry").orElseThrow(),
+ getUnicastIpAddressEntryDesc);
+
+ FREE_MIB_TABLE = LINKER.downcallHandle(LOOKUP.find("FreeMibTable").orElseThrow(), freeMibTableDesc);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows IP address manager", e);
+ }
+ }
+
+ /**
+ * 单播IP地址行(Java表示)
+ */
+ public static class UnicastIPAddressRow {
+ private InetAddress address;
+ private long interfaceLuid;
+ private int interfaceIndex;
+ private PrefixOrigin prefixOrigin;
+ private SuffixOrigin suffixOrigin;
+ private long validLifetime;
+ private long preferredLifetime;
+ private int onLinkPrefixLength;
+ private boolean skipAsSource;
+ private DadState dadState;
+ private long scopeId;
+ private Instant creationTimestamp;
+
+ // 构造方法
+ public UnicastIPAddressRow() {
+ }
+
+ public UnicastIPAddressRow(InetAddress address, long interfaceLuid) {
+ this.address = address;
+ this.interfaceLuid = interfaceLuid;
+ this.interfaceIndex = NET_IFINDEX_UNSPECIFIED;
+ this.prefixOrigin = PrefixOrigin.IpPrefixOriginManual;
+ this.suffixOrigin = SuffixOrigin.IpSuffixOriginManual;
+ this.validLifetime = 0xFFFFFFFFL; // 无限
+ this.preferredLifetime = 0xFFFFFFFFL; // 无限
+ this.onLinkPrefixLength = (address instanceof Inet4Address) ? 32 : 128;
+ this.skipAsSource = false;
+ this.dadState = DadState.IpDadStatePreferred;
+ this.scopeId = 0;
+ this.creationTimestamp = Instant.now();
+ }
+
+ // 从Native内存创建
+ public static UnicastIPAddressRow fromMemorySegment(MemorySegment segment) {
+ UnicastIPAddressRow row = new UnicastIPAddressRow();
+
+ try (Arena arena = Arena.ofConfined()) {
+ // 读取地址
+ int family = segment.get(WORD, 0); // SOCKADDR_INET中的si_family字段
+ AddressFamily addressFamily = AddressFamily.fromValue(family);
+
+ if (addressFamily == AddressFamily.AF_INET) {
+ // IPv4地址
+ byte[] ipv4Bytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ ipv4Bytes[i] = segment.get(BYTE, 4 + i); // sin_addr偏移
+ }
+ row.address = Inet4Address.getByAddress(ipv4Bytes);
+ row.onLinkPrefixLength = 32;
+ } else if (addressFamily == AddressFamily.AF_INET6) {
+ // IPv6地址
+ byte[] ipv6Bytes = new byte[16];
+ MemoryLayout ipv6Layout = SOCKADDR_IN6_LAYOUT;
+ long sin6AddrOffset = 8; // sin6_addr在SOCKADDR_IN6中的偏移
+
+ for (int i = 0; i < 16; i++) {
+ ipv6Bytes[i] = segment.get(BYTE, sin6AddrOffset + i);
+ }
+ row.address = Inet6Address.getByAddress(ipv6Bytes);
+ row.onLinkPrefixLength = 128;
+ }
+
+ // 读取接口LUID
+ long luidOffset = SOCKADDR_INET_LAYOUT.byteSize() + 2;
+ row.interfaceLuid = segment.get(DWORD64, luidOffset);
+
+ // 读取接口索引
+ long indexOffset = luidOffset + NET_LUID_LAYOUT.byteSize();
+ row.interfaceIndex = segment.get(DWORD, indexOffset);
+
+ // 读取其他字段
+ long prefixOriginOffset = indexOffset + DWORD.byteSize();
+ row.prefixOrigin = PrefixOrigin.fromValue(segment.get(DWORD, prefixOriginOffset));
+
+ long suffixOriginOffset = prefixOriginOffset + DWORD.byteSize();
+ row.suffixOrigin = SuffixOrigin.fromValue(segment.get(DWORD, suffixOriginOffset));
+
+ long validLifetimeOffset = suffixOriginOffset + DWORD.byteSize();
+ row.validLifetime = segment.get(DWORD, validLifetimeOffset) & 0xFFFFFFFFL;
+
+ long preferredLifetimeOffset = validLifetimeOffset + DWORD.byteSize();
+ row.preferredLifetime = segment.get(DWORD, preferredLifetimeOffset) & 0xFFFFFFFFL;
+
+ long onLinkPrefixLengthOffset = preferredLifetimeOffset + DWORD.byteSize();
+ row.onLinkPrefixLength = segment.get(BYTE, onLinkPrefixLengthOffset) & 0xFF;
+
+ long skipAsSourceOffset = onLinkPrefixLengthOffset + BYTE.byteSize();
+ row.skipAsSource = segment.get(BOOLEAN_LAYOUT, skipAsSourceOffset);
+
+ long dadStateOffset = skipAsSourceOffset + BOOLEAN_LAYOUT.byteSize() + 2;
+ row.dadState = DadState.fromValue(segment.get(DWORD, dadStateOffset));
+
+ long scopeIdOffset = dadStateOffset + DWORD.byteSize();
+ row.scopeId = segment.get(DWORD, scopeIdOffset) & 0xFFFFFFFFL;
+
+ // 创建时间戳(Windows FILETIME格式,100纳秒间隔自1601-01-01 UTC)
+ long timestampOffset = scopeIdOffset + SCOPE_ID_LAYOUT.byteSize();
+ long filetime = segment.get(DWORD64, timestampOffset);
+ if (filetime != 0) {
+ // 转换为Java Instant (从1601-01-01 UTC到1970-01-01 UTC的间隔)
+ long windowsEpoch = 116444736000000000L; // 1601到1970的100纳秒间隔数
+ long unixNanos = (filetime - windowsEpoch) * 100;
+ row.creationTimestamp = Instant.ofEpochSecond(unixNanos / 1_000_000_000, unixNanos % 1_000_000_000);
+ }
+ } catch (UnknownHostException e) {
+ throw new RuntimeException("Failed to parse IP address", e);
+ }
+
+ return row;
+ }
+
+ // 转换为Native内存
+ public MemorySegment toMemorySegment(Arena arena) {
+ MemorySegment segment = arena.allocate(MIB_UNICASTIPADDRESS_ROW_LAYOUT);
+
+ // 设置地址
+ byte[] addressBytes = address.getAddress();
+ if (address instanceof Inet4Address) {
+ // IPv4
+ segment.set(WORD, 0, (short) AddressFamily.AF_INET.getValue());
+ // 设置IPv4地址
+ segment.set(WORD, 2, (short) 0); // sin_port
+ for (int i = 0; i < 4; i++) {
+ segment.set(BYTE, 4 + i, addressBytes[i]);
+ }
+ // sin_zero填充
+ for (int i = 0; i < 8; i++) {
+ segment.set(BYTE, 8 + i, (byte) 0);
+ }
+ } else if (address instanceof Inet6Address) {
+ // IPv6
+ segment.set(WORD, 0, (short) AddressFamily.AF_INET6.getValue());
+ // 设置IPv6地址
+ segment.set(WORD, 2, (short) 0); // sin6_port
+ segment.set(DWORD, 4, 0); // sin6_flowinfo
+ // sin6_addr
+ for (int i = 0; i < 16; i++) {
+ segment.set(BYTE, 8 + i, addressBytes[i]);
+ }
+ segment.set(DWORD, 24, 0); // sin6_scope_id
+ }
+
+ // 设置接口LUID
+ long luidOffset = SOCKADDR_INET_LAYOUT.byteSize()+2;
+ segment.set(DWORD64, luidOffset, interfaceLuid);
+
+ // 设置接口索引
+ long indexOffset = luidOffset + NET_LUID_LAYOUT.byteSize();
+ segment.set(DWORD, indexOffset, interfaceIndex);
+
+ // 设置其他字段
+ long prefixOriginOffset = indexOffset + DWORD.byteSize();
+ segment.set(DWORD, prefixOriginOffset, prefixOrigin.getValue());
+
+ long suffixOriginOffset = prefixOriginOffset + DWORD.byteSize();
+ segment.set(DWORD, suffixOriginOffset, suffixOrigin.getValue());
+
+ long validLifetimeOffset = suffixOriginOffset + DWORD.byteSize();
+ segment.set(DWORD, validLifetimeOffset, (int) validLifetime);
+
+ long preferredLifetimeOffset = validLifetimeOffset + DWORD.byteSize();
+ segment.set(DWORD, preferredLifetimeOffset, (int) preferredLifetime);
+
+ long onLinkPrefixLengthOffset = preferredLifetimeOffset + DWORD.byteSize();
+ segment.set(BYTE, onLinkPrefixLengthOffset, (byte) onLinkPrefixLength);
+
+ long skipAsSourceOffset = onLinkPrefixLengthOffset + BYTE.byteSize();
+ segment.set(BOOLEAN_LAYOUT, skipAsSourceOffset, skipAsSource);
+
+ long dadStateOffset = skipAsSourceOffset + BOOLEAN_LAYOUT.byteSize()+2;
+ segment.set(DWORD, dadStateOffset, dadState.getValue());
+
+ long scopeIdOffset = dadStateOffset + DWORD.byteSize();
+ segment.set(DWORD, scopeIdOffset, (int) scopeId);
+
+ // 设置创建时间戳
+ long timestampOffset = scopeIdOffset + SCOPE_ID_LAYOUT.byteSize();
+ if (creationTimestamp != null) {
+ long windowsEpoch = 116444736000000000L;
+ long unixNanos = creationTimestamp.getEpochSecond() * 1_000_000_000L + creationTimestamp.getNano();
+ long filetime = windowsEpoch + (unixNanos / 100);
+ segment.set(DWORD64, timestampOffset, filetime);
+ } else {
+ segment.set(DWORD64, timestampOffset, 0L);
+ }
+
+ return segment;
+ }
+
+ // Getters和Setters
+ public InetAddress getAddress() {
+ return address;
+ }
+
+ public void setAddress(InetAddress address) {
+ this.address = address;
+ }
+
+ public long getInterfaceLuid() {
+ return interfaceLuid;
+ }
+
+ public void setInterfaceLuid(long interfaceLuid) {
+ this.interfaceLuid = interfaceLuid;
+ }
+
+ public int getInterfaceIndex() {
+ return interfaceIndex;
+ }
+
+ public void setInterfaceIndex(int interfaceIndex) {
+ this.interfaceIndex = interfaceIndex;
+ }
+
+ public PrefixOrigin getPrefixOrigin() {
+ return prefixOrigin;
+ }
+
+ public void setPrefixOrigin(PrefixOrigin prefixOrigin) {
+ this.prefixOrigin = prefixOrigin;
+ }
+
+ public SuffixOrigin getSuffixOrigin() {
+ return suffixOrigin;
+ }
+
+ public void setSuffixOrigin(SuffixOrigin suffixOrigin) {
+ this.suffixOrigin = suffixOrigin;
+ }
+
+ public long getValidLifetime() {
+ return validLifetime;
+ }
+
+ public void setValidLifetime(long validLifetime) {
+ this.validLifetime = validLifetime;
+ }
+
+ public long getPreferredLifetime() {
+ return preferredLifetime;
+ }
+
+ public void setPreferredLifetime(long preferredLifetime) {
+ this.preferredLifetime = preferredLifetime;
+ }
+
+ public int getOnLinkPrefixLength() {
+ return onLinkPrefixLength;
+ }
+
+ public void setOnLinkPrefixLength(int onLinkPrefixLength) {
+ this.onLinkPrefixLength = onLinkPrefixLength;
+ }
+
+ public boolean isSkipAsSource() {
+ return skipAsSource;
+ }
+
+ public void setSkipAsSource(boolean skipAsSource) {
+ this.skipAsSource = skipAsSource;
+ }
+
+ public DadState getDadState() {
+ return dadState;
+ }
+
+ public void setDadState(DadState dadState) {
+ this.dadState = dadState;
+ }
+
+ public long getScopeId() {
+ return scopeId;
+ }
+
+ public void setScopeId(long scopeId) {
+ this.scopeId = scopeId;
+ }
+
+ public Instant getCreationTimestamp() {
+ return creationTimestamp;
+ }
+
+ public void setCreationTimestamp(Instant creationTimestamp) {
+ this.creationTimestamp = creationTimestamp;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("UnicastIPAddressRow[address=%s, luid=0x%016X, index=%d, prefix=%s, suffix=%s]",
+ address.getHostAddress(), interfaceLuid, interfaceIndex, prefixOrigin, suffixOrigin);
+ }
+ }
+
+ /**
+ * 获取单播IP地址表
+ */
+ public static List getUnicastIpAddressTable(AddressFamily family) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ // 分配指针来接收表
+ MemorySegment tablePtrPtr = arena.allocate(POINTER);
+
+ // 调用GetUnicastIpAddressTable
+ int result = (int) GET_UNICAST_IP_ADDRESS_TABLE.invokeExact(family.getValue(), tablePtrPtr);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetUnicastIpAddressTable failed", result);
+ }
+
+ // 获取表指针
+ MemorySegment tablePtr = tablePtrPtr.get(POINTER, 0);
+ if (tablePtr.equals(MemorySegment.NULL)) {
+ return Collections.emptyList();
+ }
+
+ // 读取表头
+ tablePtr = tablePtr.reinterpret(8);
+ int numEntries = tablePtr.get(DWORD, 0);
+ MemorySegment rowsPtr = tablePtr.reinterpret(8 + numEntries * MIB_UNICASTIPADDRESS_ROW_LAYOUT.byteSize())
+ .asSlice(8);
+
+ List rows = new ArrayList<>();
+
+ // 遍历所有行
+ for (int i = 0; i < numEntries; i++) {
+ MemorySegment rowPtr = rowsPtr.asSlice(i * MIB_UNICASTIPADDRESS_ROW_LAYOUT.byteSize())
+ .reinterpret(MIB_UNICASTIPADDRESS_ROW_LAYOUT.byteSize());
+ UnicastIPAddressRow row = UnicastIPAddressRow.fromMemorySegment(rowPtr);
+ rows.add(row);
+ }
+ FREE_MIB_TABLE.invokeExact(tablePtr);
+
+ return rows;
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting unicast IP address table", e);
+ }
+ }
+
+ /**
+ * 初始化单播IP地址行
+ */
+ public static void initializeUnicastIpAddressEntry(UnicastIPAddressRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ int result = (int) INITIALIZE_UNICAST_IP_ADDRESS_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("InitializeUnicastIpAddressEntry failed", result);
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Error initializing unicast IP address entry", e);
+ }
+ }
+
+ /**
+ * 创建单播IP地址条目
+ */
+ public static void createUnicastIpAddressEntry(UnicastIPAddressRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ int result = (int) CREATE_UNICAST_IP_ADDRESS_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("CreateUnicastIpAddressEntry failed", result);
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Error creating unicast IP address entry", e);
+ }
+ }
+
+ /**
+ * 删除单播IP地址条目
+ */
+ public static void deleteUnicastIpAddressEntry(UnicastIPAddressRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ int result = (int) DELETE_UNICAST_IP_ADDRESS_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR && result != ERROR_NOT_FOUND) {
+ throw new WindowsAPIException("DeleteUnicastIpAddressEntry failed", result);
+ }
+ } catch (Throwable e) {
+ throw new RuntimeException("Error deleting unicast IP address entry", e);
+ }
+ }
+
+ /**
+ * 获取单播IP地址条目
+ */
+ public static UnicastIPAddressRow getUnicastIpAddressEntry(UnicastIPAddressRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ int result = (int) GET_UNICAST_IP_ADDRESS_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetUnicastIpAddressEntry failed", result);
+ }
+
+ // 从内存段读取更新后的行
+ return UnicastIPAddressRow.fromMemorySegment(rowSegment);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting unicast IP address entry", e);
+ }
+ }
+
+ /**
+ * 为Wintun适配器添加IP地址
+ */
+ public static void addIpAddressToAdapter(long adapterLuid, InetAddress address, int prefix)
+ throws WindowsAPIException, UnknownHostException {
+
+ // 创建IP地址行
+ UnicastIPAddressRow row = new UnicastIPAddressRow(address, adapterLuid);
+
+ // 设置前缀长度
+ row.setOnLinkPrefixLength(prefix);
+ // 设置其他参数
+ row.setPrefixOrigin(PrefixOrigin.IpPrefixOriginManual);
+ row.setSuffixOrigin(SuffixOrigin.IpSuffixOriginManual);
+ row.setValidLifetime(0xFFFFFFFFL); // 无限
+ row.setPreferredLifetime(0xFFFFFFFFL); // 无限
+ row.setSkipAsSource(false);
+
+ // 创建IP地址条目
+ createUnicastIpAddressEntry(row);
+ }
+
+ /**
+ * 获取指定接口的所有IP地址
+ */
+ public static List getIpAddressesByInterface(long interfaceLuid) throws WindowsAPIException {
+ List allAddresses = new ArrayList<>();
+
+ // 获取IPv4地址
+ try {
+ List ipv4Addresses = getUnicastIpAddressTable(AddressFamily.AF_INET);
+ allAddresses.addAll(ipv4Addresses.stream().filter(row -> row.getInterfaceLuid() == interfaceLuid)
+ .collect(Collectors.toList()));
+ } catch (Exception e) {
+ // 忽略错误,继续获取IPv6地址
+ }
+
+ // 获取IPv6地址
+ try {
+ List ipv6Addresses = getUnicastIpAddressTable(AddressFamily.AF_INET6);
+ allAddresses.addAll(ipv6Addresses.stream().filter(row -> row.getInterfaceLuid() == interfaceLuid)
+ .collect(Collectors.toList()));
+ } catch (Exception e) {
+ // 忽略错误
+ }
+
+ return allAddresses;
+ }
+
+ /**
+ * 测试方法
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("=== Windows IP Address Manager Test ===");
+
+ // 获取所有IPv4地址
+ System.out.println("\nIPv4 Addresses:");
+ List ipv4Addresses = getUnicastIpAddressTable(AddressFamily.AF_INET);
+ for (UnicastIPAddressRow row : ipv4Addresses) {
+ System.out.println(" " + row);
+ }
+
+ // 获取所有IPv6地址
+ System.out.println("\nIPv6 Addresses:");
+ List ipv6Addresses = getUnicastIpAddressTable(AddressFamily.AF_INET6);
+ for (UnicastIPAddressRow row : ipv6Addresses) {
+ System.out.println(" " + row);
+ }
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 工具方法:将IP地址字符串转换为字节数组
+ */
+ public static byte[] ipStringToBytes(String ipAddress) throws UnknownHostException {
+ return InetAddress.getByName(ipAddress).getAddress();
+ }
+
+ /**
+ * 工具方法:将字节数组转换为IP地址字符串
+ */
+ public static String bytesToIpString(byte[] bytes) throws UnknownHostException {
+ return InetAddress.getByAddress(bytes).getHostAddress();
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsIPInterfaceManager.java b/src/org/kne/cloud/network/tun/WindowsIPInterfaceManager.java
new file mode 100644
index 0000000..3d01fe0
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsIPInterfaceManager.java
@@ -0,0 +1,907 @@
+package org.kne.cloud.network.tun;
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Windows IP 接口配置管理
+ * 提供 GetIpInterfaceEntry 和 SetIpInterfaceEntry 的 Java 绑定
+ */
+public class WindowsIPInterfaceManager {
+
+ // 内存布局定义
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+ public static final ValueLayout.OfBoolean BOOLEAN_LAYOUT = ValueLayout.JAVA_BOOLEAN;
+
+ // 常量定义
+ public static final int NO_ERROR = 0;
+ public static final int AF_INET = 2;
+ public static final int AF_INET6 = 23;
+ public static final int SCOPE_LEVEL_COUNT = 16; // Windows定义的 ScopeLevelCount
+
+ // NL_ROUTER_DISCOVERY_BEHAVIOR 枚举
+ public enum RouterDiscoveryBehavior {
+ RouterDiscoveryDisabled(0),
+ RouterDiscoveryEnabled(1),
+ RouterDiscoveryDhcp(2),
+ RouterDiscoveryUnchanged(-1);
+
+ private final int value;
+ RouterDiscoveryBehavior(int value) { this.value = value; }
+ public int getValue() { return value; }
+ public static RouterDiscoveryBehavior fromValue(int value) {
+ for (RouterDiscoveryBehavior b : values()) {
+ if (b.value == value) return b;
+ }
+ return RouterDiscoveryDisabled;
+ }
+ }
+
+ // NL_LINK_LOCAL_ADDRESS_BEHAVIOR 枚举
+ public enum LinkLocalAddressBehavior {
+ LinkLocalAlwaysOff(0),
+ LinkLocalDelayed(1),
+ LinkLocalAlwaysOn(2),
+ LinkLocalUnchanged(-1);
+
+ private final int value;
+ LinkLocalAddressBehavior(int value) { this.value = value; }
+ public int getValue() { return value; }
+ public static LinkLocalAddressBehavior fromValue(int value) {
+ for (LinkLocalAddressBehavior b : values()) {
+ if (b.value == value) return b;
+ }
+ return LinkLocalAlwaysOff;
+ }
+ }
+
+ // NL_INTERFACE_OFFLOAD_ROD 结构体 (位字段)
+ public static final GroupLayout NL_INTERFACE_OFFLOAD_ROD_LAYOUT = MemoryLayout.structLayout(
+ BYTE.withName("Flags") // 位字段: 1=NlChecksumSupported, 2=NlOptionsSupported, etc.
+ ).withByteAlignment(1);
+
+ // NET_LUID 结构 (64位网络接口标识符)
+ public static final GroupLayout NET_LUID_LAYOUT = MemoryLayout.structLayout(
+ DWORD64.withName("Value")
+ ).withByteAlignment(8);
+
+ // MIB_IPINTERFACE_ROW 结构体布局 (64位系统,简化版本)
+ // 注意:实际结构体大小可能因Windows版本而异,这里使用简化的布局
+ public static final GroupLayout MIB_IPINTERFACE_ROW_LAYOUT;
+
+ static {
+ // 在64位系统上,结构体按照8字节对齐
+ // 这是基于Windows SDK头文件的简化布局
+ MIB_IPINTERFACE_ROW_LAYOUT = MemoryLayout.structLayout(
+ // 键字段
+ WORD.withName("Family"), // ADDRESS_FAMILY (2字节)
+ MemoryLayout.paddingLayout(6), // 填充到8字节对齐
+
+ NET_LUID_LAYOUT.withName("InterfaceLuid"),
+ DWORD.withName("InterfaceIndex"),
+
+ // IP接口属性
+ DWORD.withName("MaxReassemblySize"),
+ DWORD64.withName("InterfaceIdentifier"),
+ DWORD.withName("MinRouterAdvertisementInterval"),
+ DWORD.withName("MaxRouterAdvertisementInterval"),
+ BOOLEAN_LAYOUT.withName("AdvertisingEnabled"),
+ BOOLEAN_LAYOUT.withName("ForwardingEnabled"),
+ BOOLEAN_LAYOUT.withName("WeakHostSend"),
+ BOOLEAN_LAYOUT.withName("WeakHostReceive"),
+ BOOLEAN_LAYOUT.withName("UseAutomaticMetric"),
+ BOOLEAN_LAYOUT.withName("UseNeighborUnreachabilityDetection"),
+ BOOLEAN_LAYOUT.withName("ManagedAddressConfigurationSupported"),
+ BOOLEAN_LAYOUT.withName("OtherStatefulConfigurationSupported"),
+ BOOLEAN_LAYOUT.withName("AdvertiseDefaultRoute"),
+ MemoryLayout.paddingLayout(3), // 填充到4字节对齐
+
+ DWORD.withName("RouterDiscoveryBehavior"),
+
+ DWORD.withName("DadTransmits"),
+ DWORD.withName("BaseReachableTime"),
+ DWORD.withName("RetransmitTime"),
+ DWORD.withName("PathMtuDiscoveryTimeout"),
+
+ DWORD.withName("LinkLocalAddressBehavior"),
+
+ DWORD.withName("LinkLocalAddressTimeout"),
+
+ // ZoneIndices 数组 (16个ULONG)
+ MemoryLayout.sequenceLayout(SCOPE_LEVEL_COUNT, DWORD).withName("ZoneIndices"),
+
+ DWORD.withName("SitePrefixLength"),
+ DWORD.withName("Metric"),
+ DWORD.withName("NlMtu"),
+
+ BOOLEAN_LAYOUT.withName("Connected"),
+ BOOLEAN_LAYOUT.withName("SupportsWakeUpPatterns"),
+ BOOLEAN_LAYOUT.withName("SupportsNeighborDiscovery"),
+ BOOLEAN_LAYOUT.withName("SupportsRouterDiscovery"),
+
+ DWORD.withName("ReachableTime"),
+
+ NL_INTERFACE_OFFLOAD_ROD_LAYOUT.withName("TransmitOffload"),
+ NL_INTERFACE_OFFLOAD_ROD_LAYOUT.withName("ReceiveOffload"),
+ MemoryLayout.paddingLayout(6), // 填充到8字节对齐
+
+ BOOLEAN_LAYOUT.withName("DisableDefaultRoutes"),
+ MemoryLayout.paddingLayout(7) // 填充到8字节对齐
+ ).withByteAlignment(8);
+ }
+
+ // Native库加载
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ // 方法句柄
+ private static final MethodHandle GET_IP_INTERFACE_ENTRY;
+ private static final MethodHandle SET_IP_INTERFACE_ENTRY;
+
+ static {
+ try {
+ // 加载iphlpapi.dll
+ System.loadLibrary("iphlpapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // 定义函数描述符
+
+ // DWORD GetIpInterfaceEntry(
+ // PMIB_IPINTERFACE_ROW Row
+ // );
+ FunctionDescriptor getIpInterfaceEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // Row: PMIB_IPINTERFACE_ROW
+ );
+
+ // DWORD SetIpInterfaceEntry(
+ // PMIB_IPINTERFACE_ROW Row
+ // );
+ FunctionDescriptor setIpInterfaceEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // Row: PMIB_IPINTERFACE_ROW
+ );
+
+ // 获取函数句柄
+ GET_IP_INTERFACE_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("GetIpInterfaceEntry").orElseThrow(),
+ getIpInterfaceEntryDesc
+ );
+
+ SET_IP_INTERFACE_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("SetIpInterfaceEntry").orElseThrow(),
+ setIpInterfaceEntryDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows IP interface manager", e);
+ }
+ }
+
+ /**
+ * MIB_IPINTERFACE_ROW 的 Java 对象表示
+ */
+ public static class MibIpInterfaceRow {
+ private int family;
+ private long interfaceLuid;
+ private int interfaceIndex;
+ private int maxReassemblySize;
+ private long interfaceIdentifier;
+ private int minRouterAdvertisementInterval;
+ private int maxRouterAdvertisementInterval;
+ private boolean advertisingEnabled;
+ private boolean forwardingEnabled;
+ private boolean weakHostSend;
+ private boolean weakHostReceive;
+ private boolean useAutomaticMetric;
+ private boolean useNeighborUnreachabilityDetection;
+ private boolean managedAddressConfigurationSupported;
+ private boolean otherStatefulConfigurationSupported;
+ private boolean advertiseDefaultRoute;
+ private RouterDiscoveryBehavior routerDiscoveryBehavior;
+ private int dadTransmits;
+ private int baseReachableTime;
+ private int retransmitTime;
+ private int pathMtuDiscoveryTimeout;
+ private LinkLocalAddressBehavior linkLocalAddressBehavior;
+ private int linkLocalAddressTimeout;
+ private int[] zoneIndices;
+ private int sitePrefixLength;
+ private int metric;
+ private int nlMtu;
+ private boolean connected;
+ private boolean supportsWakeUpPatterns;
+ private boolean supportsNeighborDiscovery;
+ private boolean supportsRouterDiscovery;
+ private int reachableTime;
+ private byte transmitOffloadFlags;
+ private byte receiveOffloadFlags;
+ private boolean disableDefaultRoutes;
+
+ // 空构造器
+ public MibIpInterfaceRow() {}
+
+ // 从内存段创建对象
+ public static MibIpInterfaceRow fromMemorySegment(MemorySegment segment) {
+ MibIpInterfaceRow row = new MibIpInterfaceRow();
+
+ // 计算字段偏移量
+ // 使用手动计算的偏移量,因为结构体布局复杂
+ long offset = 0;
+
+ row.family = segment.get(WORD, offset);
+ offset += 8; // 2字节 + 6字节填充
+
+ row.interfaceLuid = segment.get(DWORD64, offset);
+ offset += 8;
+
+ row.interfaceIndex = segment.get(DWORD, offset);
+ offset += 4; // 4字节
+
+ row.maxReassemblySize = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.interfaceIdentifier = segment.get(DWORD64, offset);
+ offset += 8;
+
+ row.minRouterAdvertisementInterval = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.maxRouterAdvertisementInterval = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.advertisingEnabled = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.forwardingEnabled = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.weakHostSend = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.weakHostReceive = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.useAutomaticMetric = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.useNeighborUnreachabilityDetection = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.managedAddressConfigurationSupported = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.otherStatefulConfigurationSupported = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.advertiseDefaultRoute = segment.get(BOOLEAN_LAYOUT, offset++);
+
+ offset += 3; // 跳过3字节填充
+
+ row.routerDiscoveryBehavior = RouterDiscoveryBehavior.fromValue(segment.get(DWORD, offset));
+ offset += 4;
+
+ row.dadTransmits = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.baseReachableTime = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.retransmitTime = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.pathMtuDiscoveryTimeout = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.linkLocalAddressBehavior = LinkLocalAddressBehavior.fromValue(segment.get(DWORD, offset));
+ offset += 4;
+
+ row.linkLocalAddressTimeout = segment.get(DWORD, offset);
+ offset += 4;
+
+ // ZoneIndices 数组
+ row.zoneIndices = new int[SCOPE_LEVEL_COUNT];
+ for (int i = 0; i < SCOPE_LEVEL_COUNT; i++) {
+ row.zoneIndices[i] = segment.get(DWORD, offset);
+ offset += 4;
+ }
+
+ row.sitePrefixLength = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.metric = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.nlMtu = segment.get(DWORD, offset);
+ offset += 4;
+
+ row.connected = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.supportsWakeUpPatterns = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.supportsNeighborDiscovery = segment.get(BOOLEAN_LAYOUT, offset++);
+ row.supportsRouterDiscovery = segment.get(BOOLEAN_LAYOUT, offset++);
+
+
+ row.reachableTime = segment.get(DWORD, offset);
+ offset += 4; // 4字节
+
+ row.transmitOffloadFlags = segment.get(BYTE, offset++);
+ offset += 1; // NL_INTERFACE_OFFLOAD_ROD 的填充
+
+ row.receiveOffloadFlags = segment.get(BYTE, offset++);
+ offset += 6; // NL_INTERFACE_OFFLOAD_ROD 的填充 + 填充到8字节对齐
+
+ row.disableDefaultRoutes = segment.get(BOOLEAN_LAYOUT, offset);
+
+ return row;
+ }
+
+ // 将对象转换为内存段
+ public MemorySegment toMemorySegment(Arena arena) {
+ MemorySegment segment = arena.allocate(MIB_IPINTERFACE_ROW_LAYOUT);
+ long offset = 0;
+
+ segment.set(WORD, offset, (short) family);
+ offset += 8; // 2字节 + 6字节填充
+
+ segment.set(DWORD64, offset, interfaceLuid);
+ offset += 8;
+
+ segment.set(DWORD, offset, interfaceIndex);
+ offset += 4; // 4字节
+
+ segment.set(DWORD, offset, maxReassemblySize);
+ offset += 4;
+
+ segment.set(DWORD64, offset, interfaceIdentifier);
+ offset += 8;
+
+ segment.set(DWORD, offset, minRouterAdvertisementInterval);
+ offset += 4;
+
+ segment.set(DWORD, offset, maxRouterAdvertisementInterval);
+ offset += 4;
+
+ segment.set(BOOLEAN_LAYOUT, offset++, advertisingEnabled);
+ segment.set(BOOLEAN_LAYOUT, offset++, forwardingEnabled);
+ segment.set(BOOLEAN_LAYOUT, offset++, weakHostSend);
+ segment.set(BOOLEAN_LAYOUT, offset++, weakHostReceive);
+ segment.set(BOOLEAN_LAYOUT, offset++, useAutomaticMetric);
+ segment.set(BOOLEAN_LAYOUT, offset++, useNeighborUnreachabilityDetection);
+ segment.set(BOOLEAN_LAYOUT, offset++, managedAddressConfigurationSupported);
+ segment.set(BOOLEAN_LAYOUT, offset++, otherStatefulConfigurationSupported);
+ segment.set(BOOLEAN_LAYOUT, offset++, advertiseDefaultRoute);
+
+ offset += 3; // 跳过3字节填充
+
+ if(routerDiscoveryBehavior!=null)
+ segment.set(DWORD, offset, routerDiscoveryBehavior.getValue());
+ offset += 4;
+
+ segment.set(DWORD, offset, dadTransmits);
+ offset += 4;
+
+ segment.set(DWORD, offset, baseReachableTime);
+ offset += 4;
+
+ segment.set(DWORD, offset, retransmitTime);
+ offset += 4;
+
+ segment.set(DWORD, offset, pathMtuDiscoveryTimeout);
+ offset += 4;
+ if(linkLocalAddressBehavior!=null)
+ segment.set(DWORD, offset, linkLocalAddressBehavior.getValue());
+ offset += 4;
+
+ segment.set(DWORD, offset, linkLocalAddressTimeout);
+ offset += 4;
+
+ // ZoneIndices 数组
+ if(zoneIndices!=null)
+ for (int i = 0; i < SCOPE_LEVEL_COUNT; i++) {
+ segment.set(DWORD, offset, zoneIndices[i]);
+ offset += 4;
+ }
+
+ segment.set(DWORD, offset, sitePrefixLength);
+ offset += 4;
+
+ segment.set(DWORD, offset, metric);
+ offset += 4;
+
+ segment.set(DWORD, offset, nlMtu);
+ offset += 4;
+
+ segment.set(BOOLEAN_LAYOUT, offset++, connected);
+ segment.set(BOOLEAN_LAYOUT, offset++, supportsWakeUpPatterns);
+ segment.set(BOOLEAN_LAYOUT, offset++, supportsNeighborDiscovery);
+ segment.set(BOOLEAN_LAYOUT, offset++, supportsRouterDiscovery);
+
+
+ segment.set(DWORD, offset, reachableTime);
+ offset += 4; // 4字节
+
+ segment.set(BYTE, offset++, transmitOffloadFlags);
+ offset += 1; // NL_INTERFACE_OFFLOAD_ROD 的填充
+
+ segment.set(BYTE, offset++, receiveOffloadFlags);
+ offset += 6; // NL_INTERFACE_OFFLOAD_ROD 的填充 + 填充到8字节对齐
+
+ segment.set(BOOLEAN_LAYOUT, offset, disableDefaultRoutes);
+
+ return segment;
+ }
+
+ // 创建简单的构建器方法
+ public static MibIpInterfaceRow createForInterface(long interfaceLuid, int family) {
+ MibIpInterfaceRow row = new MibIpInterfaceRow();
+ row.family = family;
+ row.interfaceLuid = interfaceLuid;
+ row.interfaceIndex = 0; // 将由系统填充
+
+ // 设置合理的默认值
+ row.maxReassemblySize = 65535;
+ row.minRouterAdvertisementInterval = 0;
+ row.maxRouterAdvertisementInterval = 0;
+ row.advertisingEnabled = false;
+ row.forwardingEnabled = false;
+ row.weakHostSend = false;
+ row.weakHostReceive = false;
+ row.useAutomaticMetric = true;
+ row.useNeighborUnreachabilityDetection = true;
+ row.managedAddressConfigurationSupported = false;
+ row.otherStatefulConfigurationSupported = false;
+ row.advertiseDefaultRoute = false;
+ row.routerDiscoveryBehavior = RouterDiscoveryBehavior.RouterDiscoveryDisabled;
+ row.dadTransmits = 0;
+ row.baseReachableTime = 0;
+ row.retransmitTime = 0;
+ row.pathMtuDiscoveryTimeout = 0;
+ row.linkLocalAddressBehavior = LinkLocalAddressBehavior.LinkLocalAlwaysOn;
+ row.linkLocalAddressTimeout = 0;
+
+ row.zoneIndices = new int[SCOPE_LEVEL_COUNT];
+ for (int i = 0; i < SCOPE_LEVEL_COUNT; i++) {
+ row.zoneIndices[i] = 0;
+ }
+
+ row.sitePrefixLength = 0;
+ row.metric = 0; // 自动计算
+ row.nlMtu = 1500; // 默认MTU
+ row.connected = true;
+ row.supportsWakeUpPatterns = false;
+ row.supportsNeighborDiscovery = true;
+ row.supportsRouterDiscovery = false;
+ row.reachableTime = 0;
+ row.transmitOffloadFlags = 0;
+ row.receiveOffloadFlags = 0;
+ row.disableDefaultRoutes = false;
+
+ return row;
+ }
+
+ // Getters 和 Setters (由于字段太多,只列出关键字段)
+ public int getFamily() { return family; }
+ public void setFamily(int family) { this.family = family; }
+
+ public long getInterfaceLuid() { return interfaceLuid; }
+ public void setInterfaceLuid(long interfaceLuid) { this.interfaceLuid = interfaceLuid; }
+
+ public int getInterfaceIndex() { return interfaceIndex; }
+ public void setInterfaceIndex(int interfaceIndex) { this.interfaceIndex = interfaceIndex; }
+
+ public int getNlMtu() { return nlMtu; }
+ public void setNlMtu(int nlMtu) { this.nlMtu = nlMtu; }
+
+ public int getMetric() { return metric; }
+ public void setMetric(int metric) { this.metric = metric; }
+
+ public boolean isForwardingEnabled() { return forwardingEnabled; }
+ public void setForwardingEnabled(boolean forwardingEnabled) { this.forwardingEnabled = forwardingEnabled; }
+
+ public boolean isAdvertisingEnabled() { return advertisingEnabled; }
+ public void setAdvertisingEnabled(boolean advertisingEnabled) { this.advertisingEnabled = advertisingEnabled; }
+
+ public boolean isConnected() { return connected; }
+ public void setConnected(boolean connected) { this.connected = connected; }
+
+ public int getMaxReassemblySize() {
+ return maxReassemblySize;
+ }
+
+ public void setMaxReassemblySize(int maxReassemblySize) {
+ this.maxReassemblySize = maxReassemblySize;
+ }
+
+ public long getInterfaceIdentifier() {
+ return interfaceIdentifier;
+ }
+
+ public void setInterfaceIdentifier(long interfaceIdentifier) {
+ this.interfaceIdentifier = interfaceIdentifier;
+ }
+
+ public int getMinRouterAdvertisementInterval() {
+ return minRouterAdvertisementInterval;
+ }
+
+ public void setMinRouterAdvertisementInterval(int minRouterAdvertisementInterval) {
+ this.minRouterAdvertisementInterval = minRouterAdvertisementInterval;
+ }
+
+ public int getMaxRouterAdvertisementInterval() {
+ return maxRouterAdvertisementInterval;
+ }
+
+ public void setMaxRouterAdvertisementInterval(int maxRouterAdvertisementInterval) {
+ this.maxRouterAdvertisementInterval = maxRouterAdvertisementInterval;
+ }
+
+ public boolean isWeakHostSend() {
+ return weakHostSend;
+ }
+
+ public void setWeakHostSend(boolean weakHostSend) {
+ this.weakHostSend = weakHostSend;
+ }
+
+ public boolean isWeakHostReceive() {
+ return weakHostReceive;
+ }
+
+ public void setWeakHostReceive(boolean weakHostReceive) {
+ this.weakHostReceive = weakHostReceive;
+ }
+
+ public boolean isUseAutomaticMetric() {
+ return useAutomaticMetric;
+ }
+
+ public void setUseAutomaticMetric(boolean useAutomaticMetric) {
+ this.useAutomaticMetric = useAutomaticMetric;
+ }
+
+ public boolean isUseNeighborUnreachabilityDetection() {
+ return useNeighborUnreachabilityDetection;
+ }
+
+ public void setUseNeighborUnreachabilityDetection(boolean useNeighborUnreachabilityDetection) {
+ this.useNeighborUnreachabilityDetection = useNeighborUnreachabilityDetection;
+ }
+
+ public boolean isManagedAddressConfigurationSupported() {
+ return managedAddressConfigurationSupported;
+ }
+
+ public void setManagedAddressConfigurationSupported(boolean managedAddressConfigurationSupported) {
+ this.managedAddressConfigurationSupported = managedAddressConfigurationSupported;
+ }
+
+ public boolean isOtherStatefulConfigurationSupported() {
+ return otherStatefulConfigurationSupported;
+ }
+
+ public void setOtherStatefulConfigurationSupported(boolean otherStatefulConfigurationSupported) {
+ this.otherStatefulConfigurationSupported = otherStatefulConfigurationSupported;
+ }
+
+ public boolean isAdvertiseDefaultRoute() {
+ return advertiseDefaultRoute;
+ }
+
+ public void setAdvertiseDefaultRoute(boolean advertiseDefaultRoute) {
+ this.advertiseDefaultRoute = advertiseDefaultRoute;
+ }
+
+ public RouterDiscoveryBehavior getRouterDiscoveryBehavior() {
+ return routerDiscoveryBehavior;
+ }
+
+ public void setRouterDiscoveryBehavior(RouterDiscoveryBehavior routerDiscoveryBehavior) {
+ this.routerDiscoveryBehavior = routerDiscoveryBehavior;
+ }
+
+ public int getDadTransmits() {
+ return dadTransmits;
+ }
+
+ public void setDadTransmits(int dadTransmits) {
+ this.dadTransmits = dadTransmits;
+ }
+
+ public int getBaseReachableTime() {
+ return baseReachableTime;
+ }
+
+ public void setBaseReachableTime(int baseReachableTime) {
+ this.baseReachableTime = baseReachableTime;
+ }
+
+ public int getRetransmitTime() {
+ return retransmitTime;
+ }
+
+ public void setRetransmitTime(int retransmitTime) {
+ this.retransmitTime = retransmitTime;
+ }
+
+ public int getPathMtuDiscoveryTimeout() {
+ return pathMtuDiscoveryTimeout;
+ }
+
+ public void setPathMtuDiscoveryTimeout(int pathMtuDiscoveryTimeout) {
+ this.pathMtuDiscoveryTimeout = pathMtuDiscoveryTimeout;
+ }
+
+ public LinkLocalAddressBehavior getLinkLocalAddressBehavior() {
+ return linkLocalAddressBehavior;
+ }
+
+ public void setLinkLocalAddressBehavior(LinkLocalAddressBehavior linkLocalAddressBehavior) {
+ this.linkLocalAddressBehavior = linkLocalAddressBehavior;
+ }
+
+ public int getLinkLocalAddressTimeout() {
+ return linkLocalAddressTimeout;
+ }
+
+ public void setLinkLocalAddressTimeout(int linkLocalAddressTimeout) {
+ this.linkLocalAddressTimeout = linkLocalAddressTimeout;
+ }
+
+ public int[] getZoneIndices() {
+ return zoneIndices;
+ }
+
+ public void setZoneIndices(int[] zoneIndices) {
+ this.zoneIndices = zoneIndices;
+ }
+
+ public int getSitePrefixLength() {
+ return sitePrefixLength;
+ }
+
+ public void setSitePrefixLength(int sitePrefixLength) {
+ this.sitePrefixLength = sitePrefixLength;
+ }
+
+ public boolean isSupportsWakeUpPatterns() {
+ return supportsWakeUpPatterns;
+ }
+
+ public void setSupportsWakeUpPatterns(boolean supportsWakeUpPatterns) {
+ this.supportsWakeUpPatterns = supportsWakeUpPatterns;
+ }
+
+ public boolean isSupportsNeighborDiscovery() {
+ return supportsNeighborDiscovery;
+ }
+
+ public void setSupportsNeighborDiscovery(boolean supportsNeighborDiscovery) {
+ this.supportsNeighborDiscovery = supportsNeighborDiscovery;
+ }
+
+ public boolean isSupportsRouterDiscovery() {
+ return supportsRouterDiscovery;
+ }
+
+ public void setSupportsRouterDiscovery(boolean supportsRouterDiscovery) {
+ this.supportsRouterDiscovery = supportsRouterDiscovery;
+ }
+
+ public int getReachableTime() {
+ return reachableTime;
+ }
+
+ public void setReachableTime(int reachableTime) {
+ this.reachableTime = reachableTime;
+ }
+
+ public byte getTransmitOffloadFlags() {
+ return transmitOffloadFlags;
+ }
+
+ public void setTransmitOffloadFlags(byte transmitOffloadFlags) {
+ this.transmitOffloadFlags = transmitOffloadFlags;
+ }
+
+ public byte getReceiveOffloadFlags() {
+ return receiveOffloadFlags;
+ }
+
+ public void setReceiveOffloadFlags(byte receiveOffloadFlags) {
+ this.receiveOffloadFlags = receiveOffloadFlags;
+ }
+
+ public boolean isDisableDefaultRoutes() {
+ return disableDefaultRoutes;
+ }
+
+ public void setDisableDefaultRoutes(boolean disableDefaultRoutes) {
+ this.disableDefaultRoutes = disableDefaultRoutes;
+ }
+
+ @Override
+ public String toString() {
+ return "MibIpInterfaceRow [family=" + family + ", interfaceLuid=" + interfaceLuid + ", interfaceIndex="
+ + interfaceIndex + ", maxReassemblySize=" + maxReassemblySize + ", interfaceIdentifier="
+ + interfaceIdentifier + ", minRouterAdvertisementInterval=" + minRouterAdvertisementInterval
+ + ", maxRouterAdvertisementInterval=" + maxRouterAdvertisementInterval + ", advertisingEnabled="
+ + advertisingEnabled + ", forwardingEnabled=" + forwardingEnabled + ", weakHostSend=" + weakHostSend
+ + ", weakHostReceive=" + weakHostReceive + ", useAutomaticMetric=" + useAutomaticMetric
+ + ", useNeighborUnreachabilityDetection=" + useNeighborUnreachabilityDetection
+ + ", managedAddressConfigurationSupported=" + managedAddressConfigurationSupported
+ + ", otherStatefulConfigurationSupported=" + otherStatefulConfigurationSupported
+ + ", advertiseDefaultRoute=" + advertiseDefaultRoute + ", routerDiscoveryBehavior="
+ + routerDiscoveryBehavior + ", dadTransmits=" + dadTransmits + ", baseReachableTime="
+ + baseReachableTime + ", retransmitTime=" + retransmitTime + ", pathMtuDiscoveryTimeout="
+ + pathMtuDiscoveryTimeout + ", linkLocalAddressBehavior=" + linkLocalAddressBehavior
+ + ", linkLocalAddressTimeout=" + linkLocalAddressTimeout + ", zoneIndices="
+ + Arrays.toString(zoneIndices) + ", sitePrefixLength=" + sitePrefixLength + ", metric=" + metric
+ + ", nlMtu=" + nlMtu + ", connected=" + connected + ", supportsWakeUpPatterns="
+ + supportsWakeUpPatterns + ", supportsNeighborDiscovery=" + supportsNeighborDiscovery
+ + ", supportsRouterDiscovery=" + supportsRouterDiscovery + ", reachableTime=" + reachableTime
+ + ", transmitOffloadFlags=" + transmitOffloadFlags + ", receiveOffloadFlags=" + receiveOffloadFlags
+ + ", disableDefaultRoutes=" + disableDefaultRoutes + "]";
+ }
+ }
+
+ /**
+ * 获取 IP 接口条目
+ * @param row 包含接口标识信息的行,函数会填充其他字段
+ * @return 填充后的接口行
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static MibIpInterfaceRow getIpInterfaceEntry(MibIpInterfaceRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ // 创建内存段
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ // 调用 GetIpInterfaceEntry
+ int result = (int) GET_IP_INTERFACE_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetIpInterfaceEntry failed", result);
+ }
+
+ // 从内存段读取更新后的行
+ return MibIpInterfaceRow.fromMemorySegment(rowSegment);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling GetIpInterfaceEntry", e);
+ }
+ }
+
+ /**
+ * 设置 IP 接口条目
+ * @param row 要设置的接口行
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static void setIpInterfaceEntry(MibIpInterfaceRow row) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ // 创建内存段
+ MemorySegment rowSegment = row.toMemorySegment(arena);
+
+ // 调用 SetIpInterfaceEntry
+ int result = (int) SET_IP_INTERFACE_ENTRY.invokeExact(rowSegment);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("SetIpInterfaceEntry failed", result);
+ }
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling SetIpInterfaceEntry", e);
+ }
+ }
+
+ /**
+ * 获取指定接口的 IP 接口信息
+ * @param interfaceLuid 接口 LUID
+ * @param family 地址族 (AF_INET 或 AF_INET6)
+ * @return 接口信息
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static MibIpInterfaceRow getInterfaceInfo(long interfaceLuid, int family) throws WindowsAPIException {
+ // 创建只包含键字段的行
+ MibIpInterfaceRow row = new MibIpInterfaceRow();
+ row.setFamily(family);
+ row.setInterfaceLuid(interfaceLuid);
+ row.setInterfaceIndex(0); // 将由系统填充
+
+ // 获取完整信息
+ return getIpInterfaceEntry(row);
+ }
+
+ /**
+ * 设置接口的 MTU
+ * @param interfaceLuid 接口 LUID
+ * @param family 地址族 (AF_INET 或 AF_INET6)
+ * @param mtu MTU 值
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static void setInterfaceMtu(long interfaceLuid, int family, int mtu) throws WindowsAPIException {
+ // 1. 获取当前配置
+ MibIpInterfaceRow row = getInterfaceInfo(interfaceLuid, family);
+ row.setSitePrefixLength(0);
+ // 2. 修改 MTU
+ row.setNlMtu(mtu);
+
+ // 3. 设置回系统
+ setIpInterfaceEntry(row);
+ }
+
+ /**
+ * 设置接口的路由度量值
+ * @param interfaceLuid 接口 LUID
+ * @param family 地址族 (AF_INET 或 AF_INET6)
+ * @param metric 度量值 (越小优先级越高)
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static void setInterfaceMetric(long interfaceLuid, int family, int metric) throws WindowsAPIException {
+ // 1. 获取当前配置
+ MibIpInterfaceRow row = getInterfaceInfo(interfaceLuid, family);
+
+ // 2. 修改度量值
+ row.setMetric(metric);
+
+ // 3. 设置回系统
+ setIpInterfaceEntry(row);
+ }
+
+ /**
+ * 启用/禁用接口的 IP 转发
+ * @param interfaceLuid 接口 LUID
+ * @param family 地址族 (AF_INET 或 AF_INET6)
+ * @param enable 是否启用转发
+ * @throws WindowsAPIException 如果操作失败
+ */
+ public static void setInterfaceForwarding(long interfaceLuid, int family, boolean enable) throws WindowsAPIException {
+ // 1. 获取当前配置
+ MibIpInterfaceRow row = getInterfaceInfo(interfaceLuid, family);
+
+ // 2. 修改转发设置
+ row.setForwardingEnabled(enable);
+
+ // 3. 设置回系统
+ setIpInterfaceEntry(row);
+ }
+
+
+ /**
+ * 测试方法
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("=== Windows IP Interface Manager Test ===");
+
+ // 示例:假设我们有一个 Wintun 适配器的 LUID
+ long wintunLuid = 14918723638919168L;
+
+ System.out.println("\n1. Testing IPv4 interface info:");
+ try {
+ MibIpInterfaceRow ipv4Info = getInterfaceInfo(wintunLuid, AF_INET);
+ System.out.println(" " + ipv4Info);
+ System.out.println(" Current MTU: " + ipv4Info.getNlMtu());
+ System.out.println(" Current metric: " + ipv4Info.getMetric());
+ System.out.println(" Forwarding enabled: " + ipv4Info.isForwardingEnabled());
+ } catch (WindowsAPIException e) {
+ System.out.println(" Failed to get IPv4 info: " + e.getMessage());
+ }
+
+ System.out.println("\n2. Testing IPv6 interface info:");
+ try {
+ MibIpInterfaceRow ipv6Info = getInterfaceInfo(wintunLuid, AF_INET6);
+ System.out.println(" " + ipv6Info);
+ System.out.println(" Current MTU: " + ipv6Info.getNlMtu());
+ System.out.println(" Current metric: " + ipv6Info.getMetric());
+ System.out.println(" Forwarding enabled: " + ipv6Info.isForwardingEnabled());
+ } catch (WindowsAPIException e) {
+ System.out.println(" Failed to get IPv6 info: " + e.getMessage());
+ }
+
+ System.out.println("\n3. Testing MTU setting:");
+ try {
+ // 注意:需要管理员权限
+ setInterfaceMtu(wintunLuid, AF_INET, 1800);
+ System.out.println(" Set IPv4 MTU to 1800");
+ System.out.println(" (MTU setting requires administrator privileges)");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ System.out.println("\nTest completed!");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsInterfaceConverter.java b/src/org/kne/cloud/network/tun/WindowsInterfaceConverter.java
new file mode 100644
index 0000000..2630000
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsInterfaceConverter.java
@@ -0,0 +1,417 @@
+package org.kne.cloud.network.tun;
+import java.lang.classfile.AnnotationValue.OfLong;
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ * Windows 网络接口 LUID 和 GUID 转换工具类
+ * 提供 ConvertInterfaceLuidToGuid 和 ConvertInterfaceGuidToLuid 的 Java 实现
+ */
+public class WindowsInterfaceConverter {
+
+ // Windows API 常量
+ private static final long INVALID_LUID_VALUE = 0L;
+
+ // 内存布局
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+
+ // GUID 结构布局 (128位,16字节)
+ public static final GroupLayout GUID_LAYOUT = MemoryLayout.structLayout(
+ ValueLayout.JAVA_INT.withName("Data1"), // unsigned long
+ ValueLayout.JAVA_SHORT.withName("Data2"), // unsigned short
+ ValueLayout.JAVA_SHORT.withName("Data3"), // unsigned short
+ MemoryLayout.sequenceLayout(8, ValueLayout.JAVA_BYTE).withName("Data4") // unsigned char[8]
+ ).withByteAlignment(4);
+
+ // LUID 结构布局 (64位)
+ public static final GroupLayout LUID_LAYOUT = MemoryLayout.structLayout(
+ ValueLayout.JAVA_LONG.withName("Value") // unsigned __int64
+ );
+
+ // NET_LUID 联合布局 (Windows中的NET_LUID可以是LUID或IF_INDEX)
+ public static final GroupLayout NET_LUID_LAYOUT = MemoryLayout.structLayout(
+ MemoryLayout.unionLayout(
+ MemoryLayout.structLayout(
+ ValueLayout.JAVA_LONG.withName("Value") // LUID
+ ).withName("Luid"),
+ MemoryLayout.structLayout(
+ MemoryLayout.paddingLayout(24),
+ ValueLayout.JAVA_INT.withName("Reserved"), // 保留字段
+ ValueLayout.JAVA_INT.withName("NetLuidIndex"), // 网络LUID索引
+ ValueLayout.JAVA_INT.withName("IfIndex") // 接口索引
+ ).withName("Info")
+ ).withName("u")
+ );
+
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+ private static final Arena GLOBAL_ARENA = Arena.ofAuto();
+
+ // 方法句柄
+ private static final MethodHandle CONVERT_LUID_TO_GUID;
+ private static final MethodHandle CONVERT_GUID_TO_LUID;
+
+ static {
+ try {
+ // 加载 iphlpapi.dll
+ System.loadLibrary("iphlpapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // 定义函数描述符
+ // DWORD ConvertInterfaceLuidToGuid(const NET_LUID *Luid, GUID *Guid);
+ FunctionDescriptor luidToGuidDesc = FunctionDescriptor.of(
+ ValueLayout.JAVA_INT, // DWORD 返回值
+ POINTER, // const NET_LUID *Luid
+ POINTER // GUID *Guid
+ );
+
+ // DWORD ConvertInterfaceGuidToLuid(const GUID *Guid, NET_LUID *Luid);
+ FunctionDescriptor guidToLuidDesc = FunctionDescriptor.of(
+ ValueLayout.JAVA_INT, // DWORD 返回值
+ POINTER, // const GUID *Guid
+ POINTER // NET_LUID *Luid
+ );
+
+ // 获取方法句柄
+ CONVERT_LUID_TO_GUID = LINKER.downcallHandle(
+ LOOKUP.find("ConvertInterfaceLuidToGuid").orElseThrow(),
+ luidToGuidDesc
+ );
+
+ CONVERT_GUID_TO_LUID = LINKER.downcallHandle(
+ LOOKUP.find("ConvertInterfaceGuidToLuid").orElseThrow(),
+ guidToLuidDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows interface converter", e);
+ }
+ }
+
+ /**
+ * LUID 结构
+ */
+ public static class LUID {
+ private final long value;
+
+ public LUID(long value) {
+ this.value = value;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ public static LUID fromMemorySegment(MemorySegment segment) {
+ if (segment.byteSize() < 8) {
+ throw new IllegalArgumentException("Memory segment too small for LUID");
+ }
+ long value = segment.get(ValueLayout.JAVA_LONG, 0);
+ return new LUID(value);
+ }
+
+ public MemorySegment toMemorySegment(Arena arena) {
+ MemorySegment segment = arena.allocate(LUID_LAYOUT);
+ segment.set(ValueLayout.JAVA_LONG, 0, value);
+ return segment;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("0x%016X", value);
+ }
+ }
+
+ /**
+ * GUID 结构
+ */
+ public static class GUID {
+ private final UUID uuid;
+
+ public GUID(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ public GUID(String guidString) {
+ this.uuid = UUID.fromString(guidString);
+ }
+
+ public GUID(int data1, short data2, short data3, byte[] data4) {
+ if (data4.length != 8) {
+ throw new IllegalArgumentException("Data4 must be exactly 8 bytes");
+ }
+
+ long mostSigBits = (((long) data1) << 32) | (((long)( data2&0xffff) )<< 16) | (long)(data3&0xffff);
+ ByteBuffer bb = ByteBuffer.wrap(data4).order(ByteOrder.BIG_ENDIAN);
+ long leastSigBits = bb.getLong();
+
+ this.uuid = new UUID(mostSigBits, leastSigBits);
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public static GUID fromMemorySegment(MemorySegment segment) {
+ if (segment.byteSize() < GUID_LAYOUT.byteSize()) {
+ throw new IllegalArgumentException("Memory segment too small for GUID");
+ }
+
+ int data1 = segment.get(ValueLayout.JAVA_INT, 0);
+ short data2 = segment.get(ValueLayout.JAVA_SHORT, 4);
+ short data3 = segment.get(ValueLayout.JAVA_SHORT, 6);
+
+ byte[] data4 = new byte[8];
+ MemorySegment data4Segment = segment.asSlice(8, 8);
+ for (int i = 0; i < 8; i++) {
+ data4[i] = data4Segment.get(ValueLayout.JAVA_BYTE, i);
+ }
+
+ return new GUID(data1, data2, data3, data4);
+ }
+
+ public MemorySegment toMemorySegment(Arena arena) {
+ MemorySegment segment = arena.allocate(GUID_LAYOUT);
+
+ long mostSigBits = uuid.getMostSignificantBits();
+ long leastSigBits = uuid.getLeastSignificantBits();
+
+ // Data1 = 高32位
+ int data1 = (int) (mostSigBits >> 32);
+ // Data2 = 接下来的16位
+ short data2 = (short) ((mostSigBits >> 16) & 0xFFFF);
+ // Data3 = 最后的16位
+ short data3 = (short) (mostSigBits & 0xFFFF);
+
+ segment.set(ValueLayout.JAVA_INT, 0, data1);
+ segment.set(ValueLayout.JAVA_SHORT, 4, data2);
+ segment.set(ValueLayout.JAVA_SHORT, 6, data3);
+
+ // Data4 = 低64位的字节数组
+ ByteBuffer bb = ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN);
+ bb.putLong(leastSigBits);
+ byte[] data4 = bb.array();
+
+ MemorySegment data4Segment = segment.asSlice(8, 8);
+ for (int i = 0; i < 8; i++) {
+ data4Segment.set(ValueLayout.JAVA_BYTE, i, data4[i]);
+ }
+
+ return segment;
+ }
+
+ @Override
+ public String toString() {
+ return uuid.toString().toUpperCase();
+ }
+
+ public String toRegistryFormat() {
+ return "{" + toString() + "}";
+ }
+ }
+
+ /**
+ * 将 LUID 转换为 GUID
+ * @param luid LUID 值
+ * @return 对应的 GUID
+ */
+ public static GUID convertLuidToGuid(LUID luid) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 准备 NET_LUID 结构
+ MemorySegment netLuid = arena.allocate(NET_LUID_LAYOUT);
+ netLuid.set(ValueLayout.JAVA_LONG, 0, luid.getValue());
+
+ // 准备 GUID 输出缓冲区
+ MemorySegment guidBuffer = arena.allocate(GUID_LAYOUT);
+
+ // 调用 Windows API
+ int result = (int) CONVERT_LUID_TO_GUID.invokeExact(
+ netLuid,
+ guidBuffer
+ );
+
+ // 检查结果
+ if (result != 0) { // NO_ERROR = 0
+ throw new WindowsAPIException("ConvertInterfaceLuidToGuid failed with error: " + result);
+ }
+
+ return GUID.fromMemorySegment(guidBuffer);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error converting LUID to GUID", e);
+ }
+ }
+
+ /**
+ * 将 LUID 转换为 GUID(简化版本)
+ * @param luidValue LUID 的 long 值
+ * @return 对应的 GUID
+ */
+ public static GUID convertLuidToGuid(long luidValue) {
+ return convertLuidToGuid(new LUID(luidValue));
+ }
+
+ /**
+ * 将 GUID 转换为 LUID
+ * @param guid GUID
+ * @return 对应的 LUID
+ */
+ public static LUID convertGuidToLuid(GUID guid) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 准备 GUID 结构
+ MemorySegment guidBuffer = guid.toMemorySegment(arena);
+
+ // 准备 NET_LUID 输出缓冲区
+ MemorySegment netLuidBuffer = arena.allocate(NET_LUID_LAYOUT);
+
+ // 调用 Windows API
+ int result = (int) CONVERT_GUID_TO_LUID.invokeExact(
+ guidBuffer,
+ netLuidBuffer
+ );
+
+ // 检查结果
+ if (result != 0) { // NO_ERROR = 0
+ throw new WindowsAPIException("ConvertInterfaceGuidToLuid failed with error: " + result);
+ }
+
+ // 从 NET_LUID 结构中提取 LUID 值
+ long luidValue = netLuidBuffer.get(ValueLayout.JAVA_LONG, 0);
+ return new LUID(luidValue);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error converting GUID to LUID", e);
+ }
+ }
+
+ /**
+ * 将 GUID 字符串转换为 LUID
+ * @param guidString GUID 字符串
+ * @return 对应的 LUID
+ */
+ public static LUID convertGuidToLuid(String guidString) {
+ return convertGuidToLuid(new GUID(guidString));
+ }
+
+ /**
+ * 获取所有网络接口的 LUID 和 GUID 映射
+ * @return LUID 到 GUID 的映射
+ */
+ public static java.util.Map getAllNetworkInterfaces() {
+ // 注意:这个函数需要更多的 Windows API 调用
+ // 这里只是示例,实际实现需要调用 GetAdaptersAddresses 等函数
+ java.util.Map interfaces = new java.util.HashMap<>();
+
+ try {
+ // 这里可以添加调用 GetAdaptersAddresses 的代码
+ // 遍历所有适配器,获取它们的 LUID 和 GUID
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return interfaces;
+ }
+
+ /**
+ * Windows API 异常
+ */
+ public static class WindowsAPIException extends RuntimeException {
+ private final int errorCode;
+
+ public WindowsAPIException(String message) {
+ super(message);
+ this.errorCode = -1;
+ }
+
+ public WindowsAPIException(String message, int errorCode) {
+ super(message + " (Error code: " + errorCode + ")");
+ this.errorCode = errorCode;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+ }
+
+ /**
+ * 测试方法
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("Windows Interface Converter Test");
+ System.out.println("=================================");
+
+ // 测试 1: 创建一个测试 GUID 并转换
+ String testGuidStr = "12345678-1234-1234-1234-123456789012";
+ System.out.println("Test GUID: " + testGuidStr);
+
+ GUID testGuid = new GUID(testGuidStr);
+ System.out.println("Created GUID: " + testGuid);
+
+ // 尝试将 GUID 转换为 LUID
+ try {
+ LUID luidFromGuid = convertGuidToLuid(testGuid);
+ System.out.println("LUID from GUID: " + luidFromGuid);
+
+ // 再转换回 GUID
+ GUID guidFromLuid = convertLuidToGuid(luidFromGuid);
+ System.out.println("GUID from LUID: " + guidFromLuid);
+ System.out.println("Conversion successful: " + guidFromLuid.equals(testGuid));
+ } catch (Exception e) {
+ System.out.println("Note: This GUID might not correspond to a real interface: " + e.getMessage());
+ }
+
+ System.out.println("\nTesting with Wintun adapter:");
+ System.out.println("=============================");
+
+ // 测试 2: 与 Wintun 驱动结合使用
+ // 假设你已经有了一个 Wintun 适配器
+ // 这里展示如何获取适配器的 LUID 并转换为 GUID
+
+ // 这段代码需要在有 Wintun 适配器的情况下运行
+
+ WintunDriver.WintunAdapterHandle adapter = WintunDriver.openAdapter("MyWintun");
+ long luid = WintunDriver.getAdapterLuid(adapter);
+ LUID adapterLuid = new LUID(luid);
+ System.out.println("Wintun Adapter LUID: " + adapterLuid);
+
+ GUID adapterGuid = convertLuidToGuid(adapterLuid);
+ System.out.println("Wintun Adapter GUID: " + adapterGuid);
+
+ // 清理
+ WintunDriver.closeAdapter(adapter);
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 辅助方法:从字节数组创建 GUID
+ */
+ public static GUID createGuidFromBytes(byte[] bytes) {
+ if (bytes.length != 16) {
+ throw new IllegalArgumentException("GUID must be 16 bytes");
+ }
+
+ ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
+ long mostSigBits = bb.getLong();
+ long leastSigBits = bb.getLong();
+
+ return new GUID(new UUID(mostSigBits, leastSigBits));
+ }
+
+ /**
+ * 辅助方法:将 GUID 转换为字节数组
+ */
+ public static byte[] guidToBytes(GUID guid) {
+ ByteBuffer bb = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN);
+ bb.putLong(guid.getUuid().getMostSignificantBits());
+ bb.putLong(guid.getUuid().getLeastSignificantBits());
+ return bb.array();
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsInterfaceManager.java b/src/org/kne/cloud/network/tun/WindowsInterfaceManager.java
new file mode 100644
index 0000000..b03027a
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsInterfaceManager.java
@@ -0,0 +1,998 @@
+package org.kne.cloud.network.tun;
+
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.util.*;
+
+import org.kne.cloud.network.tun.WindowsInterfaceManager2.MibIfRow;
+
+/**
+ * Windows 网络接口管理类
+ * 实现 GetIfEntry、SetIfEntry、GetIfTable 和 FreeMibTable 功能
+ */
+public class WindowsInterfaceManager {
+
+ // 内存布局
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+
+ // 常量定义
+ public static final int MAX_INTERFACE_NAME_LEN = 256;
+ public static final int MAXLEN_PHYSADDR = 32;
+ public static final int MAXLEN_IFDESCR = 256;
+ public static final int NO_ERROR = 0;
+
+ // MIB_IFTABLE 结构体布局
+ public static final GroupLayout MIB_IFTABLE_LAYOUT = MemoryLayout.structLayout(
+ DWORD.withName("dwNumEntries"),
+ MemoryLayout.paddingLayout(4),
+ POINTER.withName("table") // 指向MIB_IFROW数组的指针
+ ).withByteAlignment(8);
+
+ // MIB_IFROW 结构体布局
+ public static final GroupLayout MIB_IFROW_LAYOUT;
+
+ static {
+ // 手动计算偏移量以确保正确对齐
+ // 注意:所有字段都是 4 字节对齐的
+ long offset = 0;
+
+ // 1. wszName: WCHAR[MAX_INTERFACE_NAME_LEN] (512 字节)
+ // 需要 2 字节对齐,但结构体开始通常是 4 字节对齐
+ var wszNameLayout = MemoryLayout.sequenceLayout(MAX_INTERFACE_NAME_LEN, WORD)
+ .withName("wszName")
+ .withByteAlignment(2);
+
+ offset += MAX_INTERFACE_NAME_LEN * 2; // 512 字节
+
+ // 2. dwIndex: IF_INDEX (4 字节)
+ // offset = 512, 是 4 的倍数
+ var dwIndexLayout = DWORD
+ .withName("dwIndex")
+ .withByteAlignment(4);
+
+ offset += 4; // 516 字节
+
+ // 3. dwType: IFTYPE (4 字节)
+ // offset = 516, 是 4 的倍数
+ var dwTypeLayout = DWORD
+ .withName("dwType")
+ .withByteAlignment(4);
+
+ offset += 4; // 520 字节
+
+ // 4. dwMtu: DWORD (4 字节)
+ // offset = 520, 是 4 的倍数
+ var dwMtuLayout = DWORD
+ .withName("dwMtu")
+ .withByteAlignment(4);
+
+ offset += 4; // 524 字节
+
+ // 5. dwSpeed: DWORD (4 字节)
+ // offset = 524, 是 4 的倍数
+ var dwSpeedLayout = DWORD
+ .withName("dwSpeed")
+ .withByteAlignment(4);
+
+ offset += 4; // 528 字节
+
+ // 6. dwPhysAddrLen: DWORD (4 字节)
+ // offset = 528, 是 4 的倍数
+ var dwPhysAddrLenLayout = DWORD
+ .withName("dwPhysAddrLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 532 字节
+
+ // 7. bPhysAddr: UCHAR[MAXLEN_PHYSADDR] (32 字节)
+ // offset = 532, 是 1 的倍数,但数组本身 1 字节对齐
+ // 实际上需要 4 字节对齐,532 是 4 的倍数 (532 % 4 = 0)
+ var bPhysAddrLayout = MemoryLayout.sequenceLayout(MAXLEN_PHYSADDR, BYTE)
+ .withName("bPhysAddr")
+ .withByteAlignment(1);
+
+ offset += MAXLEN_PHYSADDR; // 564 字节
+
+ // 8. dwAdminStatus: DWORD (4 字节)
+ // offset = 564, 是 4 的倍数
+ var dwAdminStatusLayout = DWORD
+ .withName("dwAdminStatus")
+ .withByteAlignment(4);
+
+ offset += 4; // 568 字节
+
+ // 9. dwOperStatus: INTERNAL_IF_OPER_STATUS (4 字节)
+ // offset = 568, 是 4 的倍数
+ var dwOperStatusLayout = DWORD
+ .withName("dwOperStatus")
+ .withByteAlignment(4);
+
+ offset += 4; // 572 字节
+
+ // 10. dwLastChange: DWORD (4 字节)
+ // offset = 572, 是 4 的倍数
+ var dwLastChangeLayout = DWORD
+ .withName("dwLastChange")
+ .withByteAlignment(4);
+
+ offset += 4; // 576 字节
+
+ // 11. dwInOctets: DWORD (4 字节)
+ // offset = 576, 是 4 的倍数
+ var dwInOctetsLayout = DWORD
+ .withName("dwInOctets")
+ .withByteAlignment(4);
+
+ offset += 4; // 580 字节
+
+ // 12. dwInUcastPkts: DWORD (4 字节)
+ // offset = 580, 是 4 的倍数
+ var dwInUcastPktsLayout = DWORD
+ .withName("dwInUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 584 字节
+
+ // 13. dwInNUcastPkts: DWORD (4 字节)
+ // offset = 584, 是 4 的倍数
+ var dwInNUcastPktsLayout = DWORD
+ .withName("dwInNUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 588 字节
+
+ // 14. dwInDiscards: DWORD (4 字节)
+ // offset = 588, 是 4 的倍数
+ var dwInDiscardsLayout = DWORD
+ .withName("dwInDiscards")
+ .withByteAlignment(4);
+
+ offset += 4; // 592 字节
+
+ // 15. dwInErrors: DWORD (4 字节)
+ // offset = 592, 是 4 的倍数
+ var dwInErrorsLayout = DWORD
+ .withName("dwInErrors")
+ .withByteAlignment(4);
+
+ offset += 4; // 596 字节
+
+ // 16. dwInUnknownProtos: DWORD (4 字节)
+ // offset = 596, 是 4 的倍数
+ var dwInUnknownProtosLayout = DWORD
+ .withName("dwInUnknownProtos")
+ .withByteAlignment(4);
+
+ offset += 4; // 600 字节
+
+ // 17. dwOutOctets: DWORD (4 字节)
+ // offset = 600, 是 4 的倍数
+ var dwOutOctetsLayout = DWORD
+ .withName("dwOutOctets")
+ .withByteAlignment(4);
+
+ offset += 4; // 604 字节
+
+ // 18. dwOutUcastPkts: DWORD (4 字节)
+ // offset = 604, 是 4 的倍数
+ var dwOutUcastPktsLayout = DWORD
+ .withName("dwOutUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 608 字节
+
+ // 19. dwOutNUcastPkts: DWORD (4 字节)
+ // offset = 608, 是 4 的倍数
+ var dwOutNUcastPktsLayout = DWORD
+ .withName("dwOutNUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 612 字节
+
+ // 20. dwOutDiscards: DWORD (4 字节)
+ // offset = 612, 是 4 的倍数
+ var dwOutDiscardsLayout = DWORD
+ .withName("dwOutDiscards")
+ .withByteAlignment(4);
+
+ offset += 4; // 616 字节
+
+ // 21. dwOutErrors: DWORD (4 字节)
+ // offset = 616, 是 4 的倍数
+ var dwOutErrorsLayout = DWORD
+ .withName("dwOutErrors")
+ .withByteAlignment(4);
+
+ offset += 4; // 620 字节
+
+ // 22. dwOutQLen: DWORD (4 字节)
+ // offset = 620, 是 4 的倍数
+ var dwOutQLenLayout = DWORD
+ .withName("dwOutQLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 624 字节
+
+ // 23. dwDescrLen: DWORD (4 字节)
+ // offset = 624, 是 4 的倍数
+ var dwDescrLenLayout = DWORD
+ .withName("dwDescrLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 628 字节
+
+ // 24. bDescr: UCHAR[MAXLEN_IFDESCR] (256 字节)
+ // offset = 628, 是 4 的倍数 (628 % 4 = 0)
+ var bDescrLayout = MemoryLayout.sequenceLayout(MAXLEN_IFDESCR, BYTE)
+ .withName("bDescr")
+ .withByteAlignment(1);
+
+ offset += MAXLEN_IFDESCR; // 884 字节
+
+ // 最终布局
+ MIB_IFROW_LAYOUT = MemoryLayout.structLayout(
+ // wszName: 0-511 字节 (512 字节)
+ MemoryLayout.sequenceLayout(MAX_INTERFACE_NAME_LEN, WORD)
+ .withName("wszName")
+ .withByteAlignment(2),
+
+ // dwIndex: 512-515 字节 (4 字节)
+ DWORD.withName("dwIndex"),
+
+ // dwType: 516-519 字节 (4 字节)
+ DWORD.withName("dwType"),
+
+ // dwMtu: 520-523 字节 (4 字节)
+ DWORD.withName("dwMtu"),
+
+ // dwSpeed: 524-527 字节 (4 字节)
+ DWORD.withName("dwSpeed"),
+
+ // dwPhysAddrLen: 528-531 字节 (4 字节)
+ DWORD.withName("dwPhysAddrLen"),
+
+ // bPhysAddr: 532-563 字节 (32 字节)
+ MemoryLayout.sequenceLayout(MAXLEN_PHYSADDR, BYTE)
+ .withName("bPhysAddr")
+ .withByteAlignment(1),
+
+ // dwAdminStatus: 564-567 字节 (4 字节)
+ DWORD.withName("dwAdminStatus"),
+
+ // dwOperStatus: 568-571 字节 (4 字节)
+ DWORD.withName("dwOperStatus"),
+
+ // dwLastChange: 572-575 字节 (4 字节)
+ DWORD.withName("dwLastChange"),
+
+ // dwInOctets: 576-579 字节 (4 字节)
+ DWORD.withName("dwInOctets"),
+
+ // dwInUcastPkts: 580-583 字节 (4 字节)
+ DWORD.withName("dwInUcastPkts"),
+
+ // dwInNUcastPkts: 584-587 字节 (4 字节)
+ DWORD.withName("dwInNUcastPkts"),
+
+ // dwInDiscards: 588-591 字节 (4 字节)
+ DWORD.withName("dwInDiscards"),
+
+ // dwInErrors: 592-595 字节 (4 字节)
+ DWORD.withName("dwInErrors"),
+
+ // dwInUnknownProtos: 596-599 字节 (4 字节)
+ DWORD.withName("dwInUnknownProtos"),
+
+ // dwOutOctets: 600-603 字节 (4 字节)
+ DWORD.withName("dwOutOctets"),
+
+ // dwOutUcastPkts: 604-607 字节 (4 字节)
+ DWORD.withName("dwOutUcastPkts"),
+
+ // dwOutNUcastPkts: 608-611 字节 (4 字节)
+ DWORD.withName("dwOutNUcastPkts"),
+
+ // dwOutDiscards: 612-615 字节 (4 字节)
+ DWORD.withName("dwOutDiscards"),
+
+ // dwOutErrors: 616-619 字节 (4 字节)
+ DWORD.withName("dwOutErrors"),
+
+ // dwOutQLen: 620-623 字节 (4 字节)
+ DWORD.withName("dwOutQLen"),
+
+ // dwDescrLen: 624-627 字节 (4 字节)
+ DWORD.withName("dwDescrLen"),
+
+ // bDescr: 628-883 字节 (256 字节)
+ MemoryLayout.sequenceLayout(MAXLEN_IFDESCR, BYTE)
+ .withName("bDescr")
+ .withByteAlignment(1)
+ ).withByteAlignment(4); // 整个结构体 4 字节对齐
+ }
+
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ // 方法句柄
+ private static final MethodHandle GET_IF_ENTRY;
+ private static final MethodHandle SET_IF_ENTRY;
+ private static final MethodHandle GET_IF_TABLE;
+ private static final MethodHandle FREE_MIB_TABLE;
+
+ static {
+ try {
+ // 加载 iphlpapi.dll
+ System.loadLibrary("iphlpapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // GetIfEntry 函数
+ // DWORD GetIfEntry(PMIB_IFROW pIfRow);
+ FunctionDescriptor getIfEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // pIfRow: PMIB_IFROW
+ );
+
+ // SetIfEntry 函数
+ // DWORD SetIfEntry(const PMIB_IFROW pIfRow);
+ FunctionDescriptor setIfEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // pIfRow: const PMIB_IFROW
+ );
+
+ // GetIfTable 函数
+ // DWORD GetIfTable(
+ // PMIB_IFTABLE pIfTable,
+ // PULONG pdwSize,
+ // BOOL bOrder
+ // );
+ FunctionDescriptor getIfTableDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER, // pIfTable: PMIB_IFTABLE*
+ POINTER, // pdwSize: ULONG*
+ DWORD // bOrder: BOOL (int)
+ );
+
+ // FreeMibTable 函数
+ // VOID FreeMibTable(PVOID Memory);
+ FunctionDescriptor freeMibTableDesc = FunctionDescriptor.ofVoid(
+ POINTER // Memory: PVOID
+ );
+
+ // 获取方法句柄
+ GET_IF_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("GetIfEntry").orElseThrow(),
+ getIfEntryDesc
+ );
+
+ SET_IF_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("SetIfEntry").orElseThrow(),
+ setIfEntryDesc
+ );
+
+ GET_IF_TABLE = LINKER.downcallHandle(
+ LOOKUP.find("GetIfTable").orElseThrow(),
+ getIfTableDesc
+ );
+
+ FREE_MIB_TABLE = LINKER.downcallHandle(
+ LOOKUP.find("FreeMibTable").orElseThrow(),
+ freeMibTableDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows interface manager", e);
+ }
+ }
+
+ /**
+ * 获取网络接口表
+ *
+ * @param order 是否按接口索引排序 (true=排序, false=不排序)
+ * @return 接口表指针,调用者需负责使用freeIfTable释放内存
+ */
+ public static MemorySegment getIfTable(boolean order) throws WindowsAPIException {
+ try (Arena arena = Arena.ofConfined()) {
+ // 第一次调用获取所需缓冲区大小
+ MemorySegment sizePtr = arena.allocate(DWORD);
+
+ int result = (int) GET_IF_TABLE.invokeExact(
+ MemorySegment.NULL,
+ sizePtr,
+ order ? 1 : 0
+ );
+
+ int requiredSize = sizePtr.get(DWORD, 0);
+
+ // 分配足够的内存
+ MemorySegment ifTableBuffer = Arena.ofAuto().allocate(requiredSize);
+
+ // 第二次调用获取实际数据
+ result = (int) GET_IF_TABLE.invokeExact(
+ ifTableBuffer,
+ sizePtr,
+ order ? 1 : 0
+ );
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetIfTable failed", result);
+ }
+
+ // 返回表指针
+ return ifTableBuffer;
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting interface table", e);
+ }
+ }
+
+ /**
+ * 释放接口表内存
+ *
+ * @param ifTable 接口表指针
+ */
+ public static void freeIfTable(MemorySegment ifTable) {
+ try {
+ FREE_MIB_TABLE.invokeExact(ifTable);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error freeing interface table", e);
+ }
+ }
+
+ /**
+ * 获取所有网络接口的列表
+ *
+ * @param order 是否按接口索引排序
+ * @return 接口列表
+ */
+ public static List getAllInterfaces(boolean order) throws WindowsAPIException {
+ MemorySegment ifTable = null;
+ try {
+ // 获取接口表
+ ifTable = getIfTable(order);
+
+ // 读取表头
+ int numEntries = ifTable.get(DWORD, 0);
+ MemorySegment tablePtr = ifTable.asSlice(8);
+
+ List interfaces = new ArrayList<>();
+
+ // 解析每个接口
+ for (int i = 0; i < numEntries; i++) {
+ // 注意:这里需要根据实际的MIB_IFROW_LAYOUT来计算偏移量
+ // 假设MIB_IFROW_LAYOUT存在且正确
+ long rowOffset = i * MIB_IFROW_LAYOUT.byteSize(); // 根据之前计算的MIB_IFROW大小
+ MemorySegment rowSegment = tablePtr.asSlice(rowOffset);
+
+ MibIfRow ifRow = parseMibIfRow(rowSegment);
+ interfaces.add(ifRow);
+ }
+
+ return interfaces;
+ } finally {
+ // 释放内存
+ if (ifTable != null && !ifTable.equals(MemorySegment.NULL)) {
+ freeIfTable(ifTable);
+ }
+ }
+ }
+
+ /**
+ * 查找指定名称的网络接口
+ */
+ public static MibIfRow findInterfaceByName(String name, boolean caseSensitive) throws WindowsAPIException {
+ List interfaces = getAllInterfaces(false);
+
+ for (MibIfRow ifRow : interfaces) {
+ String interfaceName = ifRow.getName();
+ if (caseSensitive) {
+ if (interfaceName.equals(name)) {
+ return ifRow;
+ }
+ } else {
+ if (interfaceName.equalsIgnoreCase(name)) {
+ return ifRow;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * 查找指定索引的网络接口
+ */
+ public static MibIfRow findInterfaceByIndex(int index) throws WindowsAPIException {
+ List interfaces = getAllInterfaces(false);
+
+ for (MibIfRow ifRow : interfaces) {
+ if (ifRow.getIndex() == index) {
+ return ifRow;
+ }
+ }
+
+ return null;
+ }
+
+
+
+
+
+
+ // ========== 以下是原有代码的辅助方法 ==========
+ /**
+ * 获取接口信息
+ * @param ifIndex 接口索引
+ * @return 接口信息对象
+ */
+ public static MibIfRow getIfEntry(int ifIndex) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 分配 MIB_IFROW 结构体
+ MemorySegment ifRow = arena.allocate(MIB_IFROW_LAYOUT);
+
+ // 清零初始化
+ ifRow.fill((byte)0);
+
+ // 设置接口索引 (dwIndex)
+ ifRow.set(DWORD, 512, ifIndex);
+
+ // 调用 GetIfEntry
+ int result = (int) GET_IF_ENTRY.invokeExact(ifRow);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetIfEntry failed", result);
+ }
+
+ // 解析结构体为 Java 对象
+ return parseMibIfRow(ifRow);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting interface entry", e);
+ }
+ }
+
+ /**
+ * 设置接口信息 (主要用来修改管理状态)
+ * @param ifRow 接口信息对象
+ * @return 操作结果 (0 = 成功)
+ */
+ public static int setIfEntry(MibIfRow ifRow) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 分配 MIB_IFROW 结构体
+ MemorySegment ifRowSegment = arena.allocate(MIB_IFROW_LAYOUT);
+
+ // 清零初始化
+ ifRowSegment.fill((byte)0);
+
+ // 填充结构体
+ fillMibIfRow(ifRowSegment, ifRow, arena);
+
+ // 调用 SetIfEntry
+ return (int) SET_IF_ENTRY.invokeExact(ifRowSegment);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error setting interface entry", e);
+ }
+ }
+ /**
+ * 写入宽字符串
+ */
+ private static void writeWideString(MemorySegment segment, long offset, String str, int maxChars) {
+ if (str == null || str.isEmpty()) {
+ return;
+ }
+
+ byte[] utf16Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
+ int copyLen = Math.min(utf16Bytes.length, (maxChars - 1) * 2);
+
+ if (copyLen > 0) {
+ MemorySegment.copy(MemorySegment.ofArray(utf16Bytes), 0, segment, offset, copyLen);
+ }
+
+ // 添加 null 终止符
+ segment.set(WORD, offset + copyLen, (short)0);
+ }
+
+ /**
+ * 填充 MIB_IFROW 结构体
+ */
+ private static void fillMibIfRow(MemorySegment ifRow, MibIfRow data, Arena arena) {
+ // 1. 设置接口索引 (必须)
+ ifRow.set(DWORD, 512, data.getIndex());
+
+ // 2. 设置接口名称 (如果需要)
+ if (data.getName() != null) {
+ writeWideString(ifRow, 0, data.getName(), MAX_INTERFACE_NAME_LEN);
+ }
+
+ // 3. 设置接口类型 (如果需要)
+ ifRow.set(DWORD, 516, data.getType());
+
+ // 4. 设置 MTU (如果需要)
+ ifRow.set(DWORD, 520, data.getMtu());
+
+ // 5. 设置速度 (如果需要)
+ ifRow.set(DWORD, 524, (int)Math.min(data.getSpeed(), 0xFFFFFFFFL));
+
+ // 6. 设置物理地址 (如果需要)
+ if (data.getPhysAddr() != null && data.getPhysAddr().length > 0) {
+ int len = Math.min(data.getPhysAddr().length, MAXLEN_PHYSADDR);
+ ifRow.set(DWORD, 528, len);
+ MemorySegment.copy(MemorySegment.ofArray(data.getPhysAddr()), 0, ifRow, 532, len);
+ }
+
+ // 7. 设置管理状态 (主要用途)
+ ifRow.set(DWORD, 564, data.getAdminStatus());
+
+ // 8. 设置操作状态 (通常只读,但这里也设置)
+ ifRow.set(DWORD, 568, data.getOperStatus());
+
+ // 9. 设置接口描述 (如果需要)
+ if (data.getDescription() != null && !data.getDescription().isEmpty()) {
+ byte[] descrBytes = data.getDescription().getBytes(java.nio.charset.StandardCharsets.UTF_8);
+ int len = Math.min(descrBytes.length, MAXLEN_IFDESCR);
+ ifRow.set(DWORD, 624, len);
+ MemorySegment.copy(MemorySegment.ofArray(descrBytes), 0, ifRow, 628, len);
+ }
+ }
+ /**
+ * 解析 MIB_IFROW 结构体为 Java 对象
+ */
+ private static MibIfRow parseMibIfRow(MemorySegment ifRow) {
+ MibIfRow result = new MibIfRow();
+ ifRow=ifRow.reinterpret(MIB_IFROW_LAYOUT.byteSize());
+ // 1. 解析接口名称 (宽字符串)
+ String name = readWideString(ifRow, 0, MAX_INTERFACE_NAME_LEN);
+ result.setName(name);
+
+ // 2. 读取基本字段
+ result.setIndex(ifRow.get(DWORD, 512));
+ result.setType(ifRow.get(DWORD, 516));
+ result.setMtu(ifRow.get(DWORD, 520));
+
+ // 3. 速度需要处理为无符号
+ result.setSpeed(Integer.toUnsignedLong(ifRow.get(DWORD, 524)));
+
+ // 4. 物理地址
+ int physAddrLen = ifRow.get(DWORD, 528);
+ if (physAddrLen > 0 && physAddrLen <= MAXLEN_PHYSADDR) {
+ byte[] physAddr = new byte[physAddrLen];
+ MemorySegment.copy(ifRow, 532, MemorySegment.ofArray(physAddr), 0, physAddrLen);
+ result.setPhysAddr(physAddr);
+ }
+
+ // 5. 状态信息
+ result.setAdminStatus(ifRow.get(DWORD, 564));
+ result.setOperStatus(ifRow.get(DWORD, 568));
+ result.setLastChange(Integer.toUnsignedLong(ifRow.get(DWORD, 572)));
+
+ // 6. 输入统计 (需要处理为无符号)
+ result.setInOctets(Integer.toUnsignedLong(ifRow.get(DWORD, 576)));
+ result.setInUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 580)));
+ result.setInNUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 584)));
+ result.setInDiscards(Integer.toUnsignedLong(ifRow.get(DWORD, 588)));
+ result.setInErrors(Integer.toUnsignedLong(ifRow.get(DWORD, 592)));
+ result.setInUnknownProtos(Integer.toUnsignedLong(ifRow.get(DWORD, 596)));
+
+ // 7. 输出统计
+ result.setOutOctets(Integer.toUnsignedLong(ifRow.get(DWORD, 600)));
+ result.setOutUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 604)));
+ result.setOutNUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 608)));
+ result.setOutDiscards(Integer.toUnsignedLong(ifRow.get(DWORD, 612)));
+ result.setOutErrors(Integer.toUnsignedLong(ifRow.get(DWORD, 616)));
+ result.setOutQLen(Integer.toUnsignedLong(ifRow.get(DWORD, 620)));
+
+ // 8. 接口描述
+ int descrLen = ifRow.get(DWORD, 624);
+ if (descrLen > 0 && descrLen <= MAXLEN_IFDESCR) {
+ byte[] descrBytes = new byte[descrLen];
+ MemorySegment.copy(ifRow, 628, MemorySegment.ofArray(descrBytes), 0, descrLen);
+ result.setDescription(new String(descrBytes, java.nio.charset.StandardCharsets.UTF_8));
+ }
+
+ return result;
+ }
+
+ /**
+ * 读取宽字符串
+ */
+ private static String readWideString(MemorySegment segment, long offset, int maxChars) {
+ try {
+ // 查找 null 终止符
+ long length = 0;
+ while (length < maxChars) {
+ short ch = segment.get(WORD, offset + length * 2);
+ if (ch == 0) {
+ break;
+ }
+ length++;
+ }
+
+ if (length == 0) {
+ return "";
+ }
+
+ // 读取字符串数据
+ byte[] bytes = new byte[(int)(length * 2)];
+ MemorySegment.copy(segment, offset, MemorySegment.ofArray(bytes), 0, bytes.length);
+
+ return new String(bytes, java.nio.charset.StandardCharsets.UTF_16LE);
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * MIB_IFROW 结构的 Java 对象封装
+ */
+ public static class MibIfRow {
+ // 接口类型常量 (部分常见类型)
+ public static final int IF_TYPE_ETHERNET_CSMACD = 6;
+ public static final int IF_TYPE_ISO88025_TOKENRING = 9;
+ public static final int IF_TYPE_PPP = 23;
+ public static final int IF_TYPE_SOFTWARE_LOOPBACK = 24;
+ public static final int IF_TYPE_ATM = 37;
+ public static final int IF_TYPE_IEEE80211 = 71;
+ public static final int IF_TYPE_TUNNEL = 131;
+ public static final int IF_TYPE_IEEE1394 = 144;
+
+ // 管理状态常量
+ public static final int MIB_IF_ADMIN_STATUS_UP = 1;
+ public static final int MIB_IF_ADMIN_STATUS_DOWN = 2;
+ public static final int MIB_IF_ADMIN_STATUS_TESTING = 3;
+
+ // 操作状态常量
+ public static final int IF_OPER_STATUS_NON_OPERATIONAL = 0;
+ public static final int IF_OPER_STATUS_UNREACHABLE = 1;
+ public static final int IF_OPER_STATUS_DISCONNECTED = 2;
+ public static final int IF_OPER_STATUS_CONNECTING = 3;
+ public static final int IF_OPER_STATUS_CONNECTED = 4;
+ public static final int IF_OPER_STATUS_OPERATIONAL = 5;
+
+ private String name; // 接口名称
+ private int index; // 接口索引
+ private int type; // 接口类型
+ private int mtu; // 最大传输单元
+ private long speed; // 接口速度 (bps)
+ private byte[] physAddr; // 物理地址 (MAC)
+ private int adminStatus; // 管理状态
+ private int operStatus; // 操作状态
+ private long lastChange; // 最后状态改变时间
+ private long inOctets; // 接收字节数
+ private long inUcastPkts; // 接收单播包数
+ private long inNUcastPkts; // 接收非单播包数
+ private long inDiscards; // 接收丢弃数
+ private long inErrors; // 接收错误数
+ private long inUnknownProtos; // 接收未知协议数
+ private long outOctets; // 发送字节数
+ private long outUcastPkts; // 发送单播包数
+ private long outNUcastPkts; // 发送非单播包数
+ private long outDiscards; // 发送丢弃数
+ private long outErrors; // 发送错误数
+ private long outQLen; // 发送队列长度
+ private String description; // 接口描述
+
+ public MibIfRow() {
+ this.physAddr = new byte[0];
+ this.description = "";
+ }
+
+ // Getters and Setters
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+
+ public int getIndex() { return index; }
+ public void setIndex(int index) { this.index = index; }
+
+ public int getType() { return type; }
+ public void setType(int type) { this.type = type; }
+
+ public int getMtu() { return mtu; }
+ public void setMtu(int mtu) { this.mtu = mtu; }
+
+ public long getSpeed() { return speed; }
+ public void setSpeed(long speed) { this.speed = speed; }
+
+ public byte[] getPhysAddr() { return physAddr; }
+ public void setPhysAddr(byte[] physAddr) { this.physAddr = physAddr; }
+
+ public int getAdminStatus() { return adminStatus; }
+ public void setAdminStatus(int adminStatus) { this.adminStatus = adminStatus; }
+
+ public int getOperStatus() { return operStatus; }
+ public void setOperStatus(int operStatus) { this.operStatus = operStatus; }
+
+ public long getLastChange() { return lastChange; }
+ public void setLastChange(long lastChange) { this.lastChange = lastChange; }
+
+ public long getInOctets() { return inOctets; }
+ public void setInOctets(long inOctets) { this.inOctets = inOctets; }
+
+ public long getInUcastPkts() { return inUcastPkts; }
+ public void setInUcastPkts(long inUcastPkts) { this.inUcastPkts = inUcastPkts; }
+
+ public long getInNUcastPkts() { return inNUcastPkts; }
+ public void setInNUcastPkts(long inNUcastPkts) { this.inNUcastPkts = inNUcastPkts; }
+
+ public long getInDiscards() { return inDiscards; }
+ public void setInDiscards(long inDiscards) { this.inDiscards = inDiscards; }
+
+ public long getInErrors() { return inErrors; }
+ public void setInErrors(long inErrors) { this.inErrors = inErrors; }
+
+ public long getInUnknownProtos() { return inUnknownProtos; }
+ public void setInUnknownProtos(long inUnknownProtos) { this.inUnknownProtos = inUnknownProtos; }
+
+ public long getOutOctets() { return outOctets; }
+ public void setOutOctets(long outOctets) { this.outOctets = outOctets; }
+
+ public long getOutUcastPkts() { return outUcastPkts; }
+ public void setOutUcastPkts(long outUcastPkts) { this.outUcastPkts = outUcastPkts; }
+
+ public long getOutNUcastPkts() { return outNUcastPkts; }
+ public void setOutNUcastPkts(long outNUcastPkts) { this.outNUcastPkts = outNUcastPkts; }
+
+ public long getOutDiscards() { return outDiscards; }
+ public void setOutDiscards(long outDiscards) { this.outDiscards = outDiscards; }
+
+ public long getOutErrors() { return outErrors; }
+ public void setOutErrors(long outErrors) { this.outErrors = outErrors; }
+
+ public long getOutQLen() { return outQLen; }
+ public void setOutQLen(long outQLen) { this.outQLen = outQLen; }
+
+ public String getDescription() { return description; }
+ public void setDescription(String description) { this.description = description; }
+
+ /**
+ * 获取接口类型名称
+ */
+ private static String getTypeName(int type) {
+ switch (type) {
+ case IF_TYPE_ETHERNET_CSMACD: return "Ethernet";
+ case IF_TYPE_ISO88025_TOKENRING: return "Token Ring";
+ case IF_TYPE_PPP: return "PPP";
+ case IF_TYPE_SOFTWARE_LOOPBACK: return "Loopback";
+ case IF_TYPE_ATM: return "ATM";
+ case IF_TYPE_IEEE80211: return "WiFi";
+ case IF_TYPE_TUNNEL: return "Tunnel";
+ case IF_TYPE_IEEE1394: return "FireWire";
+ default: return "Unknown (" + type + ")";
+ }
+ }
+
+ /**
+ * 获取管理状态名称
+ */
+ private static String getAdminStatusName(int status) {
+ switch (status) {
+ case MIB_IF_ADMIN_STATUS_UP: return "UP";
+ case MIB_IF_ADMIN_STATUS_DOWN: return "DOWN";
+ case MIB_IF_ADMIN_STATUS_TESTING: return "TESTING";
+ default: return "UNKNOWN (" + status + ")";
+ }
+ }
+
+ /**
+ * 获取操作状态名称
+ */
+ private static String getOperStatusName(int status) {
+ switch (status) {
+ case IF_OPER_STATUS_NON_OPERATIONAL: return "NON_OPERATIONAL";
+ case IF_OPER_STATUS_UNREACHABLE: return "UNREACHABLE";
+ case IF_OPER_STATUS_DISCONNECTED: return "DISCONNECTED";
+ case IF_OPER_STATUS_CONNECTING: return "CONNECTING";
+ case IF_OPER_STATUS_CONNECTED: return "CONNECTED";
+ case IF_OPER_STATUS_OPERATIONAL: return "OPERATIONAL";
+ default: return "UNKNOWN (" + status + ")";
+ }
+ }
+ @Override
+ public String toString() {
+ HexFormat hex = HexFormat.of().withDelimiter(":");
+ StringBuilder sb = new StringBuilder();
+ sb.append("Interface: ").append(name).append("\n");
+ sb.append(" Index: ").append(index).append("\n");
+ sb.append(" Type: ").append(getTypeName(type)).append(" (").append(type).append(")\n");
+ sb.append(" MTU: ").append(mtu).append("\n");
+ sb.append(" Speed: ").append(formatSpeed(speed)).append("\n");
+ if (physAddr != null && physAddr.length > 0) {
+ sb.append(" MAC: ").append(hex.formatHex(physAddr)).append("\n");
+ }
+ sb.append(" Admin Status: ").append(getAdminStatusName(adminStatus)).append("\n");
+ sb.append(" Oper Status: ").append(getOperStatusName(operStatus)).append("\n");
+ sb.append(" Description: ").append(description).append("\n");
+ sb.append(" Statistics:\n");
+ sb.append(" In: ").append(formatBytes(inOctets)).append(", ")
+ .append(inUcastPkts).append(" unicast, ")
+ .append(inNUcastPkts).append(" non-unicast\n");
+ sb.append(" Out: ").append(formatBytes(outOctets)).append(", ")
+ .append(outUcastPkts).append(" unicast, ")
+ .append(outNUcastPkts).append(" non-unicast\n");
+ return sb.toString();
+ }
+
+ private String formatSpeed(long speed) {
+ if (speed >= 1_000_000_000L) {
+ return String.format("%.1f Gbps", speed / 1_000_000_000.0);
+ } else if (speed >= 1_000_000L) {
+ return String.format("%.1f Mbps", speed / 1_000_000.0);
+ } else if (speed >= 1_000L) {
+ return String.format("%.1f Kbps", speed / 1_000.0);
+ } else {
+ return speed + " bps";
+ }
+ }
+
+ private String formatBytes(long bytes) {
+ if (bytes >= 1_073_741_824L) { // 1 GiB
+ return String.format("%.2f GiB", bytes / 1_073_741_824.0);
+ } else if (bytes >= 1_048_576L) { // 1 MiB
+ return String.format("%.2f MiB", bytes / 1_048_576.0);
+ } else if (bytes >= 1_024L) { // 1 KiB
+ return String.format("%.2f KiB", bytes / 1_024.0);
+ } else {
+ return bytes + " bytes";
+ }
+ }
+ }
+ /**
+ * 测试方法
+ */
+ /*public static void main(String[] args) {
+ try {
+ System.out.println("Windows Interface Manager");
+ System.out.println("========================\n");
+
+ // 测试获取所有接口(需要先获取接口表,这里简化测试)
+ System.out.println("Testing GetIfEntry for interface index 1:");
+
+
+ // 测试获取环回接口(通常是索引 1)
+ System.out.println("\nTesting with common interface indices:");
+
+ // 常见的接口索引范围
+ for (int i = 1; i <= 100; i++) {
+ try {
+ MibIfRow ifRow = getIfEntry(i);
+ System.out.println("Interface " + i + ": " + ifRow.getName());
+ System.out.println(ifRow);
+
+
+ } catch (Exception e) {
+ // 接口不存在是正常的
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }*/
+
+ /**
+ * 测试方法
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("=== Windows Interface Manager Test ===");
+
+ // 测试获取所有接口
+ System.out.println("\nAll Network Interfaces:");
+ List interfaces = getAllInterfaces(true);
+
+ for (MibIfRow ifRow : interfaces) {
+ System.out.printf(" [%d] %s (Type: %d)%n",
+ ifRow.getIndex(), ifRow.getName(), ifRow.getType());
+ }
+
+ System.out.println("\nTotal interfaces found: " + interfaces.size());
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsInterfaceManager2.java b/src/org/kne/cloud/network/tun/WindowsInterfaceManager2.java
new file mode 100644
index 0000000..4b9489c
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsInterfaceManager2.java
@@ -0,0 +1,841 @@
+package org.kne.cloud.network.tun;
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.util.Arrays;
+import java.util.HexFormat;
+
+/**
+ * Windows 网络接口管理类
+ * 实现 GetIfEntry 和 SetIfEntry 功能,提供 MIB_IFROW 结构的 Java 对象封装
+ */
+public class WindowsInterfaceManager2 {
+
+ // 内存布局
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+
+ // 常量定义
+ public static final int MAX_INTERFACE_NAME_LEN = 256;
+ public static final int MAXLEN_PHYSADDR = 32;
+ public static final int MAXLEN_IFDESCR = 256;
+ public static final int NO_ERROR = 0;
+
+ // 接口类型常量 (部分常见类型)
+ public static final int IF_TYPE_ETHERNET_CSMACD = 6;
+ public static final int IF_TYPE_ISO88025_TOKENRING = 9;
+ public static final int IF_TYPE_PPP = 23;
+ public static final int IF_TYPE_SOFTWARE_LOOPBACK = 24;
+ public static final int IF_TYPE_ATM = 37;
+ public static final int IF_TYPE_IEEE80211 = 71;
+ public static final int IF_TYPE_TUNNEL = 131;
+ public static final int IF_TYPE_IEEE1394 = 144;
+
+ // 管理状态常量
+ public static final int MIB_IF_ADMIN_STATUS_UP = 1;
+ public static final int MIB_IF_ADMIN_STATUS_DOWN = 2;
+ public static final int MIB_IF_ADMIN_STATUS_TESTING = 3;
+
+ // 操作状态常量
+ public static final int IF_OPER_STATUS_NON_OPERATIONAL = 0;
+ public static final int IF_OPER_STATUS_UNREACHABLE = 1;
+ public static final int IF_OPER_STATUS_DISCONNECTED = 2;
+ public static final int IF_OPER_STATUS_CONNECTING = 3;
+ public static final int IF_OPER_STATUS_CONNECTED = 4;
+ public static final int IF_OPER_STATUS_OPERATIONAL = 5;
+
+ // MIB_IFROW 结构体布局
+ public static final GroupLayout MIB_IFROW_LAYOUT;
+
+ static {
+ // 手动计算偏移量以确保正确对齐
+ // 注意:所有字段都是 4 字节对齐的
+ long offset = 0;
+
+ // 1. wszName: WCHAR[MAX_INTERFACE_NAME_LEN] (512 字节)
+ // 需要 2 字节对齐,但结构体开始通常是 4 字节对齐
+ var wszNameLayout = MemoryLayout.sequenceLayout(MAX_INTERFACE_NAME_LEN, WORD)
+ .withName("wszName")
+ .withByteAlignment(2);
+
+ offset += MAX_INTERFACE_NAME_LEN * 2; // 512 字节
+
+ // 2. dwIndex: IF_INDEX (4 字节)
+ // offset = 512, 是 4 的倍数
+ var dwIndexLayout = DWORD
+ .withName("dwIndex")
+ .withByteAlignment(4);
+
+ offset += 4; // 516 字节
+
+ // 3. dwType: IFTYPE (4 字节)
+ // offset = 516, 是 4 的倍数
+ var dwTypeLayout = DWORD
+ .withName("dwType")
+ .withByteAlignment(4);
+
+ offset += 4; // 520 字节
+
+ // 4. dwMtu: DWORD (4 字节)
+ // offset = 520, 是 4 的倍数
+ var dwMtuLayout = DWORD
+ .withName("dwMtu")
+ .withByteAlignment(4);
+
+ offset += 4; // 524 字节
+
+ // 5. dwSpeed: DWORD (4 字节)
+ // offset = 524, 是 4 的倍数
+ var dwSpeedLayout = DWORD
+ .withName("dwSpeed")
+ .withByteAlignment(4);
+
+ offset += 4; // 528 字节
+
+ // 6. dwPhysAddrLen: DWORD (4 字节)
+ // offset = 528, 是 4 的倍数
+ var dwPhysAddrLenLayout = DWORD
+ .withName("dwPhysAddrLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 532 字节
+
+ // 7. bPhysAddr: UCHAR[MAXLEN_PHYSADDR] (32 字节)
+ // offset = 532, 是 1 的倍数,但数组本身 1 字节对齐
+ // 实际上需要 4 字节对齐,532 是 4 的倍数 (532 % 4 = 0)
+ var bPhysAddrLayout = MemoryLayout.sequenceLayout(MAXLEN_PHYSADDR, BYTE)
+ .withName("bPhysAddr")
+ .withByteAlignment(1);
+
+ offset += MAXLEN_PHYSADDR; // 564 字节
+
+ // 8. dwAdminStatus: DWORD (4 字节)
+ // offset = 564, 是 4 的倍数
+ var dwAdminStatusLayout = DWORD
+ .withName("dwAdminStatus")
+ .withByteAlignment(4);
+
+ offset += 4; // 568 字节
+
+ // 9. dwOperStatus: INTERNAL_IF_OPER_STATUS (4 字节)
+ // offset = 568, 是 4 的倍数
+ var dwOperStatusLayout = DWORD
+ .withName("dwOperStatus")
+ .withByteAlignment(4);
+
+ offset += 4; // 572 字节
+
+ // 10. dwLastChange: DWORD (4 字节)
+ // offset = 572, 是 4 的倍数
+ var dwLastChangeLayout = DWORD
+ .withName("dwLastChange")
+ .withByteAlignment(4);
+
+ offset += 4; // 576 字节
+
+ // 11. dwInOctets: DWORD (4 字节)
+ // offset = 576, 是 4 的倍数
+ var dwInOctetsLayout = DWORD
+ .withName("dwInOctets")
+ .withByteAlignment(4);
+
+ offset += 4; // 580 字节
+
+ // 12. dwInUcastPkts: DWORD (4 字节)
+ // offset = 580, 是 4 的倍数
+ var dwInUcastPktsLayout = DWORD
+ .withName("dwInUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 584 字节
+
+ // 13. dwInNUcastPkts: DWORD (4 字节)
+ // offset = 584, 是 4 的倍数
+ var dwInNUcastPktsLayout = DWORD
+ .withName("dwInNUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 588 字节
+
+ // 14. dwInDiscards: DWORD (4 字节)
+ // offset = 588, 是 4 的倍数
+ var dwInDiscardsLayout = DWORD
+ .withName("dwInDiscards")
+ .withByteAlignment(4);
+
+ offset += 4; // 592 字节
+
+ // 15. dwInErrors: DWORD (4 字节)
+ // offset = 592, 是 4 的倍数
+ var dwInErrorsLayout = DWORD
+ .withName("dwInErrors")
+ .withByteAlignment(4);
+
+ offset += 4; // 596 字节
+
+ // 16. dwInUnknownProtos: DWORD (4 字节)
+ // offset = 596, 是 4 的倍数
+ var dwInUnknownProtosLayout = DWORD
+ .withName("dwInUnknownProtos")
+ .withByteAlignment(4);
+
+ offset += 4; // 600 字节
+
+ // 17. dwOutOctets: DWORD (4 字节)
+ // offset = 600, 是 4 的倍数
+ var dwOutOctetsLayout = DWORD
+ .withName("dwOutOctets")
+ .withByteAlignment(4);
+
+ offset += 4; // 604 字节
+
+ // 18. dwOutUcastPkts: DWORD (4 字节)
+ // offset = 604, 是 4 的倍数
+ var dwOutUcastPktsLayout = DWORD
+ .withName("dwOutUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 608 字节
+
+ // 19. dwOutNUcastPkts: DWORD (4 字节)
+ // offset = 608, 是 4 的倍数
+ var dwOutNUcastPktsLayout = DWORD
+ .withName("dwOutNUcastPkts")
+ .withByteAlignment(4);
+
+ offset += 4; // 612 字节
+
+ // 20. dwOutDiscards: DWORD (4 字节)
+ // offset = 612, 是 4 的倍数
+ var dwOutDiscardsLayout = DWORD
+ .withName("dwOutDiscards")
+ .withByteAlignment(4);
+
+ offset += 4; // 616 字节
+
+ // 21. dwOutErrors: DWORD (4 字节)
+ // offset = 616, 是 4 的倍数
+ var dwOutErrorsLayout = DWORD
+ .withName("dwOutErrors")
+ .withByteAlignment(4);
+
+ offset += 4; // 620 字节
+
+ // 22. dwOutQLen: DWORD (4 字节)
+ // offset = 620, 是 4 的倍数
+ var dwOutQLenLayout = DWORD
+ .withName("dwOutQLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 624 字节
+
+ // 23. dwDescrLen: DWORD (4 字节)
+ // offset = 624, 是 4 的倍数
+ var dwDescrLenLayout = DWORD
+ .withName("dwDescrLen")
+ .withByteAlignment(4);
+
+ offset += 4; // 628 字节
+
+ // 24. bDescr: UCHAR[MAXLEN_IFDESCR] (256 字节)
+ // offset = 628, 是 4 的倍数 (628 % 4 = 0)
+ var bDescrLayout = MemoryLayout.sequenceLayout(MAXLEN_IFDESCR, BYTE)
+ .withName("bDescr")
+ .withByteAlignment(1);
+
+ offset += MAXLEN_IFDESCR; // 884 字节
+
+ // 最终布局
+ MIB_IFROW_LAYOUT = MemoryLayout.structLayout(
+ // wszName: 0-511 字节 (512 字节)
+ MemoryLayout.sequenceLayout(MAX_INTERFACE_NAME_LEN, WORD)
+ .withName("wszName")
+ .withByteAlignment(2),
+
+ // dwIndex: 512-515 字节 (4 字节)
+ DWORD.withName("dwIndex"),
+
+ // dwType: 516-519 字节 (4 字节)
+ DWORD.withName("dwType"),
+
+ // dwMtu: 520-523 字节 (4 字节)
+ DWORD.withName("dwMtu"),
+
+ // dwSpeed: 524-527 字节 (4 字节)
+ DWORD.withName("dwSpeed"),
+
+ // dwPhysAddrLen: 528-531 字节 (4 字节)
+ DWORD.withName("dwPhysAddrLen"),
+
+ // bPhysAddr: 532-563 字节 (32 字节)
+ MemoryLayout.sequenceLayout(MAXLEN_PHYSADDR, BYTE)
+ .withName("bPhysAddr")
+ .withByteAlignment(1),
+
+ // dwAdminStatus: 564-567 字节 (4 字节)
+ DWORD.withName("dwAdminStatus"),
+
+ // dwOperStatus: 568-571 字节 (4 字节)
+ DWORD.withName("dwOperStatus"),
+
+ // dwLastChange: 572-575 字节 (4 字节)
+ DWORD.withName("dwLastChange"),
+
+ // dwInOctets: 576-579 字节 (4 字节)
+ DWORD.withName("dwInOctets"),
+
+ // dwInUcastPkts: 580-583 字节 (4 字节)
+ DWORD.withName("dwInUcastPkts"),
+
+ // dwInNUcastPkts: 584-587 字节 (4 字节)
+ DWORD.withName("dwInNUcastPkts"),
+
+ // dwInDiscards: 588-591 字节 (4 字节)
+ DWORD.withName("dwInDiscards"),
+
+ // dwInErrors: 592-595 字节 (4 字节)
+ DWORD.withName("dwInErrors"),
+
+ // dwInUnknownProtos: 596-599 字节 (4 字节)
+ DWORD.withName("dwInUnknownProtos"),
+
+ // dwOutOctets: 600-603 字节 (4 字节)
+ DWORD.withName("dwOutOctets"),
+
+ // dwOutUcastPkts: 604-607 字节 (4 字节)
+ DWORD.withName("dwOutUcastPkts"),
+
+ // dwOutNUcastPkts: 608-611 字节 (4 字节)
+ DWORD.withName("dwOutNUcastPkts"),
+
+ // dwOutDiscards: 612-615 字节 (4 字节)
+ DWORD.withName("dwOutDiscards"),
+
+ // dwOutErrors: 616-619 字节 (4 字节)
+ DWORD.withName("dwOutErrors"),
+
+ // dwOutQLen: 620-623 字节 (4 字节)
+ DWORD.withName("dwOutQLen"),
+
+ // dwDescrLen: 624-627 字节 (4 字节)
+ DWORD.withName("dwDescrLen"),
+
+ // bDescr: 628-883 字节 (256 字节)
+ MemoryLayout.sequenceLayout(MAXLEN_IFDESCR, BYTE)
+ .withName("bDescr")
+ .withByteAlignment(1)
+ ).withByteAlignment(4); // 整个结构体 4 字节对齐
+ }
+
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ // 方法句柄
+ private static final MethodHandle GET_IF_ENTRY;
+ private static final MethodHandle SET_IF_ENTRY;
+
+ static {
+ try {
+ // 加载 iphlpapi.dll
+ System.loadLibrary("iphlpapi");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // GetIfEntry 函数
+ // DWORD GetIfEntry(PMIB_IFROW pIfRow);
+ FunctionDescriptor getIfEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // pIfRow: PMIB_IFROW
+ );
+
+ // SetIfEntry 函数
+ // DWORD SetIfEntry(const PMIB_IFROW pIfRow);
+ FunctionDescriptor setIfEntryDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER // pIfRow: const PMIB_IFROW
+ );
+
+ // 获取方法句柄
+ GET_IF_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("GetIfEntry").orElseThrow(),
+ getIfEntryDesc
+ );
+
+ SET_IF_ENTRY = LINKER.downcallHandle(
+ LOOKUP.find("SetIfEntry").orElseThrow(),
+ setIfEntryDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize Windows interface manager", e);
+ }
+ }
+
+ /**
+ * MIB_IFROW 结构的 Java 对象封装
+ */
+ public static class MibIfRow {
+ private String name; // 接口名称
+ private int index; // 接口索引
+ private int type; // 接口类型
+ private int mtu; // 最大传输单元
+ private long speed; // 接口速度 (bps)
+ private byte[] physAddr; // 物理地址 (MAC)
+ private int adminStatus; // 管理状态
+ private int operStatus; // 操作状态
+ private long lastChange; // 最后状态改变时间
+ private long inOctets; // 接收字节数
+ private long inUcastPkts; // 接收单播包数
+ private long inNUcastPkts; // 接收非单播包数
+ private long inDiscards; // 接收丢弃数
+ private long inErrors; // 接收错误数
+ private long inUnknownProtos; // 接收未知协议数
+ private long outOctets; // 发送字节数
+ private long outUcastPkts; // 发送单播包数
+ private long outNUcastPkts; // 发送非单播包数
+ private long outDiscards; // 发送丢弃数
+ private long outErrors; // 发送错误数
+ private long outQLen; // 发送队列长度
+ private String description; // 接口描述
+
+ public MibIfRow() {
+ this.physAddr = new byte[0];
+ this.description = "";
+ }
+
+ // Getters and Setters
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+
+ public int getIndex() { return index; }
+ public void setIndex(int index) { this.index = index; }
+
+ public int getType() { return type; }
+ public void setType(int type) { this.type = type; }
+
+ public int getMtu() { return mtu; }
+ public void setMtu(int mtu) { this.mtu = mtu; }
+
+ public long getSpeed() { return speed; }
+ public void setSpeed(long speed) { this.speed = speed; }
+
+ public byte[] getPhysAddr() { return physAddr; }
+ public void setPhysAddr(byte[] physAddr) { this.physAddr = physAddr; }
+
+ public int getAdminStatus() { return adminStatus; }
+ public void setAdminStatus(int adminStatus) { this.adminStatus = adminStatus; }
+
+ public int getOperStatus() { return operStatus; }
+ public void setOperStatus(int operStatus) { this.operStatus = operStatus; }
+
+ public long getLastChange() { return lastChange; }
+ public void setLastChange(long lastChange) { this.lastChange = lastChange; }
+
+ public long getInOctets() { return inOctets; }
+ public void setInOctets(long inOctets) { this.inOctets = inOctets; }
+
+ public long getInUcastPkts() { return inUcastPkts; }
+ public void setInUcastPkts(long inUcastPkts) { this.inUcastPkts = inUcastPkts; }
+
+ public long getInNUcastPkts() { return inNUcastPkts; }
+ public void setInNUcastPkts(long inNUcastPkts) { this.inNUcastPkts = inNUcastPkts; }
+
+ public long getInDiscards() { return inDiscards; }
+ public void setInDiscards(long inDiscards) { this.inDiscards = inDiscards; }
+
+ public long getInErrors() { return inErrors; }
+ public void setInErrors(long inErrors) { this.inErrors = inErrors; }
+
+ public long getInUnknownProtos() { return inUnknownProtos; }
+ public void setInUnknownProtos(long inUnknownProtos) { this.inUnknownProtos = inUnknownProtos; }
+
+ public long getOutOctets() { return outOctets; }
+ public void setOutOctets(long outOctets) { this.outOctets = outOctets; }
+
+ public long getOutUcastPkts() { return outUcastPkts; }
+ public void setOutUcastPkts(long outUcastPkts) { this.outUcastPkts = outUcastPkts; }
+
+ public long getOutNUcastPkts() { return outNUcastPkts; }
+ public void setOutNUcastPkts(long outNUcastPkts) { this.outNUcastPkts = outNUcastPkts; }
+
+ public long getOutDiscards() { return outDiscards; }
+ public void setOutDiscards(long outDiscards) { this.outDiscards = outDiscards; }
+
+ public long getOutErrors() { return outErrors; }
+ public void setOutErrors(long outErrors) { this.outErrors = outErrors; }
+
+ public long getOutQLen() { return outQLen; }
+ public void setOutQLen(long outQLen) { this.outQLen = outQLen; }
+
+ public String getDescription() { return description; }
+ public void setDescription(String description) { this.description = description; }
+
+ @Override
+ public String toString() {
+ HexFormat hex = HexFormat.of().withDelimiter(":");
+ StringBuilder sb = new StringBuilder();
+ sb.append("Interface: ").append(name).append("\n");
+ sb.append(" Index: ").append(index).append("\n");
+ sb.append(" Type: ").append(getTypeName(type)).append(" (").append(type).append(")\n");
+ sb.append(" MTU: ").append(mtu).append("\n");
+ sb.append(" Speed: ").append(formatSpeed(speed)).append("\n");
+ if (physAddr != null && physAddr.length > 0) {
+ sb.append(" MAC: ").append(hex.formatHex(physAddr)).append("\n");
+ }
+ sb.append(" Admin Status: ").append(getAdminStatusName(adminStatus)).append("\n");
+ sb.append(" Oper Status: ").append(getOperStatusName(operStatus)).append("\n");
+ sb.append(" Description: ").append(description).append("\n");
+ sb.append(" Statistics:\n");
+ sb.append(" In: ").append(formatBytes(inOctets)).append(", ")
+ .append(inUcastPkts).append(" unicast, ")
+ .append(inNUcastPkts).append(" non-unicast\n");
+ sb.append(" Out: ").append(formatBytes(outOctets)).append(", ")
+ .append(outUcastPkts).append(" unicast, ")
+ .append(outNUcastPkts).append(" non-unicast\n");
+ return sb.toString();
+ }
+
+ private String formatSpeed(long speed) {
+ if (speed >= 1_000_000_000L) {
+ return String.format("%.1f Gbps", speed / 1_000_000_000.0);
+ } else if (speed >= 1_000_000L) {
+ return String.format("%.1f Mbps", speed / 1_000_000.0);
+ } else if (speed >= 1_000L) {
+ return String.format("%.1f Kbps", speed / 1_000.0);
+ } else {
+ return speed + " bps";
+ }
+ }
+
+ private String formatBytes(long bytes) {
+ if (bytes >= 1_073_741_824L) { // 1 GiB
+ return String.format("%.2f GiB", bytes / 1_073_741_824.0);
+ } else if (bytes >= 1_048_576L) { // 1 MiB
+ return String.format("%.2f MiB", bytes / 1_048_576.0);
+ } else if (bytes >= 1_024L) { // 1 KiB
+ return String.format("%.2f KiB", bytes / 1_024.0);
+ } else {
+ return bytes + " bytes";
+ }
+ }
+ }
+
+ /**
+ * 获取接口信息
+ * @param ifIndex 接口索引
+ * @return 接口信息对象
+ */
+ public static MibIfRow getIfEntry(int ifIndex) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 分配 MIB_IFROW 结构体
+ MemorySegment ifRow = arena.allocate(MIB_IFROW_LAYOUT);
+
+ // 清零初始化
+ ifRow.fill((byte)0);
+
+ // 设置接口索引 (dwIndex)
+ ifRow.set(DWORD, 512, ifIndex);
+
+ // 调用 GetIfEntry
+ int result = (int) GET_IF_ENTRY.invokeExact(ifRow);
+
+ if (result != NO_ERROR) {
+ throw new WindowsAPIException("GetIfEntry failed", result);
+ }
+
+ // 解析结构体为 Java 对象
+ return parseMibIfRow(ifRow);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error getting interface entry", e);
+ }
+ }
+
+ /**
+ * 设置接口信息 (主要用来修改管理状态)
+ * @param ifRow 接口信息对象
+ * @return 操作结果 (0 = 成功)
+ */
+ public static int setIfEntry(MibIfRow ifRow) {
+ try (Arena arena = Arena.ofConfined()) {
+ // 分配 MIB_IFROW 结构体
+ MemorySegment ifRowSegment = arena.allocate(MIB_IFROW_LAYOUT);
+
+ // 清零初始化
+ ifRowSegment.fill((byte)0);
+
+ // 填充结构体
+ fillMibIfRow(ifRowSegment, ifRow, arena);
+
+ // 调用 SetIfEntry
+ return (int) SET_IF_ENTRY.invokeExact(ifRowSegment);
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Error setting interface entry", e);
+ }
+ }
+
+ /**
+ * 启用接口 (设置管理状态为 UP)
+ * @param ifIndex 接口索引
+ * @return 操作结果 (0 = 成功)
+ */
+ public static int enableInterface(int ifIndex) {
+ MibIfRow ifRow = new MibIfRow();
+ ifRow.setIndex(ifIndex);
+ ifRow.setAdminStatus(MIB_IF_ADMIN_STATUS_UP);
+ return setIfEntry(ifRow);
+ }
+
+ /**
+ * 禁用接口 (设置管理状态为 DOWN)
+ * @param ifIndex 接口索引
+ * @return 操作结果 (0 = 成功)
+ */
+ public static int disableInterface(int ifIndex) {
+ MibIfRow ifRow = new MibIfRow();
+ ifRow.setIndex(ifIndex);
+ ifRow.setAdminStatus(MIB_IF_ADMIN_STATUS_DOWN);
+ return setIfEntry(ifRow);
+ }
+
+ /**
+ * 解析 MIB_IFROW 结构体为 Java 对象
+ */
+ private static MibIfRow parseMibIfRow(MemorySegment ifRow) {
+ MibIfRow result = new MibIfRow();
+
+ // 1. 解析接口名称 (宽字符串)
+ String name = readWideString(ifRow, 0, MAX_INTERFACE_NAME_LEN);
+ result.setName(name);
+
+ // 2. 读取基本字段
+ result.setIndex(ifRow.get(DWORD, 512));
+ result.setType(ifRow.get(DWORD, 516));
+ result.setMtu(ifRow.get(DWORD, 520));
+
+ // 3. 速度需要处理为无符号
+ result.setSpeed(Integer.toUnsignedLong(ifRow.get(DWORD, 524)));
+
+ // 4. 物理地址
+ int physAddrLen = ifRow.get(DWORD, 528);
+ if (physAddrLen > 0 && physAddrLen <= MAXLEN_PHYSADDR) {
+ byte[] physAddr = new byte[physAddrLen];
+ MemorySegment.copy(ifRow, 532, MemorySegment.ofArray(physAddr), 0, physAddrLen);
+ result.setPhysAddr(physAddr);
+ }
+
+ // 5. 状态信息
+ result.setAdminStatus(ifRow.get(DWORD, 564));
+ result.setOperStatus(ifRow.get(DWORD, 568));
+ result.setLastChange(Integer.toUnsignedLong(ifRow.get(DWORD, 572)));
+
+ // 6. 输入统计 (需要处理为无符号)
+ result.setInOctets(Integer.toUnsignedLong(ifRow.get(DWORD, 576)));
+ result.setInUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 580)));
+ result.setInNUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 584)));
+ result.setInDiscards(Integer.toUnsignedLong(ifRow.get(DWORD, 588)));
+ result.setInErrors(Integer.toUnsignedLong(ifRow.get(DWORD, 592)));
+ result.setInUnknownProtos(Integer.toUnsignedLong(ifRow.get(DWORD, 596)));
+
+ // 7. 输出统计
+ result.setOutOctets(Integer.toUnsignedLong(ifRow.get(DWORD, 600)));
+ result.setOutUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 604)));
+ result.setOutNUcastPkts(Integer.toUnsignedLong(ifRow.get(DWORD, 608)));
+ result.setOutDiscards(Integer.toUnsignedLong(ifRow.get(DWORD, 612)));
+ result.setOutErrors(Integer.toUnsignedLong(ifRow.get(DWORD, 616)));
+ result.setOutQLen(Integer.toUnsignedLong(ifRow.get(DWORD, 620)));
+
+ // 8. 接口描述
+ int descrLen = ifRow.get(DWORD, 624);
+ if (descrLen > 0 && descrLen <= MAXLEN_IFDESCR) {
+ byte[] descrBytes = new byte[descrLen];
+ MemorySegment.copy(ifRow, 628, MemorySegment.ofArray(descrBytes), 0, descrLen);
+ result.setDescription(new String(descrBytes, java.nio.charset.StandardCharsets.UTF_8));
+ }
+
+ return result;
+ }
+
+ /**
+ * 填充 MIB_IFROW 结构体
+ */
+ private static void fillMibIfRow(MemorySegment ifRow, MibIfRow data, Arena arena) {
+ // 1. 设置接口索引 (必须)
+ ifRow.set(DWORD, 512, data.getIndex());
+
+ // 2. 设置接口名称 (如果需要)
+ if (data.getName() != null) {
+ writeWideString(ifRow, 0, data.getName(), MAX_INTERFACE_NAME_LEN);
+ }
+
+ // 3. 设置接口类型 (如果需要)
+ ifRow.set(DWORD, 516, data.getType());
+
+ // 4. 设置 MTU (如果需要)
+ ifRow.set(DWORD, 520, data.getMtu());
+
+ // 5. 设置速度 (如果需要)
+ ifRow.set(DWORD, 524, (int)Math.min(data.getSpeed(), 0xFFFFFFFFL));
+
+ // 6. 设置物理地址 (如果需要)
+ if (data.getPhysAddr() != null && data.getPhysAddr().length > 0) {
+ int len = Math.min(data.getPhysAddr().length, MAXLEN_PHYSADDR);
+ ifRow.set(DWORD, 528, len);
+ MemorySegment.copy(MemorySegment.ofArray(data.getPhysAddr()), 0, ifRow, 532, len);
+ }
+
+ // 7. 设置管理状态 (主要用途)
+ ifRow.set(DWORD, 564, data.getAdminStatus());
+
+ // 8. 设置操作状态 (通常只读,但这里也设置)
+ ifRow.set(DWORD, 568, data.getOperStatus());
+
+ // 9. 设置接口描述 (如果需要)
+ if (data.getDescription() != null && !data.getDescription().isEmpty()) {
+ byte[] descrBytes = data.getDescription().getBytes(java.nio.charset.StandardCharsets.UTF_8);
+ int len = Math.min(descrBytes.length, MAXLEN_IFDESCR);
+ ifRow.set(DWORD, 624, len);
+ MemorySegment.copy(MemorySegment.ofArray(descrBytes), 0, ifRow, 628, len);
+ }
+ }
+
+ /**
+ * 读取宽字符串
+ */
+ private static String readWideString(MemorySegment segment, long offset, int maxChars) {
+ try {
+ // 查找 null 终止符
+ long length = 0;
+ while (length < maxChars) {
+ short ch = segment.get(WORD, offset + length * 2);
+ if (ch == 0) {
+ break;
+ }
+ length++;
+ }
+
+ if (length == 0) {
+ return "";
+ }
+
+ // 读取字符串数据
+ byte[] bytes = new byte[(int)(length * 2)];
+ MemorySegment.copy(segment, offset, MemorySegment.ofArray(bytes), 0, bytes.length);
+
+ return new String(bytes, java.nio.charset.StandardCharsets.UTF_16LE);
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ /**
+ * 写入宽字符串
+ */
+ private static void writeWideString(MemorySegment segment, long offset, String str, int maxChars) {
+ if (str == null || str.isEmpty()) {
+ return;
+ }
+
+ byte[] utf16Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
+ int copyLen = Math.min(utf16Bytes.length, (maxChars - 1) * 2);
+
+ if (copyLen > 0) {
+ MemorySegment.copy(MemorySegment.ofArray(utf16Bytes), 0, segment, offset, copyLen);
+ }
+
+ // 添加 null 终止符
+ segment.set(WORD, offset + copyLen, (short)0);
+ }
+
+ /**
+ * 获取接口类型名称
+ */
+ private static String getTypeName(int type) {
+ switch (type) {
+ case IF_TYPE_ETHERNET_CSMACD: return "Ethernet";
+ case IF_TYPE_ISO88025_TOKENRING: return "Token Ring";
+ case IF_TYPE_PPP: return "PPP";
+ case IF_TYPE_SOFTWARE_LOOPBACK: return "Loopback";
+ case IF_TYPE_ATM: return "ATM";
+ case IF_TYPE_IEEE80211: return "WiFi";
+ case IF_TYPE_TUNNEL: return "Tunnel";
+ case IF_TYPE_IEEE1394: return "FireWire";
+ default: return "Unknown (" + type + ")";
+ }
+ }
+
+ /**
+ * 获取管理状态名称
+ */
+ private static String getAdminStatusName(int status) {
+ switch (status) {
+ case MIB_IF_ADMIN_STATUS_UP: return "UP";
+ case MIB_IF_ADMIN_STATUS_DOWN: return "DOWN";
+ case MIB_IF_ADMIN_STATUS_TESTING: return "TESTING";
+ default: return "UNKNOWN (" + status + ")";
+ }
+ }
+
+ /**
+ * 获取操作状态名称
+ */
+ private static String getOperStatusName(int status) {
+ switch (status) {
+ case IF_OPER_STATUS_NON_OPERATIONAL: return "NON_OPERATIONAL";
+ case IF_OPER_STATUS_UNREACHABLE: return "UNREACHABLE";
+ case IF_OPER_STATUS_DISCONNECTED: return "DISCONNECTED";
+ case IF_OPER_STATUS_CONNECTING: return "CONNECTING";
+ case IF_OPER_STATUS_CONNECTED: return "CONNECTED";
+ case IF_OPER_STATUS_OPERATIONAL: return "OPERATIONAL";
+ default: return "UNKNOWN (" + status + ")";
+ }
+ }
+
+
+ /**
+ * 测试方法
+ */
+ public static void main(String[] args) {
+ try {
+ System.out.println("Windows Interface Manager");
+ System.out.println("========================\n");
+
+ // 测试获取所有接口(需要先获取接口表,这里简化测试)
+ System.out.println("Testing GetIfEntry for interface index 1:");
+
+ try {
+ MibIfRow ifRow = getIfEntry(1);
+ System.out.println(ifRow);
+ } catch (Exception e) {
+ System.out.println("Failed to get interface 1: " + e.getMessage());
+ }
+
+ // 测试获取环回接口(通常是索引 1)
+ System.out.println("\nTesting with common interface indices:");
+
+ // 常见的接口索引范围
+ for (int i = 1; i <= 100; i++) {
+ try {
+ MibIfRow ifRow = getIfEntry(i);
+ System.out.println("Interface " + i + ": " + ifRow.getName());
+
+ // 如果是 Wintun 接口,可以尝试启用/禁用
+ if (ifRow.getName().contains("Wintun") || ifRow.getType() == IF_TYPE_TUNNEL) {
+ System.out.println(" Found Wintun/tunnel interface!");
+
+ // 示例:启用接口
+ // int result = enableInterface(i);
+ // System.out.println(" Enable result: " + result);
+ }
+ } catch (Exception e) {
+ // 接口不存在是正常的
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WindowsTUNChannel.java b/src/org/kne/cloud/network/tun/WindowsTUNChannel.java
new file mode 100644
index 0000000..f3d290b
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsTUNChannel.java
@@ -0,0 +1,67 @@
+package org.kne.cloud.network.tun;
+
+import java.io.IOException;
+import java.lang.foreign.MemorySegment;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+
+import org.kne.cloud.network.tun.WintunDriver.Packet;
+import org.kne.cloud.network.tun.WintunDriver.SendPacket;
+import org.kne.cloud.network.tun.WintunDriver.WintunSessionHandle;
+
+public class WindowsTUNChannel implements TUNChannel {
+
+ private WintunSessionHandle session;
+ private MemorySegment waitevent;
+
+ protected WindowsTUNChannel(WintunSessionHandle session) {
+ this.session=session;
+ this.waitevent =WintunDriver.getReadWaitEvent(session);
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ if(session==null) {
+ throw new SocketException("TUN session closed!");
+ }
+ int rem=src.remaining();
+ SendPacket sendPacket = WintunDriver.allocateSendPacket(session, rem);
+ if (sendPacket != null) {
+ sendPacket.data().asByteBuffer().put(src);
+ sendPacket.send();
+ }
+ return rem;
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ while (true) {
+ if(session==null) {
+ throw new SocketException("TUN session closed!");
+ }
+ WindowsWaitHandle.waitForSingleObject(waitevent, 10);
+ Packet packet = WintunDriver.receivePacket(session);
+ if (packet != null) {
+ ByteBuffer bytebuf=packet.data().asByteBuffer();
+ int rem=Math.min(bytebuf.remaining(),dst.remaining());
+ dst.put(bytebuf);
+ packet.release();
+ return rem;
+
+ }
+ }
+ }
+
+ @Override
+ public boolean isOpen() {
+ return session!=null;
+ }
+
+ @Override
+ public void close() throws IOException {
+ WintunSessionHandle wsh=session;
+ session=null;
+ WintunDriver.endSession(wsh);
+ }
+
+}
diff --git a/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class b/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class
new file mode 100644
index 0000000..7fec2cf
Binary files /dev/null and b/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.class differ
diff --git a/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.java b/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.java
new file mode 100644
index 0000000..3f4446c
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsTUNNetworkDevice.java
@@ -0,0 +1,183 @@
+package org.kne.cloud.network.tun;
+
+import java.io.IOException;
+import java.lang.foreign.MemorySegment;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.channels.DatagramChannel;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kne.cloud.network.tun.WindowsDNSManager.DnsInterfaceSettings;
+import org.kne.cloud.network.tun.WindowsIPAddressManager.AddressFamily;
+import org.kne.cloud.network.tun.WindowsIPAddressManager.UnicastIPAddressRow;
+import org.kne.cloud.network.tun.WindowsIPInterfaceManager.MibIpInterfaceRow;
+import org.kne.cloud.network.tun.WindowsInterfaceConverter.GUID;
+import org.kne.cloud.network.tun.WintunDriver.SendPacket;
+import org.kne.cloud.network.tun.WintunDriver.WintunAdapterHandle;
+import org.kne.cloud.network.tun.WintunDriver.WintunSessionHandle;
+
+public class WindowsTUNNetworkDevice extends TUNNetworkDevice{
+
+ private WintunAdapterHandle adapter;
+
+ private long luid;
+ private GUID guid;
+
+ public WindowsTUNNetworkDevice(String name, String type) {
+ adapter = WintunDriver. createAdapter(name, type, null);
+ luid=WintunDriver.getAdapterLuid(adapter);
+ guid=WindowsInterfaceConverter .convertLuidToGuid(luid);
+ // System.out.println("创建虚拟网卡: LUID="+luid+" GUID="+guid);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return adapter!=null;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if(channel!=null&&channel.isOpen()) {
+ channel.close();
+ channel=null;
+ }
+ WintunAdapterHandle adap=adapter;
+ adapter=null;
+ if(adap!=null) {
+ WintunDriver.closeAdapter(adap);
+ }
+ }
+
+
+
+
+ @Override
+ public int getMTU() throws IOException {
+ MibIpInterfaceRow ipv4Info =WindowsIPInterfaceManager. getInterfaceInfo(luid, WindowsIPInterfaceManager. AF_INET);
+ MibIpInterfaceRow ipv6Info = WindowsIPInterfaceManager.getInterfaceInfo(luid,WindowsIPInterfaceManager. AF_INET6);
+
+ return Math.min(ipv4Info.getNlMtu(),ipv6Info. getNlMtu());
+ }
+
+ @Override
+ public void setMTU(int mtu) throws IOException {
+ /*
+ try {
+ int rez = Runtime.getRuntime()
+ .exec("netsh interface ipv6 set subinterface \"" + name + "\" mtu=" + mtu + " store=persistent")
+ .waitFor();
+ int rezx = Runtime.getRuntime()
+ .exec("netsh interface ipv4 set subinterface \"" + name + "\" mtu=" + mtu + " store=persistent")
+ .waitFor();
+ if (rez != 0 || rezx != 0) {
+ throw new IOException("set MTU failed!");
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }*/
+ WindowsIPInterfaceManager.setInterfaceMtu(luid, WindowsIPInterfaceManager. AF_INET, mtu);
+ WindowsIPInterfaceManager.setInterfaceMtu(luid, WindowsIPInterfaceManager. AF_INET6, mtu);
+ }
+
+ @Override
+ public void setDNSAddress(List addresses) throws IOException {
+ DnsInterfaceSettings dis=new DnsInterfaceSettings();
+ dis.setVersion(WindowsDNSManager.DNS_INTERFACE_SETTINGS_VERSION1);
+ dis.setFlags(WindowsDNSManager.DNS_SETTING_IPV6|WindowsDNSManager.DNS_SETTING_NAMESERVER);
+ dis.setNameServers(new ArrayList());
+
+ DnsInterfaceSettings dis4=new DnsInterfaceSettings();
+ dis4.setVersion(WindowsDNSManager.DNS_INTERFACE_SETTINGS_VERSION1);
+ dis4.setFlags(WindowsDNSManager.DNS_SETTING_NAMESERVER);
+ dis4.setNameServers(new ArrayList());
+
+ for(InetAddress addr:addresses) {
+ if(addr instanceof Inet6Address) {
+ dis.getNameServers().add(addr.getHostAddress());
+ }else {
+ dis4.getNameServers().add(addr.getHostAddress());
+ }
+ }
+ WindowsDNSManager.setInterfaceDnsSettings(guid, dis);
+ WindowsDNSManager.setInterfaceDnsSettings(guid, dis4);
+ }
+
+ @Override
+ public List getDNSAddress() throws SocketException {
+ DnsInterfaceSettings dis=new DnsInterfaceSettings();
+ dis.setFlags(WindowsDNSManager.DNS_SETTING_IPV6);
+ dis.setVersion(WindowsDNSManager.DNS_INTERFACE_SETTINGS_VERSION1);
+ dis=WindowsDNSManager.getInterfaceDnsSettings(guid, dis);
+ List strs=dis.getNameServers();
+
+ DnsInterfaceSettings dis4=new DnsInterfaceSettings();
+ dis4.setVersion(WindowsDNSManager.DNS_INTERFACE_SETTINGS_VERSION1);
+ dis4=WindowsDNSManager.getInterfaceDnsSettings(guid, dis4);
+ List strs4=dis4.getNameServers();
+
+ Listdnsaddrs=new ArrayList<>();
+ for(String str:strs) {
+ try {
+ dnsaddrs.add(InetAddress.getByName(str));
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+ for(String str:strs4) {
+ try {
+ dnsaddrs.add(InetAddress.getByName(str));
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+ return dnsaddrs;
+ }
+ WindowsTUNChannel channel;
+
+ @Override
+ public TUNChannel openSession() {
+ if(channel!=null&&channel.isOpen()) {
+ throw new IllegalStateException("Session already created!");
+ }
+ WintunSessionHandle session=WintunDriver.startSession(adapter, WintunDriver.WINTUN_MAX_RING_CAPACITY);
+ channel=new WindowsTUNChannel(session);
+ return channel;
+ }
+
+ @Override
+ public List getIPAddress() throws IOException {
+ List result=new ArrayList<>();
+ Listinfo= WindowsIPAddressManager.getUnicastIpAddressTable(AddressFamily.AF_UNSPEC);
+ for(UnicastIPAddressRow cir:info) {
+ InetAddressRow rowc=new InetAddressRow(cir.getAddress(), cir.getOnLinkPrefixLength());
+ result.add(rowc);
+ }
+ return result;
+ }
+
+ @Override
+ public void setIPAddress(List rows) throws IOException {
+ List rowsinc=new ArrayList<>(rows);
+ Listinfo= WindowsIPAddressManager.getUnicastIpAddressTable(AddressFamily.AF_UNSPEC);
+ for(UnicastIPAddressRow cir:info) {
+ if(cir.getInterfaceLuid()!=luid)
+ continue;
+ InetAddressRow rowc=new InetAddressRow(cir.getAddress(), cir.getOnLinkPrefixLength());
+ if(!rows.contains(rowc)) {
+ WindowsIPAddressManager.deleteUnicastIpAddressEntry(cir);
+ }else {
+ rowsinc.remove(rowc);
+ }
+ }
+ for(InetAddressRow row:rowsinc) {
+ InetAddress addr=row.getAddress();
+ WindowsIPAddressManager.addIpAddressToAdapter(luid, addr, row.getPerfix());
+ }
+ }
+
+}
+
diff --git a/src/org/kne/cloud/network/tun/WindowsWaitHandle.java b/src/org/kne/cloud/network/tun/WindowsWaitHandle.java
new file mode 100644
index 0000000..fd78f07
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WindowsWaitHandle.java
@@ -0,0 +1,166 @@
+package org.kne.cloud.network.tun;
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.time.Duration;
+
+/**
+ * Windows WaitForSingleObject 函数封装
+ * 专用于等待 WintunGetReadWaitEvent 返回的事件句柄
+ */
+public class WindowsWaitHandle {
+
+ // 常量定义
+ public static final long INFINITE = 0xFFFFFFFFL; // 无限等待
+ public static final long WAIT_OBJECT_0 = 0x00000000L; // 事件已发出信号
+ public static final long WAIT_TIMEOUT = 0x00000102L; // 超时
+ public static final long WAIT_FAILED = 0xFFFFFFFFL; // 失败
+
+ // 内存布局
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+
+ // Native库加载
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ // 方法句柄
+ private static final MethodHandle WAIT_FOR_SINGLE_OBJECT;
+
+ static {
+ try {
+ // 加载 kernel32.dll
+ System.loadLibrary("kernel32");
+ LOOKUP = SymbolLookup.loaderLookup();
+
+ // 定义函数描述符
+ // DWORD WINAPI WaitForSingleObject(
+ // _In_ HANDLE hHandle,
+ // _In_ DWORD dwMilliseconds
+ // );
+ FunctionDescriptor waitForSingleObjectDesc = FunctionDescriptor.of(
+ DWORD, // 返回值: DWORD
+ POINTER, // hHandle: HANDLE
+ DWORD // dwMilliseconds: DWORD
+ );
+
+ // 获取函数句柄
+ WAIT_FOR_SINGLE_OBJECT = LINKER.downcallHandle(
+ LOOKUP.find("WaitForSingleObject").orElseThrow(),
+ waitForSingleObjectDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize WindowsWaitHandle", e);
+ }
+ }
+
+ /**
+ * 等待单个对象(事件句柄)
+ *
+ * @param handle 要等待的事件句柄(MemorySegment)
+ * @param timeoutMillis 超时时间(毫秒),0表示立即返回,INFINITE表示无限等待
+ * @return 等待结果:WAIT_OBJECT_0, WAIT_TIMEOUT, 或 WAIT_FAILED
+ */
+ public static long waitForSingleObject(MemorySegment handle, long timeoutMillis) {
+ try {
+ int timeout;
+ if (timeoutMillis == INFINITE) {
+ timeout = (int)INFINITE; // 0xFFFFFFFF
+ } else if (timeoutMillis > 0xFFFFFFFFL) {
+ timeout = (int)INFINITE; // 超过DWORD最大值,使用INFINITE
+ } else {
+ timeout = (int)timeoutMillis;
+ }
+
+ int result = (int) WAIT_FOR_SINGLE_OBJECT.invokeExact(
+ handle,
+ timeout
+ );
+
+ return result & 0xFFFFFFFFL; // 无符号转换
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WaitForSingleObject", e);
+ }
+ }
+
+ /**
+ * 等待事件(使用Duration)
+ */
+ public static long waitForSingleObject(MemorySegment handle, Duration timeout) {
+ if (timeout == null) {
+ return waitForSingleObject(handle, INFINITE);
+ }
+
+ long millis = timeout.toMillis();
+ if (millis <= 0) {
+ return waitForSingleObject(handle, 0); // 立即返回
+ }
+
+ return waitForSingleObject(handle, millis);
+ }
+
+ /**
+ * 无限等待事件
+ */
+ public static long waitForSingleObjectInfinite(MemorySegment handle) {
+ return waitForSingleObject(handle, INFINITE);
+ }
+
+ /**
+ * 非阻塞检查事件(立即返回)
+ */
+ public static long waitForSingleObjectNoWait(MemorySegment handle) {
+ return waitForSingleObject(handle, 0);
+ }
+
+ /**
+ * 等待事件,带重试机制
+ */
+ public static boolean waitWithRetry(MemorySegment handle, int maxRetries, long timeoutPerRetry) {
+ for (int i = 0; i < maxRetries; i++) {
+ long result = waitForSingleObject(handle, timeoutPerRetry);
+
+ if (result == WAIT_OBJECT_0) {
+ return true; // 事件已发出信号
+ } else if (result == WAIT_TIMEOUT) {
+ // 超时,继续重试
+ continue;
+ } else if (result == WAIT_FAILED) {
+ // 失败,停止重试
+ break;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 检查等待结果
+ */
+ public static boolean isWaitSuccess(long waitResult) {
+ return waitResult == WAIT_OBJECT_0;
+ }
+
+ public static boolean isWaitTimeout(long waitResult) {
+ return waitResult == WAIT_TIMEOUT;
+ }
+
+ public static boolean isWaitFailed(long waitResult) {
+ return waitResult == WAIT_FAILED;
+ }
+
+ /**
+ * 获取等待结果的描述
+ */
+ public static String getWaitResultDescription(long waitResult) {
+ if (waitResult == WAIT_OBJECT_0) {
+ return "Event signaled (WAIT_OBJECT_0)";
+ } else if (waitResult == WAIT_TIMEOUT) {
+ return "Timeout (WAIT_TIMEOUT)";
+ } else if (waitResult == WAIT_FAILED) {
+ return "Failed (WAIT_FAILED)";
+ } else {
+ return String.format("Unknown result: 0x%08X", waitResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/cloud/network/tun/WintunDriver.java b/src/org/kne/cloud/network/tun/WintunDriver.java
new file mode 100644
index 0000000..955f825
--- /dev/null
+++ b/src/org/kne/cloud/network/tun/WintunDriver.java
@@ -0,0 +1,564 @@
+package org.kne.cloud.network.tun;
+import java.lang.foreign.*;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.kne.cloud.network.tun.WindowsDNSManager.DnsInterfaceSettings;
+import org.kne.cloud.network.tun.WindowsInterfaceConverter.GUID;
+public class WintunDriver {
+
+ // Memory layouts matching C types
+ public static final ValueLayout.OfInt DWORD = ValueLayout.JAVA_INT;
+ public static final ValueLayout.OfLong DWORD64 = ValueLayout.JAVA_LONG;
+ public static final AddressLayout POINTER = ValueLayout.ADDRESS;
+ public static final ValueLayout.OfByte BYTE = ValueLayout.JAVA_BYTE;
+ public static final ValueLayout.OfShort WORD = ValueLayout.JAVA_SHORT;
+
+ // Constants from the header
+ public static final int WINTUN_MIN_RING_CAPACITY = 0x20000; // 128kiB
+ public static final int WINTUN_MAX_RING_CAPACITY = 0x4000000; // 64MiB
+ public static final int WINTUN_MAX_IP_PACKET_SIZE = 0xFFFF;
+
+ // Opaque handle types (represented as MemorySegment)
+ public static class WintunAdapterHandle extends NativeHandle {
+ WintunAdapterHandle(MemorySegment address) {
+ super(address);
+ }
+ }
+
+ public static class WintunSessionHandle extends NativeHandle {
+ WintunSessionHandle(MemorySegment address) {
+ super(address);
+ }
+ }
+
+ // Native library loading
+ private static final SymbolLookup LOOKUP;
+ private static final Linker LINKER = Linker.nativeLinker();
+
+ static {
+ // Load wintun.dll from system or current directory
+ System.loadLibrary("wintun");
+ LOOKUP = SymbolLookup.loaderLookup();
+ }
+
+ // Native function handles
+ private static final MethodHandle WINTUN_CREATE_ADAPTER;
+ private static final MethodHandle WINTUN_OPEN_ADAPTER;
+ private static final MethodHandle WINTUN_CLOSE_ADAPTER;
+ private static final MethodHandle WINTUN_DELETE_DRIVER;
+ private static final MethodHandle WINTUN_GET_ADAPTER_LUID;
+ private static final MethodHandle WINTUN_GET_RUNNING_DRIVER_VERSION;
+ private static final MethodHandle WINTUN_SET_LOGGER;
+ private static final MethodHandle WINTUN_START_SESSION;
+ private static final MethodHandle WINTUN_END_SESSION;
+ private static final MethodHandle WINTUN_GET_READ_WAIT_EVENT;
+ private static final MethodHandle WINTUN_RECEIVE_PACKET;
+ private static final MethodHandle WINTUN_RELEASE_RECEIVE_PACKET;
+ private static final MethodHandle WINTUN_ALLOCATE_SEND_PACKET;
+ private static final MethodHandle WINTUN_SEND_PACKET;
+
+ static {
+ try {
+ // Define function descriptors matching the C signatures
+ FunctionDescriptor createAdapterDesc = FunctionDescriptor.of(
+ POINTER, // return: WINTUN_ADAPTER_HANDLE
+ POINTER, // Name: LPCWSTR
+ POINTER, // TunnelType: LPCWSTR
+ POINTER // RequestedGUID: const GUID*
+ );
+
+ FunctionDescriptor openAdapterDesc = FunctionDescriptor.of(
+ POINTER, // return: WINTUN_ADAPTER_HANDLE
+ POINTER // Name: LPCWSTR
+ );
+
+ FunctionDescriptor closeAdapterDesc = FunctionDescriptor.ofVoid(
+ POINTER // Adapter: WINTUN_ADAPTER_HANDLE
+ );
+
+ // 修正这里:去掉额外的VOID参数
+ FunctionDescriptor deleteDriverDesc = FunctionDescriptor.of(
+ ValueLayout.JAVA_INT // BOOL
+ );
+
+ FunctionDescriptor getAdapterLuidDesc = FunctionDescriptor.ofVoid(
+ POINTER, // Adapter: WINTUN_ADAPTER_HANDLE
+ POINTER // Luid: NET_LUID*
+ );
+
+ // 修正这里:去掉额外的VOID参数
+ FunctionDescriptor getDriverVersionDesc = FunctionDescriptor.of(
+ DWORD // DWORD
+ );
+
+ FunctionDescriptor setLoggerDesc = FunctionDescriptor.ofVoid(
+ POINTER // NewLogger: WINTUN_LOGGER_CALLBACK
+ );
+
+ FunctionDescriptor startSessionDesc = FunctionDescriptor.of(
+ POINTER, // return: WINTUN_SESSION_HANDLE
+ POINTER, // Adapter: WINTUN_ADAPTER_HANDLE
+ DWORD // Capacity: DWORD
+ );
+
+ FunctionDescriptor endSessionDesc = FunctionDescriptor.ofVoid(
+ POINTER // Session: WINTUN_SESSION_HANDLE
+ );
+
+ FunctionDescriptor getReadWaitEventDesc = FunctionDescriptor.of(
+ POINTER, // HANDLE
+ POINTER // Session: WINTUN_SESSION_HANDLE
+ );
+
+ FunctionDescriptor receivePacketDesc = FunctionDescriptor.of(
+ POINTER, // return: BYTE*
+ POINTER, // Session: WINTUN_SESSION_HANDLE
+ POINTER // PacketSize: DWORD*
+ );
+
+ FunctionDescriptor releaseReceivePacketDesc = FunctionDescriptor.ofVoid(
+ POINTER, // Session: WINTUN_SESSION_HANDLE
+ POINTER // Packet: const BYTE*
+ );
+
+ FunctionDescriptor allocateSendPacketDesc = FunctionDescriptor.of(
+ POINTER, // return: BYTE*
+ POINTER, // Session: WINTUN_SESSION_HANDLE
+ DWORD // PacketSize: DWORD
+ );
+
+ FunctionDescriptor sendPacketDesc = FunctionDescriptor.ofVoid(
+ POINTER, // Session: WINTUN_SESSION_HANDLE
+ POINTER // Packet: const BYTE*
+ );
+
+ // Look up the symbols
+ WINTUN_CREATE_ADAPTER = LINKER.downcallHandle(
+ LOOKUP.find("WintunCreateAdapter").orElseThrow(),
+ createAdapterDesc
+ );
+
+ WINTUN_OPEN_ADAPTER = LINKER.downcallHandle(
+ LOOKUP.find("WintunOpenAdapter").orElseThrow(),
+ openAdapterDesc
+ );
+
+ WINTUN_CLOSE_ADAPTER = LINKER.downcallHandle(
+ LOOKUP.find("WintunCloseAdapter").orElseThrow(),
+ closeAdapterDesc
+ );
+
+ WINTUN_DELETE_DRIVER = LINKER.downcallHandle(
+ LOOKUP.find("WintunDeleteDriver").orElseThrow(),
+ deleteDriverDesc
+ );
+
+ WINTUN_GET_ADAPTER_LUID = LINKER.downcallHandle(
+ LOOKUP.find("WintunGetAdapterLUID").orElseThrow(),
+ getAdapterLuidDesc
+ );
+
+ WINTUN_GET_RUNNING_DRIVER_VERSION = LINKER.downcallHandle(
+ LOOKUP.find("WintunGetRunningDriverVersion").orElseThrow(),
+ getDriverVersionDesc
+ );
+
+ WINTUN_SET_LOGGER = LINKER.downcallHandle(
+ LOOKUP.find("WintunSetLogger").orElseThrow(),
+ setLoggerDesc
+ );
+
+ WINTUN_START_SESSION = LINKER.downcallHandle(
+ LOOKUP.find("WintunStartSession").orElseThrow(),
+ startSessionDesc
+ );
+
+ WINTUN_END_SESSION = LINKER.downcallHandle(
+ LOOKUP.find("WintunEndSession").orElseThrow(),
+ endSessionDesc
+ );
+
+ WINTUN_GET_READ_WAIT_EVENT = LINKER.downcallHandle(
+ LOOKUP.find("WintunGetReadWaitEvent").orElseThrow(),
+ getReadWaitEventDesc
+ );
+
+ WINTUN_RECEIVE_PACKET = LINKER.downcallHandle(
+ LOOKUP.find("WintunReceivePacket").orElseThrow(),
+ receivePacketDesc
+ );
+
+ WINTUN_RELEASE_RECEIVE_PACKET = LINKER.downcallHandle(
+ LOOKUP.find("WintunReleaseReceivePacket").orElseThrow(),
+ releaseReceivePacketDesc
+ );
+
+ WINTUN_ALLOCATE_SEND_PACKET = LINKER.downcallHandle(
+ LOOKUP.find("WintunAllocateSendPacket").orElseThrow(),
+ allocateSendPacketDesc
+ );
+
+ WINTUN_SEND_PACKET = LINKER.downcallHandle(
+ LOOKUP.find("WintunSendPacket").orElseThrow(),
+ sendPacketDesc
+ );
+
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to initialize native function handles", e);
+ }
+ }
+
+ // Helper method to convert Java String to Windows wide string (UTF-16 LE)
+ private static MemorySegment toWideString(String str, Arena arena) {
+ if (str == null) return MemorySegment.NULL;
+
+ // Convert to UTF-16LE bytes with null terminator
+ byte[] utf16Bytes = str.getBytes(java.nio.charset.StandardCharsets.UTF_16LE);
+ MemorySegment segment = arena.allocate(utf16Bytes.length + 2);
+
+ // 使用 copyFrom 替代原来的 copy 方法
+ // 注意参数顺序:源数组 -> 目标MemorySegment
+ segment.copyFrom(MemorySegment.ofArray(utf16Bytes));
+
+ // 添加 null 终止符 (两个字节)
+ segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length, (byte)0);
+ segment.set(ValueLayout.JAVA_BYTE, utf16Bytes.length + 1, (byte)0);
+
+ return segment;
+ }
+
+ // Java API methods
+
+ public static WintunAdapterHandle createAdapter(String name, String tunnelType, MemorySegment requestedGuid) {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment nameSegment = toWideString(name, arena);
+ MemorySegment tunnelTypeSegment = toWideString(tunnelType, arena);
+
+ MemorySegment result = (MemorySegment) WINTUN_CREATE_ADAPTER.invokeExact(
+ nameSegment,
+ tunnelTypeSegment,
+ (MemorySegment)( requestedGuid != null ? requestedGuid : MemorySegment.NULL)
+ );
+
+ if (result.equals(MemorySegment.NULL)) {
+ throw new WindowsAPIException("Failed to create adapter");
+ }
+
+ return new WintunAdapterHandle(result);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunCreateAdapter", e);
+ }
+ }
+
+ public static WintunAdapterHandle openAdapter(String name) {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment nameSegment = toWideString(name, arena);
+
+ MemorySegment result = (MemorySegment) WINTUN_OPEN_ADAPTER.invokeExact(nameSegment);
+
+ if (result.equals(MemorySegment.NULL)) {
+ throw new WindowsAPIException("Failed to open adapter");
+ }
+
+ return new WintunAdapterHandle(result);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunOpenAdapter", e);
+ }
+ }
+
+ public static void closeAdapter(WintunAdapterHandle adapter) {
+ try {
+ WINTUN_CLOSE_ADAPTER.invokeExact(adapter.address());
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunCloseAdapter", e);
+ }
+ }
+
+ public static boolean deleteDriver() {
+ try {
+ int result = (int) WINTUN_DELETE_DRIVER.invokeExact();
+ return result != 0;
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunDeleteDriver", e);
+ }
+ }
+
+ public static long getAdapterLuid(WintunAdapterHandle adapter) {
+ // 直接在全局Arena中分配
+
+ try ( Arena ara=Arena.ofConfined()){
+ MemorySegment luidm = ara.allocate(ValueLayout.JAVA_LONG);
+ WINTUN_GET_ADAPTER_LUID.invokeExact(adapter.address(), luidm);
+ return luidm.get(ValueLayout.JAVA_LONG, 0);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunGetAdapterLuid", e);
+ }
+ }
+
+ public static int getRunningDriverVersion() {
+ try {
+ return (int) WINTUN_GET_RUNNING_DRIVER_VERSION.invokeExact();
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunGetRunningDriverVersion", e);
+ }
+ }
+
+ public static void setLogger(MemorySegment loggerCallback) {
+ try {
+ WINTUN_SET_LOGGER.invokeExact(loggerCallback);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunSetLogger", e);
+ }
+ }
+
+ public static WintunSessionHandle startSession(WintunAdapterHandle adapter, int capacity) {
+ try {
+ if (capacity < WINTUN_MIN_RING_CAPACITY || capacity > WINTUN_MAX_RING_CAPACITY) {
+ throw new IllegalArgumentException(
+ String.format("Capacity must be between %d and %d",
+ WINTUN_MIN_RING_CAPACITY, WINTUN_MAX_RING_CAPACITY)
+ );
+ }
+
+ // Check if capacity is power of two
+ if ((capacity & (capacity - 1)) != 0) {
+ throw new IllegalArgumentException("Capacity must be a power of two");
+ }
+
+ MemorySegment result = (MemorySegment) WINTUN_START_SESSION.invokeExact(
+ adapter.address(),
+ capacity
+ );
+
+ if (result.equals(MemorySegment.NULL)) {
+ throw new WindowsAPIException("Failed to start session");
+ }
+
+ return new WintunSessionHandle(result);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunStartSession", e);
+ }
+ }
+
+ public static void endSession(WintunSessionHandle session) {
+ try {
+ WINTUN_END_SESSION.invokeExact(session.address());
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunEndSession", e);
+ }
+ }
+
+ public static MemorySegment getReadWaitEvent(WintunSessionHandle session) {
+ try {
+ return (MemorySegment) WINTUN_GET_READ_WAIT_EVENT.invokeExact(session.address());
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunGetReadWaitEvent", e);
+ }
+ }
+
+ public static Packet receivePacket(WintunSessionHandle session) {
+ try (Arena arena = Arena.ofConfined()) {
+ MemorySegment packetSizePtr = arena.allocate(DWORD);
+
+ MemorySegment packetPtr = (MemorySegment) WINTUN_RECEIVE_PACKET.invokeExact(
+ session.address(),
+ packetSizePtr
+ );
+
+ if (packetPtr.equals(MemorySegment.NULL)) {
+ // Check for specific errors via GetLastError if needed
+ return null;
+ }
+
+ int packetSize = packetSizePtr.get(DWORD, 0);
+ MemorySegment packetData = packetPtr.reinterpret(packetSize);
+
+ return new Packet(session, packetData, packetSize);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunReceivePacket", e);
+ }
+ }
+
+ public static SendPacket allocateSendPacket(WintunSessionHandle session, int packetSize) {
+ try {
+ if (packetSize > WINTUN_MAX_IP_PACKET_SIZE) {
+ throw new IllegalArgumentException(
+ String.format("Packet size exceeds maximum of %d", WINTUN_MAX_IP_PACKET_SIZE)
+ );
+ }
+
+ MemorySegment packetPtr = (MemorySegment) WINTUN_ALLOCATE_SEND_PACKET.invokeExact(
+ session.address(),
+ packetSize
+ );
+
+ if (packetPtr.equals(MemorySegment.NULL)) {
+ return null;
+ }
+
+ MemorySegment packetData = packetPtr.reinterpret(packetSize);
+ return new SendPacket(session, packetData, packetSize);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error calling WintunAllocateSendPacket", e);
+ }
+ }
+
+ // Helper classes
+
+ public static class NativeHandle {
+ private final MemorySegment address;
+
+ protected NativeHandle(MemorySegment address) {
+ this.address = address;
+ }
+
+ public MemorySegment address() {
+ return address;
+ }
+ }
+
+ public static class Packet {
+ private final WintunSessionHandle session;
+ private final MemorySegment data;
+ private final int size;
+
+ Packet(WintunSessionHandle session, MemorySegment data, int size) {
+ this.session = session;
+ this.data = data;
+ this.size = size;
+ }
+
+ public MemorySegment data() {
+ return data;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public void release() {
+ try {
+ WINTUN_RELEASE_RECEIVE_PACKET.invokeExact(session.address(), data);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error releasing packet", e);
+ }
+ }
+ }
+
+ public static class SendPacket {
+ private final WintunSessionHandle session;
+ private final MemorySegment data;
+ private final int size;
+
+ SendPacket(WintunSessionHandle session, MemorySegment data, int size) {
+ this.session = session;
+ this.data = data;
+ this.size = size;
+ }
+
+ public MemorySegment data() {
+ return data;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public void send() {
+ try {
+ WINTUN_SEND_PACKET.invokeExact(session.address(), data);
+ } catch (Throwable e) {
+ throw new RuntimeException("Error sending packet", e);
+ }
+ }
+ }
+
+
+
+ // Logger callback interface for Java
+ @FunctionalInterface
+ public interface LoggerCallback {
+ void log(int level, long timestamp, String message);
+ }
+
+ // Create a native logger callback from Java interface
+ public static MemorySegment createLoggerCallback(LoggerCallback callback, Arena arena) {
+ return MemorySegment.ofAddress(0); // Implementation would use upcall stub
+ // Note: Full implementation requires creating upcall stub with LINKER.upcallStub
+ }
+
+ // Example usage
+ public static void main(String[] args) {
+ try {
+ // Check driver version
+ int version = getRunningDriverVersion();
+ System.out.println("Wintun driver version: " + version);
+
+ // Create adapter
+ WintunAdapterHandle adapter = createAdapter("MyWintun", "Wintun", null);
+
+
+
+ // Start session
+ WintunSessionHandle session = startSession(adapter, WINTUN_MIN_RING_CAPACITY);
+
+
+
+ // Get adapter LUID
+ GUID guid=null;
+ long luid=getAdapterLuid(adapter);
+ System.out.println("Adapter LUID: " + luid);
+ guid=WindowsInterfaceConverter.convertLuidToGuid(luid);
+ System.out.println("Adapter GUID: "+guid);
+ MemorySegment wintunGuid=guid.toMemorySegment(Arena.ofAuto());
+
+
+
+ System.out.println("\n2. Setting DNS for Wintun adapter:");
+
+ DnsInterfaceSettings dis= new DnsInterfaceSettings();
+ dis.setNameServers(List.of("8.8.8.8"));
+ dis.setFlags(WindowsDNSManager.DNS_SETTING_NAMESERVER);
+ WindowsDNSManager.setInterfaceDnsSettings(guid, dis);
+ System.out.println(dis);
+
+ // Get read wait event (could be used with Java NIO Selector)
+ MemorySegment readEvent = getReadWaitEvent(session);
+
+ try {
+ // Example packet loop
+ while (true) {
+ Packet packet = receivePacket(session);
+ if (packet != null) {
+ try {
+ // Process packet data
+ byte[] packetData = packet.data().toArray(ValueLayout.JAVA_BYTE);
+ System.out.println("Received packet size: " + packet.size());
+
+ // Create response packet
+ SendPacket sendPacket = allocateSendPacket(session, packet.size());
+ if (sendPacket != null) {
+ // Copy data to send buffer - Java 23 方式
+ sendPacket.data().copyFrom(MemorySegment.ofArray(packetData));
+ sendPacket.send();
+ }
+ } finally {
+ packet.release();
+ }
+ }
+ }
+ } finally {
+ // Cleanup
+ endSession(session);
+ closeAdapter(adapter);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/org/kne/util/SystemInfo.java b/src/org/kne/util/SystemInfo.java
new file mode 100644
index 0000000..67c8484
--- /dev/null
+++ b/src/org/kne/util/SystemInfo.java
@@ -0,0 +1,32 @@
+package org.kne.util;
+
+public class SystemInfo {
+ private String osName;
+ private String osArch;
+ private String osVersion;
+ public String getOsName() {
+ return osName;
+ }
+ public String getOsArch() {
+ return osArch;
+ }
+
+ public String getOsVersion() {
+ return osVersion;
+ }
+ public SystemInfo(String osName, String osArch, String osVersion) {
+ super();
+ this.osName = osName;
+ this.osArch = osArch;
+ this.osVersion = osVersion;
+ }
+ public SystemInfo() {
+ this.osName = System.getProperty("os.name");
+ this.osArch = System.getProperty("os.arch");
+ this.osVersion = System.getProperty("os.version");
+ }
+ @Override
+ public String toString() {
+ return "SystemInfo [osName=" + osName + ", osArch=" + osArch + ", osVersion=" + osVersion + "]";
+ }
+}
diff --git a/src/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h b/src/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h
new file mode 100644
index 0000000..bfc0e9b
--- /dev/null
+++ b/src/org_kne_cloud_network_tun_WindowsTUNNetworkDevice.h
@@ -0,0 +1,125 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class org_kne_cloud_network_tun_WindowsTUNNetworkDevice */
+
+#ifndef _Included_org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+#define _Included_org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: loadDriver
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_loadDriver
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: unloadDriver
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_unloadDriver
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: openTUNDevice
+ * Signature: (Ljava/lang/String;Ljava/lang/String;JJ)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_openTUNDevice
+ (JNIEnv *, jobject, jstring, jstring, jlong, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: closeTUNDevice
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_closeTUNDevice
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: openSession
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_openSession
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: closeSession
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_closeSession
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: readAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_readAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: waitForReadAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_waitForReadAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: read0
+ * Signature: (JLjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_read0
+ (JNIEnv *, jobject, jlong, jobject);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: writeAvaliable
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_writeAvaliable
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: write0
+ * Signature: (JLjava/nio/ByteBuffer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_write0
+ (JNIEnv *, jobject, jlong, jobject);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: setTUNDeviceIPAddressV6
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_setTUNDeviceIPAddressV6
+ (JNIEnv *, jobject, jlong, jbyteArray, jint);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: getMTU0
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_getMTU0
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: org_kne_cloud_network_tun_WindowsTUNNetworkDevice
+ * Method: setMTU0
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_org_kne_cloud_network_tun_WindowsTUNNetworkDevice_setMTU0
+ (JNIEnv *, jobject, jlong, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tuntap4j.dll b/tuntap4j.dll
new file mode 100644
index 0000000..b63010c
Binary files /dev/null and b/tuntap4j.dll differ
diff --git a/wintun.dll b/wintun.dll
new file mode 100644
index 0000000..aee04e7
Binary files /dev/null and b/wintun.dll differ
diff --git a/wintun.h b/wintun.h
new file mode 100644
index 0000000..6b7e0da
--- /dev/null
+++ b/wintun.h
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ALIGNED
+# if defined(_MSC_VER)
+# define ALIGNED(n) __declspec(align(n))
+# elif defined(__GNUC__)
+# define ALIGNED(n) __attribute__((aligned(n)))
+# else
+# error "Unable to define ALIGNED"
+# endif
+#endif
+
+/* MinGW is missing this one, unfortunately. */
+#ifndef _Post_maybenull_
+# define _Post_maybenull_
+#endif
+
+#pragma warning(push)
+#pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
+
+/**
+ * A handle representing Wintun adapter
+ */
+typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
+
+/**
+ * Creates a new Wintun adapter.
+ *
+ * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @param TunnelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
+ * If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
+ * created for each new adapter. It is called "requested" GUID because the API it uses is
+ * completely undocumented, and so there could be minor interesting complications with its usage.
+ *
+ * @return If the function succeeds, the return value is the adapter handle. Must be released with
+ * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
+ * GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC)
+(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
+
+/**
+ * Opens an existing Wintun adapter.
+ *
+ * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @return If the function succeeds, the return value is the adapter handle. Must be released with
+ * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
+ * GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
+
+/**
+ * Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
+ *
+ * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
+ */
+typedef VOID(WINAPI WINTUN_CLOSE_ADAPTER_FUNC)(_In_opt_ WINTUN_ADAPTER_HANDLE Adapter);
+
+/**
+ * Deletes the Wintun driver if there are no more adapters in use.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+typedef _Return_type_success_(return != FALSE)
+BOOL(WINAPI WINTUN_DELETE_DRIVER_FUNC)(VOID);
+
+/**
+ * Returns the LUID of the adapter.
+ *
+ * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter
+ *
+ * @param Luid Pointer to LUID to receive adapter LUID.
+ */
+typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
+
+/**
+ * Determines the version of the Wintun driver currently loaded.
+ *
+ * @return If the function succeeds, the return value is the version number. If the function fails, the return value is
+ * zero. To get extended error information, call GetLastError. Possible errors include the following:
+ * ERROR_FILE_NOT_FOUND Wintun not loaded
+ */
+typedef _Return_type_success_(return != 0)
+DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
+
+/**
+ * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
+ */
+typedef enum
+{
+ WINTUN_LOG_INFO, /**< Informational */
+ WINTUN_LOG_WARN, /**< Warning */
+ WINTUN_LOG_ERR /**< Error */
+} WINTUN_LOGGER_LEVEL;
+
+/**
+ * Called by internal logger to report diagnostic messages
+ *
+ * @param Level Message level.
+ *
+ * @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
+ *
+ * @param Message Message text.
+ */
+typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(
+ _In_ WINTUN_LOGGER_LEVEL Level,
+ _In_ DWORD64 Timestamp,
+ _In_z_ LPCWSTR Message);
+
+/**
+ * Sets logger callback function.
+ *
+ * @param NewLogger Pointer to callback function to use as a new global logger. NewLogger may be called from various
+ * threads concurrently. Should the logging require serialization, you must handle serialization in
+ * NewLogger. Set to NULL to disable.
+ */
+typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
+
+/**
+ * Minimum ring capacity.
+ */
+#define WINTUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */
+
+/**
+ * Maximum ring capacity.
+ */
+#define WINTUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */
+
+/**
+ * A handle representing Wintun session
+ */
+typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
+
+/**
+ * Starts Wintun session.
+ *
+ * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
+ *
+ * @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
+ * Must be a power of two.
+ *
+ * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
+ * NULL. To get extended error information, call GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
+
+/**
+ * Ends Wintun session.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ */
+typedef VOID(WINAPI WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
+
+/**
+ * Gets Wintun session's read-wait event handle.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @return Pointer to receive event handle to wait for available data when reading. Should
+ * WintunReceivePackets return ERROR_NO_MORE_ITEMS (after spinning on it for a while under heavy
+ * load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
+ * CloseHandle on this event - it is managed by the session.
+ */
+typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
+
+/**
+ * Maximum IP packet size
+ */
+#define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF
+
+/**
+ * Retrieves one or packet. After the packet content is consumed, call WintunReleaseReceivePacket with Packet returned
+ * from this function to release internal buffer. This function is thread-safe.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param PacketSize Pointer to receive packet size.
+ *
+ * @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the
+ * return value is NULL. To get extended error information, call GetLastError. Possible errors include the
+ * following:
+ * ERROR_HANDLE_EOF Wintun adapter is terminating;
+ * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
+ * ERROR_INVALID_DATA Wintun buffer is corrupt
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(*PacketSize)
+BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
+
+/**
+ * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param Packet Packet obtained with WintunReceivePacket
+ */
+typedef VOID(
+ WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
+
+/**
+ * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
+ * and release internal buffer. WintunAllocateSendPacket is thread-safe and the WintunAllocateSendPacket order of
+ * calls define the packet sending order.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
+ *
+ * @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
+ * the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
+ * following:
+ * ERROR_HANDLE_EOF Wintun adapter is terminating;
+ * ERROR_BUFFER_OVERFLOW Wintun buffer is full;
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(PacketSize)
+BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
+
+/**
+ * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
+ * order of calls define the packet sending order. This means the packet is not guaranteed to be sent in the
+ * WintunSendPacket yet.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param Packet Packet obtained with WintunAllocateSendPacket
+ */
+typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
+
+#pragma warning(pop)
+
+#ifdef __cplusplus
+}
+#endif