NETWORK ISOLATION · GO · 09/12

niclane

每张网卡一条车道,出口硬绑定,接口不健康时拒绝新连接。

PER-INTERFACE EGRESS ISOLATION FOR LOCAL PROXIES

lang Gover v0.4.0license MIT
SCROLL
SO_BINDTODEVICEFAIL-CLOSEDCANDIDATE LANESSOCKS5SO_BINDTODEVICEFAIL-CLOSEDCANDIDATE LANESSOCKS5
SEC.01

$做什么

niclane 是本地的 SOCKS5 / HTTP 代理,每个监听端口的出口硬绑定到一张指定网卡:Linux 用 SO_BINDTODEVICE,macOS 用 IP_BOUND_IF。车道之间不共享路由,接口不健康且 strict 为真时立即拒绝新连接。v0.4.0 起一条车道可以持有一组有序候选,切换只发生在该车道自己声明过的候选之间。

SEC.02

$快速开始

~/quickstart.sh
SEC.03

$架构

app A ──► 127.0.0.1:7891 (lane "wifi") ──[SO_BINDTODEVICE]──► WiFi NIC
app B ──► 127.0.0.1:7892 (lane "dock") ──[SO_BINDTODEVICE]──► USB NIC
app C ──► 127.0.0.1:7893 (lane "roam") ──candidates──┬─[1] dock · socks5://   静态 1000
                                                     ├─[2] discover:wifi      发现 100
                                                     └─[3] tun · http://      静态 1000
   排序 = 优先级 → 探测延迟 → 配置顺序;一条连接在 resolve / dial / UDP 全程锁定同一候选
        │
        ▼  传输层失败:拨号错误 / 超时 / 握手 IO / fail-closed 拒绝
   健康探测经候选自己的网卡:连续 2 次失败判死,1 次成功复活 → 转下一个候选
        │
        ▼  候选全灭且 strict
   SOCKS5 0x01 / HTTP 502,拒绝新连接,不改道到车道之外
   上游应用层拒绝(SOCKS5 reply ≠ 0 / CONNECT 非 2xx)原样回客户端,不扣健康分
   监视器每 2 秒复查接口;DNS 经本车道解析,支持 DoH(AliDNS / Cloudflare)

单网卡车道没有回退路径,候选车道只在自己的候选集合内切换。配置里 interface/upstream 与 candidates/discover 混写会被校验拒绝。

SEC.04

$要点

F01
📌

出口硬绑定

Linux 用 SO_BINDTODEVICE,macOS 用 IP_BOUND_IF,把 socket 钉在一张网卡上。bind_mode: ip 只绑源地址,隔离性更弱。

F02
🚧

失败即拒

监视器每 2 秒复查接口是否在线、是否有地址。不健康且 strict 时拨号直接拒绝,返回 SOCKS5 0x01 或 HTTP 502。

F03
🔎

车道内 DNS

域名解析经本车道拨出,回环 nameserver 会被替换成 dns_servers。dns: doh 走 DNS-over-HTTPS,默认端点是 AliDNS 与 Cloudflare。

F04
🔀

候选与转移

一条车道可持有有序的 (interface, upstream) 候选,排序按优先级、探测延迟、配置顺序。只有传输层失败触发转移,上游的应用层拒绝原样回给客户端。

F05
🧭

自动发现

Linux 下 discover: 枚举网卡并解析每张网卡自己的网关,只对该网关做 TCP 端口探测。发现的候选优先级 100,排在静态候选的 1000 之后。

F06
📊

上游与计量

可链 socks5:// 或 http:// 上游,上游连接本身也走本车道;UDP ASSOCIATE 经车道绑定的 socket 中继。连接数、拒绝数、双向字节、DNS 查询按 Prometheus 格式导出。

SEC.05

$路线与限制

← PREV · 08
qwenpaw-consensus-rank