结论:nmap二层扫描需用-PR参数且仅限Linux/macOS,Windows下失效;纯Python实现须用scapy发ARP包,需root/管理员权限。

直接说结论:用 nmap 做二层局域网扫描,Python 本身不负责发包,而是调用系统级 nmap 可执行文件;真要纯 Python 实现二层探测(如 ARP 扫描),得换 scapy,且必须 root / Administrator 权限。
为什么 nmap 默认扫不到同网段所有设备?
nmap 默认走的是三层(IP 层)扫描,比如 nmap -sn 192.168.1.0/24,它实际发的是 ICMP Echo Request 或 TCP SYN 到常见端口——但很多设备(尤其是 IoT 设备、手机、Win10+ 主机)会静默丢弃 ICMP,或防火墙拦截 SYN,导致“离线”误判。
- ARP 扫描才是二层真实在线依据:只要设备连在同一个交换机下、网卡处于 up 状态,就会响应 ARP 请求
-
nmap -sn -PR启用 ARP Ping(-PR),但仅限 Linux/macOS 本地网段;Windows 下该选项被忽略(nmap 会退化为 ICMP/TCP 扫描) - 即使加了
-PR,若运行环境没权限(如普通用户执行),nmap 会静默降级,不报错也不提示
用 python-nmap 调用时的典型陷阱
python-nmap 是个封装器,底层仍依赖系统 nmap。它不会帮你自动选对参数,也不会校验权限是否足够。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 别写
nm.scan('192.168.1.0/24', arguments='-sn')就完事——这在 Windows 上几乎必然漏设备 - Linux/macOS 下想强制 ARP 扫描,必须显式加
-PR:arguments='-sn -PR' - 如果脚本在 Docker 容器里跑,宿主机网络模式(
--network host)是必须的,否则容器内根本看不到物理网段 -
python-nmap的scaninfo()返回空字典?大概率是 nmap 没执行成功,检查nm.scanstats()['uphosts']和nm.scanstats()['downhosts']是否全为 0,再看nm.command_line()确认实际执行命令
更可靠的做法:用 scapy 直接发 ARP
绕过 nmap 限制,自己构造二层包。缺点是代码稍多,优点是完全可控、跨平台一致、响应即在线。
立即学习“Python免费学习笔记(深入)”;
- 需要
root(Linux/macOS)或管理员权限(Windows),否则scapy发包失败 - 核心语句就一行:
ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"), timeout=2, verbose=0) -
ans是收到 ARP 响应的设备列表,每个元素含ans[0][1].psrc(IP)和ans[0][1].hwsrc(MAC) - 注意:
srp()默认只在当前接口发包,多网卡机器需指定iface="eth0",否则可能扫错网段 - Windows 上
scapy需额外装 Npcap(不是 WinPcap),且确保 “Allow applications to use Npcap in loopback mode” 已勾选
真正难的不是写几行代码,而是理解“在线”的定义边界:ARP 响应代表链路层可达,不代表能 SSH、能 HTTP、甚至不代表 IP 层路由通——这些都得后续分层验证。别让一个“扫到了”掩盖了协议栈的真实状态。

















