WatchYourLAN 高级 ARP 扫描配置指南:IFACES、ARP_ARGS 与 ARP_STRS 实战详解
2026/9/16 16:47:57 网站建设 项目流程

WatchYourLAN 高级 ARP 扫描配置指南:IFACES、ARP_ARGS 与 ARP_STRS 实战详解

【免费下载链接】WatchYourLANLightweight network IP scanner written in Go. With notifications, history, export to Grafana项目地址: https://gitcode.com/GitHub_Trending/wa/WatchYourLAN

WatchYourLAN 是一款用 Go 编写的轻量级局域网 IP 扫描器,核心扫描引擎是系统自带的arp-scan命令行工具。本指南围绕 docs/VLAN_ARP_SCAN.md 展开,系统讲解 WatchYourLAN 向arp-scan传递参数的三种途径——IFACESARP_ARGSARP_STRS(以及用于环境变量的ARP_STRS_JOINED),并结合 arpscan.go、conf/read.go 等源码,深入说明参数解析、扫描执行与结果归属的底层原理。读完本文,你将掌握通过 Web GUI、配置文件与环境变量三种方式配置复杂 VLAN、docker0 网桥等多网段扫描的完整实战方案。

一、参数体系总览:三类参数如何拼装 arp-scan 命令

WatchYourLAN 本身不实现 ARP 探测,而是封装系统命令arp-scan。所有扫描参数最终都会拼装成arp-scan的 CLI 命令并在后台执行。根据 docs/VLAN_ARP_SCAN.md 的说明,参数分为三类,作用域完全不同:

参数是否必需作用范围默认命令形态
IFACES必需指定参与扫描的网络接口列表arp-scan -glNx -I $ONE_IFACE
ARP_ARGS可选追加到每一个接口的扫描命令中arp-scan -glNx <ARP_ARGS> -I $ONE_IFACE
ARP_STRS可选完全独立于IFACES的额外扫描串arp-scan $ONE_STRING
ARP_STRS_JOINED可选仅限环境变量方式写入ARP_STRSARP_STRS

其中-g表示生成随机源 MAC 地址(与-l冲突时自动切换)、-l使用本机 MAC、-N不做 DNS 反向解析、-x以制表符分隔输出、-I指定接口。扫描命令的实际拼装逻辑见 arpscan.go:当ARP_ARGS非空时执行arp-scan -glNx <args> -I <iface>,否则执行arp-scan -glNx -I <iface>

这三类参数都可以通过 GUI、配置文件或环境变量设置,但存在一条关键限制(详见后文):ARP_STRS只能通过 GUI 或配置文件设置,环境变量(如 docker-compose)必须使用ARP_STRS_JOINED

二、IFACES:必需的基础接口列表

2.1 参数格式与来源

IFACES是 WatchYourLAN 正常运行必需的变量,可来自 Web GUI、配置文件或环境变量。它是一个用空格分隔的网络接口列表:

IFACES: "enp4s0 wlxf4ec3892dd51"

上例中enp4s0是有线网卡,wlxf4ec3892dd51是无线网卡,WatchYourLAN 会依次对列表中的每个接口发起一次独立扫描。

获取本机接口列表的常用命令:

ip link show # 或 netstat -i

在 docker-compose.yml 中,该参数以环境变量形式注入,并明确标注为required

environment: TZ: Asia/Novosibirsk # required: needs your TZ for correct time IFACES: "enp4s0 wlxf4ec3892dd51" # required: 1 or more interface

2.2 源码实现:逐接口循环扫描

从 arpscan.go 的Scan函数可以看出,IFACES字符串会先按空格切分为切片,然后逐接口调用scanIface

if ifaces != "" { p = strings.Split(ifaces, " ") for _, iface := range p { slog.Debug("Scanning interface " + iface) text = scanIface(iface) foundHosts = append(foundHosts, parseOutput(text, iface)...) } }

注意 conf/read.go 中IFACES的默认值为空字符串,这意味着不配置该变量时 WatchYourLAN 不会扫描任何接口——这正是它在 docker-compose 中标记为 required 的原因。

2.3 默认扫描命令

对于每个接口,默认生成的扫描命令为:

arp-scan -glNx -I $ONE_IFACE

$ONE_IFACEIFACES列表中的单个接口名。

三、ARP_ARGS:附加参数作用于每个接口

3.1 参数格式

ARP_ARGS可选变量,同样可通过 GUI、配置文件或环境变量设置。它是arp-scan的附加参数,会被应用到IFACES中的每一个接口。例如:

ARP_ARGS: "-r 1"

实际生成的命令为:

arp-scan -glNx -r 1 -I $ONE_IFACE

其中-r 1表示只重试一次。arp-scan的全部可用参数请查阅man arp-scan

3.2 源码实现:附加参数全局生效

scanIface 中的逻辑非常直白:

var arpArgs string func scanIface(iface string) string { var cmd *exec.Cmd if arpArgs != "" { cmd = exec.Command("arp-scan", "-glNx", arpArgs, "-I", iface) } else { cmd = exec.Command("arp-scan", "-glNx", "-I", iface) } out, err := cmd.Output() ... }

arpArgs是包级变量,在Scan入口处由参数args赋值,因此一次扫描周期内对所有接口生效。一个使用技巧:将日志级别设为debug,WatchYourLAN 会通过slog.Debug(cmd.String())输出实际拼装好的完整命令(见 arpscan.go),便于你核对参数是否按预期生效。日志级别本身由 restart-scan.go 的setLogLevel在每次重启扫描协程时根据LOG_LEVEL重新设定。

四、ARP_STRS:VLAN、docker0 与复杂网段的独立扫描

4.1 设计动机:解决 IFACES 的局限

仅靠IFACES只能覆盖本机直连的接口。对于 VLAN 子网(如10.0.107.0/24)、Docker 默认网桥(docker0)、虚拟网桥(virbr0)等需要额外指定网段甚至 VLAN ID 的场景,IFACES无能为力。为此 WatchYourLAN 引入了ARP_STRS

ARP_STRS是一组完整的arp-scan命令字符串。只要设置了它,WatchYourLAN 就会发起一组IFACES完全独立的扫描,对列表中的每个字符串各执行一次:

arp-scan $ONE_STRING

每个字符串必须包含你要传递给arp-scan的全部信息。例如扫描 VLAN 107 对应的子网:

arp-scan -gNx 10.0.107.0/24 -Q 107 -I eth0

其中-Q 107即 VLAN ID。

[!WARNING] 字符串的最后一个元素(上例中的eth0)会被 WatchYourLAN 设置为该批发现主机的Interface字段。因此强烈建议把接口名放在字符串末尾,否则数据库中主机的接口归属会错乱。

4.2 通过配置文件设置

在配置文件(config_v2.yaml)中,ARP_STRS以 YAML 列表形式书写:

arp_strs: - -gNx 172.17.0.1/24 -I docker0 - -glNx -I virbr0

第一个字符串扫描 Docker 网桥网段172.17.0.1/24,第二个字符串扫描虚拟网桥virbr0。注意两处-I都位于字符串末尾,符合上一节的接口归属约定。

4.3 通过 Web GUI 设置

在 Web 界面的 Scan settings 面板中,找到 "Arp Strings" 输入框,一次填入一个字符串,点击Save保存后,页面会自动追加一个空输入框,供你继续填写下一个字符串。前端实现见 frontend/src/components/Config/Scan.tsx:使用 SolidJS 的<For>循环渲染已有的每个arpstrs输入框,并在末尾固定渲染一个空输入框用于新增。

点击 Save 会 POST 到/api/config_settings/,后端 api/config.go 通过c.PostFormArray("arpstrs")收集全部同名表单值,过滤掉空字符串后写入conf.AppConfig.ArpStrs,随后调用conf.Write落盘并触发routines.ScanRestart()立即重启扫描。

4.4 源码实现:独立执行与接口归属提取

ARP_STRS的执行走的是与IFACES完全不同的分支。scanStr 将整个字符串按空格拆分成参数数组后直接传给arp-scan

func scanStr(str string) string { args := strings.Split(str, " ") cmd := exec.Command("arp-scan", args...) ... }

在 Scan 中,扫描完IFACES后紧接着遍历strs

for _, s := range strs { slog.Debug("Scanning string " + s) text = scanStr(s) p = strings.Split(s, " ") foundHosts = append(foundHosts, parseOutput(text, p[len(p)-1])...) }

注意p[len(p)-1]——这正是"最后一个元素被用作接口名"这一约定的源码出处。parseOutput(arpscan.go)按制表符切分arp-scan -x的输出,将 IP、MAC、厂商信息(Hw)与接口名一起封装进models.Host结构体(定义见 models/models.go)。

五、ARP_STRS_JOINED:在 docker-compose 中注入 ARP_STRS

5.1 为什么需要它

ARP_STRS是列表类型,而环境变量是扁平字符串,无法直接表达"字符串列表"。因此 WatchYourLAN 提供了ARP_STRS_JOINED作为从 ENV 注入ARP_STRS的唯一途径。

5.2 格式要求

ARP_STRS_JOINED是用逗号分隔的字符串列表,逗号前后不能有空格

ARP_STRS_JOINED: "-gNx 172.17.0.1/24 -I docker0,-gNx 10.0.107.0/24 -Q 107 -I eth0"

解析逻辑见 conf/read.go:读取ARP_STRS_JOINED后直接按逗号切分,覆盖config.ArpStrs

joined := viper.Get("ARP_STRS_JOINED").(string) if joined != "" { config.ArpStrs = strings.Split(joined, ",") }

因此如果逗号后误留空格,切分结果会带有前导空格,导致arp-scan收到一个非法的参数(如" -I"),最终扫描失败。务必保证逗号紧贴前后字符串,不加空格。

5.3 配置优先级与回写保护

注意 conf/write.go 中的一行特殊处理:

viper.Set("ARP_STRS_JOINED", "") // Can be set only with ENV

每当配置被写回文件时,ARP_STRS_JOINED都会被置空——因为该变量只在环境变量中有意义。如果配置文件中同时存在arp_strsARP_STRS_JOINED环境变量,则环境变量的优先级更高,会覆盖文件中的arp_strs列表。

5.4 docker-compose 完整示例

version: "3" services: wyl: image: aceberg/watchyourlan network_mode: "host" restart: unless-stopped volumes: - ~/.dockerdata/wyl:/data/WatchYourLAN environment: TZ: Asia/Novosibirsk # required IFACES: "enp4s0" # required ARP_STRS_JOINED: "-gNx 172.17.0.1/24 -I docker0,-gNx 10.0.107.0/24 -Q 107 -I eth0"

使用network_mode: "host"可确保容器能看到宿主机全部网络接口与路由表,这是扫描 VLAN 与 docker0 的前提条件。配置文件config_v2.yaml存放在挂载卷/data/WatchYourLAN下,由 conf/start.go 在启动时读取。

六、实战示例汇总

以下示例均来自 docs/VLAN_ARP_SCAN.md,可直接用于ARP_STRS_JOINEDARP_STRS

6.1 扫描 VLAN 107

ARP_STRS_JOINED: "-gNx 10.0.107.0/24 -Q 107 -I eth0"

含义:扫描10.0.107.0/24网段,-Q 107指定 VLAN ID 为 107,接口为eth0(置于末尾)。

6.2 扫描 docker0 网桥

ARP_STRS_JOINED: "-gNx 172.17.0.1/24 -I docker0"

含义:扫描 Docker 默认网桥docker0所在的172.17.0.1/24网段,接口docker0位于末尾。

6.3 组合使用(逗号分隔,无空格)

ARP_STRS_JOINED: "-gNx 172.17.0.1/24 -I docker0,-gNx 10.0.107.0/24 -Q 107 -I eth0"

七、扫描结果如何进入数据库与告警链路

理解参数配置后,再看一下扫描结果的处理闭环(见 routines/scan-routine.go):

  1. startScanTIMEOUT秒(默认 120 秒,见 conf/read.go)调用一次arp.Scan,将三类参数一并传入;
  2. 扫描结果以MAC 地址为键构建映射(foundHostsMap[fHost.Mac] = fHost);
  3. compareHosts与数据库中"当前在线"的主机逐条比对:仍在线的更新 IP、接口与时间戳;已掉线的标记Now = 0新出现的未知主机会触发notify.Unknown(fHost)通过 Shoutrrr 发送上线通知;
  4. 每条记录同时写入 history 表,供历史曲线展示;若启用了 InfluxDB 或 Prometheus 输出,还会同步导出(对应 backend/internal/influx/influx.go 与 backend/internal/prometheus/prometheus.go)。

这意味着:ARP_STRS配置的 VLAN 或 docker0 网段一旦发现新设备,同样会进入完整的在线状态跟踪、历史记录与告警流程,与IFACES扫描的设备无差别对待。

八、配置建议与排查清单

  • 先确认接口存在:配置IFACES前,用ip link shownetstat -i核对接口名拼写,避免手误导致整轮扫描为空。
  • 接口放末尾:所有ARP_STRS/ARP_STRS_JOINED字符串都把接口名放在最后一个参数位置,否则主机记录会被错误归属到其他接口。
  • 逗号后不要有空格:环境变量注入ARP_STRS_JOINED时严格遵守"逗号分隔、无空格"格式。
  • 开启 debug 日志验证:将LOG_LEVEL设为debug,在日志中核对每条实际执行的arp-scan命令是否与预期一致;日志级别改动后需触发一次扫描重启(GUI 中保存任意扫描设置即可,见 Scan.tsx 的 "Pressing Save button will trigger rescan" 提示)。
  • 权限要求arp-scan发送原始 ARP 报文通常需要 root 或相应能力(CAP_NET_RAW),请确保运行 WatchYourLAN 的进程具备该权限,否则扫描输出为空(arp-scan报错会被 check.IfError 捕获并返回空结果)。
  • 依赖安装:WatchYourLAN 依赖系统提供arp-scantzdata两个外部程序,缺失任一都会导致扫描异常。

【免费下载链接】WatchYourLANLightweight network IP scanner written in Go. With notifications, history, export to Grafana项目地址: https://gitcode.com/GitHub_Trending/wa/WatchYourLAN

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询