通过 Go 实现 TCP 端口扫描

TCP-Scanner

连接网络设备时,一般都会在网络设备端选取 0-65535 之间的一个端口进行连接,端口扫描是指:检查网络设备上 0-65535 号端口哪些端口是开启状态。

如果黑客扫描到某网络设备的 80 端口是开启状态,那么很有可能是 web 服务,此时黑客会使用一些手段攻击 web 服务器,这样一来,端口扫描会增加服务器的安全负担,因此一般网络都会阻止端口扫描。

当然端口扫描对于防御性渗透测试也非常有用。我们可以扫描自己的系统来确定哪些服务暴露给了网络,这样我们就能有针对性的对系统的配置进行检查。

实现原理

该项目中,我们通过 Go 去实现一个 TCP 端口的扫描。

怎么进行扫描呢?思路就是根据目标地址对每个端口进行 TCP 连接,如果连接成功的话,就说明这个端口是开启的。

func Dial(network, address string)(Conn, error)

我们主要通过 net.Dial 方法来去建立 TCP 连接。

并发实现

显然,如果直接对所有端口循环地进行连接建立,这样的处理是非常慢的,所以比较好的实现是我们对每个端口都开启协程去进行实现。

如果我们对每个端口都进行并发请求,可能使服务资源耗尽,而且大量的并发输出可能导致结果混乱。

因此,我们可以通过并发池来去完成并发的操作,分配额定的 worker 去执行任务,这样能够避免同时的大量并发操作。

思路是这样的:

  • 1、定义 woker 函数,分别用两个 channel 表示要处理的任务和结果。
  • 2、在 main 中,对要处理的任务进行遍历,然后通过 worker 函数去进行处理。
  • 3、最后通过 close 关闭 channel,然后等待 worker 函数执行完毕。

完整代码

package main

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

func worker(ports chan int, res chan int) {
	for p := range ports {
		address := fmt.Sprintf("scanme.nmap.org:%d", p)
		conn, err := net.Dial("tcp", address)
		if err != nil {
			res <- 0
			continue
		}
		conn.Close()
		res <- p
	}
}

var openports []int

func main() {
	start := time.Now()

	ports := make(chan int, 100)
	results := make(chan int)

	for i := 0; i < cap(ports); i++ {
		go worker(ports, results)
	}

	go func() {
		for i := 1; i < 1024; i++ {
			ports <- i
		}
	}()

	for i := 1; i < 1024; i++ {
		port := <-results
		if port != 0 {
			openports = append(openports, port)
		}
	}

	close(ports)
	close(results)

	sort.Ints(openports)

	for _, port := range openports {
		fmt.Printf("%d open\n", port)
	}

	elapsed := time.Since(start)
	fmt.Printf("Took %s", elapsed)
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值