summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-02 18:09:16 +0200
committerGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-09 09:59:28 +0200
commit65052fa3393287b88bf4419bb67cd82663762022 (patch)
tree657d4fdd5b11a69000fa23346ef5dd449548b629 /src/main/java
parentc0ded372e09ba5eaf36a05b425823a6cedf9fb86 (diff)
Reformatted code so that Scan is initialized in Scan class and Scanner
takes care of the actual Scan and not initializing Scan objects anymore
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/it_jaros/jscanner/App.java2
-rw-r--r--src/main/java/com/it_jaros/jscanner/ProgressBar.java10
-rw-r--r--src/main/java/com/it_jaros/jscanner/Scan.java80
-rw-r--r--src/main/java/com/it_jaros/jscanner/ScanState.java16
-rw-r--r--src/main/java/com/it_jaros/jscanner/Scanner.java72
5 files changed, 104 insertions, 76 deletions
diff --git a/src/main/java/com/it_jaros/jscanner/App.java b/src/main/java/com/it_jaros/jscanner/App.java
index 2883a85..9693af1 100644
--- a/src/main/java/com/it_jaros/jscanner/App.java
+++ b/src/main/java/com/it_jaros/jscanner/App.java
@@ -20,7 +20,7 @@ public class App {
ScanOptions options = parseOptions(args);
if (options == null) return;
try (Scanner scanner = new Scanner(options)) {
- Scan scan = scanner.createScan(options);
+ Scan scan = Scan.create(options);
addShutdownHook(scan, scanner, options);
scanner.runScan(scan);
printScanResults(scan, options);
diff --git a/src/main/java/com/it_jaros/jscanner/ProgressBar.java b/src/main/java/com/it_jaros/jscanner/ProgressBar.java
index 2f0a384..3300b73 100644
--- a/src/main/java/com/it_jaros/jscanner/ProgressBar.java
+++ b/src/main/java/com/it_jaros/jscanner/ProgressBar.java
@@ -47,7 +47,9 @@ public class ProgressBar {
}
public void start() {
- if (quiet) { return; }
+ if (quiet) {
+ return;
+ }
System.out.print("Scanning targets...\n\n");
ui.scheduleAtFixedRate(() -> {
lock.lock();
@@ -58,7 +60,7 @@ public class ProgressBar {
private void drawProgress(boolean last) {
// find and print finished hosts one last time
- for (Iterator<Progress> it = hosts.iterator(); it.hasNext();) {
+ for (Iterator<Progress> it = hosts.iterator(); it.hasNext(); ) {
Progress p = it.next();
if (p.done().get() == p.total()) {
it.remove();
@@ -78,7 +80,7 @@ public class ProgressBar {
}
}
- public void submit(Progress progress) {
+ public void add(Progress progress) {
lock.lock();
hosts.add(progress);
lock.unlock();
@@ -106,7 +108,7 @@ public class ProgressBar {
String brackets = "[" + "#".repeat(filled) + "-".repeat(bracketWidth - filled) + "]";
int spacesBetween = terminalWidth - bracketWidth - (label + statsLeft + statsRight).length() - 5;
- return String.format("%s%s%s %s %s", label, " ".repeat(spacesBetween),statsLeft, brackets, statsRight);
+ return String.format("%s%s%s %s %s", label, " ".repeat(spacesBetween), statsLeft, brackets, statsRight);
}
public void stop() {
diff --git a/src/main/java/com/it_jaros/jscanner/Scan.java b/src/main/java/com/it_jaros/jscanner/Scan.java
index f680326..7167264 100644
--- a/src/main/java/com/it_jaros/jscanner/Scan.java
+++ b/src/main/java/com/it_jaros/jscanner/Scan.java
@@ -1,14 +1,88 @@
package com.it_jaros.jscanner;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.util.List;
-public record Scan(List<String> hosts, String ports, ScanState state) {
+public class Scan {
+ private final List<String> hosts;
+ private final ScanState state;
+ private final String ports;
+ private final Counter counter;
+ private final ProgressBar progressBar;
+
+ private Scan(List<String> hosts, String ports, ScanState state, boolean quiet) {
+ this.hosts = hosts;
+ this.ports = ports;
+ this.state = state;
+ this.counter = new Counter();
+ this.progressBar = new ProgressBar(quiet);
+ }
public List<ScanResult> getResults() {
- return this.state.getSnapshotOfScanResults();
+ return this.state.getCopyOfResults();
}
public int getPeakConcurrentConnects() {
- return this.state.getCounter().max();
+ return counter.max();
+ }
+
+ public static Scan create(ScanOptions options) {
+ if (options.hostsFile() != null) {
+ return create(options.hostsFile(), options.ports(), options.quiet());
+ }
+ return create(options.hostsArgv(), options.ports(), options.quiet());
+ }
+
+ public static Scan create(String sourceFile, String ports, boolean quiet) {
+ try (BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile))) {
+ return create(reader.lines().toList(), ports, quiet);
+ } catch (FileNotFoundException | NoSuchFileException e) {
+ System.out.printf("Could not open file %s%n", sourceFile);
+ } catch (IOException e) {
+ System.out.printf("Error while trying to read hosts: %s -> %s %n", e.getClass().getSimpleName(), e.getMessage());
+ }
+
+ return null;
+ }
+
+ public static Scan create(List<String> hostsArgv, String ports, boolean quiet) {
+ return new Scan(hostsArgv, ports, new ScanState(), quiet);
+ }
+
+ public List<String> getHosts() {
+ return hosts;
+ }
+
+ public String getPorts() {
+ return ports;
+ }
+
+ public void start() {
+ progressBar.start();
+ }
+
+ public void stop() {
+ progressBar.stop();
+ }
+
+ public void addHostProgress(Progress progress) {
+ progressBar.add(progress);
+ }
+
+ public void incSocketCounter() {
+ counter.inc();
+ }
+
+ public void decSocketCounter() {
+ counter.dec();
+ }
+
+ public void addScanResult(ScanResult scanResult) {
+ state.addScanResult(scanResult);
}
}
diff --git a/src/main/java/com/it_jaros/jscanner/ScanState.java b/src/main/java/com/it_jaros/jscanner/ScanState.java
index 86c3615..232d1a8 100644
--- a/src/main/java/com/it_jaros/jscanner/ScanState.java
+++ b/src/main/java/com/it_jaros/jscanner/ScanState.java
@@ -4,32 +4,20 @@ import java.util.ArrayList;
import java.util.List;
public class ScanState {
- private final Counter counter;
- private final ProgressBar progressBar;
private final List<ScanResult> scanResult;
- public ScanState(Counter counter, ProgressBar progressBar) {
- this.counter = counter;
- this.progressBar = progressBar;
+ public ScanState() {
// scanResult can not be given from outside because this class controls full access to it
this.scanResult = new ArrayList<>();
}
- public Counter getCounter() {
- return counter;
- }
-
- public ProgressBar getProgressBar() {
- return progressBar;
- }
-
public void addScanResult(ScanResult newResult) {
synchronized (this.scanResult) {
this.scanResult.add(newResult);
}
}
- public List<ScanResult> getSnapshotOfScanResults() {
+ public List<ScanResult> getCopyOfResults() {
synchronized (scanResult) {
return List.copyOf(scanResult);
}
diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java
index 7aeee03..286afde 100644
--- a/src/main/java/com/it_jaros/jscanner/Scanner.java
+++ b/src/main/java/com/it_jaros/jscanner/Scanner.java
@@ -1,20 +1,14 @@
package com.it_jaros.jscanner;
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
-import java.util.stream.Stream;
public class Scanner implements AutoCloseable {
@@ -25,7 +19,6 @@ public class Scanner implements AutoCloseable {
private final Semaphore socketLimit;
private final boolean bannerRecognition;
private final boolean disableOnlineCheck;
- private final boolean quiet;
private final int maxHostsLimit;
private final int maxWorkersPerHost;
private final int timeoutInMillis;
@@ -38,7 +31,6 @@ public class Scanner implements AutoCloseable {
int maxWorkersPerHost,
int maxHostsLimit,
boolean disableOnlineCheck,
- boolean quiet,
boolean bannerRecognition
) {
this.delayInNanos = TimeUnit.MILLISECONDS.toNanos(Math.max(0, delayInMillis));
@@ -46,52 +38,24 @@ public class Scanner implements AutoCloseable {
this.disableOnlineCheck = disableOnlineCheck;
this.maxHostsLimit = maxHostsLimit;
this.maxWorkersPerHost = maxWorkersPerHost;
- this.quiet = quiet;
this.socketLimit = new Semaphore(socketLimit);
this.timeoutInMillis = timeoutInMillis;
}
public Scanner(ScanOptions options) {
- this(options.openSocketLimit(), options.timeoutInMillis(), options.delayInMillis(), options.maxWorkersPerHost(), options.maxHostsLimit(), options.disableHostCheck(), options.quiet(), options.bannerRecognition());
+ this(options.openSocketLimit(), options.timeoutInMillis(), options.delayInMillis(), options.maxWorkersPerHost(), options.maxHostsLimit(), options.disableHostCheck(), options.bannerRecognition());
}
- public Scan createScan(ScanOptions options) {
- if (options.hostsFile() != null) {
- return createScan(options.hostsFile(), options.ports());
- }
- return createScan(options.hostsArgv(), options.ports());
- }
-
- public Scan createScan(String sourceFile, String ports) {
- try (BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile))) {
- return createScan(reader.lines(), ports);
- } catch (FileNotFoundException | NoSuchFileException e) {
- System.out.printf("Could not open file %s%n", sourceFile);
- } catch (IOException e) {
- System.out.printf("Error while trying to read hosts: %s -> %s %n", e.getClass().getSimpleName(), e.getMessage());
- }
-
- return null;
- }
-
- public Scan createScan(Stream<String> hosts, String ports) {
- return new Scan(hosts.toList(), ports, new ScanState(new Counter(), new ProgressBar(quiet)));
- }
-
- public Scan createScan(List<String> hostsArgv, String ports) {
- return new Scan(hostsArgv, ports, new ScanState(new Counter(), new ProgressBar(quiet)));
- }
public List<ScanResult> runScan(Scan scan) {
if (scan == null) {
throw new IllegalArgumentException("Scan argument cannot be null");
}
- ScanState scanState = scan.state();
- scanState.getProgressBar().start();
+ scan.start();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletionService<ScanResult> completionService = new ExecutorCompletionService<>(executor);
- Queue<String> hostsInQueue = new ArrayDeque<>(scan.hosts());
+ Queue<String> hostsInQueue = new ArrayDeque<>(scan.getHosts());
int hostsToProcess = hostsInQueue.size();
int activeHostWorkers = 0;
@@ -100,7 +64,7 @@ public class Scanner implements AutoCloseable {
while (!hostsInQueue.isEmpty() && activeHostWorkers < maxHostsLimit && !cancelled) {
activeHostWorkers++;
final String host = hostsInQueue.poll();
- completionService.submit(() -> scanHostPorts(host, scan.ports(), scanState));
+ completionService.submit(() -> scanHostPorts(host, scan.getPorts(), scan));
}
try {
@@ -110,7 +74,7 @@ public class Scanner implements AutoCloseable {
}
activeHostWorkers--;
hostsToProcess--;
- scanState.addScanResult(finishedHost.get());
+ scan.addScanResult(finishedHost.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
@@ -123,30 +87,30 @@ public class Scanner implements AutoCloseable {
}
}
- scanState.getProgressBar().stop();
- return scanState.getSnapshotOfScanResults();
+ scan.stop();
+ return scan.getResults();
}
- private ScanResult scanHostPorts(String host, String ports, ScanState scanState) {
+ private ScanResult scanHostPorts(String host, String ports, Scan scan) {
PortRange portRange = new PortRange(ports);
- AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
BitSet openPorts = new BitSet(PortRange.MAX_PORT);
BitSet filteredPorts = new BitSet(PortRange.MAX_PORT);
- HashMap<Integer, ServiceType> bannerRecognition = new HashMap<>();
+ HashMap<Integer, ServiceType> serviceTypes = new HashMap<>();
// 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());
- scanState.getProgressBar().submit(progress);
+ scan.addHostProgress(progress);
if (!disableOnlineCheck && !checkHostOnline(host)) {
// Visually show that this host is basically done
progress.done().set(progress.total());
- return new ScanResult(host, openPorts, filteredPorts, bannerRecognition);
+ return new ScanResult(host, openPorts, filteredPorts, serviceTypes);
}
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletionService<PortResult> completionService = new ExecutorCompletionService<>(executor);
List<Throwable> errors = new ArrayList<>();
+ AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
int activePerHostWorkers = 0;
int portsToProcess = portRange.getTotal();
while (portsToProcess > 0 && !cancelled) {
@@ -155,7 +119,7 @@ public class Scanner implements AutoCloseable {
final int currentPort = portRange.next();
completionService.submit(() -> {
waitForSlot(portSlotFactory);
- return checkPort(host, currentPort, scanState);
+ return checkPort(host, currentPort, scan);
});
}
@@ -174,7 +138,7 @@ public class Scanner implements AutoCloseable {
switch (portResult.getState()) {
case OPEN -> {
openPorts.set(portResult.getPort());
- bannerRecognition.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner()));
+ serviceTypes.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner()));
}
case FILTERED -> filteredPorts.set(portResult.getPort());
}
@@ -194,7 +158,7 @@ public class Scanner implements AutoCloseable {
}
}
- return new ScanResult(host, openPorts, filteredPorts, bannerRecognition);
+ return new ScanResult(host, openPorts, filteredPorts, serviceTypes);
}
private boolean checkHostOnline(String host) {
@@ -216,7 +180,7 @@ public class Scanner implements AutoCloseable {
}
}
- private PortResult checkPort(String host, int port, ScanState scanState) {
+ private PortResult checkPort(String host, int port, Scan scan) {
PortResult result = new PortResult();
result.setPort(port);
result.setState(PortState.UNKNOWN);
@@ -224,7 +188,7 @@ public class Scanner implements AutoCloseable {
// don't allow more sockets then specified
socketLimit.acquireUninterruptibly();
// count how many ports are concurrently checked
- scanState.getCounter().inc();
+ scan.incSocketCounter();
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeoutInMillis);
@@ -240,7 +204,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 {
- scanState.getCounter().dec();
+ scan.decSocketCounter();
socketLimit.release();
}