ClashMac 27.1.1 核心启动但 API 不可用 / 端口池耗尽导致完全断网
环境
- ClashMac 版本:27.1.1
- 核心:mihomo v1.19.27
- macOS:Sequoia
- 代理模式:TUN 模式(mixed stack)
- 订阅节点数:约 150 个
现象
核心正常启动,但:
- API 端口 9090 通过 TCP 连接返回
EADDRNOTAVAIL(Cannot assign requested address)
- 本机所有对外 TCP 连接均无法建立,包括 LAN 服务(192.168.1.x)和公网服务
- ClashMac GUI 显示核心已运行,但无法与控制面通信
- 系统代理功能完全中断
诊断过程
第一步:确认进程和端口
核心进程正常,但 9090 和 7890 端口无响应。
第二步:检查核心日志
核心日志被设为 log-level: silent,无法获取有效信息。
第三步:检查系统连接状态
netstat -an | grep TIME_WAIT | wc -l
结果显示约 16,500 条 TIME_WAIT 连接,源端口集中在 8080,目标 IP 集中在 Cloudflare CDN 段(104.16.151.x),目标端口 8080。
ss -n state time-wait | wc -l
动态端口池占用:
sysctl net.inet.ip.portrange.hilast net.inet.ip.portrange.lowfirst
net.inet.ip.portrange.hilast: 65535
net.inet.ip.portrange.lowfirst: 49152
可用端口数:65535 - 49152 = 16,383
TIME_WAIT 连接数 ~16,500,占用率 99%+,导致所有新 IPv4 TCP 连接分配端口时返回 EADDRNOTAVAIL。
根因分析
一级根因:配置生成流程损坏
ClashMac 27.1.1 在从 profiles/default.yaml(源配置)生成 work/config.json(运行时配置)时,存在字段丢失或篡改问题:
| 字段 |
源配置(用户编辑) |
运行时配置(自动生成) |
影响 |
| mixed-port |
7890 |
被删除(None) |
混合代理端口不可用 |
| external-controller |
127.0.0.1:9090 |
被删除(None) |
API 无法通过 TCP 访问 |
| log-level |
info |
被硬编码为 silent |
核心日志无法用于排查 |
| route-exclude-address |
用户配置的排除列表 |
被删除(空数组) |
局域网 / VPN 流量被 TUN 劫持 |
| sniffer.skip-domain |
用户配置的跳过列表 |
被删除 |
域名嗅探无排除列表 |
这导致用户即使修改了源配置,运行时配置仍然不符合预期,无法通过 API 进行在线重载或诊断。
二级根因:节点健康检查引发端口池耗尽
ClashMac 启动后对所有代理节点(约 150 个)同时发起健康检查,使用 HTTP HEAD 请求访问 http://www.gstatic.com/generate_204。
DNS 解析结果中包含 Cloudflare CDN IP(104.16.151.x),每次探测都建立一个独立的 IPv4 TCP 短连接,源端口固定为 8080。
关键数据:
- 总 TIME_WAIT 连接数:约 16,506
- Cloudflare IP 连接数:16,373
- macOS 默认动态端口池:16,383(49152 - 65535)
- 端口占用率:99.9%
由于健康检查持续进行,新连接的创建速率等于旧连接的过期速率(TIME_WAIT 寿命约 1s,MSL=500ms),端口池永远不会释放出可用端口,导致所有新 TCP 连接失败。
三级根因:SIP 阻止网络扩展卸载
macOS SIP(System Integrity Protection)阻止使用 systemextensionsctl 卸载网络扩展,TIME_WAIT 连接无法通过命令清理。唯一修复手段是重启机器。
恢复步骤
- 重启机器(唯一有效方案,TIME_WAIT 表清零,TUN 扩展重新加载)
- 重启后卸载 ClashMac 27.1.1,更换为其他代理软件
如何规避
对用户的建议
暂时不建议升级到 27.1.1。如果必须使用,在启动前通过命令行限制核心使用源端口的范围,或关闭自动健康检查以减少并发连接数。
对开发者的建议
-
修复配置生成流程:运行时配置应忠实反映用户源配置。mixed-port、external-controller、log-level、route-exclude-address、sniffer 等字段不应被硬编码覆盖或删除。
-
优化健康检查策略:
- 复用 TCP 连接(HTTP Keep-Alive)
- 限制并发探测数(串行或小批量)
- 增加探测间隔,避免密集短连接
- 考虑使用连接池
-
TIME_WAIT 防护:
- macOS 默认动态端口池仅 16,383,代理节点多时极易耗尽
- 监控系统连接数,达到阈值时主动降速或告警
- 建议健康检查使用长连接
-
修复 route-exclude-address:配置生成流程中确保 tun.route-exclude-address 不被覆盖,或改为累加而非替换。
-
允许用户覆盖 log-level:log-level: silent 在紧急情况下阻止了通过日志排查问题的可能性,建议允许用户通过 GUI 或配置修改日志级别。
补充信息
core/current -t -d work -f profiles/default.yaml 配置校验通过
core/current -t -d work -f work/config.json 运行时配置校验也通过
- 问题不在配置语法错误,而在 ClashMac 的配置生成逻辑
太多bug了,先转 Clash party 用着先
ClashMac 27.1.1 核心启动但 API 不可用 / 端口池耗尽导致完全断网
环境
现象
核心正常启动,但:
EADDRNOTAVAIL(Cannot assign requested address)诊断过程
第一步:确认进程和端口
核心进程正常,但 9090 和 7890 端口无响应。
第二步:检查核心日志
核心日志被设为
log-level: silent,无法获取有效信息。第三步:检查系统连接状态
结果显示约 16,500 条 TIME_WAIT 连接,源端口集中在 8080,目标 IP 集中在 Cloudflare CDN 段(104.16.151.x),目标端口 8080。
动态端口池占用:
可用端口数:65535 - 49152 = 16,383
TIME_WAIT 连接数 ~16,500,占用率 99%+,导致所有新 IPv4 TCP 连接分配端口时返回
EADDRNOTAVAIL。根因分析
一级根因:配置生成流程损坏
ClashMac 27.1.1 在从
profiles/default.yaml(源配置)生成work/config.json(运行时配置)时,存在字段丢失或篡改问题:这导致用户即使修改了源配置,运行时配置仍然不符合预期,无法通过 API 进行在线重载或诊断。
二级根因:节点健康检查引发端口池耗尽
ClashMac 启动后对所有代理节点(约 150 个)同时发起健康检查,使用 HTTP HEAD 请求访问
http://www.gstatic.com/generate_204。DNS 解析结果中包含 Cloudflare CDN IP(104.16.151.x),每次探测都建立一个独立的 IPv4 TCP 短连接,源端口固定为 8080。
关键数据:
由于健康检查持续进行,新连接的创建速率等于旧连接的过期速率(TIME_WAIT 寿命约 1s,MSL=500ms),端口池永远不会释放出可用端口,导致所有新 TCP 连接失败。
三级根因:SIP 阻止网络扩展卸载
macOS SIP(System Integrity Protection)阻止使用
systemextensionsctl卸载网络扩展,TIME_WAIT 连接无法通过命令清理。唯一修复手段是重启机器。恢复步骤
如何规避
对用户的建议
暂时不建议升级到 27.1.1。如果必须使用,在启动前通过命令行限制核心使用源端口的范围,或关闭自动健康检查以减少并发连接数。
对开发者的建议
修复配置生成流程:运行时配置应忠实反映用户源配置。
mixed-port、external-controller、log-level、route-exclude-address、sniffer等字段不应被硬编码覆盖或删除。优化健康检查策略:
TIME_WAIT 防护:
修复 route-exclude-address:配置生成流程中确保
tun.route-exclude-address不被覆盖,或改为累加而非替换。允许用户覆盖 log-level:
log-level: silent在紧急情况下阻止了通过日志排查问题的可能性,建议允许用户通过 GUI 或配置修改日志级别。补充信息
core/current -t -d work -f profiles/default.yaml配置校验通过core/current -t -d work -f work/config.json运行时配置校验也通过太多bug了,先转 Clash party 用着先