refactor(/docs): rework documentation structure layout (#179)

* refactor(/docs): rework documentation structure layout

* refactor(/docs): update file reference paths

* feat(/docs): add English version of other-proxy-protocol.md

* refacotr: move docs/templates/ docs/sync/ to hack/

* fix(example.dae|readme): update ref link to adopt new file structure

* refactor: rename other-proxy-protocol.md -> proxy-protocols.md

* docs(readme): add ref to proxy-protocols.md

* feat(/docs): add English version of how-it-works.md

* refactor: rename how-it-works; add nav links

* fix: fix linting errors

* fix: fix linting errors

---------

Co-authored-by: earrmouth <43926351+earrmouth@users.noreply.github.com>
This commit is contained in:
Kevin Yu
2023-07-09 17:31:47 +08:00
committed by GitHub
parent d12c79ec44
commit e39ec7fc05
24 changed files with 163 additions and 53 deletions

227
docs/zh/README.md Normal file
View File

@ -0,0 +1,227 @@
# 吃鹅直通手册
## Linux 内核要求
### 内核版本
使用 `uname -r` 来查看内核版本。
> **注意**
> 如果你的内核版本低于 `5.8`,可以参考 [**Upgrade Guide**](../en/user-guide/kernel-upgrade.md) 升级你的内核。
`绑定到 LAN 接口: >= 5.8`
如果你想作为路由器、网桥等中间设备,为其他设备提供代理服务,需要把 dae 绑定到 LAN 接口上。
该特性要求 dae 所在的设备的内核版本 >= 5.8。
如果你只在 `lan_interface` 中填写了接口,而未在 `wan_interface` 中填写内容,那么本地程序将无法被代理。如果你期望代理本地程序,需要在 `wan_interface` 中填写 `auto` 或是手动输入 WAN 接口。
`绑定到 WAN 接口: >= 5.8`
如果你想为本地程序提供代理服务,需要把 dae 绑定到 WAN 接口上。
该特性要求 dae 所在的设备的内核版本 >= 5.8。
如果你只在 `wan_interface` 中填写了接口或 `auto`,而未在 `lan_interface` 中填写内容,那么从局域网中传来的流量将无法被代理。如果你想同时代理本机和局域网流量,请同时填写 `wan_interface``lan_interface`
## 内核配置选项
通常,主流桌面发行版都会打开这些选项。但是为了减小内核大小,在嵌入式设备发行版(如 OpenWRT、Armbian 等)上这些选项可能处于关闭状态。使用以下命令在你的设备上显示内核配置选项:
```shell
zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}
```
dae 需要以下内核选项:
```
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_CGROUPS=y
CONFIG_KPROBES=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_BTF=y
CONFIG_KPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y
```
你可以通过以下命令检查他们:
```shell
(zcat /proc/config.gz || cat /boot/{config,config-$(uname -r)}) | grep -E 'CONFIG_(DEBUG_INFO|DEBUG_INFO_BTF|KPROBES|KPROBE_EVENTS|BPF|BPF_SYSCALL|BPF_JIT|BPF_STREAM_PARSER|NET_CLS_ACT|NET_SCH_INGRESS|NET_INGRESS|NET_EGRESS|NET_CLS_BPF|BPF_EVENTS|CGROUPS)=|# CONFIG_DEBUG_INFO_REDUCED is not set'
```
> **注意**: `Armbian` 用户可以参考 [**Upgrade Guide**](../en/user-guide/kernel-upgrade.md) 升级到支持的内核。
## 安装
### Archlinux/Manjaro
dae 已发布于 [AUR](https://aur.archlinux.org/packages/dae),使用下述命令安装:
```shell
# yay -S dae
pacman -S --needed git base-devel
git clone https://aur.archlinux.org/dae.git
cd dae
makepkg -si
```
安装后,使用 systemctl 对服务进行控制:
```shell
# 启动 dae
sudo systemctl start dae
# 开机自动启动 dae
sudo systemctl enable dae
```
### Gentoo Linux
dae 已发布于 [gentoo-zh](https://github.com/microcai/gentoo-zh),可以使用 `app-eselect/eselect-repository` 启用此 overlay:
```shell
eselect repository enable gentoo-zh
emaint sync -r gentoo-zh
emerge -a net-proxy/dae
```
### macOS
我们提供了一种比较 hacky 的方式在 macOS 上运行 dae见 [run on macOS](../en/tutorials/run-on-macos.md)。
### Docker
预编译镜像可相关文档请查阅:<https://hub.docker.com/r/daeuniverse/dae>
作为替代,你也可以使用 `docker compose`:
```shell
git clone --depth=1 https://github.com/daeuniverse/dae
docker compose up -d --build
```
### 手动安装
> **Note**: 这种方法仅建议高级用户使用。采用这种方法,用户可以灵活地测试各个版本的 dae。请注意新引入的功能有时可能存在 bug因此请自行承担风险。
dae 可以以守护进程systemd的形式运行见 [run as daemon](../en/user-guide/run-as-daemon.md)。
### 安装脚本
见 [daeuniverse/dae-installer](https://github.com/daeuniverse/dae-installer)(或使用 [镜像站](https://hubmirror.v2raya.org/daeuniverse/dae-installer))。
### 手动构建
见 [Build Guide](../en/user-guide/build-by-yourself.md)。
## 最小 dae 配置
最小可启动的配置:
```shell
global{}
routing{}
```
然而,此配置使 dae 处于空载状态。如果你希望 dae 能正常工作,以下是较小配置下的最佳实践:
```shell
global {
# 绑定到 LAN 和/或 WAN 接口。将下述接口替换成你自己的接口名。
#lan_interface: docker0
wan_interface: auto # 使用 "auto" 自动侦测 WAN 接口。
log_level: info
allow_insecure: false
auto_config_kernel_parameter: true
}
subscription {
# 在下面填入你的订阅链接。
}
# 更多的 DNS 样例见 https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/dns.md
dns {
upstream {
googledns: 'tcp+udp://dns.google.com:53'
alidns: 'udp://dns.alidns.com:53'
}
routing {
request {
fallback: alidns
}
response {
upstream(googledns) -> accept
!qname(geosite:cn) && ip(geoip:private) -> googledns
fallback: accept
}
}
}
group {
proxy {
#filter: name(keyword: HK, keyword: SG)
policy: min_moving_avg
}
}
# 更多的 Routing 样例见 https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md
routing {
pname(NetworkManager, systemd-resolved, dnsmasq) -> must_direct
dip(224.0.0.0/3, 'ff00::/8') -> direct
### 以下为自定义规则
dip(geoip:private) -> direct
dip(geoip:cn) -> direct
domain(geosite:cn) -> direct
fallback: proxy
}
```
如果你不在乎极致速度,而是更注重隐私和 DNS 泄露,使用以下配置替换上述的 dns 部分:
```shell
dns {
upstream {
googledns: 'tcp+udp://dns.google.com:53'
alidns: 'udp://dns.alidns.com:53'
}
routing {
request {
qname(geosite:cn) -> alidns
fallback: googledns
}
}
}
```
完整样例:[example.dae](https://github.com/daeuniverse/dae/blob/main/example.dae)。
如果你使用 PVE可以参考 [#37](https://github.com/daeuniverse/dae/discussions/37)。
## 热重载和暂停
当配置变化时,可以方便使用命令进行配置的热重载,在该过程中不会中断已有连接。当想暂停代理时,可使用命令进行暂停。
详见 [Reload and suspend](../en/user-guide/reload-and-suspend.md)。
## 错误排查
详见 [Troubleshooting](../en/troubleshooting.md)。
## 大鹅宇宙
Telegram: <https://t.me/daeuniverse>

59
docs/zh/how-it-works.md Normal file
View File

@ -0,0 +1,59 @@
# dae 的工作原理
dae 通过 [eBPF](https://en.wikipedia.org/wiki/EBPF) 在 Linux 内核的 tc (traffic control) 挂载点加载一个程序,通过该程序在流量进入 TCP/IP 网络栈之前进行流量分流。tc 在 Linux 网络协议栈中的位置见下图所示(图为收包路径,发包路径方向相反),其中 netfilter 是 iptables/nftables 的位置。
![](../netstack-path.webp)
## 分流原理
### 分流信息
dae 支持以域名、源 IP、目的 IP、源端口、目的端口、TCP/UDP、IPv4/IPv6、进程名、MAC 地址等对流量进行分流。
其中,源 IP、目的 IP、源端口、目的端口、TCP/UDP、IPv4/IPv6、MAC 地址均可解析 MACv2 帧而得到。
**进程名**通过在 cgroupv2 挂载点侦听本地进程的 socket、connect、sendmsg 系统调用,并读取和解析进程控制块中的命令行来得到的。这种方式会比 clash 等用户态程序对传入的 socket 扫描整个 procfs 来得到进程信息要快得多(后者甚至是 10ms 级的)。
**域名**通过劫持 DNS 请求,将 DNS 请求的域名与所查 IP 进行关联来得到。尽管这种方式有一些问题:
1. 可能会出现误判。例如需要分流到国内和国外的两个网站拥有同一个 IP且在短时间内同时被访问或浏览器有 DNS 缓存。
2. 用户的 DNS 请求必须通过 dae。例如将 dae 设为 DNS或在 dae 作为网关的情况下使用公共 DNS。
但相比其他方案,这种方案已经是较优解了。例如 Fake IP 方案存在无法通过 IP 分流且存在严重的缓存污染问题,而域名嗅探方案存在只能嗅探 TLS/HTTP 等流量的问题。实际上,通过 SNI 嗅探来进行分流确实是更优选择,但由于 eBPF 对程序复杂度的限制,以及对循环的支持不友好,我们无法在内核空间实现域名嗅探。
因此,当 DNS 请求无法通过 dae 时,基于 domain 的分流将会失效。
> 为了降低 DNS 污染,以及获得更好的 CDN 连接速度dae 在用户空间实现了域名嗅探。在 `dial_mode` 为 domain 或 domain 的变体,且流量需要被代理时,将嗅探的 domain 发送给代理服务器,而不是发送 IP这样在代理服务器侧会对域名重新进行解析并使用最优 IP 进行连接,从而解决了 DNS 污染的问题,并获得了更好的 CDN 连接速度。
>
> 同时,当高级用户已经使用了其他的分流方案,且不希望将 DNS 请求通过 dae但希望被代理的那部分流量可以基于域名进行分流例如基于目标域名一部分分流到奈飞节点一部分分流到下载节点当然也可以一部分通过 core 直连),可以通过 `dial_mode: domain++` 来强制使用嗅探的域名重新分流。
dae 会通过在 tc 挂载点的程序将流量分流,根据分流结果决定重定向到 dae 的 tproxy 端口或放其直连。
### 代理原理
dae 的代理原理和其他程序近似。区别是在绑定 LAN 接口时dae 通过 eBPF 将 tc 挂载点的需代理流量的 socket buffer 直接关联至 dae 的 tproxy 侦听端口的 socket在绑定 WAN 接口时dae 将需代理流量 socket buffer 从网卡出队列移动至网卡的入队列,禁用其 checksum并修改目的地址为 tproxy 侦听端口。
以 benchmark 来看dae 的代理性能比其他代理程序好一些,但不多。
### 直连原理
一直以来,为了分流,流量需要经过代理程序,经过分流模块之后,再决定是直连还是代理。这样流量需要经过网络栈的解析、处理、拷贝,传入代理程序,再通过网络栈拷贝、处理、封装,然后传出,消耗大量资源。特别是对于 BT 下载等场景尽管设置了直连仍然会占用大量连接数、端口、内存、CPU 资源。甚至对于游戏的场景,会由于代理程序的处理不当而影响 NAT 类型,导致连接出错。
dae 在内核的较早路径上就对流量进行了分流,直连流量将直接进行三层路由转发,节省了大量内核态到用户态的切换和拷贝开销,此时 Linux 相当于一个纯粹的交换机或路由器。
> 为了让直连生效,对于高级拓扑的用户,请确保按 [kernel-parameters](../en/user-guide/kernel-parameters.md) 配置后,在**关闭** dae 的情况下,其他设备将 dae 所在设备设为网关时,网络是畅通的。例如访问 223.5.5.5 能够得到“UrlPathError”的响应且在 dae 所在设备进行 tcpdump 可以看到客户端设备的请求报文。
因此对于直连流量dae 不会进行 SNAT对于“旁路由”用户这将形成非对称路由即客户端设备发包时流量通过 dae 设备发送到网关,收包时由网关直接发给客户端设备,绕过 dae 设备。
> 这里的旁路由定义为1被设为网关。2对 TCP/UDP 进行 SNAT。3LAN 接口和 WAN 接口属于同一个网段。
>
> 例如笔记本电脑在 192.168.0.3,旁路由在 192.168.0.2,路由器在 192.168.0.1。三层逻辑拓扑为:笔记本电脑 -> 旁路由 -> 路由器,且在路由器一侧只能看到源 IP 是 192.168.0.2 的 TCP/UDP 流量,而没有 192.168.0.3 的 TCP/UDP 流量。
>
> 据目前所知,我们是第一个对旁路由进行定义的(笑)。
非对称路由将带来一个优点和一个可能的问题:
1. 会带来性能提升。由于回包不经过 dae减少了路径直连性能将变得和没有旁路由一样快。
2. 会导致高级防火墙的状态维护失效从而丢包(例如 Sophos Firewall。这一问题在家用网络中一般不会出现。
以 benchmark 来看dae 的直连性能和其他代理程序相比就像个怪物。

View File

@ -0,0 +1,48 @@
# 其他代理协议
> **Note**: dae 目前支持以下代理协议
- [x] HTTP(S), naiveproxy
- [x] Socks
- [x] Socks4
- [x] Socks4a
- [x] Socks5
- [x] VMess(AEAD, alterID=0) / VLESS
- [x] TCP
- [x] WS
- [x] TLS
- [x] gRPC
- [x] Shadowsocks
- [x] AEAD Ciphers
- [x] Stream Ciphers
- [x] simple-obfs
- [ ] v2ray-plugin
- [x] ShadowsocksR
- [x] Trojan
- [x] Trojan-gfw
- [x] Trojan-go
- [x] Tuic (v5)
有其他需求的,一种方式是通过外接其他代理程序来扩展协议支持。下面给出外接 naiveproxy 的例子。
尽管 dae 等代理程序支持 HTTPS 协议,但由于并不使用 chromium 网络栈,削弱了 naiveproxy 的伪装效果,因此可以选择外接 naiveproxy 程序来实现。
1. 启动 naiveproxy
由于 naiveproxy 的 socks 实现可能有些问题,无法被 curl 和 dae 使用,样例中使用 naiveproxy 开启一个 HTTP 监听端口。注意HTTP 代理不支持代理 udp 流量,所以如果你外接其他代理程序,建议优先考虑使用 socks5 端口。
```bash
naiveproxy --listen=http://127.0.0.1:1090 --proxy=https://yourlink
```
2. 在 dae 配置的 node 一节中,新增一行:`http://127.0.0.1:1090`,并记得在所使用的组中使用该节点。
3. 如果你绑定了 WAN 接口,即在 `global.wan_interface` 填写了内容,确保在 routing 一节的靠上位置增加一行,以避免流量从 dae 流向 naiveproxy 之后再次流向 dae造成回环
```shell
pname(naiveproxy) -> must_direct
```
这里的 pname 的含义是进程名。你可通过启动时的命令,或运行时通过 `ps -ef` 命令或者观察 dae 的日志来确定 naiveproxy 的进程名。must_direct 的含义是所有流量,包括 dns 查询都放行直连,不重定向至 dae。
只绑定 LAN 接口的用户不需要做这一步。