如何使用Golang编写一个TCP扫描器

298 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 6 月更文挑战」的第 11 天,点击查看活动详情

可以通过使用goroutine和channel来实现并发扫描TCP端口。它通过遍历指定的端口范围,对每个端口启动一个goroutine进行连接尝试,如果连接成功,则将该端口发送到结果通道中。

worker函数是每个goroutine的执行函数,它尝试与指定的主机和端口建立TCP连接。如果连接成功,表示该端口是开放的,将该端口发送到结果通道中。

scanPorts函数负责启动多个worker goroutine,等待它们的执行完成,并将结果整理为排序后的开放端口列表。

main函数中,我们指定要扫描的主机IP地址、起始端口和结束端口,并调用scanPorts函数进行扫描。最后,输出开放端口的列表。

具体实现代买示例:

package main

import (
	"fmt"
	"net"
	"sort"
	"sync"
	"time"
)

func worker(host string, port int, results chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()

	address := fmt.Sprintf("%s:%d", host, port)
	conn, err := net.DialTimeout("tcp", address, 1*time.Second)
	if err == nil {
		conn.Close()
		results <- port
	}
}

func scanPorts(host string, startPort, endPort int) []int {
	var openPorts []int
	var wg sync.WaitGroup
	results := make(chan int)

	for port := startPort; port <= endPort; port++ {
		wg.Add(1)
		go worker(host, port, results, &wg)
	}

	go func() {
		wg.Wait()
		close(results)
	}()

	for port := range results {
		openPorts = append(openPorts, port)
	}

	sort.Ints(openPorts)
	return openPorts
}

func main() {
	host := "127.0.0.1"
	startPort := 1
	endPort := 65535

	openPorts := scanPorts(host, startPort, endPort)

	fmt.Printf("Open ports on %s:\n", host)
	for _, port := range openPorts {
		fmt.Println(port)
	}
}

当分析上述的TCP端口扫描器代码时,我们可以关注以下细节:

  1. worker函数:
  • worker函数是每个goroutine的执行函数,负责尝试与指定主机和端口建立TCP连接。
  • 使用net.DialTimeout函数进行连接尝试,并设置1秒的超时时间,以避免长时间等待。
  • 如果连接成功,表示端口是开放的,将该端口发送到结果通道results中。
  1. scanPorts函数: scanPorts函数用于管理并发的端口扫描。
  • 创建一个用于存储开放端口的切片openPorts
  • 创建一个结果通道results用于接收每个worker的扫描结果。
  • 使用sync.WaitGroup来跟踪所有worker goroutine的完成情况。
  • 使用循环创建goroutine,并调用worker函数进行端口扫描。
  • 启动一个额外的goroutine来等待所有worker的完成,并在完成后关闭结果通道。
  • results通道中接收开放端口,并将它们添加到openPorts切片中。
  • 最后,对openPorts切片进行排序,并返回排序后的开放端口列表。
  1. main函数:
  • main函数中,指定要扫描的主机IP地址、起始端口和结束端口。
  • 调用scanPorts函数进行端口扫描,并将结果存储在openPorts变量中。
  • 使用fmt.Printf和循环输出开放端口列表。

这个实现利用goroutine和channel的并发特性,可以同时扫描多个端口,提高扫描效率。通过使用sync.WaitGroup等待所有的worker goroutine完成,确保在收集结果之前等待所有的扫描操作完成。