#280 if scanning a local network, then ARP will be used in addition to chosen Pinger to detect more hosts

This commit is contained in:
Anton Keks 2022-01-21 18:42:28 +02:00
parent 9bcc4ea03d
commit ace2f3de5d
16 changed files with 108 additions and 66 deletions

View File

@ -4,6 +4,7 @@ Unreleased:
- Windows 32-bit build has been removed
- Linux deb & rpm packages now correctly specify Java 11 dependency, not 8
- Mac: display a notification if java not in PATH #279
- If scanning a local network, then ARP will be used in addition to chosen Pinger to detect more hosts #280
Changes in 3.8.1:
- Make 32-bit Windows build still run under Oracle Java 8 - it seems to still be popular #324

View File

@ -7,6 +7,7 @@ package net.azib.ipscan.core;
import net.azib.ipscan.core.values.NotAvailable;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.feeders.Feeder;
import net.azib.ipscan.fetchers.Fetcher;
import net.azib.ipscan.fetchers.FetcherRegistry;
@ -72,9 +73,9 @@ public class Scanner {
/**
* Init everything needed for scanning, including Fetchers
*/
public void init() {
public void init(Feeder feeder) {
for (Fetcher fetcher : fetcherRegistry.getSelectedFetchers()) {
fetcher.init();
fetcher.init(feeder);
}
}

View File

@ -63,9 +63,8 @@ public class ScannerDispatcherThread extends Thread implements ThreadFactory, St
this.scanningResultList = scanningResults;
try {
this.scanningResultList.initNewScan(feeder);
// initialize in the main thread in order to catch exceptions gracefully
scanner.init();
scanner.init(feeder);
}
catch (RuntimeException e) {
stateMachine.reset();

View File

@ -9,19 +9,27 @@ import static java.lang.System.currentTimeMillis;
public class ARPPinger implements Pinger {
private MACFetcher macFetcher;
private JavaPinger trigger;
private Pinger trigger;
public ARPPinger(MACFetcher macFetcher, JavaPinger trigger) {
this.macFetcher = macFetcher;
// WinMACFetcher sends an actual ARP request, so no previous UDP request is needed
this.trigger = macFetcher.getClass().getSimpleName().startsWith("Win") ? null : trigger;
this(macFetcher, macFetcher.getClass().getSimpleName().startsWith("Win") ? null : (Pinger) trigger);
}
public ARPPinger(MACFetcher macFetcher, Pinger trigger) {
this.macFetcher = macFetcher;
this.trigger = trigger;
}
@Override public PingResult ping(ScanningSubject subject, int count) throws IOException {
PingResult result = new PingResult(subject.getAddress(), 1);
PingResult result = new PingResult(subject.getAddress(), count);
if (trigger != null) count /= 2;
for (int i = 0; i < count; i++) {
long start = currentTimeMillis();
if (trigger != null) trigger.ping(subject, 1); // this should issue an ARP request for the IP
if (trigger != null) {
// this should issue an ARP request for the IP
result.merge(trigger.ping(subject, count / 2));
}
String mac = macFetcher.scan(subject);
if (mac != null) result.addReply(currentTimeMillis() - start);
}

View File

@ -12,6 +12,7 @@ import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.di.InjectException;
import net.azib.ipscan.di.Injector;
import net.azib.ipscan.fetchers.FetcherException;
import net.azib.ipscan.fetchers.MACFetcher;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@ -60,8 +61,10 @@ public class PingerRegistry {
/**
* Creates the configured pinger with configured timeout
*/
public Pinger createPinger() throws FetcherException {
return createPinger(scannerConfig.selectedPinger, scannerConfig.pingTimeout);
public Pinger createPinger(boolean isLAN) throws FetcherException {
Pinger mainPinger = createPinger(scannerConfig.selectedPinger, scannerConfig.pingTimeout);
if (isLAN) return new ARPPinger(injector.require(MACFetcher.class), mainPinger);
return mainPinger;
}
/**

View File

@ -7,6 +7,14 @@
package net.azib.ipscan.feeders;
import net.azib.ipscan.config.Labels;
import net.azib.ipscan.core.ScanningSubject;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import static net.azib.ipscan.util.InetAddressUtils.getInterface;
import static net.azib.ipscan.util.InetAddressUtils.matchingAddress;
/**
* Helper base class for built-in Feeders
@ -14,13 +22,27 @@ import net.azib.ipscan.config.Labels;
* @author Anton Keks
*/
public abstract class AbstractFeeder implements Feeder {
public String getName() {
private NetworkInterface netIf;
private InterfaceAddress ifAddr;
protected void initInterfaces(InetAddress ip) {
this.netIf = getInterface(ip);
this.ifAddr = matchingAddress(netIf, ip.getClass());
}
@Override public ScanningSubject subject(InetAddress ip) {
return new ScanningSubject(ip, netIf, ifAddr);
}
@Override public String getName() {
return Labels.getLabel(getId());
}
@Override
public String toString() {
@Override public boolean isLocalNetwork() {
return ifAddr != null;
}
@Override public String toString() {
return getName() + ": " + getInfo();
}
}

View File

@ -8,6 +8,8 @@ package net.azib.ipscan.feeders;
import net.azib.ipscan.core.Plugin;
import net.azib.ipscan.core.ScanningSubject;
import java.net.InetAddress;
/**
* Interface of a Feeder, which is used to feed scanner with IP addresses.
* Basically, classes implementing Feeder must provide an algorithm of
@ -43,4 +45,15 @@ public interface Feeder extends Plugin {
* Used for creation of Favorites, saving to file, etc.
*/
String getInfo();
/**
* @return true if scanning LAN addresses, so that ARP, etc can be used
*/
default boolean isLocalNetwork() {
return false;
}
default ScanningSubject subject(InetAddress ip) {
return new ScanningSubject(ip);
}
}

View File

@ -18,7 +18,6 @@ import java.security.SecureRandom;
* @author Anton Keks
*/
public class RandomFeeder extends AbstractFeeder {
SecureRandom random = new SecureRandom();
InetAddress currentAddress;
@ -29,10 +28,7 @@ public class RandomFeeder extends AbstractFeeder {
int addressCount;
int currentNumber;
/**
* @see Feeder#getId()
*/
public String getId() {
@Override public String getId() {
return "feeder.random";
}
@ -41,7 +37,9 @@ public class RandomFeeder extends AbstractFeeder {
public RandomFeeder(String prototypeIP, String mask, int count) {
try {
this.prototypeBytes = InetAddress.getByName(prototypeIP).getAddress();
InetAddress ip = InetAddress.getByName(prototypeIP);
initInterfaces(ip);
this.prototypeBytes = ip.getAddress();
}
catch (UnknownHostException e) {
throw new FeederException("malformedIP");

View File

@ -10,11 +10,10 @@ import net.azib.ipscan.util.InetAddressUtils;
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.*;
import static net.azib.ipscan.util.InetAddressUtils.decrement;
import static net.azib.ipscan.util.InetAddressUtils.increment;
/**
* IP Range Feeder.
@ -24,8 +23,6 @@ import static net.azib.ipscan.util.InetAddressUtils.*;
* @author Anton Keks
*/
public class RangeFeeder extends AbstractFeeder {
private NetworkInterface netIf;
private InterfaceAddress ifAddr;
private InetAddress startIP;
private InetAddress endIP;
private InetAddress originalEndIP;
@ -35,9 +32,6 @@ public class RangeFeeder extends AbstractFeeder {
double percentageComplete;
double percentageIncrement;
/**
* @see Feeder#getId()
*/
public String getId() {
return "feeder.range";
}
@ -49,8 +43,7 @@ public class RangeFeeder extends AbstractFeeder {
try {
this.startIP = this.currentIP = InetAddress.getByName(startIP);
this.endIP = this.originalEndIP = InetAddress.getByName(endIP);
this.netIf = getInterface(this.startIP);
this.ifAddr = matchingAddress(netIf, this.startIP.getClass());
initInterfaces(this.startIP);
this.isReverse = false;
}
catch (UnknownHostException e) {
@ -66,7 +59,7 @@ public class RangeFeeder extends AbstractFeeder {
initPercentageIncrement();
this.endIP = increment(this.endIP);
}
/**
* Initalizes fields, used for computation of percentage of completion.
*/
@ -95,7 +88,7 @@ public class RangeFeeder extends AbstractFeeder {
} else {
this.currentIP = increment(prevIP);
}
return new ScanningSubject(prevIP, netIf, ifAddr);
return subject(prevIP);
}
public int percentageComplete() {

View File

@ -19,7 +19,6 @@ import java.util.List;
* @author Anton Keks
*/
public class RescanFeeder extends AbstractFeeder {
private Feeder originalFeeder;
private List<InetAddress> addresses;
@ -27,22 +26,20 @@ public class RescanFeeder extends AbstractFeeder {
/**
* Initializes the RescanFeeder using the old feeder used for the real scan to delegate some calls to.
* @param oldFeeder
*/
public RescanFeeder(Feeder oldFeeder, String ... ips) {
this.originalFeeder = oldFeeder;
public RescanFeeder(Feeder originalFeeder, String ... ips) {
this.originalFeeder = originalFeeder;
initAddresses(ips);
}
/**
* @return the label of the "old" feeder
*/
public String getId() {
@Override public String getId() {
return originalFeeder.getId();
}
@Override
public String getName() {
@Override public String getName() {
return Labels.getLabel("feeder.rescan.of") + originalFeeder.getName();
}
@ -66,22 +63,23 @@ public class RescanFeeder extends AbstractFeeder {
return ips.length;
}
public boolean hasNext() {
@Override public boolean hasNext() {
return current < addresses.size();
}
public ScanningSubject next() {
return new ScanningSubject(addresses.get(current++));
@Override public ScanningSubject next() {
return originalFeeder.subject(addresses.get(current++));
}
public int percentageComplete() {
@Override public int percentageComplete() {
return current * 100 / addresses.size();
}
/**
* @return the info of the "old" feeder
*/
public String getInfo() {
@Override public String getInfo() {
return originalFeeder.getInfo();
}
@Override public boolean isLocalNetwork() {
return originalFeeder.isLocalNetwork();
}
}

View File

@ -8,6 +8,7 @@ import net.azib.ipscan.core.Plugin;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.values.NotAvailable;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.feeders.Feeder;
/**
* Interface of all IP Fetchers.
@ -50,12 +51,16 @@ public interface Fetcher extends Cloneable, Plugin {
* Special values may also be returned, such as {@link NotAvailable} or {@link NotScanned}
*/
Object scan(ScanningSubject subject);
/**
* Called before scanning has started to do any intialization stuff
* Called before scanning has started to do any initialization stuff
*/
void init();
default void init(Feeder feeder) {
init();
}
default void init() {}
/**
* Called after the scanning has been completed to do any cleanup needed
*/

View File

@ -12,6 +12,7 @@ import net.azib.ipscan.core.net.PingResult;
import net.azib.ipscan.core.net.Pinger;
import net.azib.ipscan.core.net.PingerRegistry;
import net.azib.ipscan.core.values.IntegerWithUnit;
import net.azib.ipscan.feeders.Feeder;
import net.azib.ipscan.gui.fetchers.PingFetcherPrefs;
import java.io.IOException;
@ -86,9 +87,9 @@ public class PingFetcher extends AbstractFetcher {
return result.isAlive() ? new IntegerWithUnit(result.getAverageTime(), "ms") : null;
}
public void init() {
public void init(Feeder feeder) {
if (pinger == null) {
pinger = pingerRegistry.createPinger();
pinger = pingerRegistry.createPinger(feeder.isLocalNetwork());
pingerUsers.set(1);
}
else

View File

@ -141,9 +141,7 @@ public class StartStopScanningAction implements SelectionListener, ScanningProgr
MessageBox box = new MessageBox(resultTable.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO | SWT.SHEET);
box.setText(Labels.getLabel("text.scan.new"));
box.setMessage(Labels.getLabel("text.scan.confirmation"));
if (box.open() != SWT.YES) {
return false;
}
return box.open() == SWT.YES;
}
return true;
}

View File

@ -3,6 +3,7 @@ package net.azib.ipscan.core;
import net.azib.ipscan.core.ScanningResult.ResultType;
import net.azib.ipscan.core.values.NotAvailable;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.feeders.Feeder;
import net.azib.ipscan.fetchers.AbstractFetcher;
import net.azib.ipscan.fetchers.Fetcher;
import net.azib.ipscan.fetchers.FetcherRegistry;
@ -80,8 +81,8 @@ public class ScannerTest {
}
@Test
public void testInit() throws Exception {
scanner.init();
public void testInit() {
scanner.init(mock(Feeder.class));
assertTrue(initCalled.contains(FakeFetcher.class));
assertTrue(initCalled.contains(AnotherFakeFetcher.class));
@ -89,7 +90,7 @@ public class ScannerTest {
}
@Test
public void testCleanup() throws Exception {
public void testCleanup() {
scanner.cleanup();
assertTrue(cleanupCalled.contains(FakeFetcher.class));

View File

@ -48,7 +48,7 @@ public class PingerRegistryTest {
@Test
public void createDefaultPinger() {
config.selectedPinger = "pinger.udp";
assertTrue(registry.createPinger() instanceof UDPPinger);
assertTrue(registry.createPinger(false) instanceof UDPPinger);
}
@Test

View File

@ -6,13 +6,13 @@
package net.azib.ipscan.feeders;
import net.azib.ipscan.config.Labels;
import net.azib.ipscan.core.ScanningSubject;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import net.azib.ipscan.config.Labels;
import org.junit.Test;
/**
* RescanFeederTest
*
@ -36,7 +36,7 @@ public class RescanFeederTest {
}
@Test
public void testFunctionality() throws Exception {
public void addresses() {
feeder = new RescanFeeder(mockFeeder(), "127.0.0.15", "127.0.1.35", "127.0.2.2");
assertTrue(feeder.hasNext());
@ -60,6 +60,7 @@ public class RescanFeederTest {
when(feeder.getInfo()).thenReturn("SomeInfo");
when(feeder.getId()).thenReturn("someLabel");
when(feeder.getName()).thenReturn("someName");
when(feeder.subject(any())).thenAnswer(i -> new ScanningSubject(i.getArgument(0)));
return feeder;
}