005 Project 5: Concurrent Port Scanner
005 Build a Concurrent Port Scanner
This CLI scans a host across a port range using a bounded worker pool.
ports range -> jobs channel -> workers dial tcp -> open ports channel -> sorted output
Full main.go
package main
import (
"flag"
"fmt"
"net"
"os"
"sort"
"sync"
"time"
)
func scan(host string, timeout time.Duration, jobs <-chan int, openPorts chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for p := range jobs {
addr := fmt.Sprintf("%s:%d", host, p)
conn, err := net.DialTimeout("tcp", addr, timeout)
if err == nil {
_ = conn.Close()
openPorts <- p
}
}
}
func main() {
host := flag.String("host", "127.0.0.1", "target host")
from := flag.Int("from", 1, "start port")
to := flag.Int("to", 1024, "end port")
workers := flag.Int("w", 200, "worker count")
timeout := flag.Duration("t", 300*time.Millisecond, "dial timeout")
flag.Parse()
if *from < 1 || *to > 65535 || *from > *to {
fmt.Fprintln(os.Stderr, "invalid port range")
os.Exit(2)
}
jobs := make(chan int, *workers)
openPorts := make(chan int, 1024)
var wg sync.WaitGroup
for i := 0; i < *workers; i++ {
wg.Add(1)
go scan(*host, *timeout, jobs, openPorts, &wg)
}
go func() {
for p := *from; p <= *to; p++ {
jobs <- p
}
close(jobs)
wg.Wait()
close(openPorts)
}()
var open []int
for p := range openPorts {
open = append(open, p)
}
sort.Ints(open)
fmt.Printf("open ports on %s:\n", *host)
for _, p := range open {
fmt.Println(p)
}
}Run
go run . -host scanme.nmap.org -from 1 -to 2000 -w 300 -t 200msWhat to Extend
- CIDR support for scanning multiple hosts.
- Banner grabbing for open ports.
- Rate limiting to avoid overwhelming targets.
Step-by-Step Explanation
- Model jobs, workers, and outputs explicitly.
- Bound concurrency using worker pools and buffered channels.
- Use
sync.WaitGroupfor lifecycle control. - Aggregate worker results in one place.
- Verify behavior under both normal and failure paths.
Code Anatomy
- Producer pushes jobs into a channel.
- Workers consume jobs and emit results.
- Aggregator merges results and prints summary.
Learning Goals
- Build leak-free goroutine patterns.
- Balance throughput and resource limits.
- Understand fan-out/fan-in architecture.