summaryrefslogtreecommitdiff
path: root/src/main/java/com/it_jaros/networkScanner
diff options
context:
space:
mode:
authorGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-01-22 21:05:16 +0100
committerGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-09 09:59:28 +0200
commitf42cfda65a035a8708baf36b9c212d8b8e33516a (patch)
tree12659c02f6500989cc4f5d839070f5e691005b4a /src/main/java/com/it_jaros/networkScanner
parentb41d3762f3db9f459221861883c10fe528443ee0 (diff)
Working version with semaphore counter and rate limiter
Diffstat (limited to 'src/main/java/com/it_jaros/networkScanner')
-rw-r--r--src/main/java/com/it_jaros/networkScanner/App.java41
-rw-r--r--src/main/java/com/it_jaros/networkScanner/Counter.java25
-rw-r--r--src/main/java/com/it_jaros/networkScanner/FdCounter.java37
-rw-r--r--src/main/java/com/it_jaros/networkScanner/Scanner.java50
4 files changed, 153 insertions, 0 deletions
diff --git a/src/main/java/com/it_jaros/networkScanner/App.java b/src/main/java/com/it_jaros/networkScanner/App.java
new file mode 100644
index 0000000..5d52065
--- /dev/null
+++ b/src/main/java/com/it_jaros/networkScanner/App.java
@@ -0,0 +1,41 @@
+package com.it_jaros.networkScanner;
+
+import java.util.List;
+
+public class App {
+ public static void main(String[] args) {
+ Scanner scanner = new Scanner();
+ if (args.length < 1 || args[0] == "") {
+ usageAndExit();
+ }
+ String target = args[0];
+ System.out.printf(
+ "Scanning host=%s \n",
+ target);
+
+ try (FdCounter fd = new FdCounter()) {
+ fd.start(20); // sample every 20ms
+ List<Integer> openPorts = scanner.scanPorts(target, 10000);
+ printPorts(target, openPorts);
+ System.out.println("FD limit: " + fd.maxFds());
+ System.out.println("Peak open FDs during scan: " + fd.peakOpenFds());
+ }
+ }
+
+ public static void printPorts(String address, List<Integer> openPorts) {
+ System.out.println("Address:" + address);
+ openPorts.forEach((p) -> System.out.println("Open port: " + p));
+ }
+
+ private static void usageAndExit() {
+ System.err.println("""
+ Usage:
+ java -jar scanner.jar <host>
+
+ Examples:
+ java -jar scanner.jar localhost
+ java -jar scanner.jar fd00::1
+ """);
+ System.exit(1);
+ }
+}
diff --git a/src/main/java/com/it_jaros/networkScanner/Counter.java b/src/main/java/com/it_jaros/networkScanner/Counter.java
new file mode 100644
index 0000000..a4baec0
--- /dev/null
+++ b/src/main/java/com/it_jaros/networkScanner/Counter.java
@@ -0,0 +1,25 @@
+package com.it_jaros.networkScanner;
+
+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/networkScanner/FdCounter.java b/src/main/java/com/it_jaros/networkScanner/FdCounter.java
new file mode 100644
index 0000000..05eb9a4
--- /dev/null
+++ b/src/main/java/com/it_jaros/networkScanner/FdCounter.java
@@ -0,0 +1,37 @@
+package com.it_jaros.networkScanner;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.sun.management.UnixOperatingSystemMXBean;
+
+public final class FdCounter implements AutoCloseable {
+ private final UnixOperatingSystemMXBean os =
+ (UnixOperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
+ private final ScheduledExecutorService ses =
+ Executors.newSingleThreadScheduledExecutor(Thread.ofPlatform().daemon().factory());
+ private final AtomicLong peak = new AtomicLong(0);
+
+ public void start(long everyMillis) {
+ ses.scheduleAtFixedRate(() -> {
+ long now = os.getOpenFileDescriptorCount();
+ peak.accumulateAndGet(now, Math::max);
+ }, 0, everyMillis, TimeUnit.MILLISECONDS);
+ }
+
+ public long peakOpenFds() {
+ return peak.get();
+ }
+
+ public long maxFds() {
+ return os.getMaxFileDescriptorCount();
+ }
+
+ @Override public void close() {
+ ses.shutdownNow();
+ }
+}
+
diff --git a/src/main/java/com/it_jaros/networkScanner/Scanner.java b/src/main/java/com/it_jaros/networkScanner/Scanner.java
new file mode 100644
index 0000000..1f71f56
--- /dev/null
+++ b/src/main/java/com/it_jaros/networkScanner/Scanner.java
@@ -0,0 +1,50 @@
+package com.it_jaros.networkScanner;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+
+public class Scanner {
+
+ private Counter counter = new Counter();
+ private final int socketLimitDefault = 1024;
+
+ public Scanner() {}
+
+ public List<Integer> scanPorts(String address) {
+ return scanPorts(address, socketLimitDefault);
+ }
+
+ public List<Integer> scanPorts(String address, int socketLimit) {
+ Queue<Integer> openPorts = new ConcurrentLinkedQueue<>();
+ Semaphore socketCap = new Semaphore(socketLimit);
+ try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
+ for (int port = 1; port < 65536; port++) {
+ final int currentPort = port;
+ executor.submit(() -> {
+ 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();
+ }
+ });
+ }
+ }
+ System.out.println("Peak concurrent connects: " + counter.max());
+ return openPorts.stream().toList();
+ }
+}