前言
实验课的作业进行了一点小加工,可用于指定ip或ip段的端口扫描与存活主机探测。使用Go语言,调度协程实现高并发,简易高效。欢迎指正和讨论。
GitHub地址:https://github.com/ADobie/port-scanner
端口扫描功能的实现
使用Go语言net库中的Dial函数可以实现对指定ip指定端口发起tcp连接请求,使用Go语言net库中的Dial函数可以实现对指定ip指定端口发起tcp连接请求,需要传入的参数有协议类型,我们此处使用tcp,第二个参数形式为:”ip:port”。若未返回错误信息则连接建立,反之则无法连接。
线程控制
此处threads准确的说应为协程数,cores才是线程数。默认情况下,Go运行时会将线程数会被设置为机器 CPU 逻辑核心数。同时它内置的 runtime 包提供了 GOMAXPROCS(n int) 函数允许我们动态调整线程数。通过判断用户输入想要启用的线程数是否合理来确定要为此次扫描启用的线程数。
协程调度
Go 语言里创建一个协程非常简单,使用 go 关键词加上一个函数调用就可以了。Go 语言会启动一个新的协程,函数调用将成为这个协程的入口。
(1)这里是第一处启用协程的地方,它是扫描中的一个主协程,在检测到一个ip地址有主机存活后启用,继续进行tcp连接测试端口开放情况。
(2)这里是第二处启用协程的地方,它是上面协程的子协程,用于检测并输出端口开放情况。
超时判定
在发起tcp连接请求后,为了避免目标主机长时间无应答造成阻塞增大时间消耗,我们需要设定一个时长来作为请求超时的阈值。可根据不同网络环境设定不同的阈值以达到最好的效果。我这里设为了500ms。
主机存活探测
新建一个icmp.go文件来实现对目标ip的ping指令。通过向目标主机发送icmp数据包的形式,根据是否有应答来确定目标主机状态。
此功能的实现我引入了GitHub的一个开源第三方库:github.com/go-ping/ping。使用它可以轻松地发起ping,并返回是否连通。