An article explaining in detail how to implement a port scanner in Go

藏色散人
Release: 2023-04-14 16:53:31
forward
1714 people have browsed it

This article brings you relevant knowledge about Go. It mainly introduces how to implement the port scanner in Go. There are code examples. Friends who are interested can take a look below. I hope it will be helpful to you.

Use GO to scan server ports in batches

1. Port scanner V1 - basic operation

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}
Copy after login

2. Port scanner V2 - using 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}
Copy after login

3. Port Scanner V3 - Using 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}
Copy after login

4 Port Scanner V4 - Introducing two 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}
Copy after login

The above is the detailed content of An article explaining in detail how to implement a port scanner in Go. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
go
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!