\#129 first working IPv6 pinging implementation for Windows

This commit is contained in:
Anton Keks 2019-04-09 22:13:21 +03:00
parent 021f2582ce
commit 42736eb515
5 changed files with 132 additions and 11 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="ipscan" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="3.5.5" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/out/production/classes" />
<output-test url="file://$MODULE_DIR$/out/test/classes" />
<output url="file://$MODULE_DIR$/build/classes/java/main" />
<output-test url="file://$MODULE_DIR$/build/classes/java/test" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/ext/rocksaw/src" isTestSource="false" />
@ -27,6 +27,19 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: com.google.dagger:dagger:2.19" level="project" />
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.dagger:dagger-compiler:2.19" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.dagger:dagger-spi:2.19" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.dagger:dagger-producers:2.19" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.googlejavaformat:google-java-format:1.5" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.guava:guava:25.0-jre" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.squareup:javapoet:1.11.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: javax.annotation:jsr250-api:1.0" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.checkerframework:checker-compat-qual:2.5.3" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.errorprone:javac-shaded:9-dev-r4023-3" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.code.findbugs:jsr305:1.3.9" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.errorprone:error_prone_annotations:2.1.3" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: com.google.j2objc:j2objc-annotations:1.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.codehaus.mojo:animal-sniffer-annotations:1.14" level="project" />
<orderEntry type="module-library" scope="PROVIDED">
<library name="Gradle: swt-linux64">
<CLASSES>

View File

@ -0,0 +1,20 @@
package net.azib.ipscan.core.net;
import net.azib.ipscan.core.net.WinIpHlpDll.Ip6SockAddrByRef;
import net.azib.ipscan.core.net.WinIpHlpDll.IpAddrByVal;
import java.net.InetAddress;
public class WinIpHlp {
public static IpAddrByVal toIpAddr(InetAddress address) {
IpAddrByVal addr = new IpAddrByVal();
addr.bytes = address.getAddress();
return addr;
}
public static Ip6SockAddrByRef toIp6Addr(InetAddress address) {
Ip6SockAddrByRef addr = new Ip6SockAddrByRef();
addr.bytes = address.getAddress();
return addr;
}
}

View File

@ -44,6 +44,11 @@ public interface WinIpHlpDll extends Library {
*/
Pointer IcmpCreateFile();
/**
* Wrapper for Microsoft's <a href="https://docs.microsoft.com/en-us/windows/desktop/api/icmpapi/nf-icmpapi-icmp6createfile">Icmp6CreateFile</a>
*/
Pointer Icmp6CreateFile();
/**
* Wrapper for Microsoft's <a href="http://msdn.microsoft.com/en-us/library/aa366043.aspx">IcmpCloseHandle</a>
*/
@ -63,6 +68,24 @@ public interface WinIpHlpDll extends Library {
int timeout
);
/**
* Wrapper for Microsoft's <a href="https://docs.microsoft.com/en-us/windows/desktop/api/icmpapi/nf-icmpapi-icmp6sendecho2">Icmp6SendEcho2</a>
*/
int Icmp6SendEcho2(
Pointer hIcmp,
Pointer event,
Pointer apcRoutine,
Pointer apcContext,
Ip6SockAddrByRef sourceAddress,
Ip6SockAddrByRef destinationAddress,
Pointer requestData,
short requestSize,
IpOptionInformationByRef requestOptions,
Pointer replyBuffer,
int replySize,
int timeout
);
/**
* Wrapper for Microsoft's <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366358(v=vs.85).aspx">SendARP</a>
*/
@ -80,6 +103,17 @@ public interface WinIpHlpDll extends Library {
class IpAddrByVal extends IpAddr implements Structure.ByValue {
}
class Ip6SockAddr extends AutoOrderedStructure {
public short family = 10;
public short port;
public int flowInfo;
public byte[] bytes = new byte[16];
public int scopeId;
}
class Ip6SockAddrByRef extends Ip6SockAddr implements Structure.ByReference {
}
class IpOptionInformation extends AutoOrderedStructure {
public byte ttl;
public byte tos;
@ -113,4 +147,21 @@ public interface WinIpHlpDll extends Library {
read();
}
}
class Icmp6EchoReply extends AutoOrderedStructure {
public short port;
public byte[] flowInfo = new byte[4];
public byte[] addressBytes = new byte[16];
public int scopeId;
public int status;
public int roundTripTime;
public Icmp6EchoReply() {
}
public Icmp6EchoReply(Pointer p) {
useMemory(p);
read();
}
}
}

View File

@ -8,7 +8,9 @@ package net.azib.ipscan.core.net;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.net.WinIpHlpDll.Icmp6EchoReply;
import net.azib.ipscan.core.net.WinIpHlpDll.IcmpEchoReply;
import net.azib.ipscan.core.net.WinIpHlpDll.Ip6SockAddrByRef;
import net.azib.ipscan.core.net.WinIpHlpDll.IpAddrByVal;
import java.io.IOException;
@ -16,6 +18,8 @@ import java.net.InetAddress;
import java.util.Arrays;
import static java.lang.Thread.currentThread;
import static net.azib.ipscan.core.net.WinIpHlp.toIp6Addr;
import static net.azib.ipscan.core.net.WinIpHlp.toIpAddr;
import static net.azib.ipscan.core.net.WinIpHlpDll.dll;
/**
@ -29,18 +33,23 @@ import static net.azib.ipscan.core.net.WinIpHlpDll.dll;
*/
public class WindowsPinger implements Pinger {
private int timeout;
private Ip6SockAddrByRef anyIp6SourceAddr = new Ip6SockAddrByRef();
public WindowsPinger(int timeout) {
this.timeout = timeout;
}
public PingResult ping(ScanningSubject subject, int count) throws IOException {
if (subject.isIPv6())
return ping6(subject, count);
else
return ping4(subject, count);
}
private PingResult ping4(ScanningSubject subject, int count) throws IOException {
Pointer handle = dll.IcmpCreateFile();
if (handle == null) throw new IOException("Unable to create Windows native ICMP handle");
IpAddrByVal ipaddr = new IpAddrByVal();
ipaddr.bytes = subject.getAddress().getAddress();
int sendDataSize = 56;
int replyDataSize = sendDataSize + (new IcmpEchoReply().size()) + 10;
Pointer sendData = new Memory(sendDataSize);
@ -50,6 +59,7 @@ public class WindowsPinger implements Pinger {
PingResult result = new PingResult(subject.getAddress(), count);
try {
for (int i = 1; i <= count && !currentThread().isInterrupted(); i++) {
IpAddrByVal ipaddr = toIpAddr(subject.getAddress());
int numReplies = dll.IcmpSendEcho(handle, ipaddr, sendData, (short) sendDataSize, null, replyData, replyDataSize, timeout);
IcmpEchoReply echoReply = new IcmpEchoReply(replyData);
if (numReplies > 0 && echoReply.status == 0 && Arrays.equals(echoReply.address.bytes, ipaddr.bytes)) {
@ -61,6 +71,36 @@ public class WindowsPinger implements Pinger {
finally {
dll.IcmpCloseHandle(handle);
}
return result;
}
private PingResult ping6(ScanningSubject subject, int count) throws IOException {
Pointer handle = dll.Icmp6CreateFile();
if (handle == null) throw new IOException("Unable to create Windows native ICMP6 handle");
int sendDataSize = 56;
int replyDataSize = sendDataSize + (new Icmp6EchoReply().size()) + 10;
Pointer sendData = new Memory(sendDataSize);
sendData.clear(sendDataSize);
Pointer replyData = new Memory(replyDataSize);
PingResult result = new PingResult(subject.getAddress(), count);
try {
Ip6SockAddrByRef ipaddr = toIp6Addr(subject.getAddress());
for (int i = 1; i <= count && !currentThread().isInterrupted(); i++) {
int numReplies = dll.Icmp6SendEcho2(handle, null, null, null, anyIp6SourceAddr, toIp6Addr(subject.getAddress()), sendData, (short) sendDataSize, null, replyData, replyDataSize, timeout);
Icmp6EchoReply echoReply = new Icmp6EchoReply(replyData);
if (numReplies > 0 && echoReply.status == 0 && Arrays.equals(echoReply.addressBytes, ipaddr.bytes)) {
result.addReply(echoReply.roundTripTime);
//result.setTTL(echoReply.options.ttl & 0xFF);
}
System.err.println("Icmp6SendEcho2 response: " + numReplies + " " + echoReply.status + " " + InetAddress.getByAddress(echoReply.addressBytes) + " " + Arrays.toString(echoReply.addressBytes) + " vs " + InetAddress.getByAddress(ipaddr.bytes));
System.err.println(echoReply.getFieldOrder());
}
}
finally {
dll.IcmpCloseHandle(handle);
}
return result;
}
@ -70,7 +110,7 @@ public class WindowsPinger implements Pinger {
}
public static void main(String[] args) throws IOException {
PingResult ping = new WindowsPinger(5000).ping(new ScanningSubject(InetAddress.getLocalHost()), 3);
PingResult ping = new WindowsPinger(5000).ping(new ScanningSubject(InetAddress.getByName("::1")), 1);
System.out.println(ping.getAverageTime() + "ms");
System.out.println("TTL " + ping.getTTL());
}

View File

@ -2,25 +2,22 @@ package net.azib.ipscan.fetchers;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import net.azib.ipscan.core.net.WinIpHlpDll.IpAddrByVal;
import javax.inject.Inject;
import java.net.InetAddress;
import static net.azib.ipscan.core.net.WinIpHlp.toIpAddr;
import static net.azib.ipscan.core.net.WinIpHlpDll.dll;
public class WinMACFetcher extends MACFetcher {
@Inject public WinMACFetcher() {}
@Override public String resolveMAC(InetAddress address) {
IpAddrByVal destIP = new IpAddrByVal();
destIP.bytes = address.getAddress();
Pointer pmac = new Memory(8);
Pointer plen = new Memory(4);
plen.setInt(0, 8);
int result = dll.SendARP(destIP, 0, pmac, plen);
int result = dll.SendARP(toIpAddr(address), 0, pmac, plen);
if (result != 0) return null;