jscanner

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Msrc/main/java/com/it_jaros/jscanner/App.java | 53+++++++++++++++++++++++++++++++++++++++--------------
Msrc/main/java/com/it_jaros/jscanner/CliParser.java | 8++++----
Asrc/main/java/com/it_jaros/jscanner/Scan.java | 6++++++
Msrc/main/java/com/it_jaros/jscanner/Scanner.java | 44++++++++++++++++++--------------------------
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(() -> {