同时扫描多个端口时结果不可靠

背景:


我正在阅读 Black Hat Go,作者展示了一个使用 goroutines 1的简单端口扫描器:


package main


import (

    "fmt"

    "net"

)


func main() {

    for i := 1; i <= 9000; i++ {

        go func(j int) {

            address := fmt.Sprintf("127.0.0.1:%d", j)

            conn, err := net.Dial("tcp", address)

            if err != nil {

                return

            }

            conn.Close()

            fmt.Printf("%d open\n", j)

        }(i)

    }

}

然后他提到以下内容:


同时扫描过多的主机或端口可能会导致网络或系统限制影响您的结果。


为了测试它,我在端口 8000 和 8500 上启动了 2 个 php 服务器2并运行上面的代码来扫描我的本地端口。


每次它给我的结果不一致。有时它会检测到两个打开的端口,有时它不会。


问题:


不一致的结果是否是由于 TCP 的某些限制?


有没有办法计算可以并行扫描的最佳端口数,以使结果保持正确?


编辑:


我似乎错过了上面代码中的等待组。


除此之外,是否还有其他任何东西(操作系统限制或协议限制)可以防止在大范围内进行并发端口扫描?


慕沐林林
浏览 216回答 1
1回答

红糖糍粑

一旦 for 循环完成,您的 main 函数将退出。如果 main 函数退出,所有由它启动的 goroutines 也会退出。您需要等待 goroutine 完成。例如,这可以通过 来实现sync.WaitGroup。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "net"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; // This will help you to keep track of the goroutines&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for i := 1; i <= 9000; i++ {&nbsp; &nbsp; &nbsp; &nbsp; // Increment the counter for each goroutine you start.&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(j int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Make sure the wait group counter is decremented when the goroutine exits&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; address := fmt.Sprintf("127.0.0.1:%d", j)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn, err := net.DialTimeout("tcp", address, 2 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%d open\n", j)&nbsp; &nbsp; &nbsp; &nbsp; }(i)&nbsp; &nbsp; }&nbsp; &nbsp; // Wait for all goroutines to finish before exiting main&nbsp; &nbsp; wg.Wait()}编辑:对我来说,由于缺少文件描述符,代码原样不起作用。以下功能可靠地工作。它需要更好的错误处理,但确实有效package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "log"&nbsp; &nbsp; "net"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")var minPort = 1var maxPort = 65535var timeout = 2 * time.Secondconst parallel = 50func main(){&nbsp; &nbsp; fmt.Println("portscan called")&nbsp; &nbsp; // Create a buffered channel with a size equal to the number of goroutines&nbsp; &nbsp; ctrl := make(chan int, parallel)&nbsp; &nbsp; // Keep track of the currently active goroutines&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for p := 1; p <= parallel; p++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; // Start a goroutine...&nbsp; &nbsp; &nbsp; &nbsp; go func(p int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Printf("Starting goroutine %d", p)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ...listening to the control channel.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // For every value this goroutine reads from the&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // channel...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i := range ctrl {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; address := fmt.Sprintf("127.0.0.1:%d", i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ...try to conncet to the port.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn, err := net.DialTimeout("tcp", address, timeout)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Printf("[%3d]: %5d open", p, i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TBD: ERROR HANDLING!!!&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If the channel is closed, this goroutine is done.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Printf("[%3d]: Exiting", p)&nbsp; &nbsp; &nbsp; &nbsp; }(p)&nbsp; &nbsp; }&nbsp; &nbsp; // Fill the control channel with values.&nbsp; &nbsp; // If the channel is full, the write operation&nbsp; &nbsp; // to the channel will block until one of the goroutines&nbsp; &nbsp; // reads a value from it.&nbsp; &nbsp; for i := minPort; i <= maxPort; i++ {&nbsp; &nbsp; &nbsp; &nbsp; ctrl <- i&nbsp; &nbsp; }&nbsp; &nbsp; // We have sent all values, so the channel can be closed.&nbsp; &nbsp; // The goroutines will finish their current connection attempt,&nbsp; &nbsp; // notice that the channel is closed and will in turn call wg.Done().&nbsp; &nbsp; close(ctrl)&nbsp; &nbsp; // When all goroutines have announced that they are done, we can exit.&nbsp; &nbsp; wg.Wait()}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go