kw123/Network-Scanner

GitHub: kw123/Network-Scanner

Indigo智能家居平台的网络扫描插件,通过多种探测方式发现并持续监控局域网设备的在线状态、IP地址和开放端口,支持家庭自动化联动。

Stars: 0 | Forks: 0

# 网络扫描仪 – Indigo 插件 - **发现所有设备**:扫描本地局域网,并为发现的每个唯一 MAC 地址创建一个 Indigo 设备。 设备的开/关状态反映了物理设备当前在网络中是否可达。 除了基本的局域网扫描外,该插件还提供: - **互联网 Ping 设备** — 按固定间隔通过 ICMP ping 监控外部主机(Google、Yahoo、自定义主机名等)。可通过 *Add Internet Ping Devices…* 一键创建。 - **互联网地址设备** — 追踪本机的公有 (WAN) IP;当 IP 发生变化时发出警报。通过 *Add Internet Address Device…* 创建。 - **在家或离家聚合** — 监控最多 6 个网络设备;当至少有一台设备在家时为 ON,全部离家时为 OFF。可用于在有人到达或离开时触发自动化。 - **在线 / 离线聚合** — 监控最多 3 个外部设备;当至少有一台设备可达时为 ON,全部失败时为 OFF。即时的互联网连接/断开指示器。 - **按需 Ping** — 从插件菜单 ping 任何 IP 或 DNS 主机名;结果写入 `networkScanner_pingDevice` 变量。 ## 系统要求 无需第三方包。 - **`/usr/sbin/tcpdump`** — 被动流量嗅探,捕获 ARP、mDNS(端口 5353)和 DHCP(端口 67/68) - **`/usr/sbin/arp`** — 扫描后读取 ARP 缓存 - **`/sbin/ifconfig`** — 确定本地子网(IP 和网络掩码) - **`Python socket`** — ICMP ping(`SOCK_DGRAM / IPPROTO_ICMP`)和 TCP 连接探测(`SOCK_STREAM`)—— 无需子进程,无需 root 权限 - **`MAC2Vendor.py`** — 内置的 OUI 供应商查询,首次运行时自动下载 IEEE 表并在本地缓存 ## 发现方法 1. **被动流量嗅探** — `tcpdump` 监听 ARP、mDNS(端口 5353)和 DHCP(端口 67/68)。任何匹配的数据包都会更新设备的最后出现时间戳。能够捕获抑制 ARP 的设备(iOS 隐私模式、虚拟机、IoT)。每个 MAC 每隔 30 秒最多触发一次 Indigo 更新。如果 tcpdump 尚未获得 BPF 授权,则需要 sudo 密码。 2. **主动 ARP 扫描** — 向子网上的每个主机并行发送 ICMP ping,然后使用 `arp -a` 读取内核 ARP 缓存。只有实际响应 ping 或 TCP 探测的设备才会更新其最后出现时间。陈旧的缓存条目不计为在线。处理完成后,插件会运行 `sudo arp -d -a` 刷新 ARP 缓存,这样已关机设备的陈旧条目就不会保留到下一个周期(需要 sudo 密码)。`arp -a` 的输出还会捕获每个设备的网络接口(`en0` = Wi-Fi,`en1` = 以太网),并存储在 `networkInterface` 中。 3. **周期性可达性探测** — 每次扫描间隔运行: - 通过 Python socket 进行 ICMP ping(无子进程,无需 root)— 记录往返时间(`pingMs`)和 IP TTL。 - 当没有更好的来源时,TTL 用于推导备选操作系统提示:128 → Windows · 64 → Linux / macOS / iOS · 255 → 路由器 / 网络设备。 - 如果 ICMP 被阻止,则回退到 TCP 连接,依次探测端口 80 → 443 → 22 → 8080。`ConnectionRefusedError` 也被视为存活。 - 记住每个设备成功连接的 TCP 端口,并在下次探测时优先尝试。 - 连续 5 次全端口失败后,TCP 探测将被挂起(当 ping 成功时自动重置)。 - 每台设备的 **仅 Ping** 选项会完全跳过 TCP 回退。 - **扫描新鲜度跳过:** 如果 ARP 扫描在过去的 `扫描间隔 − 10 秒` 内确认了非仅 Ping 设备,则跳过该设备的独立探测 —— 直接使用扫描结果,减少冗余探测。仅 Ping 设备有自己独立的自适应计时器(见下文)并单独处理:如果 ARP 扫描在过去 10 秒内 ping 过相同的 IP,则会跳过该周期的专用仅 Ping 探测并推进计时器,从而防止重复 ping。 - **误报防护(确认模式):** 当当前处于离线状态的设备收到 ICMP 响应时,在将设备重新上线之前会运行 TCP 探测进行确认。路由器会为最近断开连接的客户端代理 ICMP,但从不会代理 TCP,因此 TCP 回复证明了设备自身的协议栈是存活的。如果 TCP 以前对该设备有效(已设置 `curlPort`)但现在失败,则设备保持离线 —— 没有第二次 ICMP 回退(代理 ARP 可以伪造它)。第二次 ICMP 仅用于 TCP 确实从未工作过的设备(没有开放端口的纯 IoT 设备)。 - **误报防护(仅 Ping 模式):** ARP 扫描可能会在设备离线时通过代理 ARP 回复重置 `last_seen`,从而阻止离线阈值过期。`仅 Ping` 设备使用独立的 `ping_only_last_ping_ok` 时间戳,该时间戳仅由专用的 ICMP 探测更新 —— 从不通过 ARP 扫描更新。离线阈值根据此时间戳进行衡量,从而使其免受代理 ARP 扫描噪声的影响。 4. **DHCP 丰富信息** — 独立的 DHCP 嗅探器(在端口 67/68 上使用 `tcpdump -vv`)提取: - **选项 12**(主机名)→ `dhcpHostname`。仅在设备发送 DHCP 请求时填充 —— 通常在首次连接或租约续订时(对于已连接的设备可能需要数小时)。 - **选项 55**(参数请求列表)→ `dhcpOsFingerprint`。选项编号的序列可作为操作系统指纹:Windows `{249,252}` · Apple macOS/iOS `[_, 121, ...]` · Linux `{28,2}` · Android `{33,26}`。时间限制与 dhcpHostname 相同。 5. **mDNS / Bonjour 丰富信息** — `dns-sd` 每 5 分钟浏览所有广播的服务类型并解析 TXT 记录: - `md=` 字段 → `mdnsModel`(例如 `HomePod mini`、`BRAVIA XR`) - `am=` 字段 → `appleModel`(Apple 内部型号代码,例如 `AudioAccessory1,1`) - `osxvers=` 字段 → `osVersion`(macOS/iOS 内核版本) - 广播的服务类型 → `mdnsServices` 以及 → `deviceType`(通过优先级排序的服务映射推导:`_airplay._tcp` = 智能扬声器 / AV · `_ipp._tcp` = 打印机 · 等等) - 只有**主动广播 mDNS 服务**的设备才会填充这些状态。通用路由器、许多 Android 设备和大多数 Windows PC 不会。 ## 插件配置 *Plugins → Network Scanner → Configure…* - **网络接口** — 用于嗅探的接口(例如 `en0`、`eth0`)。留空以自动检测。*(默认: 自动)* - **sudo 密码** — macOS 登录密码,以便 tcpdump 可以打开 BPF socket。如果 tcpdump 已拥有该授权,则留空。 - **扫描间隔 (秒)** — 探测已知设备的频率。选项:30 / 60 / 90 / 120。*(默认: 60)* - **启用 ARP 扫描** — 每次扫描周期进行主动子网扫描。*(默认: 开启)* - **启用被动流量嗅探** — 在扫描间隔期间监听 ARP / mDNS / DHCP 流量。*(默认: 开启)* - **启用主动 mDNS 查询** — 在每次 ARP 扫描开始时发送 mDNS PTR 查询,提示所有支持 mDNS 的设备进行自我宣告。对于隐藏在代理 ARP AP 后的设备很有用。*(默认: 关闭)* - **离线阈值 (秒)** — 不可达多长时间后 → 标记为离线。选项:30–600 秒。*(默认: 180)* - **自动创建设备** — 为每个新发现的 MAC 地址创建一个 Indigo 设备。*(默认: 开启)* - **为仅 Ping 主机创建合成设备** — 如果某个 IP 响应 ping 但从未出现在 ARP 中(例如不同的 VLAN),则使用合成 MAC `00:00:00:00:00:XX` 创建一个设备。除非您需要跨 VLAN 监控,否则请保持关闭 —— 有些路由器会回复每个子网 IP 的 ping,导致插件充斥着幽灵设备。*(默认: 关闭)* - **翻转地址/备注列** — 同时交换所有插件设备的地址和备注列。关闭 (默认):地址 = MAC / 主机,备注 = IP。开启:地址 = IP,备注 = MAC / 主机。在保存时立即生效 —— 所有设备将一次性更新。*(默认: 关闭)* - **设备文件夹名称** — 用于存放 `Net_*` 设备的 Indigo 文件夹(自动创建)。留空表示根目录。*(默认: Network Devices)* - **变量文件夹名称** — 用于存放插件管理变量的 Indigo 变量文件夹。自动创建。留空表示根目录。 - **前缀名称** — 自动命名设备的前缀(例如 `Net_` → `Net_AA:BB:CC:DD:EE:FF`)。*(默认: Net_)* ### 快速设置按钮 - **▶ 立即激活追踪** — 验证 *Track Specific Device* 中的 MAC/IP,并立即开始详细追踪 —— 无需保存。 - **■ 停止追踪** — 立即清除追踪设备列表。 - **关闭所有逐设备日志** — 一键将每个受管网络设备上的 *Log Every Seen Event to File* 设置为 `false`。 ### 日志选项 - **记录新设备创建** — 在为 MAC 自动创建新的 Indigo 设备时进行记录。 - **记录在线 / 离线变化** — 将在线 ↔ 离线状态转换记录到 `plugin.log`。每条消息都包含来源,例如 *"Device X is now ONLINE via sweep (arp)"* 或 *"is now OFFLINE [timeout]"*。 - **记录 IP 地址变化** — 在设备的 IP 地址发生变化时进行记录。 - **记录每个设备被看见** — 详细的按数据包记录(内容较多)。 - **记录 ARP 扫描活动** — 记录扫描开始/结束以及 ARP 缓存刷新。 - **记录跳过的忽略 MAC** — 每次看到被忽略的 MAC 时进行记录。 - **记录 Ping / 探测结果** — 记录每个 ICMP ping 和 TCP 探测结果(在扫描期间内容较多)。 - **记录 Tcpdump ARP 回复** — 记录由 tcpdump 捕获的每个 ARP 回复,包括被限制频率的回复(内容极多)。 - **记录 ARP 扫描条目** — 记录在每次扫描期间从 `arp -a` 解析出的每个条目。 ### 逐设备诊断追踪 **追踪特定设备(MAC 或 IP)** — 在配置对话框的调试部分输入一个或多个以逗号分隔的 MAC 地址 (`aa:bb:cc:dd:ee:ff`) 或 IP 地址 (`192.168.1.5`)。 使用 **▶ 立即激活追踪** 按钮可立即开始追踪 —— 无需保存对话框。使用 **■ 停止追踪** 取消。当插件重启时,追踪总是会被自动清除,因此它绝不会在后台悄无声息地保持开启。 激活时,涉及所列出设备的每个事件都会以 `[TRACE ]` 前缀写入 `plugin.log` 中的 DEBUG 级别: - **`raw-tcpdump`** — 完整的原始 tcpdump 输出行(在任何解析或限制频率之前) - **`sniff-ARP-reply`** — 从 tcpdump 解析的 ARP 回复 - **`sniff-frame`** — 提取了源 MAC + IP 的非 ARP 帧 - **`arp-a`** — 在扫描期间从 `arp -a` 解析的条目,带有 `replied` 标志 - **`_register_device`** — 每次更新 `_known` 并推送到 Indigo 的调用,带有 `source`、`changed_ip`、`skip_push` - **`ping-recheck`** — 离线到在线确认结果(ICMP+TCP 保护) - **`_state_update`** — 每次 Indigo 状态写入 —— `online_changed`、`source`、`ip_changed` ## 设备类型 ### 网络设备 (`Net_*`) 每个被发现的 MAC 地址对应一个设备。当 **自动创建设备** 开启时自动创建。 - **地址列**MAC 地址(或当 *翻转地址/备注列* 开启时补位的 IP) - **备注列**:最后一部分被零补位的 IP(例如 `192.168.1.005`),以便按 IP 正确进行字母排序(或当 *翻转* 开启时的 MAC) - 名称以 `Net_AA:BB:CC:DD:EE:FF` 开始,然后在获知供应商/本地名称后自动重命名 ### 外部设备 按固定间隔 ping 的手动配置主机(IP 地址或 DNS 名称)。不进行 MAC 追踪 —— 适用于监控互联网连接。通过 *New Device → External Device* 创建,或使用插件菜单中的 **Add Internet Ping Devices…**。 - **地址列**:配置的主机名 / IP(或当 *翻转地址/备注列* 开启时解析的 IP) - **备注列**:解析的 IP 地址(或当 *翻转* 开启时的主机名),在每次 ping 时实时更新 ### 网络设备 — 在家或离家 监控最多 **6 个网络设备** 并追踪在场的聚合设备。 - **ON** — 至少有一个受监控的设备在线(“有人在家”) - **OFF** — 所有受监控的设备均离线(“所有人离开”) - `ParticipantsHome` — 当前在线的参与者数量 - `participants` — 所有已配置槽位的 Indigo 设备 ID,以逗号分隔 - **地址列** — 所有参与者的 MAC 地址(以空格分隔),实时更新。当 *翻转地址/备注列* 开启时:紧凑的 IP 摘要 —— 如果所有参与者共享同一个 /24 子网,则公共前缀只显示一次(例如 `192.168.1. 112 22 44`);否则显示完整 IP。 - **备注列** — 以紧凑形式显示的当前 IP 地址(例如 `192.168.1. - 12 15 25`),实时更新(或当 *翻转* 开启时的 MAC) **转为 OFF 前的延迟** — 当所有参与者离线时,设备翻转为 OFF 之前的可选宽限期(0 / 10 / 20 / 30 / 60 / 90 / 120 / 180 秒)。如果在延迟期间有任何参与者重新上线,OFF 转换将被取消,设备保持 ON。适用于吸收短暂的 WiFi 断开或代理 ARP 时间伪影,否则这些情况会过早触发离家自动化。默认为 0(立即)。 在 Indigo 条件中使用 `ParticipantsHome` 状态可检查是否 *至少有 N* 个人在家。 ### 外部设备 — 在线 / 离线 监控最多 **3 个外部设备** 并追踪互联网连接的聚合设备。 - **ON** — 至少有一个受监控的外部设备可达 - **OFF** — 所有受监控的外部设备均离线(互联网似乎断开) - `ParticipantsOnline` — 当前可达的参与者数量 - `participants` — 所有已配置槽位的 Indigo 设备 ID,以逗号分隔 - **地址列** — 创建时设置一次:被剥离了 `www.` 和 TLD 的受监控主机名,由 `·` 分隔(例如 `google · yahoo · welt`)。从不被覆盖。 - **备注列** — 首次保存时写入一次,格式为 `id,id,id - host,host,host`;从不被覆盖 ### 互联网地址 监控此机器的公有 (WAN) IP 地址。以可配置的间隔从知名的 IP 回显服务获取,并将结果存储在 `publicIp` 状态中(在 Indigo 设备列表中显示为设备显示状态)。 - **显示状态**:`publicIp` — 显示为 `on 203.0.113.42` 或 `off 203.0.113.42`,因此状态和 IP 可以一目了然。状态*值*(用于触发器和脚本)始终只是纯粹的 IP 地址。 - **ON** — 上次获取成功 - **OFF** — 所有服务不可达(互联网似乎断开) - **地址列** — 当前公有 IP 地址,在每次成功获取时更新 - **备注列** — 反映当前公有 IP 以便于阅读 **按顺序尝试的服务**(第一个响应的获胜):`api.ipify.org` → `checkip.amazonaws.com` → `icanhazip.com`。每个都有 10 秒的超时时间。 通过 *Plugins → Network Scanner → Add Internet Address Device…* 创建(可多次点击 —— 如果设备已存在则会跳过)。 ## 设备编辑 — 网络设备 *双击任何 `Net_*` 设备* ### Ping / 探测使用 探测在被动检测(ARP 扫描 + tcpdump)**基础上**运行。被动检测在看到流量时总是立即将设备标记为在线;探测则增加了主动确认的第二层。 **谁胜谁负 —— 失败的 ping 对比最近的被动发现?** - **AND** *(默认)* — 被动发现胜出。最近的 ARP/tcpdump 发现使 `timed_out = false` 保持不变,因此单次失败的 ping 无法自行使设备离线。 - **OR** — Ping 胜出。仅凭连续失败即可触发离线,即使 ARP/tcpdump 不久前还看到过该设备。 Ping **成功**无论在哪种模式下总是获胜 —— 设备立即上线。 **探测模式选项:** - **Online + Offline** — 探测是对被动检测的补充。成功 → 立即在线;失败 → 仅在达到阈值 + 连续失败条件时离线 (AND/OR)。优先使用 ICMP,如果 ICMP 被阻止则回退到 TCP。*适用于:同时响应 ping 和 TCP 的可靠设备。* - **仅在线** — 探测只能标记在线,从不标记离线。超时仍由被动超时处理。*适用于:快速恢复检测 —— 手机带回家。* - **仅离线** — 探测只能标记离线,从不标记在线。上线仍由被动检测处理。*适用于:快速离线检测。* - **确认离线** *(默认)* — 探测仅在超出 ARP/嗅探超时后触发;流量较少的静默设备。*适用于:大多数局域网设备。* - **仅 Ping** — 仅使用 ICMP(无 TCP 回退),自适应 60 秒 / 15 秒间隔 —— 见下文。*适用于:路由器、相机、打印机、手动添加的设备。* - **完全不** — 忽略探测;离线完全由 ARP/嗅探超时决定。*适用于:被动检测已足够。* #### 仅 Ping — 自适应计时 **仅 Ping** 使用独立于全局扫描间隔运行的专用探测调度(扫描循环每 15 秒检查一次仅 Ping 设备,因此无论扫描周期如何,自适应计时器都会准时触发): - **在线** — 每 60 秒(或如果已设置,则为 *Online Ping Interval*)探测一次。仅在 *Offline Threshold* 超时后才转为离线 —— 单次遗漏的 ping 绝对不够。 - **离线** — 每 15 秒(或如果已设置,则为 *Offline Check Interval*)探测一次。首次成功 ping 后立即转为在线。 离线阈值是根据 `ping_only_last_ping_ok` 来衡量的 —— 这是一个仅当专用探测本身成功时才更新的时间戳。ARP 扫描可能会收到离线设备的代理 ARP 回复,否则会重置 `last_seen`,从而导致阈值永远无法过期。`ping_only_last_ping_ok` 不受扫描结果的影响。 这使其适用于抑制 ARP 和 mDNS 的设备(路由器、相机、打印机),以及使用自定义 MAC 手动添加且不指望有被动流量的设备。此模式下不使用 *Offline Trigger Logic* 和 *Missed Pings Before Offline* 设置 —— 仅由阈值控制开→关的转换。 #### 仅 Ping — 失败时快速重试 当 *Offline Trigger Logic* 设置为 **OR** 且第一次 ping 在设备在线时失败,插件会立即在 3 秒内发送 **2 次额外的 ICMP ping**,然后才接受该失败 —— 这模仿了 `ping -c 3 -i 3` 的行为。单个丢失的数据包可以在约 6 秒内被确认或排除,而不是等待下一个 15 秒的轮询周期。 - **AND** *(默认)* — 没有重试。在离线成为可能之前,阈值必须也过期;一次失败已经是安全的。等待下一次 15 秒的轮询。 - **OR** — 2 次重试,间隔 3 秒(总共约 6 秒)。只有当全部 3 次都失败时才离线。 ### 离线触发逻辑 - **AND** *(默认)* — 超时已过 AND 探测失败 —— 误报最少。 - **OR** — 超时已过 OR 探测失败 —— 更快的离线检测。 ### 其他设置 - **离线前的遗漏 Ping 次数** — 触发离线前的连续探测失败次数(1-5)。在 *仅 Ping* 模式下不使用。*(默认: 1)* - **离线检查间隔** — 当设备离线时,为了检测恢复而进行探测的频率。仅在启用了 ping 时生效(除了 *完全不* 之外的任何模式)。`0` = 使用全局扫描间隔。较小的值能更快地捕捉到恢复,但代价是发送更多的 ping。在 *仅 Ping* 模式下不使用(它有自己 15 秒的自适应计时器)。*(默认: 0)* - **在线 Ping 间隔** — 设备在线时对其进行 ping 的频率。`0` = 默认值(*仅 Ping* 模式下为 60 秒;其他模式下为全局扫描间隔)。增加此值可减少稳定设备的流量;减少此值可加快重新确认。建议:设置为 *Offline Threshold* 的 30–50 %,以便设备在超时前至少被确认两次。适用于所有活动的 ping 模式。*(默认: 0)* - **离线阈值 (秒)** — 逐设备覆盖;`0` = 使用插件范围的默认值。在 *仅 Ping* 模式下,这是触发离线的唯一条件。*(默认: 0)* - **设置 IP 地址** — 手动覆盖此设备的 IP 地址。存储在 `ipNumber` 状态和 `known_devices.json` 中。如果在下次扫描时发现设备使用了不同的 IP,它将被覆盖。 - **是 AP 或路由器** — 将此设备标记为代理 ARP AP 或路由器。来自被动嗅探线程的 IP 更改将被忽略;只有 ARP 扫描才能更新其 IP。当在 10 分钟内检测到 3 次或更多次 IP 更改时会自动设置。可在此处清除以重新启用自动检测。*(默认: 关闭)* - **备注** — 存储在 `comment` 状态中的自由文本备注。 - **禁止 IP 更改日志记录** — 静默此设备的 IP 更改日志条目。*(默认: 关闭)* - **将每次发现事件记录到文件** — 每次看到此设备时写入一条 `plugin.log` 条目。*(默认: 关闭)* ## 设备状态 — 网络设备 - **`onOffState`** (布尔值) — `True` = 在线,`False` = 离线 - **`ipNumber`** (字符串) — 最近出现的 IP 地址 - **`previousIps`** (字符串) — 此设备最近使用的 10 个 IP 地址及日期,例如 `192.168.1.100 (2026-04-20) | 192.168.1.101 (2026-04-19)`。每次 IP 更改时更新。 - **`MACNumber`** (字符串) — MAC 地址 - **`mdnsName`** (字符串) — 来自 mDNS / Bonjour SRV 记录的主机名(例如 `iPhone-Karl.local`)。由被动嗅探线程和 mDNS 浏览填充。 - **`arpHostname`** (字符串) — 来自 `arp -a` 输出的主机名 —— 即 macOS 为该 IP 解析 Bonjour 名称时的第一个字段(例如 `iphone.localdomain`)。每次 ARP 扫描时更新。仅在找到真实名称(不是 `?`)时设置。 - **`hardwareVendor`** (字符串) — 来自内置 OUI 表的制造商 - **`dhcpHostname`** (字符串) — 来自 DHCP 选项 12 的设备主机名,在 DHCP 请求/续订时填充(例如 `Karl-iPhone`)。 - **`dhcpOsFingerprint`** (字符串) — 从 DHCP 选项 55 参数请求列表得出的操作系统猜测:`Windows` · `Apple (macOS/iOS)` · `Linux` · `Android`。仅在 DHCP 事件时填充。 - **`mdnsServices`** (字符串) — 此设备广播的以逗号分隔的 mDNS 服务类型(例如 `_airplay._tcp, _raop._tcp`)。累积性 —— 服务只会被添加,从不会被移除。 - **`mdnsModel`** (字符串) — 来自 mDNS TXT `md=` 字段的设备型号字符串(例如 `HomePod mini`、`BRAIA XR`)。 - **`deviceType`** (字符串) — 从广播的 mDNS 服务推导出的设备类别(例如 `Smart Speaker / AV` · `Printer` · `NAS / Server`)。仅为广播 mDNS 的设备设置。 - **`appleModel`** (字符串) — 来自 mDNS TXT `am=` 字段的 Apple 内部型号代码(例如 `AudioAccessory1,1`、`iPhone14,5`)。仅限 Apple 设备。 - **`osVersion`** (字符串) — 来自 mDNS TXT `osxvers=` 字段的 macOS / iOS 内核版本。仅限 Apple 设备。 - **`osHint`** (字符串) — 最佳猜测的操作系统:`Windows` · `Linux/macOS/iOS` · `Android` · `Cisco/Network`。源自 DHCP 供应商类别(选项 60)、DHCP 选项 55 指纹,或作为最后手段的 IP TTL。 - **`networkInterface`** (字符串) — 设备最后出现的网络接口,来自 `arp -a` 输出(例如 `en0` = Wi-Fi,`en1` = Ethernet)。 - **`pingMs`** (字符串) — 最后一次 ICMP 往返时间,单位为毫秒(例如 `12 ms`)。仅在 RTT 变化超过 40% 且大于 20 ms 时更新。 - **`changeToOn`** (字符串) — 最近一次离线 → 在线转换的时间戳 (`YYYY-MM-DD HH:MM:SS`)。 - **`changeToOff`** (字符串) — 最近一次在线 → 离线转换的时间戳 (`YYYY-MM-DD HH:MM:SS`)。 - **`lastOnOffChange`** (字符串) — 最近一次在线 ↔ 离线转换的时间戳。 - **`created`** (字符串) — Indigo 设备首次创建时的时间戳。 - **`openPorts`** (字符串) — 上次端口扫描中发现的开放 TCP 端口,以逗号分隔。 - **`comment`** (字符串) — 在设备编辑中设置的自由文本备注。 - **`isApOrRouter`** (布尔值) — 当设备是代理 ARP AP 或路由器时为 `True`。在 10 分钟内发生 3 次或更多次 IP 更改后自动设置,或者在设备编辑中手动设置。当为 `True` 时,来自被动嗅探的 IP 更新会被抑制 —— 只有 ARP 扫描才能更改 IP。 - **`pingMode`** (字符串) — 从设备设置同步的 Ping/探测模式(例如 `both`、`confirm`、`none`)。 - **`lastOnMessage`** (字符串) — 最近一次在线确认的时间戳 (`YYYY-MM-DD HH:MM`)。在设备在线期间最多每分钟更新一次。 - **`setOnBy`** (字符串) — 最后将设备设为在线的机制:`sweep (arp)` · `traffic observed (tcpdump)` · `ping(ICMP)` · `tcp:`。 - **`setOffBy`** (字符串) — 最后将设备设为离线的机制:`timeout` · `probe`。 - **`fingscanDeviceInfo`** (字符串) — 通过迁移工具导入的 Fing 扫描信息。 ## 设备状态 — 外部设备 - **`onOffState`** (布尔值) — `True` = 可达,`False` = 离线 - **`host`** (字符串) — 配置的主机名或 IP - **`ipNumber`** (字符串) — 解析的 IP 地址 - **`pingMs`** (字符串) — 最后一次 ping 往返时间(例如 `12 ms`)或 `timeout` - **`lastOnOffChange`** (字符串) — 最近一次在线 ↔ 离线转换的时间戳 - **`comment`** (字符串) — 自由文本备注 ## 设备状态 — 聚合设备 适用于 **网络设备 — 在家或离家** 和 **外部设备 — 在线 / 离线**。 - **`onOffState`** (布尔值) — `True` = 至少有一名参与者在线/在家 - **`ParticipantsHome`** / **`ParticipantsOnline`** (整数) — 当前在线/在家的参与者数量 - **`participants`** (字符串) — 所有已配置槽位的 Indigo 设备 ID,以逗号分隔 - **`lastOnOffChange`** (字符串) — 最近一次开/关转换的时间戳 - **`comment`** (字符串) — 自由文本备注 ## 设备状态 — 互联网地址 - **`onOffState`** (布尔值) — `True` = 上次获取成功,`False` = 所有服务不可达 - **`publicIp`** (字符串) — 当前公有 (WAN) IP 地址。状态*值* = 纯 IP;在 Indigo 设备列表中显示为 `on 203.0.113.42` / `off 203.0.113.42`。 - **`previousIp`** (字符串) — 最近一次更改前的 IP 地址 - **`lastChanged`** (字符串) — `publicIp` 最近一次更改的时间戳 - **`lastSuccessfulUpdate`** (字符串) — 最近一次成功获取的时间戳 (`YYYY-MM-DD HH:MM:SS`) - **`lastFailedUpdate`** (字符串) — 最近一次失败获取的时间戳 (`YYYY-MM-DD HH:MM:SS`) - **`comment`** (字符串) — 自由文本备注 ## 新设备通知 每当一个新的 MAC 地址被自动创建为 Indigo 设备时,变量 `networkScanner_newdevice` 就会被更新为 `{deviceId} {timestamp}`。 **使用方法:** 在 *Variable Changed → networkScanner_newdevice* 上创建一个 Indigo 触发器,然后添加一个 **Run Script** 动作: ``` info = indigo.variables["networkScanner_newdevice"].value ipDevVarNumber = int(info.split(" ")[0]) dev = indigo.devices[ipDevVarNumber] st = dev.states # shortcut theSubject = "new device on network " + dev.name theBody = "new device on network: " + dev.name + "\n" theBody += "ipNumber: " + st["ipNumber"] + "\n" theBody += "MACNumber: " + st["MACNumber"]+ "\n" theBody += "hardwareVendor: " + st["hardwareVendor"]+ "\n" theBody += "indigoID: " + str(dev.id) + "\n" indigo.server.log(theBody) indigo.server.sendEmailTo("your email address", subject=theSubject, body=theBody) ``` ## 插件变量 - **`networkScanner_newdevice`** — 每次自动创建新的网络设备时更新。值:`{deviceId} {timestamp}`。如果不存在,则在启动时创建。放置在已配置的变量文件夹中。 - **`networkScanner_pingDevice`** — 在每次手动 ping(菜单项、动作或 Add Internet Ping Devices)后更新。值:`{ip} {ms}ms on/off`(例如 `142.250.80.46 22ms on`)。如果不存在,则在启动时创建。 ## 插件菜单 *Plugins → Network Scanner* - **强制立即重新扫描** — 立即触发 ARP 扫描 + ping 检查。 - **Ping 设备 (IP 或 DNS)…** — 输入任意 IP 地址或 DNS 名称,点击 PING。结果将被记录并作为 `{ip} {ms}ms on/off` 写入 `networkScanner_pingDevice`。 - **添加互联网 Ping 设备…** — 从 Google、Yahoo、Microsoft、CNN、Siemens、SAP、Indigodomo 中选择,或输入自定义主机名。为每个选定的主机创建外部设备条目 —— 设备名称为 `Ping-{host}`。可安全多次运行 —— 跳过已存在的主机。还包含一个 **Add Internet Address device** 按钮。 - **对所有在线设备执行广泛端口扫描…** — 对每个在线设备的所有 25 个已知端口进行 TCP 连接扫描。菜单触发的运行是详细的:显示每台设备的所有已发现端口;新发现的端口会被标记为 `++++ new ++++`。它还会在凌晨 02:00 之后的夜间自动以静默模式运行一次 —— 仅打印有新发现端口的设备,如果没有变化则打印 `no new ports found`。 - **设置设备的状态…** — 手动覆盖任何插件设备上的任何状态。 - **打印工具…** — 综合报告对话框: - *所有已发现的设备* — 将所有已知 MAC 及其 IP、本地名称、供应商、开/关状态和最后出现时间打印到 plugin.log。 - *按操作系统 / 端口 / 类型分组的设备* — 按 `osHint`、`osVersion`、`dhcpOsFingerprint`、`deviceType`、`networkInterface` 和开放端口对 networkDevices 进行分组。仅显示已填充的存储桶。 - *IP 地址发生变化的设备* — 列出自插件启动以来 IP 地址发生变化的设备。 - *状态为空的设备* — 列出在所有 networkDevice 中均未填充内容的丰富信息状态名称。 - *不稳定性报告* — 列出具有非常短的开/关间隔的设备(可配置的截断时间:1-8 分钟)。 - *出现间隔统计* — 每台设备被发现频率的直方图;按 IP / 名称 / 最后出现时间排序。 - *重置出现间隔计数器* — 清除所有设备的直方图计数器。 - **管理被忽略的 MAC 地址…** — 将特定的 MAC 从扫描中排除/重新纳入。 - **追踪设备 / 日志工具…** — 按 MAC 或 IP 的逐设备调试追踪。记录列出设备的每一条 tcpdump 行、ARP 命中、ping 探测和状态变化。还包含一个可一键关闭所有逐设备日志的按钮。 - **帮助…** — 先打印简短的插件摘要(设备类型、所有菜单项),随后将完整的 README 打印到 plugin.log。 - **Fingscan 迁移工具…** — 请参阅下文的 *Fingscan 迁移* 部分。 ## 动作 *在 Indigo 动作组中可用* - **Ping 地址** — Ping 任何 IP 地址或 DNS 主机名。结果将写入 `plugin.log` 并作为 `{ip} {ms}ms on/off` 写入变量 `networkScanner_pingDevice`。 ## 出现间隔统计 追踪每个设备连续两次被发现之间的时间,并按以下区间进行划分: `≤10s` · `≤30s` · `≤60s` · `≤90s` · `≤120s` · `≤180s` · `≤240s` · `≤300s` · `>300s` ## 被忽略的 MAC *Plugins → Network Scanner → Manage Ignored MAC Addresses…* - **顶部列表** — 所有已发现的设备:选择一个 → 点击 **▼ Ignore Selected Device** - **底部列表** — 当前被忽略的设备:选择一个 → 点击 **▲ Un-ignore Selected Device** - 点击 **OK** 保存 被忽略的 MAC 既不会被扫描器创建,也不会被其更新。 ## 本地名称解析 两个独立的状态捕获来自不同来源的设备主机名: - **`mdnsName`** — 来自 mDNS / Bonjour SRV 记录(被动嗅探线程或 `dns-sd` 浏览)。示例:`iPhone-Karl.local`。更可靠;仅在看到 DNS-SD 数据包时更新。 - **`arpHostname`** — 来自 `arp -a` 输出的第一个字段,macOS 会从其 Bonjour 缓存中填充该字段。示例:`iphone-karl.localdomain`。每次 ARP 扫描时更新,但仅在找到真实名称(不是 `?`)时更新。 这两个状态都是按来源单次写入的 —— `arp -a` 中的 `?` 结果永远不会抹去以前发现的 `arpHostname`。不广播 Bonjour 名称的设备这两个状态都会是空的。 ## 扫描的 TCP 端口 21 (FTP), 22 (SSH), 23 (Telnet), 25 (SMTP), 53 (DNS), 80 (HTTP), 110 (POP3), 143 (IMAP), 443 (HTTPS), 445 (SMB), 548 (AFP), 554 (RTSP), 587 (SMTP submission), 631 (IPP/printing), 993 (IMAPS), 995 (POP3S), 1883 (MQTT), 3306 (MySQL), 3389 (RDP), 5000 (UPnP/dev server), 5900 (VNC), 8080 (HTTP-alt), 8443 (HTTPS-alt), 9100 (Raw printing), 32400 (Plex) ## 启动行为 - 如果插件管理的 Indigo 变量尚不存在,则会自动创建。 - 在启动时加载 `known_devices.json` —— 以前发现的设备将立即可用。 - 每个受管设备在启动 15 秒后会进行一次延迟端口扫描。 - **启动宽限期** (`self.in_grace_period`) 从插件启动开始,直到配置的 *Ignore offline changes at startup* 持续时间到期。当该标志为 `True` 时: - 离线状态变化会被抑制 —— 嗅探和第一次扫描有时间在标记任何设备离线之前重新确认设备。 - 跳过仅 Ping 候选设备的检测 —— 在宽限期结束前,不会评估“无 ARP 条目”的候选设备,也不会创建合成 MAC 设备,从而防止在 ARP/tcpdump 尚未有时间填充 `_known` 时出现误报。 - `passive-info` 调试日志被静默 —— 第一次扫描产生的大量状态更新不会淹没日志。 - 该标志由 `runConcurrentThread` 设置为 `False`(唯一的权威位置),并在其他所有地方直接读取 在调用点没有内联时间计算。 ## 状态持久化 所有被发现的设备数据(IP、最后出现时间、供应商、本地名称、ping 失败连续次数、统计数据、IP 更改历史)均保存至: ``` /Preferences/Plugins/com.karlwachs.networkscanner/known_devices.json ``` 在每次扫描周期结束后以及关闭时(包括收到 SIGTERM 时)保存。 ### IP 变更历史 每当设备的 IP 地址发生更改时,都会向其 `ip_history` 列表(上限 20 条记录)追加一条记录: - **`ts`** — 更改时的时间戳 - **`old_ip`** — 以前的 IP 地址 - **`new_ip`** — 新的 IP 地址 - **`source`** — `scan`(由 ARP 扫描 / 嗅探更改)或 `manual`(通过设备编辑设置) 可在 *List All Discovered Devices* 和 *Print IP-Changed Devices* 菜单项中查看,其中每行显示 `[scan]` 或 `[manual]`。 ## Fingscan 迁移 *Plugins → Network Scanner → Fingscan Migration Tools…* 下的四个工具: - **(0) 比较** — 打印一份并排报告:仅在 Fingscan 中的设备、仅在 NetworkScanner 中的设备,以及同时存在于两者中但在线/离线状态冲突的设备。 - **(1) 导入名称** — 通过 MAC 将 Fingscan 的 `IP-Device` 条目与 NetworkScanner 设备匹配,并将 Fingscan 名称写入每个匹配设备的 `fingscanDeviceInfo` 状态。 - **(2) 覆盖名称** — 使用导入的 `fingscanDeviceInfo` 值将每个 NetworkScanner 设备重命名为 `{fingscan-name}-{prefix}`(例如 `Karl iPhone-Net`)。仅重命名 `fingscanDeviceInfo` 不为空的设备。 - **(3) 复制新设备 — COPY NEW 按钮** — 查找在 NetworkScanner 中没有匹配 MAC 的 Fingscan 设备,并为每个设备创建一个新的 `networkDevice`: - `pingMode = "pingOnly"`,设备初始为**禁用**状态 —— 手动启用每一个以开始监控 - 名称格式:`{fingscan-name}-{prefix}-ping-only`(例如 `Karl iPhone-Net-ping-only`) - MAC、IP 和供应商信息由 Fingscan 填充 - **自动跳过**(显示在日志中):没有 IP、IP 为 `0.0.0.0` 或非私有(公共/互联网)IP 地址的设备 —— 请将那些作为外部设备添加。接受的私有范围:`10.x.x.x`、`172.16–31.x.x`、`192.168.x.x` *作者:Karl Wachs*
标签:ARP嗅探, ICMP Ping, Indigo插件, MAC地址识别, Python, 云存储安全, 企业安全, 厂商识别, 在线离线状态, 外部主机监控, 局域网发现, 插件系统, 数据统计, 无后门, 智能家居, 端口扫描, 网络安全, 网络扫描, 网络设备管理, 网络资产管理, 聚合监控, 设备追踪, 逆向工具, 防御绕过, 隐私保护