TCP Port Scanner & Service Prober
Build a TCP port scanner written entirely in Bash, with no nmap or netcat. It takes a list of hosts and a range of ports, checks which ports are open using Bash's built-in /dev/tcp connections, runs many checks in parallel with a limit on how many at once, and tries to identify the service behind each open port by reading the first message it sends (its banner), for example an SSH or SMTP greeting. Results come out as a sorted table, or as CSV or JSON for other tools. Only scan machines you own or have permission to test, such as your own computer or a lab virtual machine. You'll learn Bash network redirections, timeouts, parallel jobs with xargs, input parsing and structured output.
- Estimate
- ~11.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
/dev/tcp · timeout · xargs
Project roadmap
- 01
Check a single port
~1.5hWrite a function check_port HOST PORT that tries to open a connection with exec 3<>/dev/tcp/$HOST/$PORT inside timeout 1 bash -c '...', so closed or filtered ports don't hang. It prints HOST PORT open, or returns non-zero when the port is closed. Start the script with set -euo pipefail. Done when: checking port 22 on a machine running SSH says open, and an unused port returns quickly as closed.
- 02
Parse hosts and ports
~2hAccept -H for hosts (a comma-separated list, a range like 192.168.1.10-20, or a file with -f) and -p for ports (a list like 22,80,443 and ranges like 8000-8100). Expand them into one host:port pair per line. Reject invalid ports (outside 1 to 65535) and malformed ranges with a clear message and exit code 2. Done when: -H 127.0.0.1 -p 20-25,80 prints the 7 expected pairs.
- 03
Scan in parallel with a limit
~2hPipe the host:port pairs into xargs -P N, which runs check_port for each (export the function with export -f). Add a -j option for the number of parallel checks (default 50, maximum 500) and a -t option for the timeout in seconds. Print only open ports. Done when: scanning 1000 ports on localhost finishes in a few seconds, not minutes.
- 04
Grab service banners
~2.5hFor each open port, read the first line the service sends with read -t 2 from the /dev/tcp connection. Some services (like HTTP) wait for the client to speak first, so if nothing arrives, send HEAD / HTTP/1.0 followed by a blank line and read the Server header. Strip non-printable characters and cut banners to 80 characters. Done when: SSH shows its version string and a local web server shows its Server header.
- 05
Output a table, CSV or JSON
~2hCollect results into a temporary file and print them sorted by host (in IP order, using sort -V) then port, as an aligned table with host, port, state and banner. Add -o csv and -o json options. In JSON output, escape quotes and backslashes in banners correctly. Done when: all three formats print correctly for the same scan, and the JSON passes a validator such as jq .
- 06
Handle edge cases and document
~1.5hHandle Ctrl+C with a trap that stops the workers and removes temporary files, an empty port list, and a host that can't be resolved. Run shellcheck and fix every warning. In the README, explain the usage with examples and state clearly that it should only be used on systems you're allowed to scan. Done when: shellcheck is clean, and Ctrl+C leaves no temporary files behind.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack