From 6e7826fdfe0b3651e947c6dc341cabaed4f3877a Mon Sep 17 00:00:00 2001 From: Anton Keks Date: Sun, 16 Jan 2022 14:56:10 +0200 Subject: [PATCH] introduce ScanningSubject.netIf to MACFetchers get the local MAC address from it --- .../ipscan/core/ScannerDispatcherThread.java | 2 +- src/net/azib/ipscan/core/ScanningSubject.java | 21 ++++++++++++--- src/net/azib/ipscan/feeders/RangeFeeder.java | 17 +++++++----- .../azib/ipscan/fetchers/LinuxMACFetcher.java | 9 ++++--- src/net/azib/ipscan/fetchers/MACFetcher.java | 6 ++--- .../azib/ipscan/fetchers/UnixMACFetcher.java | 26 +++++-------------- .../azib/ipscan/fetchers/WinMACFetcher.java | 10 +++---- .../azib/ipscan/util/InetAddressUtils.java | 14 ++++++++++ .../azib/ipscan/core/ScanningSubjectTest.java | 7 +++-- .../ipscan/fetchers/LinuxMACFetcherTest.java | 4 ++- .../azib/ipscan/fetchers/MACFetcherTest.java | 6 ++--- .../ipscan/fetchers/MACVendorFetcherTest.java | 5 ++-- 12 files changed, 74 insertions(+), 53 deletions(-) diff --git a/src/net/azib/ipscan/core/ScannerDispatcherThread.java b/src/net/azib/ipscan/core/ScannerDispatcherThread.java index e74dfa32..29680246 100644 --- a/src/net/azib/ipscan/core/ScannerDispatcherThread.java +++ b/src/net/azib/ipscan/core/ScannerDispatcherThread.java @@ -88,7 +88,7 @@ public class ScannerDispatcherThread extends Thread implements ThreadFactory, St if ((numActiveThreads.intValue() < config.maxThreads)) { subject = feeder.next(); - if (config.skipBroadcastAddresses && isLikelyBroadcast(subject.getAddress(), subject.getIfAddr())) + if (config.skipBroadcastAddresses && isLikelyBroadcast(subject.getAddress(), subject.getIfAddress())) continue; ScanningResult result = scanningResultList.createResult(subject.getAddress()); diff --git a/src/net/azib/ipscan/core/ScanningSubject.java b/src/net/azib/ipscan/core/ScanningSubject.java index 8a03bb79..13da288a 100644 --- a/src/net/azib/ipscan/core/ScanningSubject.java +++ b/src/net/azib/ipscan/core/ScanningSubject.java @@ -9,12 +9,16 @@ import net.azib.ipscan.config.Config; import net.azib.ipscan.config.ScannerConfig; import net.azib.ipscan.core.ScanningResult.ResultType; import net.azib.ipscan.core.net.PingResult; +import net.azib.ipscan.util.InetAddressUtils; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; +import java.net.NetworkInterface; import java.util.*; +import static net.azib.ipscan.util.InetAddressUtils.matchingAddress; + /** * Scanning subject represents a single scanned * IP address and any additional arbitrary parameters, @@ -30,6 +34,8 @@ public class ScanningSubject { /** The address being scanned */ private InetAddress address; + /** Network interface in case of LAN scans, or null */ + private NetworkInterface netIf; /** Network interface address in case of LAN scans, or null */ private InterfaceAddress ifAddr; /** The requested ports that the user wishes to put more attention to, can be null. E.g. port 3128 for scanning of proxy servers. */ @@ -44,11 +50,16 @@ public class ScanningSubject { int adaptedPortTimeout = -1; public ScanningSubject(InetAddress address) { - this(address, null); + this(address, InetAddressUtils.getInterface(address)); } - public ScanningSubject(InetAddress address, InterfaceAddress ifAddr) { + public ScanningSubject(InetAddress address, NetworkInterface netIf) { + this(address, netIf, matchingAddress(netIf, address)); + } + + public ScanningSubject(InetAddress address, NetworkInterface netIf, InterfaceAddress ifAddr) { this.address = address; + this.netIf = netIf; this.ifAddr = ifAddr; this.parameters = new HashMap<>(); // single-threaded access only this.config = Config.getConfig().forScanner(); @@ -58,7 +69,11 @@ public class ScanningSubject { return address; } - public InterfaceAddress getIfAddr() { + public NetworkInterface getInterface() { + return netIf; + } + + public InterfaceAddress getIfAddress() { return ifAddr; } diff --git a/src/net/azib/ipscan/feeders/RangeFeeder.java b/src/net/azib/ipscan/feeders/RangeFeeder.java index 9d571850..6d859252 100644 --- a/src/net/azib/ipscan/feeders/RangeFeeder.java +++ b/src/net/azib/ipscan/feeders/RangeFeeder.java @@ -11,8 +11,11 @@ import org.savarese.vserv.tcpip.OctetConverter; import java.net.InetAddress; import java.net.InterfaceAddress; +import java.net.NetworkInterface; import java.net.UnknownHostException; +import static net.azib.ipscan.util.InetAddressUtils.*; + /** * IP Range Feeder. * It contains the starting and ending values, which @@ -21,6 +24,7 @@ import java.net.UnknownHostException; * @author Anton Keks */ public class RangeFeeder extends AbstractFeeder { + private NetworkInterface netIf; private InterfaceAddress ifAddr; private InetAddress startIP; private InetAddress endIP; @@ -47,9 +51,10 @@ public class RangeFeeder extends AbstractFeeder { public RangeFeeder(String startIP, String endIP, InterfaceAddress ifAddr) { try { - this.ifAddr = ifAddr; this.startIP = this.currentIP = InetAddress.getByName(startIP); this.endIP = this.originalEndIP = InetAddress.getByName(endIP); + this.netIf = getInterface(ifAddr != null ? ifAddr.getAddress() : this.startIP); + this.ifAddr = ifAddr != null ? ifAddr : matchingAddress(netIf, this.startIP); this.isReverse = false; } catch (UnknownHostException e) { @@ -60,10 +65,10 @@ public class RangeFeeder extends AbstractFeeder { } if (InetAddressUtils.greaterThan(this.startIP, this.endIP)) { this.isReverse = true; - this.endIP = InetAddressUtils.decrement(InetAddressUtils.decrement(this.endIP)); + this.endIP = decrement(decrement(this.endIP)); } initPercentageIncrement(); - this.endIP = InetAddressUtils.increment(this.endIP); + this.endIP = increment(this.endIP); } /** @@ -90,11 +95,11 @@ public class RangeFeeder extends AbstractFeeder { percentageComplete += percentageIncrement; InetAddress prevIP = this.currentIP; if (this.isReverse) { - this.currentIP = InetAddressUtils.decrement(prevIP); + this.currentIP = decrement(prevIP); } else { - this.currentIP = InetAddressUtils.increment(prevIP); + this.currentIP = increment(prevIP); } - return new ScanningSubject(prevIP, ifAddr); + return new ScanningSubject(prevIP, netIf, ifAddr); } public int percentageComplete() { diff --git a/src/net/azib/ipscan/fetchers/LinuxMACFetcher.java b/src/net/azib/ipscan/fetchers/LinuxMACFetcher.java index 81b7581f..2f3bc401 100644 --- a/src/net/azib/ipscan/fetchers/LinuxMACFetcher.java +++ b/src/net/azib/ipscan/fetchers/LinuxMACFetcher.java @@ -1,6 +1,7 @@ package net.azib.ipscan.fetchers; -import java.net.InetAddress; +import net.azib.ipscan.core.ScanningSubject; + import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Stream; @@ -25,13 +26,13 @@ public class LinuxMACFetcher extends MACFetcher { } } - @Override public String resolveMAC(InetAddress address) { + @Override public String resolveMAC(ScanningSubject subject) { try { - String ip = address.getHostAddress(); + String ip = subject.getAddress().getHostAddress(); return arpLines().filter(line -> line.startsWith(ip + " ")).findFirst() .map(line -> line.substring(macIndex, macIndex + macLength).toUpperCase()) .filter(mac -> !unavailableMac.equals(mac)) - .orElse(getLocalMAC(address)); + .orElse(getLocalMAC(subject)); } catch (Exception e) { return null; diff --git a/src/net/azib/ipscan/fetchers/MACFetcher.java b/src/net/azib/ipscan/fetchers/MACFetcher.java index 0e403e5c..d7fe1ca2 100644 --- a/src/net/azib/ipscan/fetchers/MACFetcher.java +++ b/src/net/azib/ipscan/fetchers/MACFetcher.java @@ -3,11 +3,9 @@ package net.azib.ipscan.fetchers; import net.azib.ipscan.core.ScanningSubject; import net.azib.ipscan.gui.fetchers.MACFetcherPrefs; -import java.net.InetAddress; import java.util.regex.Matcher; import java.util.regex.Pattern; -// TODO: try using java.net.NetworkInterface.getMacAddr0 with reflection instead public abstract class MACFetcher extends AbstractFetcher { public static final String ID = "fetcher.mac"; static final Pattern macAddressPattern = Pattern.compile("([a-fA-F0-9]{1,2}[-:]){5}[a-fA-F0-9]{1,2}"); @@ -20,12 +18,12 @@ public abstract class MACFetcher extends AbstractFetcher { @Override public final String scan(ScanningSubject subject) { String mac = (String) subject.getParameter(ID); - if (mac == null) mac = resolveMAC(subject.getAddress()); + if (mac == null) mac = resolveMAC(subject); subject.setParameter(ID, mac); return replaceSeparator(mac); } - protected abstract String resolveMAC(InetAddress address); + protected abstract String resolveMAC(ScanningSubject subject); static String bytesToMAC(byte[] bytes) { StringBuilder mac = new StringBuilder(); diff --git a/src/net/azib/ipscan/fetchers/UnixMACFetcher.java b/src/net/azib/ipscan/fetchers/UnixMACFetcher.java index 602f0048..fc06a882 100644 --- a/src/net/azib/ipscan/fetchers/UnixMACFetcher.java +++ b/src/net/azib/ipscan/fetchers/UnixMACFetcher.java @@ -1,14 +1,12 @@ package net.azib.ipscan.fetchers; import net.azib.ipscan.config.Platform; +import net.azib.ipscan.core.ScanningSubject; import net.azib.ipscan.util.IOUtils; import java.io.BufferedReader; import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.NetworkInterface; import java.net.SocketException; -import java.util.Enumeration; public class UnixMACFetcher extends MACFetcher { private String arp; @@ -20,8 +18,8 @@ public class UnixMACFetcher extends MACFetcher { arp = "arp -n "; // Mac and other BSD } - @Override public String resolveMAC(InetAddress address) { - String ip = address.getHostAddress(); + @Override public String resolveMAC(ScanningSubject subject) { + String ip = subject.getAddress().getHostAddress(); BufferedReader reader = null; try { // highly inefficient implementation, there must be a better way (using JNA?) @@ -32,7 +30,7 @@ public class UnixMACFetcher extends MACFetcher { if (line.contains(ip)) return extractMAC(line); } - return getLocalMAC(address); + return getLocalMAC(subject); } catch (Exception e) { return null; @@ -42,19 +40,7 @@ public class UnixMACFetcher extends MACFetcher { } } - static String getLocalMAC(InetAddress address) throws SocketException { - Enumeration ifs = NetworkInterface.getNetworkInterfaces(); - while (ifs.hasMoreElements()) { - NetworkInterface netif = ifs.nextElement(); - if (netif.isUp() && !netif.isVirtual() && !netif.isLoopback()) { - Enumeration addrs = netif.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - if (addr.equals(address)) - return bytesToMAC(netif.getHardwareAddress()); - } - } - } - return null; + static String getLocalMAC(ScanningSubject subject) throws SocketException { + return subject.isLocalHost() ? bytesToMAC(subject.getInterface().getHardwareAddress()) : null; } } diff --git a/src/net/azib/ipscan/fetchers/WinMACFetcher.java b/src/net/azib/ipscan/fetchers/WinMACFetcher.java index 647564ec..17217ed7 100644 --- a/src/net/azib/ipscan/fetchers/WinMACFetcher.java +++ b/src/net/azib/ipscan/fetchers/WinMACFetcher.java @@ -2,24 +2,22 @@ package net.azib.ipscan.fetchers; import com.sun.jna.Memory; import com.sun.jna.Pointer; +import net.azib.ipscan.core.ScanningSubject; import java.net.Inet4Address; -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 { - public WinMACFetcher() {} - - @Override public String resolveMAC(InetAddress address) { - if (!(address instanceof Inet4Address)) return null; // TODO IPv6 support + @Override public String resolveMAC(ScanningSubject subject) { + if (!(subject.getAddress() instanceof Inet4Address)) return null; // TODO IPv6 support Pointer pmac = new Memory(8); Pointer plen = new Memory(4); plen.setInt(0, 8); - int result = dll.SendARP(toIpAddr(address), 0, pmac, plen); + int result = dll.SendARP(toIpAddr(subject.getAddress()), 0, pmac, plen); if (result != 0) return null; diff --git a/src/net/azib/ipscan/util/InetAddressUtils.java b/src/net/azib/ipscan/util/InetAddressUtils.java index 12785116..4e90ec6b 100644 --- a/src/net/azib/ipscan/util/InetAddressUtils.java +++ b/src/net/azib/ipscan/util/InetAddressUtils.java @@ -192,6 +192,20 @@ public class InetAddressUtils { return anyAddress; } + public static NetworkInterface getInterface(InetAddress address) { + try { + return NetworkInterface.getByInetAddress(address); + } + catch (SocketException e) { + return null; + } + } + + public static InterfaceAddress matchingAddress(NetworkInterface netIf, InetAddress address) { + if (netIf == null) return null; + return netIf.getInterfaceAddresses().stream().filter(i -> i.getAddress().getClass() == address.getClass()).findFirst().orElse(null); + } + public static List getNetworkInterfaces() throws SocketException { List interfaces = list(NetworkInterface.getNetworkInterfaces()); if (!Platform.WINDOWS) reverse(interfaces); diff --git a/test/net/azib/ipscan/core/ScanningSubjectTest.java b/test/net/azib/ipscan/core/ScanningSubjectTest.java index 41410005..3a2ad255 100644 --- a/test/net/azib/ipscan/core/ScanningSubjectTest.java +++ b/test/net/azib/ipscan/core/ScanningSubjectTest.java @@ -10,6 +10,9 @@ import net.azib.ipscan.core.net.PingResult; import org.junit.Before; import org.junit.Test; +import java.net.InetAddress; +import java.net.UnknownHostException; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; @@ -25,9 +28,9 @@ public class ScanningSubjectTest { private PingResult pingResult; @Before - public void initTest() { + public void initTest() throws UnknownHostException { config = mock(ScannerConfig.class); - subject = new ScanningSubject(null); + subject = new ScanningSubject(InetAddress.getLocalHost()); subject.config = config; config.portTimeout = 1000; config.adaptPortTimeout = true; diff --git a/test/net/azib/ipscan/fetchers/LinuxMACFetcherTest.java b/test/net/azib/ipscan/fetchers/LinuxMACFetcherTest.java index ae668a9e..6783499c 100644 --- a/test/net/azib/ipscan/fetchers/LinuxMACFetcherTest.java +++ b/test/net/azib/ipscan/fetchers/LinuxMACFetcherTest.java @@ -1,6 +1,7 @@ package net.azib.ipscan.fetchers; import net.azib.ipscan.config.Platform; +import net.azib.ipscan.core.ScanningSubject; import org.junit.Test; import static net.azib.ipscan.util.InetAddressUtils.getLocalInterface; @@ -11,6 +12,7 @@ public class LinuxMACFetcherTest { @Test public void resolve() { assumeTrue(Platform.LINUX); - assertEquals(17, new LinuxMACFetcher().resolveMAC(getLocalInterface().getAddress()).length()); + ScanningSubject subject = new ScanningSubject(getLocalInterface().getAddress()); + assertEquals(17, new LinuxMACFetcher().resolveMAC(subject).length()); } } diff --git a/test/net/azib/ipscan/fetchers/MACFetcherTest.java b/test/net/azib/ipscan/fetchers/MACFetcherTest.java index f4eac247..8e8d1e30 100644 --- a/test/net/azib/ipscan/fetchers/MACFetcherTest.java +++ b/test/net/azib/ipscan/fetchers/MACFetcherTest.java @@ -10,7 +10,7 @@ import static org.junit.Assert.assertEquals; public class MACFetcherTest { private MACFetcher fetcher = new MACFetcher() { - @Override protected String resolveMAC(InetAddress address) { + @Override protected String resolveMAC(ScanningSubject subject) { return "00:01:02:03:04:05"; } }; @@ -28,8 +28,8 @@ public class MACFetcherTest { @Test public void bytesToMAC() { - assertEquals("", fetcher.bytesToMAC(new byte[0])); - assertEquals("00:01:02:0D", fetcher.bytesToMAC(new byte[] {0, 1, 2, 13})); + assertEquals("", MACFetcher.bytesToMAC(new byte[0])); + assertEquals("00:01:02:0D", MACFetcher.bytesToMAC(new byte[] {0, 1, 2, 13})); } @Test diff --git a/test/net/azib/ipscan/fetchers/MACVendorFetcherTest.java b/test/net/azib/ipscan/fetchers/MACVendorFetcherTest.java index c8f0367e..3d2a8cbf 100644 --- a/test/net/azib/ipscan/fetchers/MACVendorFetcherTest.java +++ b/test/net/azib/ipscan/fetchers/MACVendorFetcherTest.java @@ -1,16 +1,15 @@ package net.azib.ipscan.fetchers; +import net.azib.ipscan.core.ScanningSubject; import org.junit.Test; -import java.net.InetAddress; - import static org.junit.Assert.assertEquals; public class MACVendorFetcherTest { @Test public void findMACVendor() { MACFetcher macFetcher = new MACFetcher() { - @Override protected String resolveMAC(InetAddress address) { return null; } + @Override protected String resolveMAC(ScanningSubject subject) { return null; } }; MACVendorFetcher fetcher = new MACVendorFetcher(macFetcher); fetcher.init();