jscanner

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

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:
Msrc/main/java/com/it_jaros/network_scanner/CliParser.java | 91++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/main/java/com/it_jaros/network_scanner/ScanOptions.java | 2+-
Msrc/main/java/com/it_jaros/network_scanner/Scanner.java | 35+++++++++++++++++++++++++++++++++--
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 {