From 9ada0eae23e467d19edd4b45a9a3c215a320a06e Mon Sep 17 00:00:00 2001 From: Matthias Jaros Date: Thu, 13 Aug 2026 20:36:07 +0200 Subject: Renamed PortResultAccumulator to PortScanResultAccumulator which matches better what it does. Also now added feature to count appearance of certain exceptions and which ports are affected and print error log now in only one line instead of 10000x --- src/main/java/com/it_jaros/jns/CliPrinter.java | 7 +-- .../com/it_jaros/jns/scan/domain/ScanFailure.java | 4 +- .../jns/scan/engine/PortResultAccumulator.java | 49 ------------------ .../jns/scan/engine/PortScanResultAccumulator.java | 60 ++++++++++++++++++++++ .../com/it_jaros/jns/scan/engine/ScanHostTask.java | 4 +- 5 files changed, 69 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/com/it_jaros/jns/scan/engine/PortResultAccumulator.java create mode 100644 src/main/java/com/it_jaros/jns/scan/engine/PortScanResultAccumulator.java (limited to 'src/main') diff --git a/src/main/java/com/it_jaros/jns/CliPrinter.java b/src/main/java/com/it_jaros/jns/CliPrinter.java index c8969d9..6ceb399 100644 --- a/src/main/java/com/it_jaros/jns/CliPrinter.java +++ b/src/main/java/com/it_jaros/jns/CliPrinter.java @@ -58,10 +58,11 @@ public class CliPrinter { result.errors().size() )); String errors = result.errors().stream().map((ScanFailure error) -> String.format( - "\t%s: %s, %s", - error.port(), + "\t%dx %s: %s ports: %s", + error.ports().size(), error.exception().type(), - error.exception().message() + error.exception().message(), + error.ports().stream().sorted().map(String::valueOf).collect(Collectors.joining(",")) )).collect(Collectors.joining("\n")); sb.append(errors); sb.append("\n"); diff --git a/src/main/java/com/it_jaros/jns/scan/domain/ScanFailure.java b/src/main/java/com/it_jaros/jns/scan/domain/ScanFailure.java index 8a16a5d..a65d84e 100644 --- a/src/main/java/com/it_jaros/jns/scan/domain/ScanFailure.java +++ b/src/main/java/com/it_jaros/jns/scan/domain/ScanFailure.java @@ -2,8 +2,10 @@ package com.it_jaros.jns.scan.domain; import com.it_jaros.jns.scan.ExceptionInfo; +import java.util.List; + public record ScanFailure( - Integer port, + List ports, ExceptionInfo exception ) { } diff --git a/src/main/java/com/it_jaros/jns/scan/engine/PortResultAccumulator.java b/src/main/java/com/it_jaros/jns/scan/engine/PortResultAccumulator.java deleted file mode 100644 index bcb6432..0000000 --- a/src/main/java/com/it_jaros/jns/scan/engine/PortResultAccumulator.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.it_jaros.jns.scan.engine; - -import com.it_jaros.jns.scan.ExceptionInfo; -import com.it_jaros.jns.scan.domain.*; -import com.it_jaros.jns.scan.service.ServiceDetector; -import com.it_jaros.jns.scan.service.ServiceType; - -import java.util.*; - -final class PortResultAccumulator { - private final String host; - private final BitSet openPorts = new BitSet(PortRange.MAX_PORT); - private final BitSet filteredPorts = new BitSet(PortRange.MAX_PORT); - private final Map serviceTypes = new HashMap<>(); - private final List scanFailures = new ArrayList<>(); - - PortResultAccumulator(String host) { - this.host = host; - } - - void add(PortResult portResult) { - switch (portResult.getState()) { - case OPEN -> { - openPorts.set(portResult.getPort()); - serviceTypes.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner())); - } - case FILTERED -> { - filteredPorts.set(portResult.getPort()); - } - default -> { - // intentional no-op for uncovered port states - } - } - Exception e = portResult.getException(); - if (e != null) { - scanFailures.add(new ScanFailure(portResult.getPort(), ExceptionInfo.from(e))); - } - } - - ScanResult build() { - return new ScanResult( - host, - new PortList(openPorts), - new PortList(filteredPorts), - Collections.unmodifiableMap(serviceTypes), - Collections.unmodifiableList(scanFailures) - ); - } -} diff --git a/src/main/java/com/it_jaros/jns/scan/engine/PortScanResultAccumulator.java b/src/main/java/com/it_jaros/jns/scan/engine/PortScanResultAccumulator.java new file mode 100644 index 0000000..89238ed --- /dev/null +++ b/src/main/java/com/it_jaros/jns/scan/engine/PortScanResultAccumulator.java @@ -0,0 +1,60 @@ +package com.it_jaros.jns.scan.engine; + +import com.it_jaros.jns.scan.ExceptionInfo; +import com.it_jaros.jns.scan.domain.*; +import com.it_jaros.jns.scan.service.ServiceDetector; +import com.it_jaros.jns.scan.service.ServiceType; + +import java.util.*; + +final class PortScanResultAccumulator { + private final String host; + private final BitSet openPorts = new BitSet(PortRange.MAX_PORT); + private final BitSet filteredPorts = new BitSet(PortRange.MAX_PORT); + private final Map serviceTypes = new HashMap<>(); + private final Map, ScanFailure> failureCounts = new HashMap<>(); + + PortScanResultAccumulator(String host) { + this.host = host; + } + + void add(PortResult portResult) { + switch (portResult.getState()) { + case OPEN -> { + openPorts.set(portResult.getPort()); + serviceTypes.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner())); + } + case FILTERED -> { + filteredPorts.set(portResult.getPort()); + } + default -> { + // intentional no-op for uncovered port states + } + } + final Exception e = portResult.getException(); + if (e != null) { + ScanFailure scanFailure = failureCounts.computeIfAbsent( + e.getClass(), + k -> new ScanFailure( + new ArrayList<>(), + ExceptionInfo.from(e) + ) + ); + scanFailure.ports().add(portResult.getPort()); + } + } + + List getFailureSummary() { + return failureCounts.values().stream().toList(); + } + + ScanResult build() { + return new ScanResult( + host, + new PortList(openPorts), + new PortList(filteredPorts), + Collections.unmodifiableMap(serviceTypes), + getFailureSummary() + ); + } +} diff --git a/src/main/java/com/it_jaros/jns/scan/engine/ScanHostTask.java b/src/main/java/com/it_jaros/jns/scan/engine/ScanHostTask.java index 675dadd..d27cae2 100644 --- a/src/main/java/com/it_jaros/jns/scan/engine/ScanHostTask.java +++ b/src/main/java/com/it_jaros/jns/scan/engine/ScanHostTask.java @@ -16,17 +16,17 @@ public class ScanHostTask implements Callable { private final CancelledToken cancelledToken; private InetAddress hostAddress; + private final PortScanResultAccumulator accumulator; private final Scan scan; private final ScanExecutionContext context; private final String host; // input parameter private final boolean disableOnlineCheck; private final int maxWorkersPerHost; - private final PortResultAccumulator accumulator; public ScanHostTask(String host, ScanExecutionContext context) { this.host = host; this.context = context; - this.accumulator = new PortResultAccumulator(host); + this.accumulator = new PortScanResultAccumulator(host); this.cancelledToken = context.cancelledToken(); this.disableOnlineCheck = context.scanOptions().disableOnlineCheck(); this.maxWorkersPerHost = context.scanOptions().maxWorkersPerHost(); -- cgit v1.3.1