使用go语言进行端口扫描

发布于:2024-11-28 ⋅ 阅读:(16) ⋅ 点赞:(0)

端口扫描的原理:

端口扫描的核心原理是基于 TCP 协议的三次握手过程。当你尝试连接一个端口时,操作系统会通过 TCP 三次握手来建立连接。如果目标端口响应了握手请求(即返回 SYN-ACK 响应),则可以认为该端口是开放的;如果没有响应,或者连接超时,则认为端口是关闭的。
GO语言和Python语言都是写脚本的最佳选择,这里使用了go语言简单的写了一个端口扫描脚本。

package main

import (
	"fmt"
	"net"
	"os"
	"sync"
	"time"
)

// checkPort 函数用于检查指定 IP 地址和端口是否开放
func checkPort(ip net.IP, port int, wg *sync.WaitGroup, ch chan string, timeout chan string) {
	defer wg.Done() // 确保协程结束时,调用 Done() 函数,表示任务完成
	address := fmt.Sprintf("%s:%d", ip.String(), port)
	// 尝试连接目标 IP 和端口,连接超时时间为 20 秒
	conn, err := net.DialTimeout("tcp", address, 20*time.Second)
	if err != nil {
		// 如果连接失败,则返回(即此端口未开放)
		return
	}
	conn.Close()
	ch <- fmt.Sprintf("端口 %d 开放", port)
}

// checkIp 函数用于验证传入的 IP 地址是否合法
func checkIp(ip string) bool {
	// 解析字符串 IP 地址
	parsedIp := net.ParseIP(ip)
	// 如果解析失败,则说明 IP 地址无效
	if parsedIp == nil {
		fmt.Println("非法ip地址")
		return false
	}
	return true
}

func main() {
	// 检查命令行参数是否包含目标 IP 地址
	if len(os.Args) < 2 {
		fmt.Println("请输入目标 IP 地址")
		return
	}
	// 获取命令行中的 IP 地址
	ip := os.Args[1]
	if !checkIp(ip) {
		return
	}
	//声明一个 WaitGroup 用于等待所有 goroutine线程 执行完毕
	var wg sync.WaitGroup
	ch := make(chan string)
	timeout := make(chan string)
	start := time.Now()
	// 启动多个 goroutine 来检查 1 到 100000 之间的端口
	for port := 1; port <= 100000; port++ {
		// 每启动一个 goroutine,WaitGroup 的计数器加 1
		wg.Add(1)
		// 启动一个 goroutine 来检查该端口
		go checkPort(net.ParseIP(ip), port, &wg, ch, timeout)
	}

	// 启动一个 goroutine,在所有端口扫描完成后关闭 channels
	go func() {
		wg.Wait()     
		close(ch)     
		close(timeout)
	}()

	// 从 ch channel 中读取扫描结果并输出
	for msg := range ch {
		fmt.Println(msg) // 输出端口开放的消息
	}
	fmt.Println("扫描完成,耗时:", time.Since(start))
}

执行结果

在这里插入图片描述