golang 端口扫描工具

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang 端口扫描工具相关的知识,希望对你有一定的参考价值。

package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"sync"
	"time"
)

// command param
var (
	host            string
	start           int
	end             int
	timeout         string
	timeoutDuration time.Duration
	pause           string
	pauseDuration   time.Duration
	log             bool
)

// port util
var (
	minPort = 80
	maxPort = 65535
	isPort  = func(port int) bool {
		return port >= minPort && port <= maxPort
	}
)

// custom error
var (
	startPortError                     = fmt.Errorf("starting port out of range (should be between %d and %d)", minPort, maxPort)
	endPortError                       = fmt.Errorf("ending port out of range (should be between %d and %d)", minPort, maxPort)
	endPortIsSmallerThanStartPortError = errors.New("ending port must be greater than starting port")
)

// custom type
type status string

func (s *status) init(isOpened bool) {
	if isOpened {
		*s = "OPENED"
	} else {
		*s = "CLOSED"
	}
}

func (s status) isOpened() bool {
	return s == "OPENED"
}

func (s status) isClosed() bool {
	return s == "CLOSED"
}

// global variable
var (
	openedPorts []int
	wg          sync.WaitGroup
	lock        sync.Mutex
)

func init() {
	flag.StringVar(&host, "host", "localhost", "the host to scan")
	flag.StringVar(&timeout, "timeout", "1000ms", "timeout (e.g. 50ms or 1s)")
	flag.StringVar(&pause, "pause", "1ms", "pause after each scanned port (e.g. 5ms)")
	flag.IntVar(&start, "start", minPort, "the lower end to scan")
	flag.IntVar(&end, "end", maxPort, "the upper end to scan")
	flag.BoolVar(&log, "log", true, "print result when scanning the port (true/false)")
	flag.Parse()

	if !isPort(start) {
		panic(startPortError)
	}
	if !isPort(end) {
		panic(endPortError)
	}
	if end < start {
		panic(endPortIsSmallerThanStartPortError)
	}
	var err error
	timeoutDuration, err = time.ParseDuration(timeout)
	if err != nil {
		panic(err)
	}

	pauseDuration, err = time.ParseDuration(pause)
	if err != nil {
		panic(err)
	}
}

func scan(port int) {
	defer wg.Done()

	conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), timeoutDuration)

	var s status
	s.init(err == nil)

	if log {
		fmt.Printf("scan: %d , status: %v\n", port, s)
	}
	if s.isOpened() {
		if conn != nil {
			conn.Close()
		}

		lock.Lock()
		openedPorts = append(openedPorts, port)
		lock.Unlock()
	}

}

func main() {
	startTime := time.Now()
	for port := start; port <= end; port++ {
		wg.Add(1)
		go scan(port)
		time.Sleep(pauseDuration)
	}
	wg.Wait()

	fmt.Printf("\nscan finished in %v\n", time.Since(startTime))

	if len(openedPorts) == 0 {
		fmt.Println("Ports are off.")
		return
	}

	fmt.Println("Openned ports: ")
	for _, port := range openedPorts {
		fmt.Println(port)
	}
}

Golang检测Linux服务器端口占用

  • 代码实现
func CheckPort(port int) error 
    checkStatement := fmt.Sprintf(`netstat -anp | grep -q %d ; echo $?`, port)
    output, err := exec.Command("sh", "-c", checkStatement).CombinedOutput()
    if err != nil 
        return err
    
    // log.Println(output, string(output)) ==> [48 10] 0 或 [49 10] 1
    result, err := strconv.Atoi(strings.TrimSuffix(string(output), "\n"))
    if err != nil 
        return err
    
    if result == 0 
        return fmt.Errorf("端口%d已被占用", port)
    

    return nil
  • 纠错思路

    • 第8行原代码为:result, err := strconv.Atoi(string(output)),
      报错为: strconv.Atoi: parsing "0\n": invalid syntax
    • 经排查,CombinedOutput()函数的执行结果0\n(1\n)包含换行符\n,
      利用strings.TrimSuffix()函数删除换行符\n
  • 延伸知识

    • strings.TrimSuffix()strings.TrimRight()的区别:
      • TrimRight(s string, cutset string) string指从s右端开始,删除所有cutset中出现的字符,若从右到左的过程中遇到其他字符,则停止删除。

      • TrimSuffix(s, suffix string) string删除后缀suffix

      • eg:strings.TrimRight("abcdabcdaaaaeac", "abcd")返回"abcdabcdaaaae"
        strings.TrimRight("abcdaaaaa", "abcd")返回""

以上是关于golang 端口扫描工具的主要内容,如果未能解决你的问题,请参考以下文章

Go语言(Golang)编写 TCP 端口扫描器

端口扫描(go)

golang 可以监听多个端口吗

golang怎么检查端口被占用了

golang go lang中的网络端口转发

TODO:Golang语言TCP/UDP协议重用地址端口