jscanner

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

commit 523fe9cee4d4ddf4caa6a04dc5eabc13db5ea332
parent e0a012e946e71ba2e8769a70cc0055b5852d720d
Author: Matthias Jaros <jaros@mailbox.org>
Date:   Mon, 26 Jan 2026 15:10:48 +0100

Added multi-target functionality

Diffstat:
Msrc/main/java/com/it_jaros/networkScanner/App.java | 19++++++++++++-------
Msrc/main/java/com/it_jaros/networkScanner/CliParser.java | 13++++++++-----
Asrc/main/java/com/it_jaros/networkScanner/ScanOptions.java | 5+++++
Asrc/main/java/com/it_jaros/networkScanner/ScanResult.java | 5+++++
Dsrc/main/java/com/it_jaros/networkScanner/ScanTarget.java | 3---
Msrc/main/java/com/it_jaros/networkScanner/Scanner.java | 71++++++++++++++++++++++++++++++++++++++++++-----------------------------
6 files changed, 72 insertions(+), 44 deletions(-)

diff --git a/src/main/java/com/it_jaros/networkScanner/App.java b/src/main/java/com/it_jaros/networkScanner/App.java @@ -6,10 +6,10 @@ public class App { public static void main(String[] args) { CliParser cliParser = new CliParser(); try { - ScanTarget target = cliParser.parseArgs(args); - Scanner scanner = new Scanner(); - List<Integer> openPorts = scanner.scanPorts(target); - printResults(target, openPorts); + ScanOptions target = cliParser.parseArgs(args); + Scanner scanner = new Scanner(target.openSocketLimit()); + List<ScanResult> openPorts = scanner.scanPorts(target); + printResults(openPorts); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); cliParser.usageAndExit(); @@ -18,9 +18,14 @@ public class App { } } - public static void printResults(ScanTarget address, List<Integer> openPorts) { - System.out.println("Target: " + address.address()); + public static void printResults(List<ScanResult> results) { + results.forEach(r -> printResult(r)); + } + + private static void printResult(ScanResult result) { + System.out.println("Target: " + result.target()); System.out.print("Ports:"); - openPorts.forEach((p) -> System.out.print(" " + p)); + result.openPorts().forEach((p) -> System.out.print(" " + p)); + System.out.print("\n"); } } diff --git a/src/main/java/com/it_jaros/networkScanner/CliParser.java b/src/main/java/com/it_jaros/networkScanner/CliParser.java @@ -1,19 +1,22 @@ package com.it_jaros.networkScanner; +import java.util.HashSet; +import java.util.Set; + public class CliParser { - public ScanTarget parseArgs(String[] args) { + public ScanOptions parseArgs(String[] args) { if (args.length < 1 || args[0].trim().equals("")) { throw new IllegalArgumentException("No argument given"); } - String target = null; + Set<String> targets = new HashSet<>(); int socketLimit = 1000; int delayInMillis = 0; for (int i = 0; i < args.length; i++) { final String currentArg = args[i]; if (!currentArg.startsWith("-")) { - target = currentArg; + targets.add(currentArg); continue; } @@ -37,9 +40,9 @@ public class CliParser { } System.out.printf( - "Scanning target '%s' with socketLimit(%s), delayInMillis(%s) \n", target, socketLimit, delayInMillis); + "Scanning targets '%s' with socketLimit(%s), delayInMillis(%s) \n", targets, socketLimit, delayInMillis); - return new ScanTarget(target, socketLimit, delayInMillis); + return new ScanOptions(targets.stream().toList(), socketLimit, delayInMillis); } public void usageAndExit() { diff --git a/src/main/java/com/it_jaros/networkScanner/ScanOptions.java b/src/main/java/com/it_jaros/networkScanner/ScanOptions.java @@ -0,0 +1,5 @@ +package com.it_jaros.networkScanner; + +import java.util.List; + +public record ScanOptions(List<String> targets, int openSocketLimit, int delayInMillis) {} diff --git a/src/main/java/com/it_jaros/networkScanner/ScanResult.java b/src/main/java/com/it_jaros/networkScanner/ScanResult.java @@ -0,0 +1,5 @@ +package com.it_jaros.networkScanner; + +import java.util.Queue; + +public record ScanResult(String target, Queue<Integer> openPorts) {} diff --git a/src/main/java/com/it_jaros/networkScanner/ScanTarget.java b/src/main/java/com/it_jaros/networkScanner/ScanTarget.java @@ -1,3 +0,0 @@ -package com.it_jaros.networkScanner; - -public record ScanTarget(String address, int openSocketLimit, int delayInMillis) {} diff --git a/src/main/java/com/it_jaros/networkScanner/Scanner.java b/src/main/java/com/it_jaros/networkScanner/Scanner.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.Socket; +import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -17,44 +18,56 @@ import java.util.concurrent.locks.LockSupport; public class Scanner { private Counter counter = new Counter(); + private Semaphore socketCap; + public Scanner(int socketLimit) { + socketCap = new Semaphore(socketLimit); + } + public Scanner() {} - public List<Integer> scanPorts(ScanTarget - target) { - return scanPorts(target.address(), target.openSocketLimit(), target.delayInMillis()); + public List<ScanResult> scanPorts(ScanOptions target) { + return scanPorts(target.targets(), target.delayInMillis()); } - public List<Integer> scanPorts(String address, int socketLimit, int delayInMillis) { - Queue<Integer> openPorts = new ConcurrentLinkedQueue<>(); - Semaphore socketCap = new Semaphore(socketLimit); + public List<ScanResult> scanPorts(List<String> targets, int delayInMillis) { + List<ScanResult> results = new ArrayList<>(); long delayInNanos = TimeUnit.MILLISECONDS.toNanos(Math.max(0, delayInMillis)); - AtomicLong nextStartNanos = new AtomicLong(System.nanoTime()); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { - for (int port = 1; port < 65536; port++) { - final int currentPort = port; - executor.submit(() -> { - if (delayInNanos > 0) { - long mySlot = nextStartNanos.getAndAdd(delayInNanos); - long wait = mySlot - System.nanoTime(); - if (wait > 0) LockSupport.parkNanos(wait); - } - socketCap.acquireUninterruptibly(); - counter.inc(); - try (Socket socket = new Socket()) { - socket.connect(new InetSocketAddress(address, currentPort)); - openPorts.add(currentPort); - } catch (ConnectException ignored) { - } catch (IOException e) { - System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage()); - } finally { - counter.dec(); - socketCap.release(); - } - }); + for (String target : targets) { + results.add(scanTargetAsync(target, delayInNanos, executor)); } } System.out.println("Peak concurrent connects: " + counter.max()); - return openPorts.stream().toList(); + return results; + } + + private ScanResult scanTargetAsync(String target, long delayInNanos, ExecutorService executor) { + AtomicLong nextStartNanos = new AtomicLong(System.nanoTime()); + Queue<Integer> openPorts = new ConcurrentLinkedQueue<>(); + for (int port = 1; port < 65536; port++) { + final int currentPort = port; + executor.submit(() -> { + if (delayInNanos > 0) { + long mySlot = nextStartNanos.getAndAdd(delayInNanos); + long wait = mySlot - System.nanoTime(); + if (wait > 0) + LockSupport.parkNanos(wait); + } + socketCap.acquireUninterruptibly(); + counter.inc(); + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress(target, currentPort)); + openPorts.add(currentPort); + } catch (ConnectException ignored) { + } catch (IOException e) { + System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage()); + } finally { + counter.dec(); + socketCap.release(); + } + }); + } + return new ScanResult(target, openPorts); } }