跳转至

客户端

简介

长期以来,图形操作系统的现代代理客户端使用方式和原理一直没有得到清晰的描述。 不过,我们可以将它们分为三种类型:系统代理、防火墙重定向和虚拟接口。

系统代理

几乎所有图形环境都支持系统级代理,它们本质上是只支持 TCP 的普通 HTTP 代理。

操作系统 / 桌面环境 系统代理 应用支持
Windows
macOS
GNOME/KDE
Android 需要 ROOT 或 adb(权限)
Android/iOS(使用 sing-box 图形客户端) 通过 tun.platform.http_proxy

作为最著名的代理方式之一,它有许多缺点: 许多不是基于 HTTP 的 TCP 客户端不会检查和使用系统代理。 此外,UDP 和 ICMP 流量会绕过代理。

flowchart LR
    dns[DNS 查询] -- Is HTTP request? --> proxy[HTTP 代理]
    dns --> leak[泄漏]
    tcp[TCP 连接] -- Is HTTP request? --> proxy
    tcp -- 检查并使用 HTTP CONNECT? --> proxy
    tcp --> leak
    udp[UDP 数据包] --> leak

防火墙重定向

这类用法通常依赖于操作系统提供的防火墙或钩子接口, 如 Windows 的 WFP、Linux 的 redirect、TProxy 和 eBPF,以及 macOS 的 pf。 虽然这种方式侵入性强且配置繁琐, 但由于对软件技术要求较低,它在 V2Ray 等业余代理开源项目社区中仍然很受欢迎。

虚拟接口

所有 L2/L3 代理(严格定义的 VPN,如 OpenVPN、WireGuard)都基于虚拟网络接口, 这也是所有 L4 代理在 Android、iOS 等移动平台上作为 VPN 工作的唯一方式。

sing-box 继承并发展了 clash-premium 的 TUN 入站(L3 到 L4 转换), 作为执行透明代理的最合理方法。

flowchart TB
    packet[IP 数据包]
    packet --> windows[Windows / macOS]
    packet --> linux[Linux]
    tun[TUN 接口]
    windows -. 路由 .-> tun
    linux -. iproute2 路由/规则 .-> tun
    tun --> gvisor[gVisor TUN 堆栈]
    tun --> system[系统 TUN 堆栈]
    assemble([L3 到 L4 组装])
    gvisor --> assemble
    system --> assemble
    assemble --> conn[TCP 和 UDP 连接]
    conn --> router[sing-box 路由器]
    router --> direct[直连出站]
    router --> proxy[代理出站]
    router -- DNS 劫持 --> dns_out[DNS 出站]
    dns_out --> dns_router[DNS 路由器]
    dns_router --> router
    direct --> adi([自动检测接口])
    proxy --> adi
    adi --> default[系统默认网络接口]
    default --> destination[目标服务器]
    default --> proxy_server[代理服务器]
    proxy_server --> destination

示例

面向中国用户的基本 TUN 用法

{
  "dns": {
    "servers": [
      {
        "tag": "google",
        "type": "tls",
        "server": "8.8.8.8"
      },
      {
        "tag": "local",
        "type": "udp",
        "server": "223.5.5.5"
      }
    ],
    "strategy": "ipv4_only"
  },
  "inbounds": [
    {
      "type": "tun",
      "address": ["172.19.0.1/30"],
      "auto_route": true,
      // "auto_redirect": true, // 在 Linux 上
      "strict_route": true
    }
  ],
  "outbounds": [
    // ...
    {
      "type": "direct",
      "tag": "direct"
    }
  ],
  "route": {
    "rules": [
      {
        "action": "sniff"
      },
      {
        "protocol": "dns",
        "action": "hijack-dns"
      },
      {
        "ip_is_private": true,
        "outbound": "direct"
      }
    ],
    "default_domain_resolver": "local",
    "auto_detect_interface": true
  }
}
{
  "dns": {
    "servers": [
      {
        "tag": "google",
        "type": "tls",
        "server": "8.8.8.8"
      },
      {
        "tag": "local",
        "type": "udp",
        "server": "223.5.5.5"
      }
    ]
  },
  "inbounds": [
    {
      "type": "tun",
      "address": ["172.19.0.1/30", "fdfe:dcba:9876::1/126"],
      "auto_route": true,
      // "auto_redirect": true, // 在 Linux 上
      "strict_route": true
    }
  ],
  "outbounds": [
    // ...
    {
      "type": "direct",
      "tag": "direct"
    }
  ],
  "route": {
    "rules": [
      {
        "action": "sniff"
      },
      {
        "protocol": "dns",
        "action": "hijack-dns"
      },
      {
        "ip_is_private": true,
        "outbound": "direct"
      }
    ],
    "default_domain_resolver": "local",
    "auto_detect_interface": true
  }
}
{
  "dns": {
    "servers": [
      {
        "tag": "google",
        "type": "tls",
        "server": "8.8.8.8"
      },
      {
        "tag": "local",
        "type": "udp",
        "server": "223.5.5.5"
      },
      {
        "tag": "remote",
        "type": "fakeip",
        "inet4_range": "198.18.0.0/15",
        "inet6_range": "fc00::/18"
      }
    ],
    "rules": [
      {
        "query_type": [
          "A",
          "AAAA"
        ],
        "server": "remote"
      }
    ],
    "independent_cache": true
  },
  "inbounds": [
    {
      "type": "tun",
      "address": ["172.19.0.1/30","fdfe:dcba:9876::1/126"],
      "auto_route": true,
      // "auto_redirect": true, // 在 Linux 上
      "strict_route": true
    }
  ],
  "outbounds": [
    // ...
    {
      "type": "direct",
      "tag": "direct"
    }
  ],
  "route": {
    "rules": [
      {
        "action": "sniff"
      },
      {
        "protocol": "dns",
        "action": "hijack-dns"
      },
      {
        "ip_is_private": true,
        "outbound": "direct"
      }
    ],
    "default_domain_resolver": "local",
    "auto_detect_interface": true
  }
}

面向中国用户的流量绕过用法

{
  "dns": {
    "servers": [
      {
        "tag": "google",
        "type": "tls",
        "server": "8.8.8.8"
      },
      {
        "tag": "local",
        "type": "https",
        "server": "223.5.5.5"
      }
    ],
    "rules": [
      {
        "rule_set": "geosite-geolocation-cn",
        "server": "local"
      },
      {
        "type": "logical",
        "mode": "and",
        "rules": [
          {
            "rule_set": "geosite-geolocation-!cn",
            "invert": true
          },
          {
            "rule_set": "geoip-cn"
          }
        ],
        "server": "local"
      }
    ]
  },
  "route": {
    "default_domain_resolver": "local",
    "rule_set": [
      {
        "type": "remote",
        "tag": "geosite-geolocation-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
      },
      {
        "type": "remote",
        "tag": "geosite-geolocation-!cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
      },
      {
        "type": "remote",
        "tag": "geoip-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
      }
    ]
  },
  "experimental": {
    "cache_file": {
      "enabled": true,
      "store_rdrc": true
    },
    "clash_api": {
      "default_mode": "Enhanced"
    }
  }
}
{
  "dns": {
    "servers": [
      {
        "tag": "google",
        "type": "tls",
        "server": "8.8.8.8"
      },
      {
        "tag": "local",
        "type": "https",
        "server": "223.5.5.5"
      }
    ],
    "rules": [
      {
        "rule_set": "geosite-geolocation-cn",
        "server": "local"
      },
      {
        "type": "logical",
        "mode": "and",
        "rules": [
          {
            "rule_set": "geosite-geolocation-!cn",
            "invert": true
          },
          {
            "rule_set": "geoip-cn"
          }
        ],
        "server": "google",
        "client_subnet": "114.114.114.114/24" // 任意中国客户端 IP 地址
      }
    ]
  },
  "route": {
    "default_domain_resolver": "local",
    "rule_set": [
      {
        "type": "remote",
        "tag": "geosite-geolocation-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
      },
      {
        "type": "remote",
        "tag": "geosite-geolocation-!cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
      },
      {
        "type": "remote",
        "tag": "geoip-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
      }
    ]
  },
  "experimental": {
    "cache_file": {
      "enabled": true,
      "store_rdrc": true
    },
    "clash_api": {
      "default_mode": "Enhanced"
    }
  }
}
{
  "outbounds": [
    {
      "type": "direct",
      "tag": "direct"
    }
  ],
  "route": {
    "rules": [
      {
        "action": "sniff"
      },
      {
        "type": "logical",
        "mode": "or",
        "rules": [
          {
            "protocol": "dns"
          },
          {
            "port": 53
          }
        ],
        "action": "hijack-dns"
      },
      {
        "ip_is_private": true,
        "outbound": "direct"
      },
      {
        "type": "logical",
        "mode": "or",
        "rules": [
          {
            "port": 853
          },
          {
            "network": "udp",
            "port": 443
          },
          {
            "protocol": "stun"
          }
        ],
        "action": "reject"
      },
      {
        "rule_set": "geosite-geolocation-cn",
        "outbound": "direct"
      },
      {
        "type": "logical",
        "mode": "and",
        "rules": [
          {
            "rule_set": "geoip-cn"
          },
          {
            "rule_set": "geosite-geolocation-!cn",
            "invert": true
          }
        ],
        "outbound": "direct"
      }
    ],
    "rule_set": [
      {
        "type": "remote",
        "tag": "geoip-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
      },
      {
        "type": "remote",
        "tag": "geosite-geolocation-cn",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
      }
    ]
  }
}