perf: 优化ICMP.go的代码,添加注释,规范输出

This commit is contained in:
ZacharyZcR 2024-12-18 23:39:18 +08:00
parent 23fea2c290
commit 59e5b88600

View File

@ -14,88 +14,118 @@ import (
) )
var ( var (
AliveHosts []string AliveHosts []string // 存活主机列表
ExistHosts = make(map[string]struct{}) ExistHosts = make(map[string]struct{}) // 已发现主机记录
livewg sync.WaitGroup livewg sync.WaitGroup // 存活检测等待组
) )
// CheckLive 检测主机存活状态
func CheckLive(hostslist []string, Ping bool) []string { func CheckLive(hostslist []string, Ping bool) []string {
// 创建主机通道
chanHosts := make(chan string, len(hostslist)) chanHosts := make(chan string, len(hostslist))
go func() {
for ip := range chanHosts {
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
ExistHosts[ip] = struct{}{}
if Common.Silent == false {
if Ping == false {
fmt.Printf("(icmp) Target %-15s is alive\n", ip)
} else {
fmt.Printf("(ping) Target %-15s is alive\n", ip)
}
}
AliveHosts = append(AliveHosts, ip)
}
livewg.Done()
}
}()
if Ping == true { // 处理存活主机
//使用ping探测 go handleAliveHosts(chanHosts, hostslist, Ping)
// 根据Ping参数选择检测方式
if Ping {
// 使用ping方式探测
RunPing(hostslist, chanHosts) RunPing(hostslist, chanHosts)
} else { } else {
//优先尝试监听本地icmp,批量探测 probeWithICMP(hostslist, chanHosts)
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err == nil {
RunIcmp1(hostslist, conn, chanHosts)
} else {
Common.LogError(err)
//尝试无监听icmp探测
fmt.Println("trying RunIcmp2")
conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
defer func() {
if conn != nil {
conn.Close()
}
}()
if err == nil {
RunIcmp2(hostslist, chanHosts)
} else {
Common.LogError(err)
//使用ping探测
fmt.Println("The current user permissions unable to send icmp packets")
fmt.Println("start ping")
RunPing(hostslist, chanHosts)
}
}
} }
// 等待所有检测完成
livewg.Wait() livewg.Wait()
close(chanHosts) close(chanHosts)
if len(hostslist) > 1000 { // 输出存活统计信息
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true) printAliveStats(hostslist)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0.0/16", arrLen[i])
Common.LogSuccess(output)
}
}
if len(hostslist) > 256 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0/24", arrLen[i])
Common.LogSuccess(output)
}
}
return AliveHosts return AliveHosts
} }
// handleAliveHosts 处理存活主机信息
func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
for ip := range chanHosts {
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
ExistHosts[ip] = struct{}{}
// 输出存活信息
if !Common.Silent {
protocol := "ICMP"
if isPing {
protocol = "PING"
}
fmt.Printf("[+] 目标 %-15s 存活 (%s)\n", ip, protocol)
}
AliveHosts = append(AliveHosts, ip)
}
livewg.Done()
}
}
// probeWithICMP 使用ICMP方式探测
func probeWithICMP(hostslist []string, chanHosts chan string) {
// 尝试监听本地ICMP
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err == nil {
RunIcmp1(hostslist, conn, chanHosts)
return
}
Common.LogError(err)
fmt.Println("[-] 正在尝试无监听ICMP探测...")
// 尝试无监听ICMP探测
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
if err == nil {
defer conn2.Close()
RunIcmp2(hostslist, chanHosts)
return
}
Common.LogError(err)
fmt.Println("[-] 当前用户权限不足,无法发送ICMP包")
fmt.Println("[*] 切换为PING方式探测...")
// 降级使用ping探测
RunPing(hostslist, chanHosts)
}
// printAliveStats 打印存活统计信息
func printAliveStats(hostslist []string) {
// 大规模扫描时输出 /16 网段统计
if len(hostslist) > 1000 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] B段 %-16s 存活主机数: %d", arrTop[i]+".0.0/16", arrLen[i])
Common.LogSuccess(output)
}
}
// 输出 /24 网段统计
if len(hostslist) > 256 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] C段 %-16s 存活主机数: %d", arrTop[i]+".0/24", arrLen[i])
Common.LogSuccess(output)
}
}
}
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) { func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
endflag := false endflag := false
// 启动监听协程
go func() { go func() {
for { for {
if endflag == true { if endflag {
return return
} }
// 接收ICMP响应
msg := make([]byte, 100) msg := make([]byte, 100)
_, sourceIP, _ := conn.ReadFrom(msg) _, sourceIP, _ := conn.ReadFrom(msg)
if sourceIP != nil { if sourceIP != nil {
@ -105,71 +135,93 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
} }
}() }()
// 发送ICMP请求
for _, host := range hostslist { for _, host := range hostslist {
dst, _ := net.ResolveIPAddr("ip", host) dst, _ := net.ResolveIPAddr("ip", host)
IcmpByte := makemsg(host) IcmpByte := makemsg(host)
conn.WriteTo(IcmpByte, dst) conn.WriteTo(IcmpByte, dst)
} }
//根据hosts数量修改icmp监听时间
// 等待响应
start := time.Now() start := time.Now()
for { for {
// 所有主机都已响应则退出
if len(AliveHosts) == len(hostslist) { if len(AliveHosts) == len(hostslist) {
break break
} }
// 根据主机数量设置超时时间
since := time.Since(start) since := time.Since(start)
var wait time.Duration wait := time.Second * 6
switch { if len(hostslist) <= 256 {
case len(hostslist) <= 256:
wait = time.Second * 3 wait = time.Second * 3
default:
wait = time.Second * 6
} }
if since > wait { if since > wait {
break break
} }
} }
endflag = true endflag = true
conn.Close() conn.Close()
} }
// RunIcmp2 使用ICMP并发探测主机存活(无监听模式)
func RunIcmp2(hostslist []string, chanHosts chan string) { func RunIcmp2(hostslist []string, chanHosts chan string) {
// 控制并发数
num := 1000 num := 1000
if len(hostslist) < num { if len(hostslist) < num {
num = len(hostslist) num = len(hostslist)
} }
var wg sync.WaitGroup var wg sync.WaitGroup
limiter := make(chan struct{}, num) limiter := make(chan struct{}, num)
// 并发探测
for _, host := range hostslist { for _, host := range hostslist {
wg.Add(1) wg.Add(1)
limiter <- struct{}{} limiter <- struct{}{}
go func(host string) { go func(host string) {
defer func() {
<-limiter
wg.Done()
}()
if icmpalive(host) { if icmpalive(host) {
livewg.Add(1) livewg.Add(1)
chanHosts <- host chanHosts <- host
} }
<-limiter
wg.Done()
}(host) }(host)
} }
wg.Wait() wg.Wait()
close(limiter) close(limiter)
} }
// icmpalive 检测主机ICMP是否存活
func icmpalive(host string) bool { func icmpalive(host string) bool {
startTime := time.Now() startTime := time.Now()
// 建立ICMP连接
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second) conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
if err != nil { if err != nil {
return false return false
} }
defer conn.Close() defer conn.Close()
// 设置超时时间
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil { if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
return false return false
} }
// 构造并发送ICMP请求
msg := makemsg(host) msg := makemsg(host)
if _, err := conn.Write(msg); err != nil { if _, err := conn.Write(msg); err != nil {
return false return false
} }
// 接收ICMP响应
receive := make([]byte, 60) receive := make([]byte, 60)
if _, err := conn.Read(receive); err != nil { if _, err := conn.Read(receive); err != nil {
return false return false
@ -178,133 +230,174 @@ func icmpalive(host string) bool {
return true return true
} }
// RunPing 使用系统Ping命令并发探测主机存活
func RunPing(hostslist []string, chanHosts chan string) { func RunPing(hostslist []string, chanHosts chan string) {
var wg sync.WaitGroup var wg sync.WaitGroup
// 限制并发数为50
limiter := make(chan struct{}, 50) limiter := make(chan struct{}, 50)
// 并发探测
for _, host := range hostslist { for _, host := range hostslist {
wg.Add(1) wg.Add(1)
limiter <- struct{}{} limiter <- struct{}{}
go func(host string) { go func(host string) {
defer func() {
<-limiter
wg.Done()
}()
if ExecCommandPing(host) { if ExecCommandPing(host) {
livewg.Add(1) livewg.Add(1)
chanHosts <- host chanHosts <- host
} }
<-limiter
wg.Done()
}(host) }(host)
} }
wg.Wait() wg.Wait()
} }
// ExecCommandPing 执行系统Ping命令检测主机存活
func ExecCommandPing(ip string) bool { func ExecCommandPing(ip string) bool {
var command *exec.Cmd var command *exec.Cmd
// 根据操作系统选择不同的ping命令
switch runtime.GOOS { switch runtime.GOOS {
case "windows": case "windows":
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false")
case "darwin": case "darwin":
command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false")
default: //linux default: // linux
command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false" command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false")
} }
outinfo := bytes.Buffer{}
// 捕获命令输出
var outinfo bytes.Buffer
command.Stdout = &outinfo command.Stdout = &outinfo
err := command.Start()
if err != nil { // 执行命令
if err := command.Start(); err != nil {
return false return false
} }
if err = command.Wait(); err != nil {
if err := command.Wait(); err != nil {
return false return false
} else {
if strings.Contains(outinfo.String(), "true") && strings.Count(outinfo.String(), ip) > 2 {
return true
} else {
return false
}
} }
// 分析输出结果
output := outinfo.String()
return strings.Contains(output, "true") && strings.Count(output, ip) > 2
} }
// makemsg 构造ICMP echo请求消息
func makemsg(host string) []byte { func makemsg(host string) []byte {
msg := make([]byte, 40) msg := make([]byte, 40)
// 获取标识符
id0, id1 := genIdentifier(host) id0, id1 := genIdentifier(host)
msg[0] = 8
msg[1] = 0 // 设置ICMP头部
msg[2] = 0 msg[0] = 8 // Type: Echo Request
msg[3] = 0 msg[1] = 0 // Code: 0
msg[4], msg[5] = id0, id1 msg[2] = 0 // Checksum高位(待计算)
msg[6], msg[7] = genSequence(1) msg[3] = 0 // Checksum低位(待计算)
msg[4], msg[5] = id0, id1 // Identifier
msg[6], msg[7] = genSequence(1) // Sequence Number
// 计算校验和
check := checkSum(msg[0:40]) check := checkSum(msg[0:40])
msg[2] = byte(check >> 8) msg[2] = byte(check >> 8) // 设置校验和高位
msg[3] = byte(check & 255) msg[3] = byte(check & 255) // 设置校验和低位
return msg return msg
} }
// checkSum 计算ICMP校验和
func checkSum(msg []byte) uint16 { func checkSum(msg []byte) uint16 {
sum := 0 sum := 0
length := len(msg) length := len(msg)
// 按16位累加
for i := 0; i < length-1; i += 2 { for i := 0; i < length-1; i += 2 {
sum += int(msg[i])*256 + int(msg[i+1]) sum += int(msg[i])*256 + int(msg[i+1])
} }
// 处理奇数长度情况
if length%2 == 1 { if length%2 == 1 {
sum += int(msg[length-1]) * 256 sum += int(msg[length-1]) * 256
} }
// 将高16位加到低16位
sum = (sum >> 16) + (sum & 0xffff) sum = (sum >> 16) + (sum & 0xffff)
sum = sum + (sum >> 16) sum = sum + (sum >> 16)
answer := uint16(^sum)
return answer // 取反得到校验和
return uint16(^sum)
} }
// genSequence 生成ICMP序列号
func genSequence(v int16) (byte, byte) { func genSequence(v int16) (byte, byte) {
ret1 := byte(v >> 8) ret1 := byte(v >> 8) // 高8位
ret2 := byte(v & 255) ret2 := byte(v & 255) // 低8位
return ret1, ret2 return ret1, ret2
} }
// genIdentifier 根据主机地址生成标识符
func genIdentifier(host string) (byte, byte) { func genIdentifier(host string) (byte, byte) {
return host[0], host[1] return host[0], host[1] // 使用主机地址前两个字节
} }
// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) { func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
if len(arrInit) == 0 { if len(arrInit) == 0 {
return return
} }
arrMap1 := make(map[string]int)
arrMap2 := make(map[string]int) // 统计各网段出现次数
for _, value := range arrInit { segmentCounts := make(map[string]int)
line := strings.Split(value, ".") for _, ip := range arrInit {
if len(line) == 4 { segments := strings.Split(ip, ".")
if flag { if len(segments) != 4 {
value = fmt.Sprintf("%s.%s", line[0], line[1]) continue
} else {
value = fmt.Sprintf("%s.%s.%s", line[0], line[1], line[2])
}
} }
if arrMap1[value] != 0 {
arrMap1[value]++ // 根据flag确定统计B段还是C段
var segment string
if flag {
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B段
} else { } else {
arrMap1[value] = 1 segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C段
} }
}
for k, v := range arrMap1 { segmentCounts[segment]++
arrMap2[k] = v
} }
i := 0 // 创建副本用于排序
for range arrMap1 { sortMap := make(map[string]int)
var maxCountKey string for k, v := range segmentCounts {
var maxCountVal = 0 sortMap[k] = v
for key, val := range arrMap2 { }
if val > maxCountVal {
maxCountVal = val // 获取TOP N结果
maxCountKey = key for i := 0; i < length && len(sortMap) > 0; i++ {
maxSegment := ""
maxCount := 0
// 查找当前最大值
for segment, count := range sortMap {
if count > maxCount {
maxCount = count
maxSegment = segment
} }
} }
arrTop = append(arrTop, maxCountKey)
arrLen = append(arrLen, maxCountVal) // 添加到结果集
i++ arrTop = append(arrTop, maxSegment)
if i >= length { arrLen = append(arrLen, maxCount)
return
} // 从待处理map中删除已处理项
delete(arrMap2, maxCountKey) delete(sortMap, maxSegment)
} }
return return
} }