一、前言
想要快速掌握局域网中有哪些设备、它们是什么类型(手机/电脑/摄像头/服务器)并长期留存记录?本篇提供一个超级轻量、可立刻落地的方案:使用 arp-scan 做局域网扫描、用 nmap 获取开放端口,Python 脚本解析并把结果写入 SQLite,再用简单规则(或自定义)做设备类型分类。覆盖 硬件(网卡/MAC/厂商)→ 网络(扫描/端口)→ 数据库(SQLite)→ 编程(Python 自动化),脚本短小易懂,适合家庭/小型办公室快速部署。

二、适用场景
- 快速盘点内网设备(谁在线、哪些 IP/ MAC)
- 定期扫描并记录设备行为变化(端口打开/关闭)
- 对可疑设备做简单分组与告警(例如出现未知服务器)
三、准备(示例基于 Debian/Ubuntu / Raspberry Pi OS)
sudo apt update
sudo apt install -y arp-scan nmap python3 python3-pip sqlite3
# 可选:用于更好地解析 nmap 输出
pip3 install prettytable
说明:
- arp-scan:快速发现同网段设备及厂商(需要 root 权限)
- nmap:探测常见端口,协助判断设备类型(也需要 root 做某些扫描)
- sqlite3:轻量数据库保存扫描记录
- Python:用来整合扫描并写入数据库
四、一次性快速手动扫描(验证环境)
切换到 root(或在命令前加 sudo):
sudo arp-scan –localnet
示例输出(简化):
192.168.1.2 00:11:22:33:44:55 Apple, Inc.
192.168.1.10 aa:bb:cc:dd:ee:ff Raspberry Pi Foundation
选取一台设备做端口扫描(示例扫描常见端口):
sudo nmap -Pn -p 22,80,443,554,8000 192.168.1.10
根据开放端口可以初步判断设备用途(例如 22 一般为 SSH;554 可能是 RTSP 摄像头)。
五、Python 自动化脚本(可直接运行)
把下面脚本保存为
/opt/net_finger/scan_and_store.py,并赋可执行权限 chmod +x
/opt/net_finger/scan_and_store.py。脚本做的事:
- 用 arp-scan 获取 IP/MAC/厂商;
- 对每台设备用 nmap 检查几个常用端口;
- 按规则分类设备类型(手机/电脑/摄像头/服务器/未知);
- 写入 SQLite(保留历史扫描记录,可用于趋势分析)。
#!/usr/bin/env python3
# /opt/net_finger/scan_and_store.py
import subprocess, sqlite3, time, os, shlex
DB = '/opt/net_finger/devices.db'
ARP_CMD = “arp-scan –localnet –retry=2 –timeout=200”
# 要检查的常见端口(可按需修改)
PORTS = “22,80,443,554,8000,1883,3306”
def run(cmd):
try:
out = subprocess.check_output(shlex.split(cmd), stderr=subprocess.DEVNULL, text=True)
return out
except subprocess.CalledProcessError as e:
return e.output or “”
def init_db():
os.makedirs(os.path.dirname(DB), exist_ok=True)
conn = sqlite3.connect(DB)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS scans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT,
mac TEXT,
vendor TEXT,
ports TEXT,
device_type TEXT,
ts INTEGER
)''')
conn.commit()
conn.close()
def parse_arp(output):
# arp-scan 输出中每行一般:IP MAC VENDOR
devices = []
for line in output.splitlines():
parts = line.split()
if len(parts) >= 3 and parts[0][0].isdigit():
ip = parts[0]
mac = parts[1]
vendor = ' '.join(parts[2:])
devices.append((ip, mac, vendor))
return devices
def scan_ports(ip):
# 用 nmap 快速扫描指定端口,返回开放端口列表字符串
cmd = f”nmap -Pn -p {PORTS} {ip} –open –min-rate 1000 -T4″
out = run(cmd)
open_ports = []
for line in out.splitlines():
line = line.strip()
# nmap 端口行示例:22/tcp open ssh
if “/tcp” in line and “open” in line:
try:
port = line.split('/')[0]
open_ports.append(port)
except:
pass
return ','.join(open_ports)
def classify_device(vendor, open_ports):
low = vendor.lower()
ports = set(open_ports.split(',')) if open_ports else set()
# 简单规则优先匹配
if 'camera' in low or 'hikvision' in low or 'dahua' in low or 'rtsp' in low or 'ipcam' in low:
return 'Camera'
if 'raspberry' in low or 'pi foundation' in low:
# Raspberry Pi 一般是开发板,可能作为服务器/edge
if '22' in ports or '3306' in ports:
return 'Server/Edge'
return 'Embedded'
if 'apple' in low or 'samsung' in low or 'huawei' in low or 'xiaomi' in low:
return 'Phone/Tablet'
# 端口判定
if '22' in ports and ('80' in ports or '443' in ports):
return 'Server'
if '554' in ports or '8000' in ports:
return 'Camera/Stream'
if '1883' in ports:
return 'IoT (MQTT)'
# fallback
if ports:
return 'Unknown (ports)'
return 'Unknown'
def main():
init_db()
print(“Running ARP scan (need sudo)…”)
arp_out = run(ARP_CMD)
devices = parse_arp(arp_out)
ts = int(time.time())
conn = sqlite3.connect(DB)
c = conn.cursor()
for ip, mac, vendor in devices:
print(f”Found {ip} {mac} {vendor}”)
ports = scan_ports(ip)
dtype = classify_device(vendor, ports)
c.execute('INSERT INTO scans (ip,mac,vendor,ports,device_type,ts) VALUES (?,?,?,?,?,?)',
(ip, mac, vendor, ports, dtype, ts))
conn.commit()
print(f” -> ports: {ports or '-'} type: {dtype}”)
conn.close()
print(“Scan finished.”)
if __name__ == “__main__”:
main()
注意事项:
- 该脚本需以 root 或 sudo 运行,由于 arp-scan 与 nmap 部分扫描需要特权:sudo python3 /opt/net_finger/scan_and_store.py。
- nmap 的一些扫描选项会触发 IDS,生产环境使用时请提前沟通网络管理策略。
- 规则式分类简单可用;若你想更智能,可把历史 scans 表导出做机器学习训练(后续可扩展)。
六、定时与查看结果
把脚本加入 root 的 cron(例如每天凌晨 3 点):
sudo crontab -e
# 添加
0 3 * * * /usr/bin/python3 /opt/net_finger/scan_and_store.py >/var/log/net_finger_scan.log 2>&1
查看最近 50 条扫描记录:
sqlite3 /opt/net_finger/devices.db “SELECT datetime(ts,'unixepoch','localtime'),ip,mac,vendor,ports,device_type FROM scans ORDER BY ts DESC LIMIT 50;”
快速统计每类设备数量(按最新一次记录计算)
# 获取每ip的最新记录并统计 device_type
sqlite3 /opt/net_finger/devices.db <<'SQL'
WITH latest AS (
SELECT ip, device_type, max(ts) as mts FROM scans GROUP BY ip
)
SELECT device_type, count(*) FROM latest GROUP BY device_type;
SQL
七、常见问题与排查
- 没有发现设备? 确认脚本在与目标设备同一网段(arp-scan 只扫描本地网段),且网段内无 VLAN 隔离。
- nmap 太慢或被阻断? 可缩减 PORTS 列表为你关心的端口,或在 nmap 中降低扫描侵略性(移除 -T4)。
- 权限问题? 请用 sudo 执行脚本(或给 arp-scan 与 nmap 特权)。
- 分类不准确? 修改 classify_device() 的规则,或导出数据用简单的 ML(例如决策树)训练一个模型替换规则。
八、扩展提议(非必须)
- 将结果写入 InfluxDB/Prometheus 并用 Grafana 可视化在线/离线设备趋势。
- 把 vendor 对应的 OUI 表本地缓存,以便更准确地识别厂商。
- 对特定设备(如摄像头)设置端口/固件变更告警(出现新开端口或未知设备则邮件提醒)。
- 收集多次扫描数据训练一个简单的分类模型(scikit-learn)提高识别准确率。
九、总结
本文给出了一套轻量且可复制的局域网设备指纹方案:从硬件(MAC、厂商)与网络(端口)入手,用简单 Python 脚本写入 SQLite 并用规则做归类。脚本短小、依赖少,适合立刻在 Raspberry Pi 或任意 Linux 机上跑通并长期记录网络内设备变化。
