diff --git a/pom.xml b/pom.xml
index 7825112..79b4913 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
scanner-core
- 6.2.4-SNAPSHOT
+ 6.2.3
Scanner Core
A generic scanner framework which can execute a set of probes and combine the results into a report.
diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java b/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java
new file mode 100644
index 0000000..ef9f9be
--- /dev/null
+++ b/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java
@@ -0,0 +1,52 @@
+/*
+ * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis.
+ *
+ * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH
+ *
+ * Licensed under Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
+ */
+package de.rub.nds.scanner.core.execution;
+
+import de.rub.nds.scanner.core.probe.ScannerProbe;
+import de.rub.nds.scanner.core.report.ScanReport;
+
+/**
+ * Callback interface for receiving probe execution progress updates. This interface allows external
+ * components to be notified when individual probes complete during a scan, enabling real-time
+ * progress monitoring and streaming of partial results.
+ *
+ * @param the type of scan report
+ * @param the type of state object used by probes
+ */
+@FunctionalInterface
+public interface ProbeProgressCallback {
+
+ /**
+ * Called when a probe has completed execution and merged its results into the report.
+ *
+ * @param probe the probe that completed execution
+ * @param report the scan report with the probe's results merged in
+ * @param completedProbes the number of probes that have completed so far
+ * @param totalProbes the total number of probes scheduled for this scan
+ */
+ void onProbeCompleted(
+ ScannerProbe probe,
+ ReportT report,
+ int completedProbes,
+ int totalProbes);
+
+ /**
+ * Creates a no-op callback that does nothing when probes complete. Useful as a default when no
+ * progress tracking is needed.
+ *
+ * @param the type of scan report
+ * @param the type of state object
+ * @return a callback that performs no operations
+ */
+ static ProbeProgressCallback noOp() {
+ return (probe, report, completedProbes, totalProbes) -> {
+ // No operation
+ };
+ }
+}
diff --git a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java
index 3222639..1aa896c 100644
--- a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java
+++ b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java
@@ -49,6 +49,9 @@ public abstract class Scanner<
private final List afterList;
private final boolean fillProbeListsAtScanStart;
+ // Optional callback for probe progress updates
+ private ProbeProgressCallback progressCallback = ProbeProgressCallback.noOp();
+
/**
* Creates a new scanner instance.
*
@@ -131,6 +134,18 @@ protected List getGuidelines() {
return List.of();
}
+ /**
+ * Sets the progress callback to be invoked when probes complete during scanning. This allows
+ * external components to receive real-time updates about scan progress and partial results.
+ *
+ * @param progressCallback the callback to invoke on probe completion, or null to disable
+ * callbacks
+ */
+ public void setProgressCallback(ProbeProgressCallback progressCallback) {
+ this.progressCallback =
+ progressCallback != null ? progressCallback : ProbeProgressCallback.noOp();
+ }
+
/**
* Performs the scan. It will take care of all the necessary steps to perform a scan, including
* filling the probe list by calling {@link #fillProbeLists}, checking the scan prerequisites by
@@ -166,6 +181,8 @@ public ReportT scan() {
scanJob,
executorConfig.getParallelProbes(),
"ScannerProbeExecutor " + report.getRemoteName())) {
+ // Set the progress callback on the executor
+ scanJobExecutor.setProgressCallback(progressCallback);
ProgressSpinner.startSpinnerTask("Executing:");
report.setScanStartTime(System.currentTimeMillis());
scanJobExecutor.execute(report);
diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java
index a27e2fa..17abfc5 100644
--- a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java
+++ b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java
@@ -60,6 +60,9 @@ public class ThreadedScanJobExecutor<
private volatile int probeCount;
private final AtomicInteger finishedProbes = new AtomicInteger(0);
+ // Callback for probe progress updates (optional)
+ private ProbeProgressCallback progressCallback = ProbeProgressCallback.noOp();
+
/**
* Creates a new ThreadedScanJobExecutor with a custom thread pool.
*
@@ -103,6 +106,18 @@ public ThreadedScanJobExecutor(
this.futureResults = new LinkedList<>();
}
+ /**
+ * Sets the progress callback to be invoked when probes complete. This allows external
+ * components to receive real-time updates about scan progress.
+ *
+ * @param progressCallback the callback to invoke on probe completion, or null to disable
+ * callbacks
+ */
+ public void setProgressCallback(ProbeProgressCallback progressCallback) {
+ this.progressCallback =
+ progressCallback != null ? progressCallback : ProbeProgressCallback.noOp();
+ }
+
/**
* Executes the scan job by running probes concurrently and populating the report with results.
* This method manages probe dependencies and ensures probes are executed in the correct order.
@@ -146,7 +161,8 @@ private void executeProbesTillNoneCanBeExecuted(ReportT report) throws Interrupt
try {
probeResult = result.get();
LOGGER.info(
- "[{}/{}] {} probe executed",
+ "[{}] [{}/{}] {} probe executed",
+ report.getRemoteName(),
String.format("%2d", currentFinishedProbes),
String.format("%2d", probeCount),
probeResult.getType().getName());
@@ -157,6 +173,14 @@ private void executeProbesTillNoneCanBeExecuted(ReportT report) throws Interrupt
finishedFutures.add(result);
probeResult.merge(report);
report.markProbeAsExecuted(probeResult);
+
+ // Notify progress callback
+ try {
+ progressCallback.onProbeCompleted(
+ probeResult, report, currentFinishedProbes, probeCount);
+ } catch (Exception e) {
+ LOGGER.warn("Progress callback threw exception, continuing scan", e);
+ }
}
}
futureResults.removeAll(finishedFutures);