dsy19811981 2015-12-25 12:08
浏览 30

尝试在Go中实现端口扫描程序

I recently started to learn go. The only reson for that is the goroutine thing which seem to exist only in this language (I have java background and, to be honest, won't ever completely switch to go). I wanted to implement a simple port scanner which is to find every http server (host with opened port 80) in the given network range. Here's how I am doing this:

package main

import (
    "net"
    "fmt"
    "regexp"
    "strconv"
    "time"
)

// next two functions are shamelessly copied from somewhere 

func ip2long(ipstr string) (ip uint32) {
    r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
    reg, err := regexp.Compile(r)
    if err != nil {
        return
    }
    ips := reg.FindStringSubmatch(ipstr)
    if ips == nil {
        return
    }
    ip1, _ := strconv.Atoi(ips[1])
    ip2, _ := strconv.Atoi(ips[2])
    ip3, _ := strconv.Atoi(ips[3])
    ip4, _ := strconv.Atoi(ips[4])
    if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
        return
}
    ip += uint32(ip1 * 0x1000000)
    ip += uint32(ip2 * 0x10000)
    ip += uint32(ip3 * 0x100)
    ip += uint32(ip4)
    return
}
func long2ip(ip uint32) string {
    return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24)
}

// the actual code
func main() {
    seconds := 10 // timeout
    fmt.Println(seconds) // just to see it
    timeOut := time.Duration(seconds) * time.Second // time out to pass to the DialTimeout 
    can := make(chan int) // a chan
    req := func (ip string){ // parallelized function to do requests 
    c, err := net.DialTimeout("tcp", ip+":80",timeOut) // connect to ip with given timeout
    if err == nil { // if we're connected
        fmt.Println(ip) // output the successful ip
        c.Close() // close connection
    }
    can <- 0 // tell that we're done

}

    startIp := ip2long("50.97.99.0") // starting ip
    endIp := ip2long("50.97.102.0")
    curIp := startIp // current ip

    go func(){ // a demon function ran as goroutine which listens to the chan
        count := 0 // how many ips we processed
        looper: // label to break
        for{
            <- can // wait for some goroutine to finish
            curIp++ // next ip
            count++
            go req(long2ip(curIp)) // start new goroutine
            if (curIp > endIp) { // if we've walked through the range
                fmt.Println("final")
                break looper;
            }
        }
    }()
    numGoes := 100 // number of goroutines ran at one time
    for i := 0; i < numGoes; i++{
        can <- 0 // start 100 goroutines
    }
    // standard way to make the program hung
    var input string
    fmt.Scanln(&input)
}

I hope the code is well-commented so you can see what I'm trying to do. The ip range is the range of some hosting company and I know for sure that the IP 50.97.99.189 runs http server, but the problem is that this IP never shows up in console, when I run my given code, although the host is up and ping time is around 156 ms so 10 secs is more than enough. So the question - what am I doing wrong?

  • 写回答

1条回答 默认 最新

  • doumi1944 2015-12-25 22:04
    关注

    Here is a slightly reworked version that is more idiomatic go.

    There are shorter ways to write it, but this is probably more clear.

    Logic is basically the same. I just ran it and it worked fine, printed out several ips it connected to. This version also prints why it fails, which is more for troubleshooting.

    Do you still have issues running this version? If so, what error are you getting?

    My version, on Play.

    package main
    
    import (
        "fmt"
        "net"
        "regexp"
        "strconv"
        "sync"
        "time"
    )
    
    // next two functions are shamelessly copied from somewhere
    
    func ip2long(ipstr string) (uint32, error) {
        r := `^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})`
        reg, err := regexp.Compile(r)
        if err != nil {
            return 0, err
        }
        ips := reg.FindStringSubmatch(ipstr)
        if ips == nil {
            return 0, fmt.Errorf("Invalid ip address")
        }
        var ip1, ip2, ip3, ip4 int
        if ip1, err = strconv.Atoi(ips[1]); err != nil {
            return 0, err
        }
        if ip2, err = strconv.Atoi(ips[2]); err != nil {
            return 0, err
        }
        if ip3, err = strconv.Atoi(ips[3]); err != nil {
            return 0, err
        }
        if ip4, err = strconv.Atoi(ips[4]); err != nil {
            return 0, err
        }
        if ip1 > 255 || ip2 > 255 || ip3 > 255 || ip4 > 255 {
            return 0, fmt.Errorf("Invalid ip address")
        }
        ip := uint32(ip1 * 0x1000000)
        ip += uint32(ip2 * 0x10000)
        ip += uint32(ip3 * 0x100)
        ip += uint32(ip4)
        return ip, nil
    }
    func long2ip(ip uint32) string {
        return fmt.Sprintf("%d.%d.%d.%d", ip>>24, ip<<8>>24, ip<<16>>24, ip<<24>>24)
    }
    
    // the actual code
    func main() {
        timeOut := 10 * time.Second // time out to pass to the DialTimeout
        fmt.Println("Timeout is:", timeOut)
        req := func(ip string) { // parallelized function to do requests
            c, err := net.DialTimeout("tcp", ip+":80", timeOut) // connect to ip with given timeout
            if err == nil {                                     // if we're connected
                fmt.Println(ip) // output the successful ip
                c.Close()       // close connection
            } else {
                fmt.Println("Error is:", err)
            }
        }
    
        startIp, err := ip2long("50.97.99.0") // starting ip
        if err != nil {
            fmt.Println(err)
            return
        }
        endIp, err := ip2long("50.97.102.0")
        if err != nil {
            fmt.Println(err)
            return
        }
        var wg sync.WaitGroup    // synchronizer for main routine to wait for spawned workers
        ips := make(chan uint32) // channel to feed ip addrs
    
        //spawn 100 workers
        for idx := 0; idx < 100; idx++ {
            wg.Add(1)
            go func() {
                for ip := range ips {
                    req(long2ip(ip)) // perform check of ip
                }
                wg.Done()
            }()
        }
    
        // send ip addrs to workers to process
        for curIp := startIp; curIp <= endIp; curIp++ {
            ips <- curIp
        }
        close(ips) // signal goroutines to end
        wg.Wait()  //wait for all goroutines to complete
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向