支持并发的TCP全连接端口扫描器

0x00 扫描器并发的实现

使用sync.WaitGroup与channel配 合实现的并发方式,代码片断如下所示

func RunTask(tasks []map[string]int) {
	wg := &sync.WaitGroup{}

	// 创建一个buffer为vars.threadNum * 2的channel
	taskChan := make(chan map[string]int, vars.ThreadNum*2)

	// 创建vars.ThreadNum个协程
	for i := 0; i < vars.ThreadNum; i++ {
		go Scan(taskChan, wg)
	}

	// 生产者,不断地往taskChan channel发送数据,直接channel阻塞
	for _, task := range tasks {
		wg.Add(1)
		taskChan <- task
	}

	close(taskChan)
	wg.Wait()
}

func Scan(taskChan chan map[string]int, wg *sync.WaitGroup) {
	// 每个协程都从channel中读取数据后开始扫描并入库
	for task := range taskChan {
		for ip, port := range task {
			err := SaveResult(Connect(ip, port))
			_ = err
			wg.Done()
		}
	}
}

RunTask函数不断地将扫描任务发送到taskChan中,Scan会不断 地消费taskChan中的数据。

0x01生成扫描任务列表

生成扫描任务列表:
首先解析出需要扫描的IP与端口的切片, 然后将需要扫描的IP与端口列表放入一个[]map[string]int中, map的key为IP地址,value为端口,[]map[string]int表示所有需 要扫描的IP与端口对的切片。
具体代码实现:

func GenerateTask(ipList []net.IP, ports []int) ([]map[string]int, int) {
	tasks := make([]map[string]int, 0)

	for _, ip := range ipList {
		for _, port := range ports {
			ipPort := map[string]int{ip.String(): port}
			tasks = append(tasks, ipPort)
		}
	}

	return tasks, len(tasks)
}

0x02 输出结果

展示扫描结果,直接通过sync.map的Range方法枚举出所有结 果并展示出来,代码如下所示:

func PrintResult() {
	vars.Result.Range(func(key, value interface{}) bool {
		fmt.Printf("ip:%v\n", key)
		fmt.Printf("ports: %v\n", value)
		fmt.Println(strings.Repeat("-", 100))
		return true
	})
}

运行结果:

go run main.go 45.33.32.156,114.114.114.114 22,23,53,80-100
ip:114.114.114.114
ports: [53]
----------------------------------------------------------------------------------------------------
ip:45.33.32.156
ports: [22 80]
----------------------------------------------------------------------------------------------------

也是比全连接加上了并发

posted @ 2023-04-13 11:17  MeetA  阅读(50)  评论(0)    收藏  举报