How can I safely implement a progress bar in a concurrent Go port scanner?

1 week ago 13
ARTICLE AD BOX

I wrote an open port scanner in Go. For local adresses scans are instant. However, when I scan an external address it takes a bit longer, and I want to see the progress. I tried to implement a progress bar, however due to concurrency the output is garbled.

Is there a safe way to implement a progress bar without getting garbled output?

Code:

package main import ( "flag" "fmt" "log" "net" "strconv" "sync" "time" "sync/atomic" ) func scanhost(host string, start int, step int, end int, wg *sync.WaitGroup, openPorts *int32) { defer wg.Done() for i := start; i <= end; i += step { address := host + ":" + strconv.Itoa(i) conn, err := net.DialTimeout("tcp", address, 500*time.Millisecond) if err != nil { continue } fmt.Printf("\x1b[0;42mOPEN\x1b[0m %v\n", address) atomic.AddInt32(openPorts, 1) conn.Close() } } func GetOutboundIP() net.IP { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { log.Fatal(err) } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP } func main() { hostFlag := flag.String("host", "", "Target host to scan (default: auto-detect outbound IP)") workersFlag := flag.Int("workers", 20, "Number of concurrent workers") startPortFlag := flag.Int("start", 1, "Starting port") endPortFlag := flag.Int("end", 65535, "Ending port") flag.Parse() host := *hostFlag if host == "" { host = GetOutboundIP().String() fmt.Printf("No host specified. Using local IP address: %v\n", host) } else { fmt.Printf("Scanning host: %v\n", host) } var wg sync.WaitGroup workers := *workersFlag var openPorts int32 = 0 for i := 0; i < workers; i++ { wg.Add(1) go scanhost(host, *startPortFlag+i, workers, *endPortFlag, &wg, &openPorts) } wg.Wait() fmt.Printf("\nScan complete. Total open ports found: %d\n", openPorts) }
Read Entire Article