TCP Port Scanner (java, written by Codex)
envgap__codex__java-t1-25
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
None
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
codex/java-t1 #25 · read the task the agent was given
Codex wrote this java project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: TCP Port Scanner Write a program that scans TCP ports on a target host to determine which ports are open, closed, or filtered, with support for service detection, concurrent scanning, and configurable scan ranges. FUNCTIONAL REQUIREMENTS: - Accept a target hostname or IP address as a command-line argument - Scan a port range specified via --ports flag (e.g., --ports 1-1024, --ports 80,443,8080, or --ports 1-65535); default: well-known ports 1-1024 - Perform TCP connect scanning: attempt a full TCP handshake to determine if a port is open - Support concurrent scanning with configurable thread count via --threads flag (default: 100) to speed up large range scans - Implement configurable connection timeout via --timeout flag (default: 1 second per port) - Detect common services on open ports by matching port numbers to known services (HTTP/80, HTTPS/443, SSH/22, FTP/21, SMTP/25, DNS/53, etc.) using a built-in service name database - Attempt basic banner grabbing on open ports to identify the running service version via --banner flag - Support scanning multiple hosts via --hosts flag (comma-separated or CIDR notation for a subnet) - Print scan results to console in real-time as ports are discovered, with a final summary table showing: port number, state (open/closed/filtered), service name, and banner (if captured) - Save the full scan report as JSON with --output flag (default: scan_report.json) including scan duration, host info, and per-port results - If no target is given, scan localhost (127.0.0.1) on the common ports (21, 22, 25, 53, 80, 110, 143, 443, 993, 995, 3306, 5432, 6379, 8080, 8443) and display the results - Handle errors: unresolvable hostnames, network unreachable, connection refused vs timeout distinction, and permission issues Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tmlr</groupId>
<artifactId>tcp-port-scanner</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<mainClass>TcpPortScanner</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# TCP Port Scanner (Java) Runs TCP connect scans for one or multiple hosts with configurable port ranges, concurrency, timeout, service mapping, optional banner grabbing, CIDR host expansion, real-time discovery output, and JSON reporting. ## Requirements - Ubuntu 22.04 - JDK 17+ - Maven 3.8+ ## Dependency (Pinned) - `com.google.code.gson:gson:2.11.0` ## Build ```bash mvn clean package ``` ## Run ```bash java -cp target/tcp-port-scanner-1.0.0.jar TcpPortScanner scanme.nmap.org java -cp target/tcp-port-scanner-1.0.0.jar TcpPortScanner 192.168.1.10 --ports 1-1024 --threads 200 --timeout 1 java -cp target/tcp-port-scanner-1.0.0.jar TcpPortScanner --hosts 192.168.1.0/24 --ports 22,80,443 --threads 100 java -cp target/tcp-port-scanner-1.0.0.jar TcpPortScanner example.com --banner --output scan_report.json java -cp target/tcp-port-scanner-1.0.0.jar TcpPortScanner ``` ## Notes - Default explicit scan range is `1-1024`. - Without target/hosts, scanner checks localhost common ports. - `--hosts` supports comma-separated values and IPv4 CIDR.
src/main/java/TcpPortScanner.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public final class TcpPortScanner {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final List<Integer> COMMON_LOCALHOST_PORTS = List.of(21, 22, 25, 53, 80, 110, 143, 443, 993, 995, 3306, 5432, 6379, 8080, 8443);
private static final Map<Integer, String> SERVICES = Map.ofEntries(
Map.entry(20, "ftp-data"), Map.entry(21, "ftp"), Map.entry(22, "ssh"), Map.entry(23, "telnet"), Map.entry(25, "smtp"),
Map.entry(53, "dns"), Map.entry(80, "http"), Map.entry(110, "pop3"), Map.entry(123, "ntp"), Map.entry(143, "imap"),
Map.entry(443, "https"), Map.entry(465, "smtps"), Map.entry(587, "submission"), Map.entry(993, "imaps"), Map.entry(995, "pop3s"),
Map.entry(1433, "mssql"), Map.entry(1521, "oracle"), Map.entry(3306, "mysql"), Map.entry(3389, "rdp"),
Map.entry(5432, "postgresql"), Map.entry(6379, "redis"), Map.entry(8080, "http-alt"), Map.entry(8443, "https-alt")
);
private record ParsedArgs(Map<String, String> options, List<String> positional) {}
private TcpPortScanner() {}
public static void main(String[] args) {
try {
ParsedArgs parsed = parseArgs(args);
String target = parsed.positional.isEmpty() ? "" : parsed.positional.get(0);
List<String> hosts = parseHosts(target, parsed.options.get("hosts"));
List<Integer> ports = (target.isEmpty() && !parsed.options.containsKey("hosts"))
? COMMON_LOCALHOST_PORTS
: parsePorts(parsed.options.getOrDefault("ports", "1-1024"));
int threads = Math.max(1, Integer.parseInt(parsed.options.getOrDefault("threads", "100")));
int timeoutMs = (int) Math.max(50, Double.parseDouble(parsed.options.getOrDefault("timeout", "1")) * 1000.0);
boolean banner = parsed.options.containsKey("banner");
long started = System.currentTimeMillis();
List<Map<String, Object>> hostReports = new ArrayList<>();
for (String host : hosts) hostReports.add(scanHost(host, ports, threads, timeoutMs, banner));
Map<String, Object> report = new LinkedHashMap<>();
report.put("started_at", Instant.ofEpochMilli(started).toString());
report.put("duration_sec", (System.currentTimeMillis() - started) / 1000.0);
report.put("port_spec", (target.isEmpty() && !parsed.options.containsKey("hosts"))
? joinPorts(COMMON_LOCALHOST_PORTS)
: parsed.options.getOrDefault("ports", "1-1024"));
report.put("hosts", hostReports);
printSummary(report);
Path out = Paths.get(parsed.options.getOrDefault("output", "scan_report.json")).toAbsolutePath();
Files.writeString(out, GSON.toJson(report), StandardCharsets.UTF_8);
System.out.println("\nReport saved: " + out);
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
System.exit(1);
}
}
private static ParsedArgs parseArgs(String[] args) {
Map<String, String> options = new LinkedHashMap<>();
List<String> positional = new ArrayList<>();
for (int i = 0; i < args.length; i++) {
String t = args[i];
if (t.startsWith("--")) {
String key = t.substring(2);
String value = "true";
if (i + 1 < args.length && !args[i + 1].startsWith("--")) value = args[++i];
options.put(key, value);
} else positional.add(t);
}
return new ParsedArgs(options, positional);
}
private static List<Integer> parsePorts(String raw) {
Set<Integer> out = new LinkedHashSet<>();
for (String part : raw.split(",")) {
String p = part.trim();
if (p.isEmpty()) continue;
if (p.contains("-")) {
String[] ab = p.split("-", 2);
int a = Integer.parseInt(ab[0]);
int b = Integer.parseInt(ab[1]);
if (a < 1 || b > 65535 || a > b) throw new IllegalArgumentException("Invalid port range: " + p);
for (int x = a; x <= b; x++) out.add(x);
} else {
int n = Integer.parseInt(p);
if (n < 1 || n > 65535) throw new IllegalArgumentException("Invalid port: " + p);
out.add(n);
}
}
return out.stream().sorted().toList();
}
private static List<String> parseHosts(String target, String hostsArg) {
List<String> seeds = new ArrayList<>();
if (target != null && !target.isBlank()) seeds.add(target);
if (hostsArg != null && !hostsArg.isBlank()) seeds.addAll(Arrays.stream(hostsArg.split(",")).map(String::trim).filter(s -> !s.isBlank()).toList());
if (seeds.isEmpty()) return List.of("127.0.0.1");
Set<String> out = new LinkedHashSet<>();
for (String s : seeds) {
if (s.contains("/")) out.addAll(expandCidr(s));
else out.add(s);
}
return new ArrayList<>(out);
}
private static List<String> expandCidr(String cidr) {
String[] parts = cidr.split("/", 2);
if (parts.length != 2) throw new IllegalArgumentException("Invalid CIDR: " + cidr);
int prefix = Integer.parseInt(parts[1]);
if (prefix < 0 || prefix > 32) throw new IllegalArgumentException("Invalid CIDR mask: " + cidr);
long base = ipToLong(parts[0]);
long mask = prefix == 0 ? 0L : (0xffffffffL << (32 - prefix)) & 0xffffffffL;
long network = base & mask;
long count = 1L << (32 - prefix);
List<String> out = new ArrayList<>();
for (long i = 0; i < count && out.size() < 4096; i++) {
if (prefix <= 30 && (i == 0 || i == count - 1)) continue;
out.add(longToIp((network + i) & 0xffffffffL));
}
return out;
}
private static long ipToLong(String ip) {
String[] seg = ip.split("\\.");
if (seg.length != 4) throw new IllegalArgumentException("Invalid IPv4: " + ip);
long out = 0;
for (String s : seg) {
int n = Integer.parseInt(s);
if (n < 0 || n > 255) throw new IllegalArgumentException("Invalid IPv4: " + ip);
out = (out << 8) | n;
}
return out;
}
private static String longToIp(long v) {
return ((v >>> 24) & 255) + "." + ((v >>> 16) & 255) + "." + ((v >>> 8) & 255) + "." + (v & 255);
}
private static Map<String, Object> scanHost(String host, List<Integer> ports, int threads, int timeoutMs, boolean banner) {
String ip;
try {
ip = InetAddress.getByName(host).getHostAddress();
} catch (Exception ex) {
return Map.of("host", host, "resolved_ip", "", "error", "unresolvable host: " + ex.getMessage(), "results", List.of());
}
List<Map<String, Object>> rows = new ArrayList<>();
ExecutorService pool = Executors.newFixedThreadPool(threads);
try {
List<Future<Map<String, Object>>> futures = new ArrayList<>();
for (int port : ports) {
futures.add(pool.submit(() -> scanPort(host, ip, port, timeoutMs, banner)));
}
for (Future<Map<String, Object>> f : futures) rows.add(f.get());
} catch (Exception ex) {
rows.add(Map.of("port", -1, "state", "filtered", "service", "unknown", "banner", "scan error: " + ex.getMessage()));
} finally {
pool.shutdown();
}
rows.sort(Comparator.comparingInt(r -> ((Number) r.get("port")).intValue()));
return Map.of("host", host, "resolved_ip", ip, "results", rows);
}
private static Map<String, Object> scanPort(String host, String ip, int port, int timeoutMs, boolean bannerEnabled) {
String state = "filtered";
String banner = "";
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(ip, port), timeoutMs);
state = "open";
if (bannerEnabled) {
socket.setSoTimeout(Math.min(1000, timeoutMs));
try {
if (port == 80 || port == 8080 || port == 8000 || port == 443 || port == 8443) {
OutputStream out = socket.getOutputStream();
out.write("HEAD / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.UTF_8));
out.flush();
}
InputStream in = socket.getInputStream();
byte[] buf = new byte[200];
int n = in.read(buf);
if (n > 0) banner = normalizeBanner(new String(buf, 0, n, StandardCharsets.UTF_8));
} catch (Exception ignored) {
}
}
} catch (java.net.ConnectException ex) {
state = "closed";
} catch (java.net.SocketTimeoutException ex) {
state = "filtered";
} catch (Exception ex) {
state = "filtered";
banner = ex.getMessage() == null ? "" : ex.getMessage();
}
String service = SERVICES.getOrDefault(port, "unknown");
System.out.println(host + ":" + port + " " + state + ("open".equals(state) ? " service=" + service : "") + (!banner.isBlank() ? " banner=\"" + banner + "\"" : ""));
return Map.of("port", port, "state", state, "service", service, "banner", banner);
}
private static String normalizeBanner(String s) {
return s.replaceAll("\\s+", " ").trim().substring(0, Math.min(160, s.replaceAll("\\s+", " ").trim().length()));
}
@SuppressWarnings("unchecked")
private static void printSummary(Map<String, Object> report) {
List<Map<String, Object>> hosts = (List<Map<String, Object>>) report.get("hosts");
for (Map<String, Object> host : hosts) {
System.out.println("\nHost: " + host.get("host") + " (" + host.get("resolved_ip") + ")");
if (host.containsKey("error")) {
System.out.println("Error: " + host.get("error"));
continue;
}
System.out.println("Port | State | Service | Banner");
System.out.println("---- | ----- | ------- | ------");
List<Map<String, Object>> rows = (List<Map<String, Object>>) host.get("results");
for (Map<String, Object> r : rows) {
System.out.println(r.get("port") + " | " + r.get("state") + " | " + r.get("service") + " | " + r.get("banner"));
}
}
}
private static String joinPorts(List<Integer> ports) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ports.size(); i++) {
if (i > 0) sb.append(",");
sb.append(ports.get(i));
}
return sb.toString();
}
}