一文详解Go如何实现端口扫描器
短信预约 -IT技能 免费直播动态提醒
本篇文章给大家带来了关于Go的相关知识,其中主要跟大家介绍Go怎么实现端口扫描器,有代码示例,感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。
利用 GO 批量扫描服务器端口
1、端口扫描器 V1 - 基本操作
package mainimport (
"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 mainimport (
"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 mainimport (
"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
// packagepackage mainimport (
"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}
以上就是一文详解Go如何实现端口扫描器的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341