我在代码里定义了两个通道,分别用于生产端口和限制连接数,如果不限制连接数,容易被对方检测到或导致对方服务器不能正常运行。
1
2
3
4
5
|
// 生产端口 var port = make(chan int , 10) // 限制并发数 var connect = make(chan string, 5) |
可以使用net库的Dial函数做为socket客户端,需要注意的是要设置超时时间,因为若主机不存在,或目标端口是关闭的,往往需要花费数秒才返回错误,这样扫描大量端口时效率会极其低下。在go中可以使用net.Dialer结构体设置超时时间,然后在调用Dial方法:
1
2
|
d := net.Dialer{Timeout: time .Second} dial, err := d.Dial( "tcp" , target) |
只要err不等于nil,表示目标端口是对外开放的。
完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
package main import ( "fmt" "net" "sync" "time" ) var wg sync.WaitGroup func main() { var start, end int var address string fmt.Printf( "请输入目标IP:> " ) fmt.Scan(&address) fmt.Printf( "请输入起始端口:> " ) fmt.Scan(&start) fmt.Printf( "请输入结束端口:> " ) fmt.Scan(&end) wg.Add(end - start + 1) Run(address, start, end) wg.Wait() fmt.Println( "执行完毕" ) } // 生产端口 var port = make(chan int , 10) // 限制并发数 var connect = make(chan string, 5) func Run(address string, start, end int ) { go func() { for i := start; i <= end; i++ { port <- i } }() go func() { // 消费端口 for p := range port { // 往通道写入目标地址,超过限制并发数会阻塞 connect <- fmt.Sprintf( "%s:%d" , address, p) } }() go Connect() } func Connect() { // 并发请求 for target := range connect { // 设置超时时间 d := net.Dialer{Timeout: time .Second} dial, err := d.Dial( "tcp" , target) if err == nil { fmt.Printf( "%s 连接成功\n" , target) dial.Close() } else { fmt.Printf( "%s 连接失败\n" , target) } wg.Done() } } |
这里端口生产通道不是必须的,只是为了演示消费生产并发模型,当然这还是最简单的。
在Run函数里我没有关闭这两个通道,按官方的说法是gc会回收不使用的通道,如果要手动关闭,可以定义defer闭包进行close。
我本地运行结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
请输入目标IP:> 127.0.0.1 请输入起始端口:> 8080 请输入结束端口:> 8094 127.0.0.1:8080 连接成功 127.0.0.1:8081 连接成功 127.0.0.1:8082 连接成功 127.0.0.1:8083 连接成功 127.0.0.1:8084 连接成功 127.0.0.1:8085 连接成功 127.0.0.1:8086 连接成功 127.0.0.1:8087 连接成功 127.0.0.1:8088 连接成功 127.0.0.1:8089 连接成功 127.0.0.1:8090 连接成功 127.0.0.1:8091 连接成功 127.0.0.1:8092 连接成功 127.0.0.1:8093 连接失败 127.0.0.1:8094 连接失败 执行完毕 |
这个版本比较简陋,TCP连接过程也可以简化,后续再写另外一篇文章。因为最近在学rust语言,语法内容比较多,所以后面暂时发布编程相关的文章,提升一下语法熟练度。
以上就是go 实现简易端口扫描的示例的详细内容,更多关于go 实现端口扫描的资料请关注服务器之家其它相关文章!
原文链接:https://mp.weixin.qq.com/s/YXvJ2sm-VZgN2lXi8-xvFQ