diff --git a/README.md b/README.md
index 06d0276..51bc44c 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,184 @@
# lmap
-lmap (LinuxHub's Nmap) is the nmap next generation pro plus max, made by 浪神 (from THE GREAT [LinuxHub](https://github.com/LinuxHub-Group)).
+[](https://www.gnu.org/licenses/gpl-3.0)
-# LICENSE
+
LinuxHub's Nmap - 下一代网络扫描工具
- Copyright (C) <2021>
+
+ 比 nmap 更强大、更灵活的网络探测与扫描能力
+
+ 探索 lmap 的功能 »
+
+
+ 报告 Bug
+ ·
+ 请求新功能
+ ·
+ 贡献
+
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+## 目录
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+- [关于项目](#关于项目)
+- [功能特性](#功能特性)
+- [快速开始](#快速开始)
+ - [安装](#安装)
+ - [使用方法](#使用方法)
+- [构建选项](#构建选项)
+- [贡献](#贡献)
+- [许可证](#许可证)
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
+## 关于项目
+
+lmap (LinuxHub's Nmap) 是 LinuxHub 团队开发的下一代网络扫描工具,被称为 nmap 的 Pro Plus Max 版本。它是一个现代化的网络扫描工具,旨在提供比传统 nmap 更强大、更灵活的网络探测与扫描能力。
+
+该工具专为网络安全工程师、系统管理员和渗透测试人员设计,帮助他们快速识别网络中的活动主机、开放端口和服务。
+
+### 为什么选择 lmap?
+
+- **快速扫描** - 利用 Go 语言的并发特性,实现高速网络扫描
+- **跨平台支持** - 支持 Windows、Linux、macOS 等多种操作系统
+- **易于使用** - 简洁的命令行界面,直观的参数设置
+- **高度可定制** - 支持灵活的排除规则和扫描配置
+- **开源免费** - 基于 GPL-3.0 许可证,完全开源
+
+## 功能特性
+
+- [x] 🚀 **网络扫描** - 快速扫描指定网络段中的活动主机
+- [x] ✅ **IP检查** - 验证IP地址有效性并检查主机是否在线
+- [x] 🔍 **子网解析** - 解析CIDR格式的子网并生成IP地址列表
+- [x] 📡 **ICMP监听** - 监听网络中的ICMP数据包
+- [x] 🏓 **Ping探测** - 使用ICMP协议探测主机是否在线
+- [x] ⚡ **并发处理** - 支持高并发扫描,提高扫描效率
+- [x] 🚫 **排除规则** - 支持排除特定IP或子网,避免扫描不必要目标
+- [x] 📋 **详细输出** - 提供详细的扫描过程信息
+
+## 快速开始
+
+### 安装
+
+#### 预编译二进制文件
+
+从 [Releases](https://github.com/LinuxHub-Group/lmap/releases) 页面下载适用于您系统的预编译二进制文件。
+
+#### 从源码构建
+
+**要求**:
+- Go 1.16 或更高版本
+
+```bash
+# 克隆项目
+git clone https://github.com/LinuxHub-Group/lmap.git
+cd lmap
+
+# 构建
+make
+
+# 或者直接使用Go构建
+go build ./cmd/lmap
+```
+
+构建完成后,您将在项目根目录下获得 [lmap](file:///D:/works/lmap/lmap/lmap.exe) 可执行文件。
+
+### 使用方法
+
+#### 基本扫描
+
+```bash
+# 扫描单个子网
+./lmap -subnet 192.168.1.0/24
+
+# 扫描多个子网
+./lmap -subnet 192.168.1.0/24 -subnet 10.0.0.0/16
+
+# 详细输出模式
+./lmap -subnet 192.168.1.0/24 -v
+```
+
+#### 排除特定IP或子网
+
+```bash
+# 排除单个IP
+./lmap -subnet 192.168.1.0/24 -exclude 192.168.1.1
+
+# 排除多个IP或子网
+./lmap -subnet 192.168.1.0/24 -exclude 192.168.1.1 -exclude 192.168.1.10/32
+```
+
+#### 命令行选项
+
+| 选项 | 描述 | 示例 |
+|------|------|------|
+| `-subnet` | 要扫描的网络段,CIDR格式 (可多次指定) | `-subnet 192.168.1.0/24` |
+| `-exclude` | 要排除的IP或子网 (可多次指定) | `-exclude 192.168.1.1` |
+| `-v` | 详细输出模式 | `-v` |
+
+## 构建选项
+
+```bash
+# 默认构建当前平台版本
+make
+
+# 构建所有平台版本
+make all
+
+# 格式化代码
+make fmt
+
+# 运行测试
+make test
+
+# 清理构建产物
+make clean
+```
+
+## 贡献
+
+欢迎任何形式的贡献!如果您想为 lmap 做出贡献,请遵循以下步骤:
+
+1. Fork 项目
+2. 创建您的特性分支 (`git checkout -b feature/AmazingFeature`)
+3. 提交您的更改 (`git commit -m 'Add some AmazingFeature'`)
+4. 推送到分支 (`git push origin feature/AmazingFeature`)
+5. 开启一个 Pull Request
+
+### 开发环境设置
+
+```bash
+# 1. 克隆项目
+git clone https://github.com/LinuxHub-Group/lmap.git
+
+# 2. 进入项目目录
+cd lmap
+
+# 3. 安装依赖
+make install
+
+# 4. 运行测试
+make test
+```
+
+## 社区和支持
+
+- [报告 Bug](https://github.com/LinuxHub-Group/lmap/issues)
+- [请求新功能](https://github.com/LinuxHub-Group/lmap/issues)
+- [查看已知问题](https://github.com/LinuxHub-Group/lmap/issues)
+
+## 许可证
+
+```
+Copyright (C) <2021>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+```
\ No newline at end of file
diff --git a/cmd/lmap/main.go b/cmd/lmap/main.go
index 8f1da3f..cc221b5 100644
--- a/cmd/lmap/main.go
+++ b/cmd/lmap/main.go
@@ -28,12 +28,51 @@ import (
func main() {
isVerbose := false
- flag.BoolVar(&isVerbose, "v", false, "be verbose")
+ flag.BoolVar(&isVerbose, "v", false, "详细输出")
+
+ subnets := multiArg{}
+ flag.Var(&subnets, "subnet", "要扫描的网络段,CIDR格式 (可多次指定)")
+
+ excludes := multiArg{}
+ flag.Var(&excludes, "exclude", "要排除的IP或子网 (可多次指定)")
+
flag.Parse()
- args := flag.Args()
- if len(args) < 1 {
- _, _ = fmt.Fprintf(os.Stderr, "使用方法:%s [-v] <网络号>/\n", os.Args[0])
- os.Exit(-1)
+
+ if len(subnets) < 1 {
+ printUsage()
+ os.Exit(1)
+ }
+
+ lmap.CheckIP(subnets, excludes, isVerbose)
+}
+
+// printUsage prints the usage information for the program
+func printUsage() {
+ progName := os.Args[0]
+ if progName == "" {
+ progName = "lmap"
}
- lmap.CheckIP(args[0], isVerbose)
+
+ fmt.Fprintf(os.Stderr, "使用方法: %s [选项] -subnet <网络号>/ [-subnet ...]\n", progName)
+ fmt.Fprintln(os.Stderr, "")
+ fmt.Fprintln(os.Stderr, "选项:")
+ flag.PrintDefaults()
+ fmt.Fprintln(os.Stderr, "")
+ fmt.Fprintln(os.Stderr, "示例:")
+ fmt.Fprintf(os.Stderr, " %s -subnet 192.168.1.0/24\n", progName)
+ fmt.Fprintf(os.Stderr, " %s -subnet 192.168.1.0/24 -subnet 10.0.0.0/16\n", progName)
+ fmt.Fprintf(os.Stderr, " %s -subnet 192.168.1.0/24 -exclude 192.168.1.1\n", progName)
+ fmt.Fprintf(os.Stderr, " %s -subnet 192.168.1.0/24 -exclude 192.168.1.10/32 -v\n", progName)
+}
+
+// multiArg implements the flag.Value interface for collecting multiple string values
+type multiArg []string
+
+func (m *multiArg) String() string {
+ return fmt.Sprintf("%v", *m)
+}
+
+func (m *multiArg) Set(value string) error {
+ *m = append(*m, value)
+ return nil
}
diff --git a/go.mod b/go.mod
index 2dc3fc7..6609805 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,23 @@
module github.com/LinuxHub-Group/lmap
-go 1.16
+go 1.23.0
require (
- github.com/ysmood/got v0.30.0
- golang.org/x/net v0.0.0-20220607020251-c690dde0001d
+ github.com/ysmood/got v0.41.0
+ golang.org/x/net v0.43.0
+)
+
+require (
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/ysmood/gop v0.2.0 // indirect
+ github.com/yuin/goldmark v1.4.13 // indirect
+ golang.org/x/crypto v0.41.0 // indirect
+ golang.org/x/mod v0.26.0 // indirect
+ golang.org/x/sync v0.16.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+ golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b // indirect
+ golang.org/x/term v0.34.0 // indirect
+ golang.org/x/text v0.28.0 // indirect
+ golang.org/x/tools v0.35.0 // indirect
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect
)
diff --git a/go.sum b/go.sum
index 5e95a94..640a7f4 100644
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,28 @@
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg=
+github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk=
github.com/ysmood/got v0.30.0 h1:n6KVknQ2gjU2FsEVvMrpEw20uoqkhRDvAoNK69bOV/U=
github.com/ysmood/got v0.30.0/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
+github.com/ysmood/got v0.41.0 h1:XiFH311ltTSGyxjeKcNvy7dzbJjjTzn6DBgK313JHBs=
+github.com/ysmood/got v0.41.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/pkg/lmap/check_ip.go b/pkg/lmap/check_ip.go
index 1517663..368f461 100644
--- a/pkg/lmap/check_ip.go
+++ b/pkg/lmap/check_ip.go
@@ -25,39 +25,64 @@ import (
"time"
)
-const OUTPUT_IP_PER_LINE = 3
+const (
+ OUTPUT_IP_PER_LINE = 3
+ MAX_CONCURRENT_PINGS = 100
+)
-func CheckIP(subnet string, isVerbose bool) {
+// CheckIP scans the given subnets for active hosts
+// subnets: list of CIDR notation networks to scan
+// excludes: list of IPs or subnets to exclude from scanning
+// isVerbose: if true, print detailed information during scanning
+func CheckIP(subnets, excludes []string, isVerbose bool) {
checkerGroup := &sync.WaitGroup{}
t := time.Now()
- hosts, _ := GetAllIPsFromCIDR(subnet)
- for index := range hosts {
- //time.Sleep(500)
+
+ // Use a semaphore to limit concurrent pings
+ semaphore := make(chan struct{}, MAX_CONCURRENT_PINGS)
+
+ var allHosts []HostInfo
+ for _, subnet := range subnets {
+ hosts, err := GetAllIPsFromCIDR(subnet, excludes)
+ if err != nil {
+ _, _ = fmt.Fprintf(os.Stderr, "Error parsing subnet %s: %v\n", subnet, err)
+ continue
+ }
+ allHosts = append(allHosts, hosts...)
+ }
+
+ for index := range allHosts {
checkerGroup.Add(1)
+ semaphore <- struct{}{} // Acquire semaphore
go func(index int) {
defer checkerGroup.Done()
- hosts[index].isUsed = Ping(hosts[index].host)
+ defer func() { <-semaphore }() // Release semaphore
+
+ allHosts[index].isUsed = Ping(allHosts[index].host)
if isVerbose {
- if hosts[index].isUsed {
- fmt.Println("已使用IP:", hosts[index].host.String())
+ if allHosts[index].isUsed {
+ fmt.Println("已使用IP:", allHosts[index].host.String())
} else {
- fmt.Println("未使用IP:", hosts[index].host.String())
+ fmt.Println("未使用IP:", allHosts[index].host.String())
}
}
}(index)
}
+
checkerGroup.Wait()
elapsed := time.Since(t)
_, _ = fmt.Fprintln(os.Stderr, "IP扫描完成,耗时", elapsed)
fmt.Println("已使用IP:")
- printIPList(hosts, true)
+ printIPList(allHosts, true)
fmt.Println("未使用IP:")
- printIPList(hosts, false)
+ printIPList(allHosts, false)
}
+// printIPList prints the list of IPs based on the filter
+// hosts: list of HostInfo to print
+// boolFilter: if true, print used IPs; if false, print unused IPs
func printIPList(hosts []HostInfo, boolFilter bool) {
-
position := 1
for _, hostInfo := range hosts {
@@ -71,5 +96,12 @@ func printIPList(hosts []HostInfo, boolFilter bool) {
position++
}
}
- fmt.Println()
+
+ // Only add a newline if we've printed something and it didn't end with a newline
+ if position > 1 && (position-1)%OUTPUT_IP_PER_LINE != 0 {
+ fmt.Println()
+ } else if position == 1 {
+ // No IPs to print
+ fmt.Println("(无)")
+ }
}
diff --git a/pkg/lmap/common.go b/pkg/lmap/common.go
index ec0b578..93119bd 100644
--- a/pkg/lmap/common.go
+++ b/pkg/lmap/common.go
@@ -20,7 +20,10 @@ package lmap
import "net"
+// HostInfo represents information about a host in the network
type HostInfo struct {
- host net.IP
+ // host is the IP address of the host
+ host net.IP
+ // isUsed indicates whether the host is active/responding
isUsed bool
}
diff --git a/pkg/lmap/listen_icmp.go b/pkg/lmap/listen_icmp.go
index 55d60ff..18d21e2 100644
--- a/pkg/lmap/listen_icmp.go
+++ b/pkg/lmap/listen_icmp.go
@@ -17,3 +17,45 @@
*/
package lmap
+
+import (
+ "fmt"
+
+ "golang.org/x/net/icmp"
+ "golang.org/x/net/ipv4"
+)
+
+// ListenICMP listens for ICMP packets on the specified address
+// This function can be used to listen for ICMP replies when doing network scanning
+func ListenICMP(addr string) error {
+ conn, err := icmp.ListenPacket("ip4:icmp", addr)
+ if err != nil {
+ return fmt.Errorf("failed to listen on ICMP: %w", err)
+ }
+ defer conn.Close()
+
+ fmt.Printf("Listening for ICMP packets on %s...\n", addr)
+
+ for {
+ buf := make([]byte, 1500)
+ n, peer, err := conn.ReadFrom(buf)
+ if err != nil {
+ return fmt.Errorf("failed to read ICMP packet: %w", err)
+ }
+
+ msg, err := icmp.ParseMessage(1, buf[:n]) // 1 = ICMPv4
+ if err != nil {
+ fmt.Printf("Failed to parse ICMP message from %s: %v\n", peer, err)
+ continue
+ }
+
+ switch msg.Type {
+ case ipv4.ICMPTypeEchoReply:
+ fmt.Printf("Received ICMP Echo Reply from %s\n", peer)
+ case ipv4.ICMPTypeEcho:
+ fmt.Printf("Received ICMP Echo Request from %s\n", peer)
+ default:
+ fmt.Printf("Received ICMP message type %v from %s\n", msg.Type, peer)
+ }
+ }
+}
diff --git a/pkg/lmap/parse_subnet.go b/pkg/lmap/parse_subnet.go
index ed49bc1..e89d35a 100644
--- a/pkg/lmap/parse_subnet.go
+++ b/pkg/lmap/parse_subnet.go
@@ -18,9 +18,12 @@
package lmap
-import "net"
+import (
+ "net"
+ "strings"
+)
-func GetAllIPsFromCIDR(cidr string) ([]HostInfo, error) {
+func GetAllIPsFromCIDR(cidr string, excludes []string) ([]HostInfo, error) {
ip, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
@@ -28,15 +31,44 @@ func GetAllIPsFromCIDR(cidr string) ([]HostInfo, error) {
var ips []HostInfo
for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); inc(ip) {
- ips = append(ips, HostInfo{
- host: dupIP(ip),
- isUsed: false,
- })
+ ipStr := ip.String()
+ if !isExcluded(ipStr, excludes) {
+ ips = append(ips, HostInfo{
+ host: dupIP(ip),
+ isUsed: false,
+ })
+ }
+ }
+
+ // For larger networks, remove network and broadcast addresses
+ // For very small networks (like /31, /32), keep all addresses
+ ones, bits := ipNet.Mask.Size()
+ if bits-ones > 2 && len(ips) > 2 {
+ return ips[1 : len(ips)-1], nil // Remove network and broadcast addresses
}
- if len(ips) <= 2 {
- return ips, nil
+ return ips, nil
+}
+
+func isExcluded(ip string, excludes []string) bool {
+ for _, exclude := range excludes {
+ if strings.Contains(exclude, "/") {
+ _, excludeNet, err := net.ParseCIDR(exclude)
+ if err != nil {
+ //fmt.Printf("解析排除规则 %s 失败: %v\n", exclude, err)
+ continue
+ }
+ if excludeNet.Contains(net.ParseIP(ip)) {
+ //fmt.Printf("IP %s 被排除规则 %s 排除\n", ip, exclude)
+ return true
+ }
+ } else {
+ if ip == exclude {
+ //fmt.Printf("IP %s 被排除规则 %s 排除\n", ip, exclude)
+ return true
+ }
+ }
}
- return ips[0 : len(ips)-1], nil
+ return false
}
func inc(ip net.IP) {
@@ -49,7 +81,6 @@ func inc(ip net.IP) {
}
func dupIP(ip net.IP) net.IP {
- // To save space, try and only use 4 bytes
if x := ip.To4(); x != nil {
ip = x
}
diff --git a/pkg/lmap/ping.go b/pkg/lmap/ping.go
index b09c070..314af3a 100644
--- a/pkg/lmap/ping.go
+++ b/pkg/lmap/ping.go
@@ -27,23 +27,27 @@ import (
"golang.org/x/net/ipv4"
)
+// Ping sends an ICMP echo request to the given IP address and waits for a reply
+// Returns true if a reply is received within the timeout, false otherwise
func Ping(ip net.IP) bool {
msg := icmp.Message{
Type: ipv4.ICMPTypeEcho,
Code: 0,
- Body: &icmp.RawBody{
- Data: ip,
+ Body: &icmp.Echo{
+ ID: 12345,
+ Seq: 1,
+ Data: []byte("lmap ping"),
},
}
sendBytes, err := msg.Marshal(nil)
if err != nil {
log.Println("marshal icmp message", err)
+ return false
}
// Start listening for icmp replies
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
-
if err != nil {
log.Println("dial error:", err)
return false
@@ -54,19 +58,33 @@ func Ping(ip net.IP) bool {
IP: ip,
})
if err != nil {
+ log.Println("write error:", err)
return false
}
+
_ = conn.SetReadDeadline(time.Now().Add(time.Second * 2))
- for {
- recvBuf := make([]byte, 20)
- _, addr, err := conn.ReadFrom(recvBuf)
+ // Only read a limited number of times to avoid infinite loop
+ for i := 0; i < 5; i++ {
+ recvBuf := make([]byte, 1500)
+ n, addr, err := conn.ReadFrom(recvBuf)
if err != nil {
+ // Timeout or other error, return false
return false
}
if addr.String() == ip.String() {
- return true
+ // Parse the received message to ensure it's an echo reply
+ reply, err := icmp.ParseMessage(1, recvBuf[:n])
+ if err != nil {
+ continue
+ }
+
+ if reply.Type == ipv4.ICMPTypeEchoReply {
+ return true
+ }
}
}
+
+ return false
}
diff --git a/pkg/lmap/ping_test.go b/pkg/lmap/ping_test.go
index 27c3548..2938332 100644
--- a/pkg/lmap/ping_test.go
+++ b/pkg/lmap/ping_test.go
@@ -29,3 +29,19 @@ func TestPing(t *testing.T) {
res := Ping(ip)
got.T(t).True(res)
}
+
+func TestPingWithInvalidIP(t *testing.T) {
+ // 测试无效IP的情况
+ invalidIP := net.ParseIP("0.0.0.0")
+ res := Ping(invalidIP)
+ // 对于无效IP,期望返回false
+ got.T(t).False(res)
+}
+
+func TestPingWithLocalhost(t *testing.T) {
+ // 测试本地回环地址
+ localhost := net.ParseIP("127.0.0.1")
+ res := Ping(localhost)
+ // 本地回环地址通常应该返回true
+ got.T(t).True(res)
+}