| OSI 层 | TCP/IP 层 | 核心设备 | 关键协议 | 地址类型 | 广播域 |
|---|---|---|---|---|---|
| 7 应用层 | 应用层 | 终端软件 | HTTP/SSH/DNS | — | — |
| 4 传输层 | 传输层 | 防火墙 | TCP/UDP | 端口号 | — |
| 3 网络层 | 网际层 | 路由器 | IP/ICMP/OSPF/BGP | IP 地址 | ❌ 不广播 |
| 2 数据链路层 | 网络接口层 | 交换机 | ARP/Ethernet/VLAN | MAC 地址 | ✅ 广播域 |
| 1 物理层 | 网络接口层 | 网线/光纤 | 电信号/光信号 | — | — |
关键结论:
展开代码主机 A (192.168.1.10) 想访问 192.168.1.20 ↓ 查 ARP 缓存:无记录 ↓ 构造 ARP Request 广播帧: 发送方 MAC: AA:AA:AA:AA:AA:AA 发送方 IP: 192.168.1.10 目标 MAC: 00:00:00:00:00:00 (未知) 目标 IP: 192.168.1.20 以太网目标: FF:FF:FF:FF:FF:FF (广播) ↓ 交换机泛洪到同一 VLAN 所有端口 ↓ 192.168.1.20 收到 → 单播 ARP Reply: 目标 MAC: AA:AA:AA:AA:AA:AA 发送方 MAC: BB:BB:BB:BB:BB:BB 发送方 IP: 192.168.1.20 ↓ 主机 A 缓存 MAC,开始二层通信
| 字段 | 长度 | 说明 |
|---|---|---|
| 目标 MAC | 6 bytes | FF:FF:FF:FF:FF:FF = 广播 |
| 源 MAC | 6 bytes | 请求者 MAC |
| 类型 | 2 bytes | 0x0806 = ARP |
| 硬件类型 | 2 bytes | 0x0001 = Ethernet |
| 协议类型 | 2 bytes | 0x0800 = IPv4 |
| 操作码 | 2 bytes | 0x0001 = Request, 0x0002 = Reply |
| 发送方 MAC | 6 bytes | |
| 发送方 IP | 4 bytes | |
| 目标 MAC | 6 bytes | 请求时全 0 |
| 目标 IP | 4 bytes | 被查询的 IP |
| 场景 | 结果 | 原因 |
|---|---|---|
同网段 192.168.1.0/24 | ✅ 能扫到 | 二层广播可达 |
跨网段 192.168.2.0/24 | ❌ 扫不到 | 路由器阻断广播 |
| 目标关机但 IP 在交换机 MAC 表 | ⚠️ 可能误报 | 交换机缓存未过期 |
| 目标开防火墙禁 ping | ✅ ARP 仍能通 | ARP 在防火墙之前 |
展开代码主机 A (192.168.1.10) ping 192.168.2.20 ↓ 判断:目标 IP 不在同一子网 ↓ 查路由表:走默认网关 192.168.1.1 ↓ ARP 解析网关 MAC → 封装 ICMP 包: IP 头:源 192.168.1.10,目标 192.168.2.20 以太网:目标 MAC = 网关 MAC ↓ 路由器 R1 收到 → 查路由表 → 转发到 R2 → ... → 目标网络 ↓ 192.168.2.20 收到 ICMP Echo Request ↓ 回复 ICMP Echo Reply(逆向路径) ↓ 主机 A 收到 → 显示存活
| 特性 | ARP | ICMP (Ping) |
|---|---|---|
| OSI 层 | 二层 (Data Link) | 三层 (Network) |
| 依赖地址 | MAC 地址 | IP 地址 |
| 能否跨网段 | ❌ 不能 | ✅ 能 |
| 经过路由 | ❌ 不经过 | ✅ 经过 |
| 防火墙拦截 | 很难拦截 | 容易被禁 |
| 响应速度 | 极快 (<1ms) | 较慢 (几 ms~几百 ms) |
| 准确性 | 高(直连) | 中(可能被过滤) |
| 工具 | 技术 | 层 | 跨网段 | 速度 | 隐蔽性 | 准确度 |
|---|---|---|---|---|---|---|
arp-scan | ARP 广播 | 二层 | ❌ | 极快 (秒级/256IP) | 高(无日志) | 极高 |
arping | ARP 单播 | 二层 | ❌ | 慢 (逐 IP) | 高 | 极高 |
nmap -sn | ICMP/ARP/TCP | 智能 | ✅ | 快 | 中 | 高 |
nmap -PS | TCP SYN | 三层 | ✅ | 快 | 低(有日志) | 中 |
masscan | 自定义 TCP | 三层 | ✅ | 极快 (万级/秒) | 低 | 中 |
fping | ICMP 并行 | 三层 | ✅ | 极快 | 中 | 高 |
展开代码# 安装 sudo apt install arp-scan # 自动识别本地网卡并扫描 sudo arp-scan -l # 指定网卡和网段 sudo arp-scan -I eth0 192.168.1.0/24 # 输出格式控制(只显示 IP+MAC) sudo arp-scan 192.168.1.0/24 | grep -E '^[0-9]' | awk '{print $1}'
输出解析:
展开代码Interface: eth0, type: EN10MB, MAC: xx:xx:xx:xx:xx:xx, IPv4: 192.168.1.10 Starting arp-scan 1.9.7 with 256 hosts 192.168.1.1 aa:bb:cc:dd:ee:ff Huawei Technologies 192.168.1.10 11:22:33:44:55:66 (Unknown: locally administered) 192.168.1.20 77:88:99:aa:bb:cc Apple, Inc. 3 packets received by filter, 0 packets dropped by kernel Ending arp-scan 1.9.7: 256 hosts scanned in 2.456 seconds. 3 responded
已用 IP:3 个(.1, .10, .20) 空闲 IP:256 - 3 = 253 个
展开代码#!/usr/bin/env python3 """ arp_free_ip.py - 查找同网段空闲 IP 需要 root 权限 """ from scapy.all import ARP, Ether, srp, conf import sys import ipaddress from concurrent.futures import ThreadPoolExecutor conf.verb = 0 # 关闭 Scapy 冗余输出 def arp_ping(ip): """单 IP ARP 探测""" pkt = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=str(ip)) ans, _ = srp(pkt, timeout=1, retry=0) return str(ip), len(ans) > 0 def scan_network(network, max_workers=50): """批量扫描网段""" net = ipaddress.ip_network(network, strict=False) hosts = list(net.hosts()) # 排除网络地址和广播地址 used = [] free = [] print(f"[*] 开始扫描 {network},共 {len(hosts)} 个主机...") with ThreadPoolExecutor(max_workers=max_workers) as executor: results = executor.map(arp_ping, hosts) for ip, is_alive in results: if is_alive: used.append(ip) print(f"[+] 存活: {ip}") else: free.append(ip) return used, free def main(): if len(sys.argv) != 2: print(f"用法: sudo python3 {sys.argv[0]} 192.168.1.0/24") sys.exit(1) network = sys.argv[1] used, free = scan_network(network) print(f"\n{'='*50}") print(f"扫描完成: {network}") print(f"已用 IP: {len(used)} 个") print(f"空闲 IP: {len(free)} 个") print(f"\n前 10 个空闲 IP:") for ip in free[:10]: print(f" - {ip}") # 保存到文件 with open("free_ips.txt", "w") as f: f.write(f"# 空闲 IP 列表 - {network}\n") f.write(f"# 生成时间: {__import__('datetime').datetime.now()}\n") for ip in free: f.write(f"{ip}\n") print(f"\n[+] 空闲 IP 已保存到 free_ips.txt") if __name__ == "__main__": main()
运行:
展开代码sudo pip3 install scapy sudo python3 arp_free_ip.py 192.168.1.0/24
展开代码# 默认:同网段用 ARP,跨网段用 ICMP sudo nmap -sn 192.168.1.0/24 # 本地网段(实际走 ARP) sudo nmap -sn 192.168.2.0/24 # 跨网段(走 ICMP) # 强制只用 ICMP(防火墙可能禁 ping) sudo nmap -sn -PE 192.168.2.0/24 # 强制 TCP SYN(防火墙禁 ping 时用) sudo nmap -sn -PS22,80,443 192.168.2.0/24 # 强制 UDP(某些 Windows 主机只回 UDP) sudo nmap -sn -PU53,161 192.168.2.0/24
输出解析:
展开代码Starting Nmap 7.94 ( https://nmap.org ) Nmap scan report for 192.168.2.1 [host down] Nmap scan report for 192.168.2.10 Host is up (0.0023s latency). MAC Address: AA:BB:CC:DD:EE:FF (Huawei Technologies) ... Nmap done: 256 IP addresses (3 hosts up) scanned in 3.45 seconds
展开代码# 安装 sudo apt install fping # 扫描并分类输出 fping -a -g 192.168.2.0/24 2>/dev/null | tee alive_ips.txt fping -u -g 192.168.2.0/24 2>/dev/null | tee dead_ips.txt # -a = alive, -u = unreachable, -g = 生成网段
展开代码# 安装 sudo apt install masscan # 扫描存活(0 端口 = 只 ping) sudo masscan 192.168.2.0/24 -p0 --rate 10000 # 扫描常用端口(更快判断存活) sudo masscan 192.168.2.0/24 -p22,80,443,3389 --rate 10000
展开代码# 如果网络有 DHCP 服务器,直接查租约 cat /var/lib/dhcp/dhcpd.leases | grep "lease\|hardware\|client-hostname" # 或路由器 Web 界面导出
展开代码# 查交换机 MAC 地址表,反推已用 IP snmpwalk -v 2c -c public 192.168.1.1 1.3.6.1.2.1.17.4.3.1.1 # OID: dot1dTpFdbAddress (MAC 表)
展开代码# tcpdump 抓 ARP 请求,被动记录存活主机 sudo tcpdump -i eth0 arp -w arp_traffic.pcap # 分析:tshark -r arp_traffic.pcap -T fields -e arp.src.proto_ipv4 | sort -u
展开代码# IPv6 没有 ARP,用 NDP (Neighbor Discovery Protocol) sudo ip -6 neigh show # 查看邻居表 sudo ndisc6 -r 5 2001:db8::1 eth0 # 主动探测
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 同网段找空闲 IP | arp-scan / Python Scapy | 二层最快,防火墙挡不住 |
| 跨网段找空闲 IP | nmap -sn -PS | 智能 fallback,TCP 穿透防火墙 |
| 极速扫描(10万+ IP) | masscan | 自定义协议栈,万级/秒 |
| 企业内网(有交换机权限) | SNMP + MAC 表 | 不发包,零影响 |
| 隐蔽探测(红队) | tcpdump 被动监听 | 不主动发包,无日志 |
| 自动化集成 | Python Scapy / Nmap XML | 结构化输出,易解析 |
同网段用 ARP(arp-scan),跨网段用 ICMP/TCP(nmap),极速用 masscan,隐蔽用被动监听,企业用 SNMP。 二层广播不路由,三层路由不广播——选错层,扫空网。
展开代码150..161 | ForEach-Object { ip = "10.73.2._" ok = Test-Connection -Count 1 -Delay 1 -Quiet -ComputerName ip if ($ok) { Write-Output "UP $ip" } else { Write-Output "DOWN $ip" } }
展开代码#!/bin/bash # 探测 192.168.88.150-220 存活主机 MAX_JOB=30 LOG_T=$(date +%F_%H-%M) up_log="up_ip_${LOG_T}.log" down_log="down_ip_${LOG_T}.log" > "$up_log" > "$down_log" # 清空旧日志 for i in {150..220};do ip="192.168.88.$i" { if ping -c 2 -i 0.2 -w 1 "$ip" &>/dev/null;then echo "$ip 运行中~~~~~" else echo "$ip 挂了" >&2 fi } >> "$up_log" 2>>"$down_log" & # 控制并发 while [ $(jobs -r | wc -l) -ge $MAX_JOB ];do sleep 0.5;done done wait echo "扫描完成,结果已写入 $up_log $down_log"
本文作者:zzz
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!