端口扫描的原理:
端口扫描的核心原理是基于 TCP 协议的三次握手过程。当你尝试连接一个端口时,操作系统会通过 TCP 三次握手来建立连接。如果目标端口响应了握手请求(即返回 SYN-ACK 响应),则可以认为该端口是开放的;如果没有响应,或者连接超时,则认为端口是关闭的。
GO语言和Python语言都是写脚本的最佳选择,这里使用了go语言简单的写了一个端口扫描脚本。
package mainimport ("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.WaitGroupch := make(chan string)timeout := make(chan string)start := time.Now()// 启动多个 goroutine 来检查 1 到 100000 之间的端口for port := 1; port <= 100000; port++ {// 每启动一个 goroutine,WaitGroup 的计数器加 1wg.Add(1)// 启动一个 goroutine 来检查该端口go checkPort(net.ParseIP(ip), port, &wg, ch, timeout)}// 启动一个 goroutine,在所有端口扫描完成后关闭 channelsgo func() {wg.Wait() close(ch) close(timeout)}()// 从 ch channel 中读取扫描结果并输出for msg := range ch {fmt.Println(msg) // 输出端口开放的消息}fmt.Println("扫描完成,耗时:", time.Since(start))
}