Golang 写一个端口扫描器

前话

最近痴迷于Golang这个新兴语言,因为它是强类型编译型语言,可以直接编译成三大平台的二进制执行文件,可以直接运行无需其他依赖环境。而且Golang独特的goroutine使得多线程任务执行如new一个对象般简单。

带着为学习理解Golang的好奇心情,我试着写了个端口扫描器。

github项目链接如下, 更多的实用工具我会慢慢添加。
https://github.com/pwcong/go-tools

源码

package main

import (
	"flag"
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

var port int
var portRange string

var parallelCounts int

func init() {

	flag.IntVar(&port, "p", 80, "port")
	flag.StringVar(&portRange, "r", "", "range ports. format is <from>~<to>. eg. 100~200")
	flag.IntVar(&parallelCounts, "n", 1, "parallel counts")

	// 修改提示信息
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\nUsage: %s [Options] <IP>\n\nOptions:\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

}

func printOpeningPort(port int) {

	fmt.Println("port " + strconv.Itoa(port) + " is opening")

}

func checkPort(ip net.IP, port int, wg *sync.WaitGroup, parallelChan *chan int) {

	defer wg.Done()

	tcpAddr := net.TCPAddr{
		IP:   ip,
		Port: port,
	}

	conn, err := net.DialTCP("tcp", nil, &tcpAddr)

	if err == nil {
		printOpeningPort(port)
		conn.Close()

	}

	<-*parallelChan

}

func main() {

	args := flag.Args()

	if len(args) != 1 {
		flag.Usage()
	} else {

		ip := net.ParseIP(flag.Arg(0))

		// 用于协程任务控制
		wg := sync.WaitGroup{}

		if portRange != "" {

			matched, _ := regexp.Match(`^\d+~\d+$`, []byte(portRange))

			if !matched {

				flag.Usage()

			} else {

				portSecs := strings.Split(portRange, "~")

				startPort, err1 := strconv.Atoi(portSecs[0])
				endPort, err2 := strconv.Atoi(portSecs[1])

				if err1 != nil || err2 != nil || startPort < 1 || endPort < 2 || endPort <= startPort || parallelCounts < 1 {
					flag.Usage()
				} else {

					wg.Add(endPort - startPort + 1)

					// 用于控制协程数
					parallelChan := make(chan int, parallelCounts)

					for i := startPort; i <= endPort; i++ {

						parallelChan <- 1

						go checkPort(ip, i, &wg, &parallelChan)

					}

					wg.Wait()

				}

			}

		} else {

			wg.Add(1)

			parallelChan := make(chan int)

			go func() {
				parallelChan <- 1
			}()

			go checkPort(ip, port, &wg, &parallelChan)

			wg.Wait()

		}

	}

}

运行结果

  1. 执行 go build ./main.go, 生成二进制文件
  2. 运行二进制文件,结果如下:
    $ port-scanner.exe
    
    Usage: E:\Program Files\GoPath\bin\port-scanner.exe [Options] <IP>
    
    Options:
    
      -n int
            parallel counts (default 1)
      -p int
            port (default 80)
      -r string
            range ports. format is <from>~<to>. eg. 100~200
    
    $ port-scanner.exe -p 80 127.0.0.1
    port 80 is opening
    
    $ port-scanner.exe -r 1~100 -n 50 127.0.0.1
    port 80 is opening
    
posted @ 2017-12-18 20:24  Pwcong  阅读(1106)  评论(0编辑  收藏  举报