☰
ScanLan 局域网扫描:ARP 原理、Python 实现与设备清单管理
2026/10/8 10:35:51 网站建设 项目流程

简介:这是一份面向网络管理与安全初学者的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 需要先装 Npcap,Linux 直接 root 运行。

# arp_scan.py from scapy.all import ARP, Ether, srp import ipaddress def scan_lan(cidr): # 构造 ARP 请求:目标 MAC 为广播,目标 IP 为待探测地址 arp = ARP(pdst=cidr) ether = Ether(dst="ff:ff:ff:ff:ff:ff") packet = ether / arp # srp 发送并接收二层帧,timeout 控制等待时间,retry 控制重试次数 result = srp(packet, timeout=2, retry=1, verbose=False)[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(f"IP={d['ip']:<15} MAC={d['mac']}")

逻辑说明:ARP(pdst=cidr)里的pdst可以直接写 CIDR,scapy 会自动展开成多个目标地址。Ether(dst="ff:ff:ff:ff:ff:ff")是广播帧,保证同一广播域内所有网卡都能收到。srp是二层发送接收,返回两个列表,第一个是“请求-响应”配对。timeout=2表示等 2 秒,retry=1表示重试一次。参数怎么调:网段大就加大 timeout,无线环境丢包多就加 retry,但别超过 3,否则扫描时间线性增长。

2.3 不装 scapy 的替代方案:系统命令 + 正则解析

有些生产环境不让装第三方库,那就用系统自带命令。Linux 下arp-scan最直接,Windows 下可以用for /L循环 ping 一遍再读arp -a。

# Linux 安装 arp-scan 后执行 sudo arp-scan --interface=eth0 --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:i+2] 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', encoding='utf-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 位去匹配。参数说明:如果查不到,不要瞎猜,直接标“未知厂商”。有些虚拟机会用随机 MAC,OUI 查出来是 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。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询