Home  >  Article  >  Backend Development  >  Teach you step by step how to build a simple TCP port scanner using Go language

Teach you step by step how to build a simple TCP port scanner using Go language

Go语言进阶学习
Go语言进阶学习forward
2023-07-24 15:33:201625browse

#The essence of TCP scanning

When we use TCP to connect, we need to knowthe other party’s machineip:port

Normal handshake

ConnectionIf successful, the process is as follows.

Teach you step by step how to build a simple TCP port scanner using Go language

Connection failed

If there is normal, there will befailed, ifIf the connected party is closed, the process is as follows.

Teach you step by step how to build a simple TCP port scanner using Go language

If there is a firewall

There is another possibility,The port is open, but is blocked by the firewall. The process is as follows.

Teach you step by step how to build a simple TCP port scanner using Go language

Code

##After you understand the essence, you can start coding.

In Go, we usually use net.Dial for TCP connection.

Justtwo situations

  • Success: Return conn.

  • Failed:err != nil.

Normal version

Relatively speaking, at the beginning, we may not be too bold. Write the prototype first, without considering performance.

Code

package main


import (
    "fmt"
    "net"
)


func main() {
    var ip = "192.168.43.34"
    for i := 21; i <= 120; i++ {
        var address = fmt.Sprintf("%s:%d", ip, i)
        conn, err := net.Dial("tcp", address)
        if err != nil {
            fmt.Println(address, "是关闭的")
            continue
        }
        conn.Close()
        fmt.Println(address, "打开")
  }
}

Execution Result

Teach you step by step how to build a simple TCP port scanner using Go language

#But this process is very slow.

因为net.Dial如果连接的是未开放的端口,一个端口可能就是20s+,所以,我们为什么学习多线程懂了把!!!

多线程版

上述是通过循环去一个个连接ip:port的,那我们就知道了,在一个个连接的位置,让多个人去干就好了。

所以,多线程如下。

代码

package main


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


func main() {


    var begin =time.Now()
    //wg
    var wg sync.WaitGroup
    //ip
    var ip = "192.168.99.112"
    //var ip = "192.168.43.34"
    //循环
    for j := 21; j <= 65535; j++ {
        //添加wg
        wg.Add(1)
        go func(i int) {
            //释放wg
            defer wg.Done()
            var address = fmt.Sprintf("%s:%d", ip, i)
            //conn, err := net.DialTimeout("tcp", address, time.Second*10)
            conn, err := net.Dial("tcp", address)
            if err != nil {
                //fmt.Println(address, "是关闭的", err)
                return
            }
            conn.Close()
            fmt.Println(address, "打开")
        }(j)
}
    //等待wg
    wg.Wait()
    var elapseTime = time.Now().Sub(begin)
    fmt.Println("耗时:", elapseTime)
}

执行结果

Teach you step by step how to build a simple TCP port scanner using Go language

In fact, 6W multiple threads are opened at the same time to scan each ip:port.

So the time it takes the longest thread to end is the time the program ends.

It feels ok, I scanned more than 60,000 ports in 20 seconds! ! !

Thread pool version

Above we are simple and crude The method creates a coroutine for each ip:port.

Although in Go, theoretically it is no problem to open hundreds of thousands of coroutines, there is still some pressureof.

所以我们应该采用一种相对节约的方式进行精简代码,一般采用线程池方式。


本次使用的线程池包:gohive

地址:https://github.com/loveleshsharma/gohive

简单介绍

Teach you step by step how to build a simple TCP port scanner using Go language

代码

package main


//线程池方式
import (
    "fmt"
    "github.com/loveleshsharma/gohive"
    "net"
    "sync"
    "time"
)


//wg
var wg sync.WaitGroup


//地址管道,100容量
var addressChan = make(chan string, 100)


//工人
func worker() {
    //函数结束释放连接
    defer wg.Done()
    for {
        address, ok := <-addressChan
        if !ok {
            break
        }
        //fmt.Println("address:", address)
        conn, err := net.Dial("tcp", address)
        //conn, err := net.DialTimeout("tcp", address, 10)
        if err != nil {
            //fmt.Println("close:", address, err)
            continue
        }
        conn.Close()
        fmt.Println("open:", address)
}
}
func main() {
    var begin = time.Now()
    //ip
    var ip = "192.168.99.112"
    //线程池大小
    var pool_size = 70000
    var pool = gohive.NewFixedSizePool(pool_size)


    //拼接ip:端口
    //启动一个线程,用于生成ip:port,并且存放到地址管道种
    go func() {
        for port := 1; port <= 65535; port++ {
            var address = fmt.Sprintf("%s:%d", ip, port)
            //将address添加到地址管道
            //fmt.Println("<-:",address)
            addressChan <- address
        }
        //发送完关闭 addressChan 管道
        close(addressChan)
}()
    //启动pool_size工人,处理addressChan种的每个地址
    for work := 0; work < pool_size; work++ {
        wg.Add(1)
        pool.Submit(worker)
}
    //等待结束
    wg.Wait()
    //计算时间
    var elapseTime = time.Now().Sub(begin)
    fmt.Println("耗时:", elapseTime)
}

执行结果

Teach you step by step how to build a simple TCP port scanner using Go language

我设置的线程池大小是7w个,所以也是一下子开启6w多个协程的,但是我们已经可以进行线程大小约束了。


Suppose there is such a request now. There are 100 ip, and each one needs to be scanned. ipOpen port, if you use a simple and crude way to open a thread.

That is100 65535=6552300, more than 600 w threads still consume a lot of memory, and the system may crash if the thread pool method is used.

Control the thread pool to 500,000, maybe the situation will be much better.

But one thing is that in Go, the thread pool usually needs to be used in conjunction with chan. It may be necessary Not a bad foundation.

Summary

This article is more of a fun article, let’s get to know it Fun stuff.

In fact, you can also connect through net.DialTimeoutip:port , this timeout can be set, for example, if it times out 5s, it will be determined that the port is not open.

I won’t give an example here.

We mainly use three methods to implement functions.

  • Normal version, no concurrency, very slow.

  • Multiple coroutines version, concurrency, high performance, but too many coroutines may crash.

  • Coroutine Pool version, concurrency, high performance, controllable number of coroutines.

Normally, if the foundation is OK, it is more RecommendedUse the coroutine pool Way.

The above is the detailed content of Teach you step by step how to build a simple TCP port scanner using Go language. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:Go语言进阶学习. If there is any infringement, please contact admin@php.cn delete