summaryrefslogtreecommitdiff
path: root/src/main/java/com/it_jaros/network_scanner
diff options
context:
space:
mode:
authorGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-04-13 17:31:55 +0200
committerGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-09 09:59:28 +0200
commit8b881560dd8884e8e54e1e64654f79749d9ff456 (patch)
treefaffd2348b9430bcda9591120a0aa392923e422c /src/main/java/com/it_jaros/network_scanner
parentb1bdcf02479f67a65f6176ed8a87b47925903e81 (diff)
Renamed package from network_scanner to jscanner
Diffstat (limited to 'src/main/java/com/it_jaros/network_scanner')
-rw-r--r--src/main/java/com/it_jaros/network_scanner/App.java45
-rw-r--r--src/main/java/com/it_jaros/network_scanner/CliDefaults.java12
-rw-r--r--src/main/java/com/it_jaros/network_scanner/CliParser.java112
-rw-r--r--src/main/java/com/it_jaros/network_scanner/Counter.java25
-rw-r--r--src/main/java/com/it_jaros/network_scanner/PortRange.java91
-rw-r--r--src/main/java/com/it_jaros/network_scanner/PortResult.java4
-rw-r--r--src/main/java/com/it_jaros/network_scanner/PortState.java7
-rw-r--r--src/main/java/com/it_jaros/network_scanner/Progress.java5
-rw-r--r--src/main/java/com/it_jaros/network_scanner/ProgressBar.java118
-rw-r--r--src/main/java/com/it_jaros/network_scanner/ScanOptions.java5
-rw-r--r--src/main/java/com/it_jaros/network_scanner/ScanResult.java5
-rw-r--r--src/main/java/com/it_jaros/network_scanner/Scanner.java209
12 files changed, 0 insertions, 638 deletions
diff --git a/src/main/java/com/it_jaros/network_scanner/App.java b/src/main/java/com/it_jaros/network_scanner/App.java
deleted file mode 100644
index ca8f649..0000000
--- a/src/main/java/com/it_jaros/network_scanner/App.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.BitSet;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class App {
- public static void main(String[] args) {
- CliParser cliParser = new CliParser();
- try {
- ScanOptions options = cliParser.parseArgs(args);
- Scanner scanner = new Scanner(options.openSocketLimit(), options.timeoutInMillis(),
- options.delayInMillis(), options.maxWorkersPerHost(), options.maxHostsLimit(), options.disableHostCheck());
- printResults(scanner.scan(options), options.showFilteredPorts());
- } catch (IllegalArgumentException e) {
- System.out.printf("Error while parsing arguments: %s", e.getMessage());
- cliParser.usageAndExit();
- } catch (Exception e) {
- System.out.printf("ERROR: %s", e.getMessage());
- }
- }
-
- public static void printResults(List<ScanResult> results, boolean showFilteredPorts) {
- results.forEach((ScanResult r) -> printResult(r, showFilteredPorts));
- }
-
- private static void printResult(ScanResult result, boolean showFilteredPorts) {
- if (result.openPorts().isEmpty() && (!showFilteredPorts || result.filteredPorts().isEmpty())) {
- return;
- }
-
- System.out.println(result.host());
- if (!result.openPorts().isEmpty()) {
- System.out.printf("\t (%d) open:\t%s%n", result.openPorts().cardinality(), map(result.openPorts()));
- }
- if (showFilteredPorts && !result.filteredPorts().isEmpty()) {
- System.out.printf("\t (%d) filtered:\t%s%n", result.filteredPorts().cardinality(), map(result.filteredPorts()));
- }
- System.out.println();
- }
-
- private static String map(BitSet ports) {
- return ports.stream().mapToObj(String::valueOf).collect(Collectors.joining(","));
- }
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/CliDefaults.java b/src/main/java/com/it_jaros/network_scanner/CliDefaults.java
deleted file mode 100644
index c6c15bd..0000000
--- a/src/main/java/com/it_jaros/network_scanner/CliDefaults.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.it_jaros.network_scanner;
-
-public class CliDefaults {
- public static final int SOCKET_LIMIT = 1000;
- public static final int DELAY_IN_MILLIS = 0;
- public static final int TIMEOUT_IN_MILLIS = 300;
- public static final int MAX_WORKERS_PER_HOST = 1000;
- public static final int MAX_HOSTS_LIMIT = 10;
- public static final String PORTS = "1-1024";
- public static final boolean SHOW_FILTERED_PORTS = false;
- public static final boolean DISABLE_HOST_CHECK = false;
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/CliParser.java b/src/main/java/com/it_jaros/network_scanner/CliParser.java
deleted file mode 100644
index bf2fa7a..0000000
--- a/src/main/java/com/it_jaros/network_scanner/CliParser.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class CliParser {
-
- public ScanOptions parseArgs(String[] args) {
- if (args.length < 1 || args[0].trim().equals("")) {
- throw new IllegalArgumentException("No argument given");
- }
-
- Set<String> hostsArgv = new HashSet<>();
- int socketLimit = CliDefaults.SOCKET_LIMIT;
- int delayInMillis = CliDefaults.DELAY_IN_MILLIS;
- int timeoutInMillis = CliDefaults.TIMEOUT_IN_MILLIS;
- int maxWorkersPerHost = CliDefaults.MAX_WORKERS_PER_HOST;
- int maxHostsLimit = CliDefaults.MAX_HOSTS_LIMIT;
- String ports = CliDefaults.PORTS;
- boolean showFilteredPorts = CliDefaults.SHOW_FILTERED_PORTS;
- boolean disableHostCheck = CliDefaults.DISABLE_HOST_CHECK;
- String hostsFile = null;
-
- for (int i = 0; i < args.length; i++) {
- final String currentArg = args[i];
- if (!currentArg.startsWith("-")) {
- hostsArgv.add(currentArg);
- continue;
- }
-
- switch (currentArg) {
- case "--help", "-h":
- usageAndExit();
- break;
- case "--socketLimit", "-sl":
- socketLimit = parseIntOption(args, ++i, currentArg);
- break;
- case "--delay", "-d":
- delayInMillis = parseIntOption(args, ++i, currentArg);
- break;
- case "--timeout", "-t":
- timeoutInMillis = parseIntOption(args, ++i, currentArg);
- break;
- case "--maxWorkersPerHost", "-wh":
- maxWorkersPerHost = parseIntOption(args, ++i, currentArg);
- break;
- case "--maxHostsLimit", "-tl":
- maxHostsLimit = parseIntOption(args, ++i, currentArg);
- break;
- case "--ports", "-p":
- ports = requireValue(args, ++i, currentArg);
- break;
- case "--showFilteredPorts", "-sf":
- showFilteredPorts = true;
- break;
- case "--disableHostCheck", "-dt":
- disableHostCheck = true;
- break;
- case "--file", "-f":
- hostsFile = requireValue(args, ++i, currentArg);
- break;
- default:
- throw new IllegalArgumentException("No such param " + currentArg);
- }
- }
-
- System.out.printf(
- "Parsed arguments: hostsArgv('%s'), ports(%s), socketLimit(%s), delayInMillis(%s), timeoutInMillis(%s), maxWorkersPerHost(%s), maxTargetsLimit(%s), showFilteredPorts(%s), disableTargetCheck(%s), file(%s) %n",
- hostsArgv, ports, socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, showFilteredPorts, disableHostCheck, hostsFile);
-
- return new ScanOptions(hostsArgv.stream().toList(), socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, ports, showFilteredPorts, disableHostCheck, hostsFile);
- }
-
- private String requireValue(String[] args, int index, String option) {
- if (index >= args.length) {
- throw new IllegalArgumentException(String.format("Missing argument for option %s", option));
- }
- return args[index];
- }
-
- private int parseIntOption(String[] args, int index, String option) {
- String value = requireValue(args, index, option);
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(String.format("Invalid argument %s for option %s", value, option));
- }
- }
-
- public void usageAndExit() {
- System.err.println("""
- Usage:
- java -jar scanner.jar [OPTIONS] <host>
-
- Options:
- --delay, -d:\t\tWaiting period in millis for connection attempts for a host (Default: 0)
- --socketLimit, -sl:\t\tSocket Connection limit for a host (Default: 1000)
- --timeout, -t:\t\tTimeout per connection attempt, 0 means infinite (Default: 1000)
- --ports, -p:\t\tPorts to be scanned
- --maxWorkersPerHost, -wh:\tVirtual Worker Threads run per Host. Higher doesn't mean necessarily faster. But the more you use the more RAM is required (Default: 1000)
- --maxHostsLimit, -tl:\tMax number of Hosts that are scanned at the same time (Default: 10)
- --showFilteredPorts, -sf:\tShow also filtered ports
- --disableHostCheck, -dt:\tDon't check if Host is reachable
- --file, -f:\t\t\tRead hosts to scan from file instead of stdin
-
- Examples:
- java -jar scanner.jar localhost
- java -jar scanner.jar fd00::1
- """);
- System.exit(1);
- }
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/Counter.java b/src/main/java/com/it_jaros/network_scanner/Counter.java
deleted file mode 100644
index f9ff67a..0000000
--- a/src/main/java/com/it_jaros/network_scanner/Counter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-public final class Counter {
- private final AtomicInteger current = new AtomicInteger(0);
- private final AtomicInteger max = new AtomicInteger(0);
-
- public void inc() {
- int now = current.incrementAndGet();
- max.accumulateAndGet(now, Math::max);
- }
-
- public void dec() {
- current.decrementAndGet();
- }
-
- public int current() {
- return current.get();
- }
-
- public int max() {
- return max.get();
- }
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/PortRange.java b/src/main/java/com/it_jaros/network_scanner/PortRange.java
deleted file mode 100644
index 2fd3909..0000000
--- a/src/main/java/com/it_jaros/network_scanner/PortRange.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.BitSet;
-import java.util.NoSuchElementException;
-
-public class PortRange {
-
- public static final int MIN_PORT = 1;
- public static final int MAX_PORT = 65535;
- private final BitSet specifiedPorts = new BitSet(MAX_PORT);
- private final BitSet availablePorts = new BitSet(MAX_PORT);
-
- private int cursor;
- private int done = 0;
-
- public PortRange(String ports) {
- if (ports == null || "".equals(ports)) {
- // keep defaults
- specifiedPorts.set(1, 1024 + 1);
- return;
- }
-
- String[] splitComma = ports.split(",");
- for (String commaValue : splitComma) {
- if (commaValue.contains("-")) {
- String[] rangeValue = commaValue.split("-");
- if (rangeValue.length > 2) {
- throw new IllegalArgumentException(String.format("Argument contains too many '-'' %s", commaValue));
- }
-
- int start = Integer.parseInt(rangeValue[0]);
- int end = Integer.parseInt(rangeValue[1]);
- checkValues(start, end);
- specifiedPorts.set(start, end + 1);
- } else {
- int port = Integer.parseInt(commaValue);
- checkValue(port);
- specifiedPorts.set(Integer.parseInt(commaValue));
- }
- }
-
- availablePorts.or(specifiedPorts);
- cursor = availablePorts.nextSetBit(MIN_PORT);
- }
-
- private void checkValues(int start, int end) {
- checkValue(start);
- checkValue(end);
-
- if (start >= end) {
- throw new IllegalArgumentException(
- String.format("Start value cannot be equal or bigger than end value '%s >= %s'", start, end));
- }
- }
-
- private void checkValue(int port) {
- if (port < MIN_PORT) {
- throw new IllegalArgumentException(
- String.format("Start value smaller than allowed range %s < %s", port, MIN_PORT));
- }
-
- if (port > MAX_PORT) {
- throw new IllegalArgumentException(
- String.format("End value bigger than allowed range %s > %s", port, MAX_PORT));
- }
- }
-
- public int next() {
- int p = availablePorts.nextSetBit(cursor);
- if (p > 0) {
- availablePorts.clear(p);
- cursor = p + 1;
- done++;
- return p;
- }
-
- throw new NoSuchElementException("Reached end of port range");
- }
-
- public boolean hasNext() {
- return availablePorts.nextSetBit(cursor) > 0;
- }
-
- public int getTotal() {
- return specifiedPorts.cardinality();
- }
-
- public int getDone() {
- return done;
- }
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/PortResult.java b/src/main/java/com/it_jaros/network_scanner/PortResult.java
deleted file mode 100644
index d5ebf7c..0000000
--- a/src/main/java/com/it_jaros/network_scanner/PortResult.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.it_jaros.network_scanner;
-
-public record PortResult(int port, PortState state) {
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/PortState.java b/src/main/java/com/it_jaros/network_scanner/PortState.java
deleted file mode 100644
index c22bc2d..0000000
--- a/src/main/java/com/it_jaros/network_scanner/PortState.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.it_jaros.network_scanner;
-
-public enum PortState {
- OPEN,
- CLOSED,
- FILTERED
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/Progress.java b/src/main/java/com/it_jaros/network_scanner/Progress.java
deleted file mode 100644
index e39b9fe..0000000
--- a/src/main/java/com/it_jaros/network_scanner/Progress.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-public record Progress(String host, int total, AtomicInteger done, AtomicInteger open, AtomicInteger filtered) {} \ No newline at end of file
diff --git a/src/main/java/com/it_jaros/network_scanner/ProgressBar.java b/src/main/java/com/it_jaros/network_scanner/ProgressBar.java
deleted file mode 100644
index 184f82e..0000000
--- a/src/main/java/com/it_jaros/network_scanner/ProgressBar.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class ProgressBar {
-
- private final ScheduledExecutorService ui = Executors.newSingleThreadScheduledExecutor();
- private final ReentrantLock lock = new ReentrantLock();
- private final int columnWidth = ProgressBar.getColumnWidth();
-
- private List<Progress> hosts;
-
- private static int getColumnWidth() {
- try {
- Process process = new ProcessBuilder("sh", "-c", "stty size < /dev/tty").start();
-
- try (BufferedReader reader = new BufferedReader(
- new InputStreamReader(process.getInputStream()))) {
- String line = reader.readLine();
- if (line != null && !line.isBlank()) {
- Matcher matcher = Pattern.compile("^\\d+\\s+(\\d+)").matcher(line.trim());
- if (matcher.matches()) {
- return Integer.parseInt(matcher.group(1));
- }
- }
- }
- } catch (Exception ignored) {
- // does not matter why it did not work
- }
-
- return 120;
- }
-
- public void start() {
- this.hosts = new ArrayList<>();
- System.out.print("Scanning targets...\n\n");
- ui.scheduleAtFixedRate(() -> {
- lock.lock();
- drawProgress(false);
- lock.unlock();
- }, 1, 200, TimeUnit.MILLISECONDS);
- }
-
- private void drawProgress(boolean last) {
- // find and print finished hosts one last time
- for (Iterator<Progress> it = hosts.iterator(); it.hasNext();) {
- Progress p = it.next();
- if (p.done().get() == p.total()) {
- it.remove();
- drawBar(p);
- }
- }
-
- // the more progressed the host the more up it is
- hosts.sort(Comparator.comparingInt((Progress p) -> p.done().get()).reversed());
- for (Progress progress : hosts) {
- drawBar(progress);
- }
-
- if (!last) {
- // move cursor up again
- System.out.print("\u001b[" + hosts.size() + "A");
- }
- }
-
- public void submit(Progress progress) {
- lock.lock();
- hosts.add(progress);
- lock.unlock();
- }
-
- private void drawBar(Progress progress) {
- System.out.print("\u001b[2K\r"); // clear whole line
- System.out.println(createBar(
- progress.host(),
- progress.open().get(),
- progress.filtered().get(),
- progress.done().get(),
- progress.total()));
- }
-
- public String createBar(String label, int open, int filtered, int done, int total) {
- int terminalWidth = columnWidth;
- int bracketWidth = terminalWidth / 3;
- double pct = total == 0 ? 1.0 : (done / (double) total);
- int percent = (int) (pct * 100);
-
- String statsLeft = String.format("open:%d filtered:%d (%d/%d)", open, filtered, done, total);
- String statsRight = String.format("%3d%%", percent);
- int filled = (int) (pct * bracketWidth);
- 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);
- }
-
- public void stop() {
- ui.shutdown();
- try {
- ui.awaitTermination(10, TimeUnit.SECONDS);
- // we need to draw one last time for the 100% to appear
- drawProgress(true);
- } catch (InterruptedException ignored) {
- Thread.currentThread().interrupt();
- }
- }
-}
diff --git a/src/main/java/com/it_jaros/network_scanner/ScanOptions.java b/src/main/java/com/it_jaros/network_scanner/ScanOptions.java
deleted file mode 100644
index 8d4931c..0000000
--- a/src/main/java/com/it_jaros/network_scanner/ScanOptions.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.List;
-
-public record ScanOptions(List<String> hostsArgv, int openSocketLimit, int delayInMillis, int timeoutInMillis, int maxWorkersPerHost, int maxHostsLimit, String ports, boolean showFilteredPorts, boolean disableHostCheck, String hostsFile) {}
diff --git a/src/main/java/com/it_jaros/network_scanner/ScanResult.java b/src/main/java/com/it_jaros/network_scanner/ScanResult.java
deleted file mode 100644
index 312538b..0000000
--- a/src/main/java/com/it_jaros/network_scanner/ScanResult.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.util.BitSet;
-
-public record ScanResult(String host, BitSet openPorts, BitSet filteredPorts) {}
diff --git a/src/main/java/com/it_jaros/network_scanner/Scanner.java b/src/main/java/com/it_jaros/network_scanner/Scanner.java
deleted file mode 100644
index 070a164..0000000
--- a/src/main/java/com/it_jaros/network_scanner/Scanner.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package com.it_jaros.network_scanner;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.*;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-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 {
-
- private final Counter counter = new Counter();
- private final ProgressBar progressBar = new ProgressBar();
- private final Semaphore socketLimit;
- private final int timeoutInMillis;
- private final long delayInNanos;
- private final int maxWorkersPerHost;
- private final int maxHostsLimit;
- private final boolean disableHostCheck;
-
- public Scanner(int socketLimit, int timeoutInMillis, int delayInMillis, int maxWorkersPerHost, int maxHostsLimit, boolean disableHostCheck) {
- this.timeoutInMillis = timeoutInMillis;
- this.delayInNanos = TimeUnit.MILLISECONDS.toNanos(Math.max(0, delayInMillis));
- this.socketLimit = new Semaphore(socketLimit);
- this.maxWorkersPerHost = maxWorkersPerHost;
- this.maxHostsLimit = maxHostsLimit;
- this.disableHostCheck = disableHostCheck;
- }
-
- public List<ScanResult> scan(ScanOptions options) {
- if (options.hostsFile() != null) {
- return scanHosts(options.hostsFile(), options.ports());
- }
- return scanHosts(options.hostsArgv(), options.ports());
- }
-
- public List<ScanResult> scanHosts(String sourceFile, String ports) {
- try (BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile))) {
- return scanHosts(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();
- }
-
- 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());
- }
-
- return List.of();
- }
-
- public List<ScanResult> scanHosts(Stream<String> hosts, String ports) throws IOException {
- List<ScanResult> results = new ArrayList<>();
- progressBar.start();
- try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
- List<Future<ScanResult>> futures = new ArrayList<>();
- Semaphore maxHosts = new Semaphore(maxHostsLimit);
- hosts.forEach((final String host) -> {
- maxHosts.acquireUninterruptibly();
- futures.add(executor.submit(() -> {
- try {
- return scanHost(host, ports);
- } finally {
- maxHosts.release();
- }
- }));
- });
-
- futures.forEach((Future<ScanResult> f) -> {
- try {
- results.add(f.get());
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- System.out.printf("%s -> %s%n", e.getClass().getSimpleName(), e.getMessage());
- }
- });
- }
-
- progressBar.stop();
- System.out.println("--------------------");
- System.out.println("Finished scan!");
- System.out.println("Stats:");
- System.out.println("Peak concurrent connects: " + counter.max());
- System.out.println("--------------------");
- return results;
- }
-
- private ScanResult scanHost(String host, String ports) {
- PortRange portRange = new PortRange(ports);
- AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
- Semaphore maxWorkers = new Semaphore(maxWorkersPerHost);
- BitSet openPorts = new BitSet(PortRange.MAX_PORT);
- BitSet filteredPorts = new BitSet(PortRange.MAX_PORT);
-
- Progress progress = new Progress(host, portRange.getTotal(), new AtomicInteger(), new AtomicInteger(), new AtomicInteger());
- progressBar.submit(progress);
-
- if(!disableHostCheck && !checkHostOnline(host)) {
- // Visually show that this host is basically done
- progress.done().set(progress.total());
- return new ScanResult(host, openPorts, filteredPorts);
- }
-
- try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
- List<Future<PortResult>> futures = new ArrayList<>();
- while (portRange.hasNext()) {
- maxWorkers.acquireUninterruptibly();
- final int currentPort = portRange.next();
- futures.add(executor.submit(() -> {
- try {
- waitForSlot(portSlotFactory);
- PortState state = getPortState(host, currentPort);
- if (state.equals(PortState.OPEN)) {
- progress.open().incrementAndGet();
- } else if (state.equals(PortState.FILTERED)) {
- progress.filtered().incrementAndGet();
- }
- return new PortResult(currentPort, state);
- } finally {
- maxWorkers.release();
- progress.done().incrementAndGet();
- }
- }));
- }
-
- List<Throwable> errors = new ArrayList<>();
- for (Future<PortResult> f : futures) {
- try {
- // bitset is not thread-safe, so it is set
- // outside the other virtual threads that update progress
- PortResult portResult = f.get();
- if (portResult.state().equals(PortState.OPEN)) {
- openPorts.set(portResult.port());
- } else if (portResult.state().equals(PortState.FILTERED)) {
- filteredPorts.set(portResult.port());
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } catch (ExecutionException e) {
- errors.add(e);
- }
- }
-
- if (!errors.isEmpty()) {
- System.out.printf("Errors happened during scan of host %s%nErrors:%s -> %s", host, errors.size(), errors);
- }
- }
-
- return new ScanResult(host, openPorts, filteredPorts);
- }
-
- private boolean checkHostOnline(String host) {
- try {
- return InetAddress.getByName(host).isReachable(timeoutInMillis);
- } catch (IOException e) {
- // something went wrong
- }
-
- return false;
- }
-
- private void waitForSlot(AtomicLong scanSlotFactory) {
- if (delayInNanos > 0) {
- long slot = scanSlotFactory.getAndAdd(delayInNanos);
- long wait = slot - System.nanoTime();
- if (wait > 0)
- LockSupport.parkNanos(wait);
- }
- }
-
- private PortState getPortState(String host, int port) {
- socketLimit.acquireUninterruptibly();
- counter.inc();
- try (Socket socket = new Socket()) {
- socket.connect(new InetSocketAddress(host, port), timeoutInMillis);
- return PortState.OPEN;
- } catch (NoRouteToHostException ignored) {
- // this can be safely ignored because the port is closed if a host is unreachable
- } catch (SocketTimeoutException ignored) {
- return PortState.FILTERED;
- } catch (ConnectException ignored) {
- return PortState.CLOSED;
- } catch (IOException ignored) {
- // Will happen a lot when scanning for open ports, so not needed
- } finally {
- counter.dec();
- socketLimit.release();
- }
-
- return PortState.CLOSED;
- }
-}