0822
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// Scanner 网段扫描器(并发 ping 探测)
|
||||
// Scanner 网段扫描器(并发 ping 探测,支持 CIDR 和 IP 范围格式)
|
||||
type Scanner struct {
|
||||
CIDR string
|
||||
Timeout time.Duration // 单 IP 探测超时
|
||||
@@ -40,7 +40,7 @@ func (s *Scanner) Scan() []model.Device {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("[扫描] 网段 %s,共 %d 个IP,%d 并发 ping 探测...\n", s.CIDR, len(ips), s.Concurrency)
|
||||
fmt.Printf("[扫描] 目标 %s,共 %d 个IP,%d 并发 ping 探测...\n", s.CIDR, len(ips), s.Concurrency)
|
||||
|
||||
jobs := make(chan string, len(ips))
|
||||
results := make(chan model.Device, len(ips))
|
||||
@@ -75,8 +75,21 @@ func (s *Scanner) Scan() []model.Device {
|
||||
return devices
|
||||
}
|
||||
|
||||
// candidateIPs 解析网段并生成候选 IP 列表(排除网络地址和广播地址)
|
||||
// candidateIPs 解析网段并生成候选 IP 列表。
|
||||
// 支持两种格式:
|
||||
// - CIDR: "10.0.3.0/24"(排除网络地址和广播地址)
|
||||
// - IP 范围: "10.0.3.1-10.0.3.100"(包含起始和结束 IP)
|
||||
func (s *Scanner) candidateIPs() ([]string, bool) {
|
||||
// 检查是否为 IP 范围格式
|
||||
if strings.Contains(s.CIDR, "-") {
|
||||
return s.parseIPRange()
|
||||
}
|
||||
// 否则按 CIDR 解析
|
||||
return s.parseCIDR()
|
||||
}
|
||||
|
||||
// parseCIDR 解析 CIDR 格式并生成候选 IP 列表
|
||||
func (s *Scanner) parseCIDR() ([]string, bool) {
|
||||
_, ipnet, err := net.ParseCIDR(s.CIDR)
|
||||
if err != nil {
|
||||
fmt.Printf("[扫描] 网段解析失败: %v\n", err)
|
||||
@@ -93,6 +106,49 @@ func (s *Scanner) candidateIPs() ([]string, bool) {
|
||||
return ips, true
|
||||
}
|
||||
|
||||
// parseIPRange 解析 IP 范围格式(如 "10.0.3.1-10.0.3.100")
|
||||
func (s *Scanner) parseIPRange() ([]string, bool) {
|
||||
parts := strings.SplitN(s.CIDR, "-", 2)
|
||||
if len(parts) != 2 {
|
||||
fmt.Printf("[扫描] IP 范围格式无效: %s\n", s.CIDR)
|
||||
return nil, false
|
||||
}
|
||||
startIP := net.ParseIP(strings.TrimSpace(parts[0]))
|
||||
endIP := net.ParseIP(strings.TrimSpace(parts[1]))
|
||||
if startIP == nil || endIP == nil {
|
||||
fmt.Printf("[扫描] IP 地址解析失败: %s\n", s.CIDR)
|
||||
return nil, false
|
||||
}
|
||||
// 转换为 4 字节 IPv4
|
||||
start := startIP.To4()
|
||||
end := endIP.To4()
|
||||
if start == nil || end == nil {
|
||||
fmt.Printf("[扫描] 仅支持 IPv4 范围: %s\n", s.CIDR)
|
||||
return nil, false
|
||||
}
|
||||
// 确保起始 <= 结束
|
||||
if ipToUint32(start) > ipToUint32(end) {
|
||||
fmt.Printf("[扫描] 起始 IP 大于结束 IP: %s\n", s.CIDR)
|
||||
return nil, false
|
||||
}
|
||||
var ips []string
|
||||
for ip := make(net.IP, len(start)); ; {
|
||||
copy(ip, start)
|
||||
ips = append(ips, ip.String())
|
||||
if start.Equal(end) {
|
||||
break
|
||||
}
|
||||
inc(start)
|
||||
}
|
||||
return ips, true
|
||||
}
|
||||
|
||||
// ipToUint32 将 IPv4 地址转换为 uint32 用于比较
|
||||
func ipToUint32(ip net.IP) uint32 {
|
||||
ip = ip.To4()
|
||||
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
|
||||
}
|
||||
|
||||
// ping 探测单个 IP 是否存活(ICMP,经系统 ping 命令)。
|
||||
// 仅凭 exit code 不可靠(Windows 在某些代答/虚拟网卡场景会返回 0),
|
||||
// 因此解析输出,要求至少收到 1 个回包。
|
||||
|
||||
Reference in New Issue
Block a user