端口扫描的原理:
端口扫描的核心原理是基于 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))
}