A comprehensive, multi-threaded port scanner implementation using Java Sockets with both command-line and GUI interfaces.
Project Structure
PortScanner/ ├── src/ │ ├── com/portscanner/ │ │ ├── core/ │ │ ├── gui/ │ │ ├── models/ │ │ └── utils/ │ └── resources/ └── lib/
Core Implementation
Port Scanner Engine
package com.portscanner.core;
import com.portscanner.models.ScanResult;
import com.portscanner.models.ScanConfig;
import java.net.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class PortScanner {
private final ExecutorService executorService;
private final int timeout;
private final int maxThreads;
private final AtomicInteger completedScans;
private final AtomicInteger openPortsFound;
private volatile boolean isScanning;
private List<ScanResult> results;
public PortScanner() {
this(1000, 100); // Default timeout: 1s, max threads: 100
}
public PortScanner(int timeout, int maxThreads) {
this.timeout = timeout;
this.maxThreads = maxThreads;
this.executorService = Executors.newFixedThreadPool(maxThreads);
this.completedScans = new AtomicInteger(0);
this.openPortsFound = new AtomicInteger(0);
this.results = Collections.synchronizedList(new ArrayList<>());
}
public List<ScanResult> scan(ScanConfig config) {
return scan(config.getHost(), config.getStartPort(), config.getEndPort(),
config.getScanType(), config.isServiceDetection());
}
public List<ScanResult> scan(String host, int startPort, int endPort,
ScanConfig.ScanType scanType, boolean serviceDetection) {
resetScanner();
isScanning = true;
int totalPorts = endPort - startPort + 1;
List<Future<ScanResult>> futures = new ArrayList<>();
System.out.printf("Starting scan of %s, ports %d-%d (%d ports)%n",
host, startPort, endPort, totalPorts);
for (int port = startPort; port <= endPort; port++) {
if (!isScanning) {
break;
}
final int currentPort = port;
Future<ScanResult> future = executorService.submit(() -> {
if (!isScanning) {
return new ScanResult(currentPort, ScanResult.PortStatus.CANCELLED);
}
ScanResult result = scanPort(host, currentPort, scanType, serviceDetection);
completedScans.incrementAndGet();
if (result.getStatus() == ScanResult.PortStatus.OPEN) {
openPortsFound.incrementAndGet();
System.out.printf("Found open port: %d (%s)%n",
currentPort, result.getService());
}
return result;
});
futures.add(future);
}
// Wait for all tasks to complete and collect results
for (Future<ScanResult> future : futures) {
try {
ScanResult result = future.get();
if (result != null) {
results.add(result);
}
} catch (InterruptedException | ExecutionException e) {
System.err.println("Error scanning port: " + e.getMessage());
}
}
isScanning = false;
System.out.printf("Scan completed. Found %d open ports.%n", openPortsFound.get());
return getResults();
}
private ScanResult scanPort(String host, int port, ScanConfig.ScanType scanType,
boolean serviceDetection) {
ScanResult result = new ScanResult(port);
try {
long startTime = System.currentTimeMillis();
switch (scanType) {
case TCP_CONNECT:
result = tcpConnectScan(host, port);
break;
case TCP_SYN:
result = tcpSynScan(host, port);
break;
case UDP:
result = udpScan(host, port);
break;
}
long endTime = System.currentTimeMillis();
result.setResponseTime(endTime - startTime);
// Service detection
if (serviceDetection && result.getStatus() == ScanResult.PortStatus.OPEN) {
detectService(host, port, result);
}
} catch (Exception e) {
result.setStatus(ScanResult.PortStatus.ERROR);
result.setErrorMessage(e.getMessage());
}
return result;
}
private ScanResult tcpConnectScan(String host, int port) {
ScanResult result = new ScanResult(port);
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeout);
result.setStatus(ScanResult.PortStatus.OPEN);
result.setProtocol("TCP");
} catch (SocketTimeoutException e) {
result.setStatus(ScanResult.PortStatus.FILTERED);
} catch (ConnectException e) {
if (e.getMessage().contains("Connection refused")) {
result.setStatus(ScanResult.PortStatus.CLOSED);
} else {
result.setStatus(ScanResult.PortStatus.ERROR);
result.setErrorMessage(e.getMessage());
}
} catch (IOException e) {
result.setStatus(ScanResult.PortStatus.ERROR);
result.setErrorMessage(e.getMessage());
}
return result;
}
private ScanResult tcpSynScan(String host, int port) {
// SYN scan requires raw socket access, which Java doesn't provide natively
// This is a simplified implementation using TCP connect
// For real SYN scanning, you'd need JNI or a native library
ScanResult result = new ScanResult(port);
result.setStatus(ScanResult.PortStatus.NOT_IMPLEMENTED);
result.setErrorMessage("SYN scan requires raw socket access (not available in pure Java)");
return result;
}
private ScanResult udpScan(String host, int port) {
ScanResult result = new ScanResult(port);
try (DatagramSocket socket = new DatagramSocket()) {
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] sendData = "SCAN".getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, address, port);
socket.send(sendPacket);
// Try to receive response
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
result.setStatus(ScanResult.PortStatus.OPEN);
result.setProtocol("UDP");
} catch (SocketTimeoutException e) {
// UDP ports often don't respond even when open
result.setStatus(ScanResult.PortStatus.OPEN_FILTERED);
} catch (IOException e) {
if (e.getMessage().contains("Connection refused")) {
result.setStatus(ScanResult.PortStatus.CLOSED);
} else {
result.setStatus(ScanResult.PortStatus.ERROR);
result.setErrorMessage(e.getMessage());
}
}
return result;
}
private void detectService(String host, int port, ScanResult result) {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeout);
// Try to read banner
socket.setSoTimeout(2000);
InputStream input = socket.getInputStream();
OutputStream output = socket.getOutputStream();
String service = guessServiceByPort(port);
result.setService(service);
// Attempt banner grabbing for common services
if (port == 21 || port == 22 || port == 25 || port == 80 || port == 110) {
String banner = grabBanner(input, output, port);
if (banner != null && !banner.isEmpty()) {
result.setBanner(banner);
result.setService(service + " - " + banner.split("\n")[0]);
}
}
} catch (Exception e) {
// Banner grabbing failed, but port is still open
result.setService(guessServiceByPort(port));
}
}
private String grabBanner(InputStream input, OutputStream output, int port) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
switch (port) {
case 21: // FTP
return reader.readLine();
case 22: // SSH
// SSH sends banner immediately upon connection
StringBuilder sshBanner = new StringBuilder();
while (reader.ready()) {
sshBanner.append(reader.readLine()).append("\n");
}
return sshBanner.toString().trim();
case 25: // SMTP
return reader.readLine();
case 80: // HTTP
PrintWriter writer = new PrintWriter(output, true);
writer.println("HEAD / HTTP/1.0\r\n");
writer.println("User-Agent: PortScanner/1.0\r\n");
writer.println("\r\n");
StringBuilder httpResponse = new StringBuilder();
String line;
while ((line = reader.readLine()) != null && !line.isEmpty()) {
httpResponse.append(line).append("\n");
}
return httpResponse.toString();
case 110: // POP3
return reader.readLine();
}
} catch (Exception e) {
// Banner grabbing failed silently
}
return null;
}
private String guessServiceByPort(int port) {
// Common port to service mapping
switch (port) {
case 21: return "FTP";
case 22: return "SSH";
case 23: return "Telnet";
case 25: return "SMTP";
case 53: return "DNS";
case 80: return "HTTP";
case 110: return "POP3";
case 143: return "IMAP";
case 443: return "HTTPS";
case 993: return "IMAPS";
case 995: return "POP3S";
case 1433: return "MSSQL";
case 1521: return "Oracle";
case 3306: return "MySQL";
case 3389: return "RDP";
case 5432: return "PostgreSQL";
case 5900: return "VNC";
case 6379: return "Redis";
case 27017: return "MongoDB";
default:
if (port <= 1024) return "Well-known";
else if (port <= 49151) return "Registered";
else return "Dynamic/Private";
}
}
public void stopScan() {
isScanning = false;
executorService.shutdownNow();
System.out.println("Scan stopped by user.");
}
public boolean isScanning() {
return isScanning;
}
public int getCompletedScans() {
return completedScans.get();
}
public int getOpenPortsFound() {
return openPortsFound.get();
}
public List<ScanResult> getResults() {
return new ArrayList<>(results);
}
public List<ScanResult> getOpenPorts() {
return results.stream()
.filter(r -> r.getStatus() == ScanResult.PortStatus.OPEN)
.sorted(Comparator.comparingInt(ScanResult::getPort))
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
private void resetScanner() {
completedScans.set(0);
openPortsFound.set(0);
results.clear();
isScanning = false;
}
public void shutdown() {
if (!executorService.isShutdown()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
Data Models
package com.portscanner.models;
import java.util.Objects;
public class ScanResult {
private final int port;
private PortStatus status;
private String service;
private String banner;
private String protocol;
private long responseTime;
private String errorMessage;
public enum PortStatus {
OPEN("Open"),
CLOSED("Closed"),
FILTERED("Filtered"),
OPEN_FILTERED("Open|Filtered"),
ERROR("Error"),
CANCELLED("Cancelled"),
NOT_IMPLEMENTED("Not Implemented");
private final String displayName;
PortStatus(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
@Override
public String toString() {
return displayName;
}
}
public ScanResult(int port) {
this.port = port;
this.status = PortStatus.CLOSED;
}
// Getters and setters
public int getPort() { return port; }
public PortStatus getStatus() { return status; }
public void setStatus(PortStatus status) { this.status = status; }
public String getService() { return service; }
public void setService(String service) { this.service = service; }
public String getBanner() { return banner; }
public void setBanner(String banner) { this.banner = banner; }
public String getProtocol() { return protocol; }
public void setProtocol(String protocol) { this.protocol = protocol; }
public long getResponseTime() { return responseTime; }
public void setResponseTime(long responseTime) { this.responseTime = responseTime; }
public String getErrorMessage() { return errorMessage; }
public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScanResult that = (ScanResult) o;
return port == that.port;
}
@Override
public int hashCode() {
return Objects.hash(port);
}
@Override
public String toString() {
return String.format("Port %d: %s (%s) - %dms",
port, status.getDisplayName(), service, responseTime);
}
}
package com.portscanner.models;
public class ScanConfig {
private String host;
private int startPort;
private int endPort;
private ScanType scanType;
private int timeout;
private int maxThreads;
private boolean serviceDetection;
private boolean bannerGrabbing;
public enum ScanType {
TCP_CONNECT("TCP Connect"),
TCP_SYN("TCP SYN"),
UDP("UDP");
private final String displayName;
ScanType(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
@Override
public String toString() {
return displayName;
}
}
public ScanConfig() {
this.host = "localhost";
this.startPort = 1;
this.endPort = 1000;
this.scanType = ScanType.TCP_CONNECT;
this.timeout = 1000;
this.maxThreads = 100;
this.serviceDetection = true;
this.bannerGrabbing = false;
}
// Getters and setters
public String getHost() { return host; }
public void setHost(String host) { this.host = host; }
public int getStartPort() { return startPort; }
public void setStartPort(int startPort) { this.startPort = startPort; }
public int getEndPort() { return endPort; }
public void setEndPort(int endPort) { this.endPort = endPort; }
public ScanType getScanType() { return scanType; }
public void setScanType(ScanType scanType) { this.scanType = scanType; }
public int getTimeout() { return timeout; }
public void setTimeout(int timeout) { this.timeout = timeout; }
public int getMaxThreads() { return maxThreads; }
public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; }
public boolean isServiceDetection() { return serviceDetection; }
public void setServiceDetection(boolean serviceDetection) { this.serviceDetection = serviceDetection; }
public boolean isBannerGrabbing() { return bannerGrabbing; }
public void setBannerGrabbing(boolean bannerGrabbing) { this.bannerGrabbing = bannerGrabbing; }
public void validate() throws IllegalArgumentException {
if (host == null || host.trim().isEmpty()) {
throw new IllegalArgumentException("Host cannot be empty");
}
if (startPort < 1 || startPort > 65535) {
throw new IllegalArgumentException("Start port must be between 1 and 65535");
}
if (endPort < 1 || endPort > 65535) {
throw new IllegalArgumentException("End port must be between 1 and 65535");
}
if (startPort > endPort) {
throw new IllegalArgumentException("Start port cannot be greater than end port");
}
if (timeout < 100) {
throw new IllegalArgumentException("Timeout must be at least 100ms");
}
if (maxThreads < 1 || maxThreads > 1000) {
throw new IllegalArgumentException("Max threads must be between 1 and 1000");
}
}
@Override
public String toString() {
return String.format("ScanConfig{host='%s', ports=%d-%d, type=%s, threads=%d}",
host, startPort, endPort, scanType, maxThreads);
}
}
Command Line Interface
package com.portscanner;
import com.portscanner.core.PortScanner;
import com.portscanner.models.ScanConfig;
import com.portscanner.models.ScanResult;
import java.util.List;
import java.util.Scanner;
public class CommandLineScanner {
private final PortScanner scanner;
private final Scanner inputScanner;
public CommandLineScanner() {
this.scanner = new PortScanner();
this.inputScanner = new Scanner(System.in);
}
public void start() {
System.out.println("=== Java Port Scanner ===");
System.out.println();
ScanConfig config = getScanConfigFromUser();
try {
config.validate();
performScan(config);
} catch (IllegalArgumentException e) {
System.err.println("Configuration error: " + e.getMessage());
} finally {
scanner.shutdown();
inputScanner.close();
}
}
private ScanConfig getScanConfigFromUser() {
ScanConfig config = new ScanConfig();
System.out.print("Enter target host (default: localhost): ");
String host = inputScanner.nextLine().trim();
if (!host.isEmpty()) {
config.setHost(host);
}
System.out.print("Enter start port (default: 1): ");
String startPortStr = inputScanner.nextLine().trim();
if (!startPortStr.isEmpty()) {
config.setStartPort(Integer.parseInt(startPortStr));
}
System.out.print("Enter end port (default: 1000): ");
String endPortStr = inputScanner.nextLine().trim();
if (!endPortStr.isEmpty()) {
config.setEndPort(Integer.parseInt(endPortStr));
}
System.out.print("Enable service detection? (y/n, default: y): ");
String serviceDetect = inputScanner.nextLine().trim();
if (serviceDetect.equalsIgnoreCase("n")) {
config.setServiceDetection(false);
}
System.out.print("Enter timeout in ms (default: 1000): ");
String timeoutStr = inputScanner.nextLine().trim();
if (!timeoutStr.isEmpty()) {
config.setTimeout(Integer.parseInt(timeoutStr));
}
System.out.print("Enter max threads (default: 100): ");
String threadsStr = inputScanner.nextLine().trim();
if (!threadsStr.isEmpty()) {
config.setMaxThreads(Integer.parseInt(threadsStr));
}
return config;
}
private void performScan(ScanConfig config) {
System.out.println();
System.out.println("Starting scan with configuration:");
System.out.println(" Target: " + config.getHost());
System.out.println(" Ports: " + config.getStartPort() + " - " + config.getEndPort());
System.out.println(" Timeout: " + config.getTimeout() + "ms");
System.out.println(" Threads: " + config.getMaxThreads());
System.out.println(" Service Detection: " + (config.isServiceDetection() ? "Yes" : "No"));
System.out.println();
long startTime = System.currentTimeMillis();
// Start a separate thread for progress updates
Thread progressThread = new Thread(() -> {
while (scanner.isScanning()) {
try {
Thread.sleep(1000);
int completed = scanner.getCompletedScans();
int total = config.getEndPort() - config.getStartPort() + 1;
int percent = (int) ((completed / (double) total) * 100);
System.out.printf("\rProgress: %d/%d ports (%d%%) - Found: %d open",
completed, total, percent, scanner.getOpenPortsFound());
} catch (InterruptedException e) {
break;
}
}
});
progressThread.setDaemon(true);
progressThread.start();
// Perform the scan
List<ScanResult> results = scanner.scan(config);
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println();
System.out.println();
System.out.println("=== Scan Results ===");
System.out.println("Scan duration: " + duration + "ms");
System.out.println("Total ports scanned: " + results.size());
System.out.println("Open ports found: " + scanner.getOpenPortsFound());
System.out.println();
// Display open ports
List<ScanResult> openPorts = scanner.getOpenPorts();
if (openPorts.isEmpty()) {
System.out.println("No open ports found.");
} else {
System.out.println("Open ports:");
System.out.println("Port\tService\tProtocol\tResponse Time");
System.out.println("----\t-------\t--------\t-------------");
for (ScanResult result : openPorts) {
System.out.printf("%d\t%s\t%s\t\t%dms%n",
result.getPort(),
result.getService() != null ? result.getService() : "Unknown",
result.getProtocol() != null ? result.getProtocol() : "TCP",
result.getResponseTime());
if (result.getBanner() != null && !result.getBanner().isEmpty()) {
System.out.println(" Banner: " + result.getBanner().replace("\n", " "));
}
}
}
// Save results option
System.out.println();
System.out.print("Save results to file? (y/n): ");
String save = inputScanner.nextLine().trim();
if (save.equalsIgnoreCase("y")) {
saveResultsToFile(results, config);
}
}
private void saveResultsToFile(List<ScanResult> results, ScanConfig config) {
String filename = "portscan_" + config.getHost().replace(".", "_") + "_" +
System.currentTimeMillis() + ".txt";
try (java.io.PrintWriter writer = new java.io.PrintWriter(filename)) {
writer.println("Port Scan Results");
writer.println("=================");
writer.println("Target: " + config.getHost());
writer.println("Port Range: " + config.getStartPort() + " - " + config.getEndPort());
writer.println("Scan Type: " + config.getScanType());
writer.println("Date: " + new java.util.Date());
writer.println();
writer.println("Open Ports:");
writer.println("-----------");
for (ScanResult result : scanner.getOpenPorts()) {
writer.printf("%d\t%s\t%s\t%dms%n",
result.getPort(),
result.getService() != null ? result.getService() : "Unknown",
result.getProtocol() != null ? result.getProtocol() : "TCP",
result.getResponseTime());
}
System.out.println("Results saved to: " + filename);
} catch (java.io.IOException e) {
System.err.println("Error saving results: " + e.getMessage());
}
}
public static void main(String[] args) {
new CommandLineScanner().start();
}
}
Graphical User Interface
package com.portscanner.gui;
import com.portscanner.core.PortScanner;
import com.portscanner.models.ScanConfig;
import com.portscanner.models.ScanResult;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class PortScannerGUI extends JFrame {
private final PortScanner scanner;
private JTextField hostField;
private JSpinner startPortSpinner;
private JSpinner endPortSpinner;
private JComboBox<String> scanTypeComboBox;
private JCheckBox serviceDetectionCheckBox;
private JSpinner timeoutSpinner;
private JSpinner threadsSpinner;
private JProgressBar progressBar;
private JButton scanButton;
private JButton stopButton;
private JTable resultsTable;
private DefaultTableModel tableModel;
private JTextArea logArea;
private SwingWorker<List<ScanResult>, ScanResult> scanWorker;
public PortScannerGUI() {
this.scanner = new PortScanner();
initializeGUI();
}
private void initializeGUI() {
setTitle("Java Port Scanner");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(900, 700);
setLocationRelativeTo(null);
// Create main panel
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
// Configuration panel
mainPanel.add(createConfigPanel(), BorderLayout.NORTH);
// Results panel
mainPanel.add(createResultsPanel(), BorderLayout.CENTER);
// Log panel
mainPanel.add(createLogPanel(), BorderLayout.SOUTH);
add(mainPanel);
}
private JPanel createConfigPanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Scan Configuration"));
// Host
panel.add(new JLabel("Target Host:"));
hostField = new JTextField("localhost");
panel.add(hostField);
// Port range
panel.add(new JLabel("Start Port:"));
startPortSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 65535, 1));
panel.add(startPortSpinner);
panel.add(new JLabel("End Port:"));
endPortSpinner = new JSpinner(new SpinnerNumberModel(1000, 1, 65535, 1));
panel.add(endPortSpinner);
// Scan type
panel.add(new JLabel("Scan Type:"));
scanTypeComboBox = new JComboBox<>(new String[]{"TCP Connect", "TCP SYN", "UDP"});
panel.add(scanTypeComboBox);
// Service detection
panel.add(new JLabel("Service Detection:"));
serviceDetectionCheckBox = new JCheckBox("", true);
panel.add(serviceDetectionCheckBox);
// Timeout
panel.add(new JLabel("Timeout (ms):"));
timeoutSpinner = new JSpinner(new SpinnerNumberModel(1000, 100, 10000, 100));
panel.add(timeoutSpinner);
// Threads
panel.add(new JLabel("Max Threads:"));
threadsSpinner = new JSpinner(new SpinnerNumberModel(100, 1, 500, 10));
panel.add(threadsSpinner);
// Buttons
JPanel buttonPanel = new JPanel(new FlowLayout());
scanButton = new JButton("Start Scan");
stopButton = new JButton("Stop Scan");
stopButton.setEnabled(false);
scanButton.addActionListener(this::startScan);
stopButton.addActionListener(this::stopScan);
buttonPanel.add(scanButton);
buttonPanel.add(stopButton);
JPanel container = new JPanel(new BorderLayout());
container.add(panel, BorderLayout.CENTER);
container.add(buttonPanel, BorderLayout.SOUTH);
return container;
}
private JPanel createResultsPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder("Scan Results"));
// Table
String[] columnNames = {"Port", "Status", "Service", "Protocol", "Response Time", "Banner"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
resultsTable = new JTable(tableModel);
resultsTable.setAutoCreateRowSorter(true);
JScrollPane scrollPane = new JScrollPane(resultsTable);
// Progress bar
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
panel.add(progressBar, BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createLogPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder("Scan Log"));
panel.setPreferredSize(new Dimension(0, 150));
logArea = new JTextArea();
logArea.setEditable(false);
logArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane scrollPane = new JScrollPane(logArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private void startScan(ActionEvent e) {
ScanConfig config = createConfigFromUI();
try {
config.validate();
startScanWorker(config);
} catch (IllegalArgumentException ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(),
"Configuration Error", JOptionPane.ERROR_MESSAGE);
}
}
private ScanConfig createConfigFromUI() {
ScanConfig config = new ScanConfig();
config.setHost(hostField.getText().trim());
config.setStartPort((Integer) startPortSpinner.getValue());
config.setEndPort((Integer) endPortSpinner.getValue());
config.setScanType(ScanConfig.ScanType.TCP_CONNECT); // Default
config.setServiceDetection(serviceDetectionCheckBox.isSelected());
config.setTimeout((Integer) timeoutSpinner.getValue());
config.setMaxThreads((Integer) threadsSpinner.getValue());
return config;
}
private void startScanWorker(ScanConfig config) {
scanWorker = new SwingWorker<List<ScanResult>, ScanResult>() {
@Override
protected List<ScanResult> doInBackground() throws Exception {
log("Starting scan: " + config);
return scanner.scan(config);
}
@Override
protected void process(List<ScanResult> chunks) {
for (ScanResult result : chunks) {
if (result.getStatus() == ScanResult.PortStatus.OPEN) {
addResultToTable(result);
log("Open port found: " + result.getPort() + " (" + result.getService() + ")");
}
}
// Update progress
int total = config.getEndPort() - config.getStartPort() + 1;
int completed = scanner.getCompletedScans();
int percent = (int) ((completed / (double) total) * 100);
progressBar.setValue(percent);
progressBar.setString(String.format("%d/%d ports (%d%%) - %d open",
completed, total, percent, scanner.getOpenPortsFound()));
}
@Override
protected void done() {
scanButton.setEnabled(true);
stopButton.setEnabled(false);
progressBar.setValue(100);
try {
List<ScanResult> results = get();
log("Scan completed. Found " + scanner.getOpenPortsFound() + " open ports.");
// Show summary
JOptionPane.showMessageDialog(PortScannerGUI.this,
String.format("Scan completed!\n\n" +
"Target: %s\n" +
"Ports scanned: %d\n" +
"Open ports found: %d",
config.getHost(), results.size(), scanner.getOpenPortsFound()),
"Scan Complete", JOptionPane.INFORMATION_MESSAGE);
} catch (InterruptedException | ExecutionException ex) {
log("Scan failed: " + ex.getMessage());
JOptionPane.showMessageDialog(PortScannerGUI.this,
"Scan failed: " + ex.getMessage(),
"Scan Error", JOptionPane.ERROR_MESSAGE);
}
}
};
// Clear previous results
tableModel.setRowCount(0);
logArea.setText("");
// Update UI state
scanButton.setEnabled(false);
stopButton.setEnabled(true);
progressBar.setValue(0);
scanWorker.execute();
}
private void stopScan(ActionEvent e) {
if (scanWorker != null && !scanWorker.isDone()) {
scanner.stopScan();
scanWorker.cancel(true);
log("Scan stopped by user.");
}
scanButton.setEnabled(true);
stopButton.setEnabled(false);
}
private void addResultToTable(ScanResult result) {
Object[] row = {
result.getPort(),
result.getStatus().getDisplayName(),
result.getService(),
result.getProtocol(),
result.getResponseTime() + "ms",
result.getBanner()
};
tableModel.addRow(row);
}
private void log(String message) {
SwingUtilities.invokeLater(() -> {
logArea.append("[" + java.time.LocalTime.now() + "] " + message + "\n");
logArea.setCaretPosition(logArea.getDocument().getLength());
});
}
@Override
public void dispose() {
scanner.shutdown();
super.dispose();
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel());
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(() -> {
new PortScannerGUI().setVisible(true);
});
}
}
Advanced Features
Service Detection Database
package com.portscanner.utils;
import java.util.HashMap;
import java.util.Map;
public class ServiceDatabase {
private static final Map<Integer, String> PORT_SERVICES = new HashMap<>();
static {
// Well-known ports
PORT_SERVICES.put(7, "Echo");
PORT_SERVICES.put(20, "FTP Data");
PORT_SERVICES.put(21, "FTP Control");
PORT_SERVICES.put(22, "SSH");
PORT_SERVICES.put(23, "Telnet");
PORT_SERVICES.put(25, "SMTP");
PORT_SERVICES.put(53, "DNS");
PORT_SERVICES.put(67, "DHCP Server");
PORT_SERVICES.put(68, "DHCP Client");
PORT_SERVICES.put(69, "TFTP");
PORT_SERVICES.put(80, "HTTP");
PORT_SERVICES.put(110, "POP3");
PORT_SERVICES.put(123, "NTP");
PORT_SERVICES.put(143, "IMAP");
PORT_SERVICES.put(161, "SNMP");
PORT_SERVICES.put(162, "SNMP Trap");
PORT_SERVICES.put(443, "HTTPS");
PORT_SERVICES.put(465, "SMTPS");
PORT_SERVICES.put(587, "SMTP Submission");
PORT_SERVICES.put(993, "IMAPS");
PORT_SERVICES.put(995, "POP3S");
// Database services
PORT_SERVICES.put(1433, "MSSQL");
PORT_SERVICES.put(1521, "Oracle");
PORT_SERVICES.put(3306, "MySQL");
PORT_SERVICES.put(5432, "PostgreSQL");
PORT_SERVICES.put(27017, "MongoDB");
PORT_SERVICES.put(6379, "Redis");
// Remote access
PORT_SERVICES.put(3389, "RDP");
PORT_SERVICES.put(5900, "VNC");
// File sharing
PORT_SERVICES.put(2049, "NFS");
PORT_SERVICES.put(445, "SMB");
// Messaging
PORT_SERVICES.put(5222, "XMPP");
PORT_SERVICES.put(5269, "XMPP Server");
}
public static String getService(int port) {
return PORT_SERVICES.getOrDefault(port, "Unknown");
}
public static boolean isWellKnownPort(int port) {
return port <= 1024;
}
public static boolean isRegisteredPort(int port) {
return port > 1024 && port <= 49151;
}
public static boolean isDynamicPort(int port) {
return port > 49151;
}
}
Usage Examples
Basic Scanning
// Simple port scan
PortScanner scanner = new PortScanner();
List<ScanResult> results = scanner.scan("localhost", 1, 1000,
ScanConfig.ScanType.TCP_CONNECT, true);
// Print open ports
for (ScanResult result : scanner.getOpenPorts()) {
System.out.println(result);
}
Advanced Configuration
// Custom configuration
ScanConfig config = new ScanConfig();
config.setHost("192.168.1.1");
config.setStartPort(20);
config.setEndPort(443);
config.setTimeout(2000);
config.setMaxThreads(50);
config.setServiceDetection(true);
PortScanner scanner = new PortScanner(config.getTimeout(), config.getMaxThreads());
List<ScanResult> results = scanner.scan(config);
Key Features
- Multi-threaded Scanning - Fast parallel port scanning
- Multiple Scan Types - TCP Connect, SYN (theoretical), UDP
- Service Detection - Automatic service identification
- Banner Grabbing - Retrieve service banners
- Progress Tracking - Real-time progress updates
- Results Export - Save scan results to file
- User-friendly Interfaces - Both CLI and GUI versions
- Configurable Parameters - Timeout, threads, port ranges
Security Notes
- Always ensure you have permission to scan target systems
- Port scanning may be considered intrusive or illegal in some contexts
- Use responsibly and ethically
- Some networks may have intrusion detection systems that will detect port scans
This port scanner provides a comprehensive tool for network analysis and security testing with professional-grade features and user interfaces.