introduce ScanningSubject.netIf to MACFetchers get the local MAC address from it

This commit is contained in:
Anton Keks 2022-01-16 14:56:10 +02:00
parent 22e5ed36bd
commit 6e7826fdfe
12 changed files with 74 additions and 53 deletions

View File

@ -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());

View File

@ -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;
}

View File

@ -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() {

View File

@ -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;

View File

@ -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();

View File

@ -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<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
while (ifs.hasMoreElements()) {
NetworkInterface netif = ifs.nextElement();
if (netif.isUp() && !netif.isVirtual() && !netif.isLoopback()) {
Enumeration<InetAddress> 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;
}
}

View File

@ -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;

View File

@ -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<NetworkInterface> getNetworkInterfaces() throws SocketException {
List<NetworkInterface> interfaces = list(NetworkInterface.getNetworkInterfaces());
if (!Platform.WINDOWS) reverse(interfaces);

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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

View File

@ -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();