diff --git a/CHANGELOG b/CHANGELOG index 0e61f653..5fd10fd9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/src/net/azib/ipscan/core/Scanner.java b/src/net/azib/ipscan/core/Scanner.java index 388f91f7..5e5b6688 100644 --- a/src/net/azib/ipscan/core/Scanner.java +++ b/src/net/azib/ipscan/core/Scanner.java @@ -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); } } diff --git a/src/net/azib/ipscan/core/ScannerDispatcherThread.java b/src/net/azib/ipscan/core/ScannerDispatcherThread.java index 29680246..0ea21623 100644 --- a/src/net/azib/ipscan/core/ScannerDispatcherThread.java +++ b/src/net/azib/ipscan/core/ScannerDispatcherThread.java @@ -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(); diff --git a/src/net/azib/ipscan/core/net/ARPPinger.java b/src/net/azib/ipscan/core/net/ARPPinger.java index bd00d577..01c5813c 100644 --- a/src/net/azib/ipscan/core/net/ARPPinger.java +++ b/src/net/azib/ipscan/core/net/ARPPinger.java @@ -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); } diff --git a/src/net/azib/ipscan/core/net/PingerRegistry.java b/src/net/azib/ipscan/core/net/PingerRegistry.java index b304547a..b3a8e025 100644 --- a/src/net/azib/ipscan/core/net/PingerRegistry.java +++ b/src/net/azib/ipscan/core/net/PingerRegistry.java @@ -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; } /** diff --git a/src/net/azib/ipscan/feeders/AbstractFeeder.java b/src/net/azib/ipscan/feeders/AbstractFeeder.java index 40b8e1b4..e6e3b283 100644 --- a/src/net/azib/ipscan/feeders/AbstractFeeder.java +++ b/src/net/azib/ipscan/feeders/AbstractFeeder.java @@ -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(); } } diff --git a/src/net/azib/ipscan/feeders/Feeder.java b/src/net/azib/ipscan/feeders/Feeder.java index 17bc5e94..1fc6ff9c 100644 --- a/src/net/azib/ipscan/feeders/Feeder.java +++ b/src/net/azib/ipscan/feeders/Feeder.java @@ -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); + } } diff --git a/src/net/azib/ipscan/feeders/RandomFeeder.java b/src/net/azib/ipscan/feeders/RandomFeeder.java index 633fe3a6..7e06be1a 100644 --- a/src/net/azib/ipscan/feeders/RandomFeeder.java +++ b/src/net/azib/ipscan/feeders/RandomFeeder.java @@ -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"); diff --git a/src/net/azib/ipscan/feeders/RangeFeeder.java b/src/net/azib/ipscan/feeders/RangeFeeder.java index a10aa589..5762985f 100644 --- a/src/net/azib/ipscan/feeders/RangeFeeder.java +++ b/src/net/azib/ipscan/feeders/RangeFeeder.java @@ -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() { diff --git a/src/net/azib/ipscan/feeders/RescanFeeder.java b/src/net/azib/ipscan/feeders/RescanFeeder.java index bfd2a2b9..585dbcb0 100644 --- a/src/net/azib/ipscan/feeders/RescanFeeder.java +++ b/src/net/azib/ipscan/feeders/RescanFeeder.java @@ -19,7 +19,6 @@ import java.util.List; * @author Anton Keks */ public class RescanFeeder extends AbstractFeeder { - private Feeder originalFeeder; private List 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(); + } } diff --git a/src/net/azib/ipscan/fetchers/Fetcher.java b/src/net/azib/ipscan/fetchers/Fetcher.java index 2e4f2989..7d3fa91e 100644 --- a/src/net/azib/ipscan/fetchers/Fetcher.java +++ b/src/net/azib/ipscan/fetchers/Fetcher.java @@ -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 */ diff --git a/src/net/azib/ipscan/fetchers/PingFetcher.java b/src/net/azib/ipscan/fetchers/PingFetcher.java index 97436bae..d2c391db 100644 --- a/src/net/azib/ipscan/fetchers/PingFetcher.java +++ b/src/net/azib/ipscan/fetchers/PingFetcher.java @@ -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 diff --git a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java index 47f660df..6e4612e5 100644 --- a/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java +++ b/src/net/azib/ipscan/gui/actions/StartStopScanningAction.java @@ -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; } diff --git a/test/net/azib/ipscan/core/ScannerTest.java b/test/net/azib/ipscan/core/ScannerTest.java index aca559f6..5d97104b 100644 --- a/test/net/azib/ipscan/core/ScannerTest.java +++ b/test/net/azib/ipscan/core/ScannerTest.java @@ -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)); diff --git a/test/net/azib/ipscan/core/net/PingerRegistryTest.java b/test/net/azib/ipscan/core/net/PingerRegistryTest.java index 208e1afe..5dbc2515 100644 --- a/test/net/azib/ipscan/core/net/PingerRegistryTest.java +++ b/test/net/azib/ipscan/core/net/PingerRegistryTest.java @@ -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 diff --git a/test/net/azib/ipscan/feeders/RescanFeederTest.java b/test/net/azib/ipscan/feeders/RescanFeederTest.java index a7a56f0c..7ee4dfa7 100644 --- a/test/net/azib/ipscan/feeders/RescanFeederTest.java +++ b/test/net/azib/ipscan/feeders/RescanFeederTest.java @@ -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; }