• 技术文章 >后端开发 >Golang

    一文详解Go如何实现端口扫描器

    藏色散人藏色散人2023-04-14 16:53:31转载100

    本篇文章给大家带来了关于Go的相关知识,其中主要跟大家介绍Go怎么实现端口扫描器,有代码示例,感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。

    利用 GO 批量扫描服务器端口

    1、端口扫描器 V1 - 基本操作

    package mainimport (
        "fmt"
        "net"
        "time"
        "unsafe")func main() {
        tcpScan("127.0.0.1", 1, 65535)}func tcpScan(ip string, portStart int, portEnd int) {
        start := time.Now()
    
        // 参数校验
        isok := verifyParam(ip, portStart, portEnd)
        if isok == false {
            fmt.Printf("[Exit]\n")
        }
    
        for i := portStart; i <= portEnd; i++ {
            address := fmt.Sprintf("%s:%d", ip, i)
            conn, err := net.Dial("tcp", address)
            if err != nil {
                fmt.Printf("[info] %s Close \n", address)
                continue
            }
            conn.Close()
            fmt.Printf("[info] %s Open \n", address)
        }
    
        cost := time.Since(start)
        fmt.Printf("[tcpScan] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool {
        netip := net.ParseIP(ip)
        if netip == nil {
            fmt.Println("[Error] ip type is must net.ip")
            return false
        }
        fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
    
        if portStart < 1 || portEnd > 65535 {
            fmt.Println("[Error] port is must in the range of 1~65535")
            return false
        }
        fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
    
        return true}

    2、端口扫描器 V2 - 使用 goroutine

    package mainimport (
        "fmt"
        "net"
        "sync"
        "time"
        "unsafe")func main() {
        tcpScanByGoroutine("127.0.0.1", 1, 65535)}func tcpScanByGoroutine(ip string, portStart int, portEnd int) {
        start := time.Now()
        // 参数校验
        isok := verifyParam(ip, portStart, portEnd)
        if isok == false {
            fmt.Printf("[Exit]\n")
        }
    
        var wg sync.WaitGroup    for i := portStart; i <= portEnd; i++ {
            wg.Add(1)
    
            go func(j int) {
                defer wg.Done()
                address := fmt.Sprintf("%s:%d", ip, j)
                conn, err := net.Dial("tcp", address)
                if err != nil {
                    fmt.Printf("[info] %s Close \n", address)
                    return
                }
                conn.Close()
                fmt.Printf("[info] %s Open \n", address)
            }(i)
        }
        wg.Wait()
    
        cost := time.Since(start)
        fmt.Printf("[tcpScanByGoroutine] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool {
        netip := net.ParseIP(ip)
        if netip == nil {
            fmt.Println("[Error] ip type is must net.ip")
            return false
        }
        fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
    
        if portStart < 1 || portEnd > 65535 {
            fmt.Println("[Error] port is must in the range of 1~65535")
            return false
        }
        fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
    
        return true}

    3、端口扫描器 V3 - 利用 Goroutine + Channel

    package mainimport (
        "fmt"
        "net"
        "sync"
        "time"
        "unsafe")func main() {
        tcpScanByGoroutineWithChannel("127.0.0.1", 1, 65535)}func handleWorker(ip string, ports chan int, wg *sync.WaitGroup) {
        for p := range ports {
            address := fmt.Sprintf("%s:%d", ip, p)
            conn, err := net.Dial("tcp", address)
            if err != nil {
                fmt.Printf("[info] %s Close \n", address)
                wg.Done()
                continue
            }
            conn.Close()
            fmt.Printf("[info] %s Open \n", address)
            wg.Done()
        }}func tcpScanByGoroutineWithChannel(ip string, portStart int, portEnd int) {
        start := time.Now()
    
        // 参数校验
        isok := verifyParam(ip, portStart, portEnd)
        if isok == false {
            fmt.Printf("[Exit]\n")
        }
    
        ports := make(chan int, 100)
        var wg sync.WaitGroup    for i := 0; i < cap(ports); i++ {
            go handleWorker(ip, ports, &wg)
        }
    
        for i := portStart; i <= portEnd; i++ {
            wg.Add(1)
            ports <- i    }
    
        wg.Wait()
        close(ports)
    
        cost := time.Since(start)
        fmt.Printf("[tcpScanByGoroutineWithChannel] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool {
        netip := net.ParseIP(ip)
        if netip == nil {
            fmt.Println("[Error] ip type is must net.ip")
            return false
        }
        fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
    
        if portStart < 1 || portEnd > 65535 {
            fmt.Println("[Error] port is must in the range of 1~65535")
            return false
        }
        fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
    
        return true}

    4 端口扫描器 V4 - 引入两个 Channel

    // packagepackage mainimport (
        "fmt"
        "net"
        "sort"
        "time"
        "unsafe")func main() {
        tcpScanByGoroutineWithChannelAndSort("127.0.0.1", 1, 65535)}// The function handles checking if ports are open or closed for a given IP address.func handleWorker(ip string, ports chan int, results chan int) {
        for p := range ports {
            address := fmt.Sprintf("%s:%d", ip, p)
            conn, err := net.Dial("tcp", address)
            if err != nil {
                // fmt.Printf("[debug] ip %s Close \n", address)
                results <- (-p)
                continue
            }
            // fmt.Printf("[debug] ip %s Open \n", address)
            conn.Close()
            results <- p    }}func tcpScanByGoroutineWithChannelAndSort(ip string, portStart int, portEnd int) {
        start := time.Now()
    
        // 参数校验
        isok := verifyParam(ip, portStart, portEnd)
        if isok == false {
            fmt.Printf("[Exit]\n")
        }
    
        ports := make(chan int, 50)
        results := make(chan int)
        var openSlice []int
        var closeSlice []int
    
        // 任务生产者-分发任务 (新起一个 goroutinue ,进行分发数据)
        go func(a int, b int) {
            for i := a; i <= b; i++ {
                ports <- i        }
        }(portStart, portEnd)
    
        // 任务消费者-处理任务  (每一个端口号都分配一个 goroutinue ,进行扫描)
        // 结果生产者-每次得到结果 再写入 结果 chan 中
        for i := 0; i < cap(ports); i++ {
            go handleWorker(ip, ports, results)
        }
    
        // 结果消费者-等待收集结果 (main中的 goroutinue 不断从 chan 中阻塞式读取数据)
        for i := portStart; i <= portEnd; i++ {
            resPort := <-results        if resPort > 0 {
                openSlice = append(openSlice, resPort)
            } else {
                closeSlice = append(closeSlice, -resPort)
            }
        }
    
        // 关闭 chan
        close(ports)
        close(results)
    
        // 排序
        sort.Ints(openSlice)
        sort.Ints(closeSlice)
    
        // 输出
        for _, p := range openSlice {
            fmt.Printf("[info] %s:%-8d Open\n", ip, p)
        }
        // for _, p := range closeSlice {
        //     fmt.Printf("[info] %s:%-8d Close\n", ip, p)
        // }
    
        cost := time.Since(start)
        fmt.Printf("[tcpScanByGoroutineWithChannelAndSort] cost %s second \n", cost)}func verifyParam(ip string, portStart int, portEnd int) bool {
        netip := net.ParseIP(ip)
        if netip == nil {
            fmt.Println("[Error] ip type is must net.ip")
            return false
        }
        fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
    
        if portStart < 1 || portEnd > 65535 {
            fmt.Println("[Error] port is must in the range of 1~65535")
            return false
        }
        fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
    
        return true}

    以上就是一文详解Go如何实现端口扫描器的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:learnku,如有侵犯,请联系admin@php.cn删除
    专题推荐:Go
    上一篇:深入浅析Go语言中要有GMP调度模型的原因 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • 【总结】golang中各种数据类型间的转换方法• 聊聊Golang中的转码系统及其相关技术• 如何在Go语言中使用HTTPS协议进行请求• 深入浅析Go语言中要有GMP调度模型的原因
    1/1

    PHP中文网