commit c8793f11da22a7da4296dad1ba84617f83433944
parent 977f376ff96ef8fcc1e4d9c3e451c1405d6b3f0e
Author: Matthias Jaros <jaros@mailbox.org>
Date: Mon, 30 Mar 2026 12:20:33 +0200
Refactored cli option parsing and added -file option. Refactored reading
of hosts to have less redundancy.
Diffstat:
3 files changed, 87 insertions(+), 41 deletions(-)
diff --git a/src/main/java/com/it_jaros/network_scanner/CliParser.java b/src/main/java/com/it_jaros/network_scanner/CliParser.java
@@ -19,6 +19,7 @@ public class CliParser {
String ports = CliDefaults.PORTS;
boolean showFilteredPorts = CliDefaults.SHOW_FILTERED_PORTS;
boolean disableHostCheck = CliDefaults.DISABLE_HOST_CHECK;
+ String file = null;
for (int i = 0; i < args.length; i++) {
final String currentArg = args[i];
@@ -27,49 +28,63 @@ public class CliParser {
continue;
}
- try {
- switch (currentArg) {
- case "--help", "-h":
- usageAndExit();
- break;
- case "--socketLimit", "-sl":
- socketLimit = Integer.parseInt(args[++i]);
- break;
- case "--delay", "-d":
- delayInMillis = Integer.parseInt(args[++i]);
- break;
- case "--timeout", "-t":
- timeoutInMillis = Integer.parseInt(args[++i]);
- break;
- case "--maxWorkersPerHost", "-wh":
- maxWorkersPerHost = Integer.parseInt(args[++i]);
- break;
- case "--maxHostsLimit", "-tl":
- maxHostsLimit = Integer.parseInt(args[++i]);
- break;
- case "--ports", "-p":
- ports = args[++i];
- break;
- case "--showFilteredPorts", "-sf":
- showFilteredPorts = true;
- break;
- case "--disableHostCheck", "-dt":
- disableHostCheck = true;
- break;
- default:
- throw new IllegalArgumentException("No such param " + currentArg);
- }
- } catch (IndexOutOfBoundsException | NumberFormatException e) {
- System.out.printf("Missing or wrong argument for option %s", currentArg);
- System.exit(2);
+ 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":
+ file = requireValue(args, ++i, currentArg);
+ break;
+ default:
+ throw new IllegalArgumentException("No such param " + currentArg);
}
}
System.out.printf(
- "Parsed arguments: targetHosts('%s'), ports(%s), socketLimit(%s), delayInMillis(%s), timeoutInMillis(%s), maxWorkersPerHost(%s), maxTargetsLimit(%s), showFilteredPorts(%s), disableTargetCheck(%s) %n",
- targetHosts, ports, socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, showFilteredPorts, disableHostCheck);
+ "Parsed arguments: targetHosts('%s'), ports(%s), socketLimit(%s), delayInMillis(%s), timeoutInMillis(%s), maxWorkersPerHost(%s), maxTargetsLimit(%s), showFilteredPorts(%s), disableTargetCheck(%s), file(%s) %n",
+ targetHosts, ports, socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, showFilteredPorts, disableHostCheck, file);
- return new ScanOptions(targetHosts.stream().toList(), socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, ports, showFilteredPorts, disableHostCheck);
+ return new ScanOptions(targetHosts.stream().toList(), socketLimit, delayInMillis, timeoutInMillis, maxWorkersPerHost, maxHostsLimit, ports, showFilteredPorts, disableHostCheck, file);
+ }
+
+ 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() {
diff --git a/src/main/java/com/it_jaros/network_scanner/ScanOptions.java b/src/main/java/com/it_jaros/network_scanner/ScanOptions.java
@@ -2,4 +2,4 @@ package com.it_jaros.network_scanner;
import java.util.List;
-public record ScanOptions(List<String> targetHosts, int openSocketLimit, int delayInMillis, int timeoutInMillis, int maxWorkersPerHost, int maxHostsLimit, String ports, boolean showFilteredPorts, boolean disableHostCheck) {}
+public record ScanOptions(List<String> targetHosts, int openSocketLimit, int delayInMillis, int timeoutInMillis, int maxWorkersPerHost, int maxHostsLimit, String ports, boolean showFilteredPorts, boolean disableHostCheck, String file) {}
diff --git a/src/main/java/com/it_jaros/network_scanner/Scanner.java b/src/main/java/com/it_jaros/network_scanner/Scanner.java
@@ -1,7 +1,12 @@
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;
@@ -9,6 +14,7 @@ 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 {
@@ -31,16 +37,41 @@ public class Scanner {
}
public List<ScanResult> scan(ScanOptions options) {
+ if (options.file() != null) {
+ return scanHosts(options.file(), options.ports());
+ }
return scanHosts(options.targetHosts(), 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> targetHosts, String ports) {
+ try (Stream<String> stream = targetHosts.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);
- for (String host : targetHosts) {
+ hosts.forEach((final String host) -> {
maxHosts.acquireUninterruptibly();
futures.add(executor.submit(() -> {
try {
@@ -49,7 +80,7 @@ public class Scanner {
maxHosts.release();
}
}));
- }
+ });
futures.forEach((Future<ScanResult> f) -> {
try {