diff options
| author | 2026-07-02 11:29:17 +0200 | |
|---|---|---|
| committer | 2026-07-09 09:59:28 +0200 | |
| commit | 2624f889d5adadc592c015e31deeb32a8d0e3a23 (patch) | |
| tree | 6f777d3ff292b9627fd6bf1197f46c0a7ed3e35f | |
| parent | cf6c30c75b4569cc60fa731434274b2bc249fdbc (diff) | |
Added new Class ScanState in order to make Scanner
stateless during scan process. Not regarding config
which is given to the constructor
| -rw-r--r-- | src/main/java/com/it_jaros/jscanner/ProgressBar.java | 15 | ||||
| -rw-r--r-- | src/main/java/com/it_jaros/jscanner/ScanState.java | 5 | ||||
| -rw-r--r-- | src/main/java/com/it_jaros/jscanner/Scanner.java | 58 |
3 files changed, 47 insertions, 31 deletions
diff --git a/src/main/java/com/it_jaros/jscanner/ProgressBar.java b/src/main/java/com/it_jaros/jscanner/ProgressBar.java index 35c8fd5..fdae944 100644 --- a/src/main/java/com/it_jaros/jscanner/ProgressBar.java +++ b/src/main/java/com/it_jaros/jscanner/ProgressBar.java @@ -15,11 +15,15 @@ import java.util.regex.Pattern; public class ProgressBar { - private final ScheduledExecutorService ui = Executors.newSingleThreadScheduledExecutor(); + private List<Progress> hosts = new ArrayList<>(); private final ReentrantLock lock = new ReentrantLock(); + private final ScheduledExecutorService ui = Executors.newSingleThreadScheduledExecutor(); + private final boolean quiet; private final int columnWidth = ProgressBar.getColumnWidth(); - private List<Progress> hosts; + public ProgressBar(boolean quiet) { + this.quiet = quiet; + } private static int getColumnWidth() { try { @@ -42,10 +46,9 @@ public class ProgressBar { return 120; } - public void start(boolean quiet) { - this.hosts = new ArrayList<>(); - System.out.print("Scanning targets...\n\n"); + public void start() { if (quiet) { return; } + System.out.print("Scanning targets...\n\n"); ui.scheduleAtFixedRate(() -> { lock.lock(); drawProgress(false); @@ -106,7 +109,7 @@ public class ProgressBar { return String.format("%s%s%s %s %s", label, " ".repeat(spacesBetween),statsLeft, brackets, statsRight); } - public void stop(boolean quiet) { + public void stop() { ui.shutdown(); try { ui.awaitTermination(10, TimeUnit.SECONDS); diff --git a/src/main/java/com/it_jaros/jscanner/ScanState.java b/src/main/java/com/it_jaros/jscanner/ScanState.java new file mode 100644 index 0000000..e3a4300 --- /dev/null +++ b/src/main/java/com/it_jaros/jscanner/ScanState.java @@ -0,0 +1,5 @@ +package com.it_jaros.jscanner; + +import java.util.List; + +public record ScanState(Counter counter, ProgressBar progressBar, List<ScanResult> scanResult) {} diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java index 4d951f5..5a6ccbb 100644 --- a/src/main/java/com/it_jaros/jscanner/Scanner.java +++ b/src/main/java/com/it_jaros/jscanner/Scanner.java @@ -21,11 +21,8 @@ public class Scanner implements AutoCloseable { private static final int READ_BUFFER_SIZE = 1024; - private ArrayList<ScanResult> scanResult; private volatile boolean cancelled = false; - private final Counter counter = new Counter(); - private final ProgressBar progressBar = new ProgressBar(); private final Semaphore socketLimit; private final boolean disableOnlineCheck; private final boolean quiet; @@ -34,14 +31,22 @@ public class Scanner implements AutoCloseable { private final int timeoutInMillis; private final long delayInNanos; - public Scanner(int socketLimit, int timeoutInMillis, int delayInMillis, int maxWorkersPerHost, int maxHostsLimit, boolean disableOnlineCheck, boolean quiet) { - this.timeoutInMillis = timeoutInMillis; + public Scanner( + int socketLimit, + int timeoutInMillis, + int delayInMillis, + int maxWorkersPerHost, + int maxHostsLimit, + boolean disableOnlineCheck, + boolean quiet + ) { this.delayInNanos = TimeUnit.MILLISECONDS.toNanos(Math.max(0, delayInMillis)); - this.socketLimit = new Semaphore(socketLimit); - this.maxWorkersPerHost = maxWorkersPerHost; - this.maxHostsLimit = maxHostsLimit; this.disableOnlineCheck = disableOnlineCheck; + this.maxHostsLimit = maxHostsLimit; + this.maxWorkersPerHost = maxWorkersPerHost; this.quiet = quiet; + this.socketLimit = new Semaphore(socketLimit); + this.timeoutInMillis = timeoutInMillis; } public Scanner(ScanOptions options) { @@ -78,8 +83,8 @@ public class Scanner implements AutoCloseable { } public List<ScanResult> scanHosts(Stream<String> hosts, String ports) throws IOException { - this.scanResult = new ArrayList<>(); - progressBar.start(quiet); + ScanState scanState = new ScanState(new Counter(), new ProgressBar(quiet), new ArrayList<>()); + scanState.progressBar().start(); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { CompletionService<ScanResult> completionService = new ExecutorCompletionService<>(executor); Queue<String> hostsInQueue = hosts.collect(Collectors.toCollection(ArrayDeque::new)); @@ -91,7 +96,7 @@ public class Scanner implements AutoCloseable { while (!hostsInQueue.isEmpty() && activeHostWorkers <= maxHostsLimit && !cancelled) { activeHostWorkers++; final String host = hostsInQueue.poll(); - completionService.submit(() -> scanHost(host, ports)); + completionService.submit(() -> scanHost(host, ports, scanState)); } try { @@ -101,7 +106,7 @@ public class Scanner implements AutoCloseable { } activeHostWorkers--; hostsToProcess--; - this.scanResult.add(finishedHost.get()); + scanState.scanResult().add(finishedHost.get()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { @@ -114,16 +119,16 @@ public class Scanner implements AutoCloseable { } } - progressBar.stop(quiet); + scanState.progressBar().stop(); System.out.println("--------------------"); System.out.println("Finished scan!"); System.out.println("Stats:"); - System.out.println("Peak concurrent connects: " + counter.max()); + System.out.println("Peak concurrent connects: " + scanState.counter().max()); System.out.println("--------------------"); - return scanResult; + return scanState.scanResult(); } - private ScanResult scanHost(String host, String ports) { + private ScanResult scanHost(String host, String ports, ScanState scanState) { PortRange portRange = new PortRange(ports); AtomicLong portSlotFactory = new AtomicLong(System.nanoTime()); BitSet openPorts = new BitSet(PortRange.MAX_PORT); @@ -132,7 +137,7 @@ public class Scanner implements AutoCloseable { // Give progressbar the current progress object which is then updated in the sub virtual threads Progress progress = new Progress(host, portRange.getTotal(), new AtomicInteger(), new AtomicInteger(), new AtomicInteger()); - progressBar.submit(progress); + scanState.progressBar().submit(progress); if (!disableOnlineCheck && !checkHostOnline(host)) { // Visually show that this host is basically done @@ -151,13 +156,13 @@ public class Scanner implements AutoCloseable { final int currentPort = portRange.next(); completionService.submit(() -> { waitForSlot(portSlotFactory); - return checkPort(host, currentPort); + return checkPort(host, currentPort, scanState); }); } try { - Future<PortResult> f = completionService.poll(10, TimeUnit.MILLISECONDS); - if (f == null) { + Future<PortResult> portResultFuture = completionService.poll(10, TimeUnit.MILLISECONDS); + if (portResultFuture == null) { continue; } activePerHostWorkers--; @@ -166,7 +171,7 @@ public class Scanner implements AutoCloseable { // bitset is not thread-safe, so it is set // outside the other virtual threads that update progress - PortResult portResult = f.get(); + PortResult portResult = portResultFuture.get(); switch (portResult.getState()) { case OPEN -> { openPorts.set(portResult.getPort()); @@ -212,12 +217,15 @@ public class Scanner implements AutoCloseable { } } - private PortResult checkPort(String host, int port) { - socketLimit.acquireUninterruptibly(); - counter.inc(); + private PortResult checkPort(String host, int port, ScanState scanState) { PortResult result = new PortResult(); result.setPort(port); result.setState(PortState.UNKNOWN); + + // don't allow more sockets then specified + socketLimit.acquireUninterruptibly(); + // count how many ports are concurrently checked + scanState.counter().inc(); try (Socket socket = new Socket()) { socket.connect(new InetSocketAddress(host, port), timeoutInMillis); result.setBanner(getBanner(socket)); @@ -230,7 +238,7 @@ public class Scanner implements AutoCloseable { // NoRouteToHostException: this can be safely ignored because the port is closed if a host is unreachable // Will happen a lot when scanning for open ports, so not needed } finally { - counter.dec(); + scanState.counter().dec(); socketLimit.release(); } |
