commit f97bac7d89c170ef8b28c02ce08fc473460bc615
parent c7e87c2e43a569e7a4fb72178ac3c5b5c7d13216
Author: Matthias Jaros <jaros@mailbox.org>
Date: Thu, 2 Jul 2026 14:12:28 +0200
Finally i managed to print also intermediate results when stopping
process from running with strg-c
Diffstat:
4 files changed, 67 insertions(+), 44 deletions(-)
diff --git a/src/main/java/com/it_jaros/jscanner/App.java b/src/main/java/com/it_jaros/jscanner/App.java
@@ -9,28 +9,41 @@ public class App {
private static Thread shutdownHook;
public static void main(String[] args) {
- CliParser cliParser = new CliParser();
+ // just in case catch everything
+ try {
+ ScanOptions options = parseOptions(args);
+ if (options == null) return;
+ try (Scanner scanner = new Scanner(options)) {
+ Scan scan = scanner.createScan(options);
+ addShutdownHook(scan, scanner, options);
+ printScanResults(scanner.runScan(scan), scan.state(), options);
+ } finally {
+ removeShutdownHook();
+ }
+ } catch (Exception e) {
+ System.out.printf("ERROR: %s", e.getMessage());
+ }
+ }
+
+ private static ScanOptions parseOptions(String[] args) {
+ CliParser cliParser = new CliParser();
try {
- ScanOptions options = cliParser.parseArgs(args);
- Scanner scanner = new Scanner(options);
- addShutdownHook(scanner, options.showFilteredPorts());
- printResults(scanner.scan(options), options.showFilteredPorts());
+ return cliParser.parseArgs(args);
} catch (IllegalArgumentException e) {
System.out.printf("Error while parsing arguments: %s", e.getMessage());
System.out.println();
- cliParser.usageAndExit();
- } catch (Exception e) {
- System.out.printf("ERROR: %s", e.getMessage());
- } finally {
- removeShutdownHook();
}
+
+ cliParser.usageAndExit(1);
+ return null;
}
- private static void addShutdownHook(Scanner scanner, boolean showFilteredPorts) {
+ private static void addShutdownHook(Scan scan, Scanner scanner, ScanOptions scanOptions) {
shutdownHook = new Thread(() -> {
System.err.println("\nCtrl-C received.");
scanner.cancel();
+ printScanIntermediateResult(scan, scanOptions);
});
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
@@ -47,11 +60,23 @@ public class App {
}
}
- public static void printResults(List<ScanResult> results, boolean showFilteredPorts) {
- results.forEach((ScanResult r) -> printResult(r, showFilteredPorts));
+ public static void printScanIntermediateResult(Scan scan, ScanOptions scanOptions) {
+ printScanResults(scan.state().getSnapshotOfScanResults(), scan.state(), scanOptions);
+ }
+
+ private static void printScanResults(List<ScanResult> result, ScanState state, ScanOptions options) {
+ printStats(state);
+ result.forEach((ScanResult r) -> printPortsResults(r, options.showFilteredPorts()));
+ }
+
+ private static void printStats(ScanState state) {
+ System.out.println("--------------------");
+ System.out.println("Stats:");
+ System.out.println("Peak concurrent connects: " + state.getCounter().max());
+ System.out.println("--------------------");
}
- private static void printResult(ScanResult result, boolean showFilteredPorts) {
+ private static void printPortsResults(ScanResult result, boolean showFilteredPorts) {
if (result.openPorts().isEmpty() && (!showFilteredPorts || result.filteredPorts().isEmpty())) {
return;
}
diff --git a/src/main/java/com/it_jaros/jscanner/CliParser.java b/src/main/java/com/it_jaros/jscanner/CliParser.java
@@ -41,7 +41,7 @@ public class CliParser {
disableOnlineCheck = true;
break;
case "--help", "-h":
- usageAndExit();
+ usageAndExit(0);
break;
case "--input", "-i":
hostsFile = requireValue(args, ++i, currentArg);
@@ -91,7 +91,7 @@ public class CliParser {
}
}
- public void usageAndExit() {
+ public void usageAndExit(int returnCode) {
StringBuilder usage = new StringBuilder();
usage.append("""
Usage:
@@ -114,12 +114,12 @@ public class CliParser {
""".formatted(CliDefaults.BANNER_RECOGNITION, CliDefaults.DELAY_IN_MILLIS, CliDefaults.DISABLE_HOST_CHECK, CliDefaults.MAX_HOSTS_LIMIT, CliDefaults.MAX_WORKERS_PER_HOST, CliDefaults.PORTS, CliDefaults.QUIET, CliDefaults.SHOW_FILTERED_PORTS, CliDefaults.SOCKET_LIMIT, CliDefaults.TIMEOUT_IN_MILLIS)
);
usage.append("""
-
+
Examples:
java -jar jscanner.jar localhost
java -jar jscanner.jar fd00::1
""");
System.err.println(usage);
- System.exit(0);
+ System.exit(returnCode);
}
}
diff --git a/src/main/java/com/it_jaros/jscanner/Scan.java b/src/main/java/com/it_jaros/jscanner/Scan.java
@@ -0,0 +1,6 @@
+package com.it_jaros.jscanner;
+
+import java.util.List;
+
+public record Scan(List<String> hosts, String ports, ScanState state) {
+}
diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java
@@ -14,7 +14,6 @@ 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.Collectors;
import java.util.stream.Stream;
public class Scanner implements AutoCloseable {
@@ -56,50 +55,48 @@ public class Scanner implements AutoCloseable {
this(options.openSocketLimit(), options.timeoutInMillis(), options.delayInMillis(), options.maxWorkersPerHost(), options.maxHostsLimit(), options.disableHostCheck(), options.quiet(), options.bannerRecognition());
}
- public List<ScanResult> scan(ScanOptions options) {
+ public Scan createScan(ScanOptions options) {
if (options.hostsFile() != null) {
- return scanHosts(options.hostsFile(), options.ports());
+ return createScan(options.hostsFile(), options.ports());
}
- return scanHosts(options.hostsArgv(), options.ports());
+ return createScan(options.hostsArgv(), options.ports());
}
- public List<ScanResult> scanHosts(String sourceFile, String ports) {
+ public Scan createScan(String sourceFile, String ports) {
try (BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile))) {
- return scanHosts(reader.lines(), ports);
+ 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 List.of();
+ return null;
}
- public List<ScanResult> scanHosts(List<String> hostsArgv, String ports) {
- try (Stream<String> stream = hostsArgv.stream()) {
- return scanHosts(stream, ports);
- } catch (IOException e) {
- System.out.printf("Error while trying to read hosts: %s -> %s %n", e.getClass().getSimpleName(), e.getMessage());
- }
+ public Scan createScan(Stream<String> hosts, String ports) {
+ return new Scan(hosts.toList(), ports, new ScanState(new Counter(), new ProgressBar(quiet)));
+ }
- return List.of();
+ public Scan createScan(List<String> hostsArgv, String ports) {
+ return new Scan(hostsArgv, ports, new ScanState(new Counter(), new ProgressBar(quiet)));
}
- public List<ScanResult> scanHosts(Stream<String> hosts, String ports) throws IOException {
- ScanState scanState = new ScanState(new Counter(), new ProgressBar(quiet));
+ public List<ScanResult> runScan(Scan scan) {
+ ScanState scanState = scan.state();
scanState.getProgressBar().start();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletionService<ScanResult> completionService = new ExecutorCompletionService<>(executor);
- Queue<String> hostsInQueue = hosts.collect(Collectors.toCollection(ArrayDeque::new));
+ Queue<String> hostsInQueue = new ArrayDeque<>(scan.hosts());
int hostsToProcess = hostsInQueue.size();
int activeHostWorkers = 0;
while (hostsToProcess > 0 && !cancelled) {
// process queue
- while (!hostsInQueue.isEmpty() && activeHostWorkers <= maxHostsLimit && !cancelled) {
+ while (!hostsInQueue.isEmpty() && activeHostWorkers < maxHostsLimit && !cancelled) {
activeHostWorkers++;
final String host = hostsInQueue.poll();
- completionService.submit(() -> scanHost(host, ports, scanState));
+ completionService.submit(() -> scanHostPorts(host, scan.ports(), scanState));
}
try {
@@ -123,15 +120,10 @@ public class Scanner implements AutoCloseable {
}
scanState.getProgressBar().stop();
- System.out.println("--------------------");
- System.out.println("Finished scan!");
- System.out.println("Stats:");
- System.out.println("Peak concurrent connects: " + scanState.getCounter().max());
- System.out.println("--------------------");
return scanState.getSnapshotOfScanResults();
}
- private ScanResult scanHost(String host, String ports, ScanState scanState) {
+ private ScanResult scanHostPorts(String host, String ports, ScanState scanState) {
PortRange portRange = new PortRange(ports);
AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
BitSet openPorts = new BitSet(PortRange.MAX_PORT);
@@ -154,7 +146,7 @@ public class Scanner implements AutoCloseable {
int activePerHostWorkers = 0;
int portsToProcess = portRange.getTotal();
while (portsToProcess > 0 && !cancelled) {
- while (!cancelled && portRange.hasNext() && activePerHostWorkers <= maxWorkersPerHost) {
+ while (!cancelled && portRange.hasNext() && activePerHostWorkers < maxWorkersPerHost) {
activePerHostWorkers++;
final int currentPort = portRange.next();
completionService.submit(() -> {