利用 GO 批次掃描伺服器埠
1、埠掃描器 V1 - 基本操作
package main
import (
"fmt"
"net"
"time"
"unsafe"
)
func main() {
tcpScan("127.0.0.1", 1, 65535)
}
func tcpScan(ip string, portStart int, portEnd int) {
start := time.Now()
// 引數校驗
isok := verifyParam(ip, portStart, portEnd)
if isok == false {
fmt.Printf("[Exit]\n")
}
for i := portStart; i <= portEnd; i++ {
address := fmt.Sprintf("%s:%d", ip, i)
conn, err := net.Dial("tcp", address)
if err != nil {
fmt.Printf("[info] %s Close \n", address)
continue
}
conn.Close()
fmt.Printf("[info] %s Open \n", address)
}
cost := time.Since(start)
fmt.Printf("[tcpScan] cost %s second \n", cost)
}
func verifyParam(ip string, portStart int, portEnd int) bool {
netip := net.ParseIP(ip)
if netip == nil {
fmt.Println("[Error] ip type is must net.ip")
return false
}
fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
if portStart < 1 || portEnd > 65535 {
fmt.Println("[Error] port is must in the range of 1~65535")
return false
}
fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
return true
}
2、埠掃描器 V2 - 使用 goroutine
package main
import (
"fmt"
"net"
"sync"
"time"
"unsafe"
)
func main() {
tcpScanByGoroutine("127.0.0.1", 1, 65535)
}
func tcpScanByGoroutine(ip string, portStart int, portEnd int) {
start := time.Now()
// 引數校驗
isok := verifyParam(ip, portStart, portEnd)
if isok == false {
fmt.Printf("[Exit]\n")
}
var wg sync.WaitGroup
for i := portStart; i <= portEnd; i++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
address := fmt.Sprintf("%s:%d", ip, j)
conn, err := net.Dial("tcp", address)
if err != nil {
fmt.Printf("[info] %s Close \n", address)
return
}
conn.Close()
fmt.Printf("[info] %s Open \n", address)
}(i)
}
wg.Wait()
cost := time.Since(start)
fmt.Printf("[tcpScanByGoroutine] cost %s second \n", cost)
}
func verifyParam(ip string, portStart int, portEnd int) bool {
netip := net.ParseIP(ip)
if netip == nil {
fmt.Println("[Error] ip type is must net.ip")
return false
}
fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
if portStart < 1 || portEnd > 65535 {
fmt.Println("[Error] port is must in the range of 1~65535")
return false
}
fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
return true
}
3、埠掃描器 V3 - 利用 Goroutine + Channel
package main
import (
"fmt"
"net"
"sync"
"time"
"unsafe"
)
func main() {
tcpScanByGoroutineWithChannel("127.0.0.1", 1, 65535)
}
func handleWorker(ip string, ports chan int, wg *sync.WaitGroup) {
for p := range ports {
address := fmt.Sprintf("%s:%d", ip, p)
conn, err := net.Dial("tcp", address)
if err != nil {
fmt.Printf("[info] %s Close \n", address)
wg.Done()
continue
}
conn.Close()
fmt.Printf("[info] %s Open \n", address)
wg.Done()
}
}
func tcpScanByGoroutineWithChannel(ip string, portStart int, portEnd int) {
start := time.Now()
// 引數校驗
isok := verifyParam(ip, portStart, portEnd)
if isok == false {
fmt.Printf("[Exit]\n")
}
ports := make(chan int, 100)
var wg sync.WaitGroup
for i := 0; i < cap(ports); i++ {
go handleWorker(ip, ports, &wg)
}
for i := portStart; i <= portEnd; i++ {
wg.Add(1)
ports <- i
}
wg.Wait()
close(ports)
cost := time.Since(start)
fmt.Printf("[tcpScanByGoroutineWithChannel] cost %s second \n", cost)
}
func verifyParam(ip string, portStart int, portEnd int) bool {
netip := net.ParseIP(ip)
if netip == nil {
fmt.Println("[Error] ip type is must net.ip")
return false
}
fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
if portStart < 1 || portEnd > 65535 {
fmt.Println("[Error] port is must in the range of 1~65535")
return false
}
fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
return true
}
4 埠掃描器 V4 - 引入兩個 Channel
// package
package main
import (
"fmt"
"net"
"sort"
"time"
"unsafe"
)
func main() {
tcpScanByGoroutineWithChannelAndSort("127.0.0.1", 1, 65535)
}
// The function handles checking if ports are open or closed for a given IP address.
func handleWorker(ip string, ports chan int, results chan int) {
for p := range ports {
address := fmt.Sprintf("%s:%d", ip, p)
conn, err := net.Dial("tcp", address)
if err != nil {
// fmt.Printf("[debug] ip %s Close \n", address)
results <- (-p)
continue
}
// fmt.Printf("[debug] ip %s Open \n", address)
conn.Close()
results <- p
}
}
func tcpScanByGoroutineWithChannelAndSort(ip string, portStart int, portEnd int) {
start := time.Now()
// 引數校驗
isok := verifyParam(ip, portStart, portEnd)
if isok == false {
fmt.Printf("[Exit]\n")
}
ports := make(chan int, 50)
results := make(chan int)
var openSlice []int
var closeSlice []int
// 任務生產者-分發任務 (新起一個 goroutinue ,進行分發資料)
go func(a int, b int) {
for i := a; i <= b; i++ {
ports <- i
}
}(portStart, portEnd)
// 任務消費者-處理任務 (每一個埠號都分配一個 goroutinue ,進行掃描)
// 結果生產者-每次得到結果 再寫入 結果 chan 中
for i := 0; i < cap(ports); i++ {
go handleWorker(ip, ports, results)
}
// 結果消費者-等待收集結果 (main中的 goroutinue 不斷從 chan 中阻塞式讀取資料)
for i := portStart; i <= portEnd; i++ {
resPort := <-results
if resPort > 0 {
openSlice = append(openSlice, resPort)
} else {
closeSlice = append(closeSlice, -resPort)
}
}
// 關閉 chan
close(ports)
close(results)
// 排序
sort.Ints(openSlice)
sort.Ints(closeSlice)
// 輸出
for _, p := range openSlice {
fmt.Printf("[info] %s:%-8d Open\n", ip, p)
}
// for _, p := range closeSlice {
// fmt.Printf("[info] %s:%-8d Close\n", ip, p)
// }
cost := time.Since(start)
fmt.Printf("[tcpScanByGoroutineWithChannelAndSort] cost %s second \n", cost)
}
func verifyParam(ip string, portStart int, portEnd int) bool {
netip := net.ParseIP(ip)
if netip == nil {
fmt.Println("[Error] ip type is must net.ip")
return false
}
fmt.Printf("[Info] ip=%s | ip type is: %T | ip size is: %d \n", netip, netip, unsafe.Sizeof(netip))
if portStart < 1 || portEnd > 65535 {
fmt.Println("[Error] port is must in the range of 1~65535")
return false
}
fmt.Printf("[Info] port start:%d end:%d \n", portStart, portEnd)
return true
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結