问题背景

在 MacOS 系统上运行 Surge 时,有时会遇到 DHCP(Dynamic Host Configuration Protocol)服务无法启动的问题。这通常是由于系统内置的 DHCP 服务(bootpd)与 Surge 的 DHCP 服务发生端口冲突导致的。DHCP 服务默认使用 UDP 67 端口,当系统中存在多个 DHCP 服务时,就会出现此类问题。

问题表现

当尝试在 Surge 中启用 DHCP 服务时,会遇到启动失败的情况,如下图所示:

surge-error

通过查看 DHCP 服务日志,可以看到具体的错误信息:

Internet Systems Consortium DHCP Server 4.4.2
Copyright 2004-2020 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/
Config file: /Users/USERNAME/Library/Application Support/com.nssurge.surge-mac/dhcpd/dhcpd.conf
Database file: /Users/USERNAME/Library/Application Support/com.nssurge.surge-mac/dhcpd/lease
PID file: /Users/USERNAME/Library/Application Support/com.nssurge.surge-mac/dhcpd/pid
Wrote 0 deleted host decls to leases file.
Wrote 0 new dynamic host decls to leases file.
Wrote 65 leases to leases file.
Listening on BPF/en4/00:0e:c6:c2:35:54/192.168.31.0/24
Sending on   BPF/en4/00:0e:c6:c2:35:54/192.168.31.0/24
Can't bind to dhcp address: Address already in use

关键错误信息是 “Can’t bind to dhcp address: Address already in use”,这表明 DHCP 所需的端口已被其他进程占用。

问题诊断

1. 检查端口占用情况

首先,我们需要确认是哪些进程占用了 DHCP 服务端口(UDP 67):

sudo lsof -i :67

输出结果:

COMMAND  PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
launchd    1 root   15u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
launchd    1 root   25u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
launchd    1 root   54u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
launchd    1 root   55u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
bootpd  3970 root    0u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
bootpd  3970 root    1u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps
bootpd  3970 root    2u  IPv4 0xe266e99ee0d4eae7      0t0  UDP *:bootps

从输出可以看到,系统的 launchd(PID 1)和 bootpd(PID 3970)进程都在监听 UDP 67 端口。

解决方案

1. 禁用系统 DHCP 服务

在 MacOS 中,需要通过 launchctl 命令来禁用系统自带的 DHCP 服务:

sudo launchctl unload -w /System/Library/LaunchDaemons/bootps.plist

这个命令会:

  1. 停止当前运行的 bootpd 服务
  2. 禁用该服务的自动启动
  3. 释放 UDP 67 端口

2. 验证服务状态

执行完上述命令后,可以再次检查端口占用情况:

sudo lsof -i :67

如果输出为空,说明 DHCP 端口已经被成功释放。

3. 重启 Surge DHCP 服务

此时可以在 Surge 中重新启用 DHCP 服务,应该就能正常工作了。

注意事项

  1. 如果后续需要恢复系统 DHCP 服务,可以使用以下命令:

    sudo launchctl load -w /System/Library/LaunchDaemons/bootps.plist
    
  2. 在某些 MacOS 版本中,LaunchDaemons 的位置可能会有所不同,也可以在以下位置查找:

    • /Library/LaunchDaemons
    • /Library/LaunchAgents
  3. 建议在修改系统服务之前,先备份相关配置文件。

社区贡献

在解决这个问题的过程中,我最初在 Surge 社区寻求帮助。虽然得到了官方的回复,但并没有完全解决问题。经过深入研究和实践,我找到了上述完整的解决方案,并将其分享到了 Surge 社区,以帮助其他遇到类似问题的用户。

您可以在这里查看完整的社区讨论:Surge 社区 - DHCP 问题讨论

参考资料