资讯动态

ScanLan 局域网扫描:ARP 原理、Python 实现与设备清单管理

发布时间:2026/10/8 10:36:06 来源:尧图企业网站定制
简介这是一份面向网络管理与安全初学者的VC局域网扫描工具源码用于快速发现同一网段内所有主机的IP与MAC地址可服务于网络设备盘点、IP冲突排查、未授权设备识别等场景。压缩包共15个文件约13KB以C源码为主体包含5个h头文件与4个cpp实现文件另有rc、rc2资源脚本、ico图标、dsw与dsp工程文件及clw类向导文件构成一套可直接用Visual C打开编译的完整工程。据描述该工具通过ARP或ICMP协议探测局域网设备约30秒即可扫完一个网段的255台机器并借助进程间通信机制完成数据传递。目前已有733人学习下载适合想理解二层MAC寻址、ARP请求流程与MFC工程组织方式的读者参考也可作为网络扫描类课程设计或二次开发的基础模板。1. ScanLan 扫描局域网从 ARP 表到全网段设备清单办公室里总有那么几台设备你知道它在但就是找不到它的 IP。路由器后台只显示在线主机名交换机没有管理口同事说“我电脑能上网啊”可你 ping 不通他的共享文件夹。这时候最省事的做法不是挨个问而是跑一遍 ScanLan 这类局域网扫描工具把当前网段里所有活着的 IP 和对应 MAC 地址一次性拉出来。ScanLan 扫描得到局域网中所有机子的 IP 和 MAC 地址这件事听起来简单背后其实是 ARP 协议在干活同一广播域内只要对方在线ARP 请求就会拿到它的 MAC 回应。适合谁用运维排查 IP 冲突、开发调试局域网服务、安全自查陌生设备、普通用户找摄像头或打印机都用得上。下面从原理到代码把这条路走通。2. 局域网扫描的底层逻辑ARP、ICMP 与邻居表2.1 为什么 ping 扫不全ARP 才是关键很多人第一反应是写个循环去 ping 整个网段能通的就是在线设备。这个做法在跨网段时没问题但在同一局域网里会漏掉一批“装死”的机器。原因在于 ICMP 是网络层协议很多系统防火墙默认丢弃 ping 请求但 ARP 是链路层协议只要网卡启用、协议栈正常它就必须回应 ARP 请求否则自己都没法通信。所以局域网扫描的核心不是 ICMP而是 ARP。Windows 上可以用arp -a看本机邻居表Linux 上是ip neigh或arp -n。但这个表只包含最近通信过的设备不完整。要拿全得主动向整个网段发 ARP 请求。常见做法是构造 ARP request 广播帧目标 IP 遍历网段谁回应就记录谁的 IP 和 MAC。这就是 ScanLan 这类工具的基本盘。提示ARP 只能扫同一广播域同一 VLAN、同一子网。跨网段扫描要靠 ICMP 或 SNMP不在本文讨论范围。2.2 用 Python 的 scapy 实现一次完整 ARP 扫描下面这段代码是我在 Linux 和 Windows 上都跑过的版本依赖 scapy。Windows 需要先装 NpcapLinux 直接 root 运行。# arp_scan.py from scapy.all import ARP, Ether, srp import ipaddress def scan_lan(cidr): # 构造 ARP 请求目标 MAC 为广播目标 IP 为待探测地址 arp ARP(pdstcidr) ether Ether(dstff:ff:ff:ff:ff:ff) packet ether / arp # srp 发送并接收二层帧timeout 控制等待时间retry 控制重试次数 result srp(packet, timeout2, retry1, verboseFalse)[0] devices [] for sent, received in result: devices.append({ip: received.psrc, mac: received.hwsrc}) return devices if __name__ __main__: # 改成你自己的网段比如 192.168.1.0/24 for d in scan_lan(192.168.1.0/24): print(fIP{d[ip]:15} MAC{d[mac]})逻辑说明ARP(pdstcidr)里的pdst可以直接写 CIDRscapy 会自动展开成多个目标地址。Ether(dstff:ff:ff:ff:ff:ff)是广播帧保证同一广播域内所有网卡都能收到。srp是二层发送接收返回两个列表第一个是“请求-响应”配对。timeout2表示等 2 秒retry1表示重试一次。参数怎么调网段大就加大 timeout无线环境丢包多就加 retry但别超过 3否则扫描时间线性增长。2.3 不装 scapy 的替代方案系统命令 正则解析有些生产环境不让装第三方库那就用系统自带命令。Linux 下arp-scan最直接Windows 下可以用for /L循环 ping 一遍再读arp -a。# Linux 安装 arp-scan 后执行 sudo arp-scan --interfaceeth0 --localnet:: Windows 批处理先 ping 全网段填充 ARP 表再读表 for /L %i in (1,1,254) do ping -n 1 -w 100 192.168.1.%i nul arp -a逻辑说明Windows 的ping虽然可能被防火墙拦但发送过程中系统会先发 ARP 请求解析目标 MAC即使 ICMP 没回ARP 表里也会留下记录。-w 100是超时 100 毫秒254 个地址大约 25 秒跑完。arp -a输出里动态类型的条目就是局域网设备。这个方法土但零依赖适合临时排查。3. 从扫描结果到可用清单解析、去重与厂商识别3.1 解析 IP 和 MAC 的三种输出格式扫描拿到的原始数据通常长这样192.168.1.1 aa:bb:cc:dd:ee:ff。但不同工具输出格式不一样写脚本时要统一。下面是一个解析函数兼容冒号、连字符和 Cisco 点分格式。import re def parse_mac(mac_str): # 去掉所有非十六进制字符统一转小写 clean re.sub(r[^0-9a-fA-F], , mac_str).lower() if len(clean) ! 12: return None # 统一输出 aa:bb:cc:dd:ee:ff return :.join(clean[i:i2] for i in range(0, 12, 2)) # 测试 print(parse_mac(AA-BB-CC-DD-EE-FF)) # aa:bb:cc:dd:ee:ff print(parse_mac(aabb.ccdd.eeff)) # aa:bb:cc:dd:ee:ff逻辑说明MAC 地址本质是 12 位十六进制数格式只是分隔符差异。re.sub把所有非十六进制字符删掉再按两位一组重新拼接。参数说明如果长度不是 12说明输入有问题返回 None 让调用方处理。这个函数在合并多个扫描工具结果时特别有用。3.2 用 OUI 查厂商MAC 前三位能告诉你什么MAC 地址前 24 位是 OUI组织唯一标识符由 IEEE 分配给厂商。拿到 MAC 后查一下 OUI就能知道这是小米手机、海康摄像头还是 TP-Link 路由器。本地维护一份 OUI 表最靠谱网上有公开的 CSV 可以下载但注意不要用来源不明的库。# oui_lookup.py def load_oui(path): oui_map {} with open(path, r, encodingutf-8) as f: for line in f: parts line.strip().split(\t) if len(parts) 2: prefix parts[0].replace(-, ).lower() oui_map[prefix] parts[1] return oui_map def vendor_of(mac, oui_map): prefix mac.replace(:, ).lower()[:6] return oui_map.get(prefix, 未知厂商)逻辑说明OUI 文件通常是AA-BB-CC\t厂商名的格式。加载时把前缀统一成 6 位小写十六进制。查询时取 MAC 前 6 位去匹配。参数说明如果查不到不要瞎猜直接标“未知厂商”。有些虚拟机会用随机 MACOUI 查出来是 QEMU 或 VMware这是正常的。3.3 去重与合并同一设备多个 IP 怎么处理一台设备可能有多个网卡或者同时有 IPv4 和 IPv6扫描结果里会出现多条记录。去重逻辑不能只看 IP也不能只看 MAC要按业务需求来。如果目的是“找设备”按 MAC 去重如果目的是“找可用 IP”按 IP 去重。def dedup_by_mac(devices): seen {} for d in devices: mac d[mac] if mac not in seen: seen[mac] d else: # 保留第一个或者按某种规则合并 pass return list(seen.values())逻辑说明用字典的键做去重时间复杂度 O(n)。参数说明如果同一 MAC 有多个 IP说明设备有多网卡或走了 NAT这时候要结合交换机端口信息才能准确定位单靠扫描做不到。4. 避坑与排查扫描不到、扫错、扫崩的常见问题4.1 现象扫描结果只有网关和自己原因网卡不在目标网段或者虚拟机的网络模式是 NAT。NAT 模式下虚拟机在独立子网里ARP 广播出不去。解决把虚拟机网络改成桥接模式或者直接在宿主机上扫。如果是物理机检查子网掩码和 VLAN 配置确认自己确实在目标广播域内。4.2 现象能 ping 通但 ARP 扫不到原因对方在另一个网段中间隔了路由器。ARP 是二层协议路由器不转发广播。解决跨网段扫描改用 ICMP 或 SNMP或者登录路由器看 ARP 表。另一个可能是对方用了静态 ARP 绑定不回应动态请求这种情况只能查交换机 MAC 地址表。4.3 现象扫描速度极慢254 个地址跑了十分钟原因timeout 设太大或者无线网络重传严重。解决把 timeout 降到 1 秒retry 设为 0先快速扫一遍再对可疑地址单独重试。有线环境通常 254 个地址 3 到 5 秒能扫完。无线环境建议分批次每批 64 个地址避免广播风暴。4.4 现象扫出来的 MAC 全是 ff:ff:ff:ff:ff:ff原因抓包位置不对或者用了错误的接口。比如在 Docker 容器里扫看到的可能是虚拟网桥的广播帧。解决用ip link或ifconfig确认接口名指定物理网卡。Windows 上用Get-NetAdapter看接口描述选对的那个。4.5 现象扫描触发安全告警原因短时间内大量 ARP 请求会被入侵检测系统判定为 ARP 扫描攻击。解决降低发送速率加inter参数控制包间隔。生产环境扫描前先报备别在业务高峰期跑。5. 进阶技巧把扫描结果变成可查询的资产表5.1 用 SQLite 存历史扫描记录追踪设备上线离线单次扫描只能看到当前状态把每次结果写进数据库就能回答“这台设备什么时候第一次出现”“哪个 IP 昨天还在今天没了”。下面建表语句和插入逻辑。CREATE TABLE IF NOT EXISTS scan_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, scan_time TEXT NOT NULL, ip TEXT NOT NULL, mac TEXT NOT NULL, vendor TEXT, UNIQUE(scan_time, mac) ); CREATE INDEX idx_mac ON scan_history(mac); CREATE INDEX idx_time ON scan_history(scan_time);逻辑说明UNIQUE(scan_time, mac)防止同一秒重复插入。索引加在 mac 和 scan_time 上方便按设备或时间范围查询。参数说明scan_time 用 ISO8601 格式比如2025-01-15T10:30:00排序和比较都方便。5.2 对比两次扫描找出新增和消失的设备def diff_scans(old_devices, new_devices): old_macs {d[mac] for d in old_devices} new_macs {d[mac] for d in new_devices} added new_macs - old_macs removed old_macs - new_macs return added, removed逻辑说明用集合差集算新增和消失。参数说明如果设备换了网卡MAC 会变这种情况会被误判为“消失新增”。要避免的话得结合主机名或 DHCP 租约信息做关联。5.3 一个我常用的习惯扫描前先确认自己的网段每次跑扫描之前我都会先执行一条命令确认自己在哪个网段ip -4 addr show | grep inet或者 Windows 上Get-NetIPAddress -AddressFamily IPv4 | Select-Object IPAddress, PrefixLength这个习惯帮我省了很多后悔药。有一次我在 10.0.0.0/24 的机器上扫 192.168.1.0/24跑了半天一个结果没有还以为是工具坏了。后来发现是网段写错了。扫描这件事工具再强也救不了写错的 CIDR。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑