xdp-dns-evadeproxy README

The project's README from github.com/Oihalitz/xdp-dns-evadeproxy. As one markdown file: README.md.

xdp.es

evade-proxy

Cuando un operador bloquea IPs de forma indiscriminada, esto se lo salta.

Proxy DNS del resolver público xdp.es

Usar el DNS · Estadísticas · Cómo funciona · IPs bloqueadas

Desarrollado por Oihalitz con mateodd1


Usar el DNS de xdp.es

No hace falta clonar este repo. Guía y copiar-y-pegar en xdp.es.

Adblock

publicidad y malware fuera · DNSSEC · zero-logs

Webhttps://xdp.es
DNS85.208.114.51   2a0e:97c0:c40::51
DoHhttps://dns.xdp.es/dns-query
DoTdns.xdp.es · puerto 853
DoQquic://dns.xdp.es:853
iOS / macOSperfil DoH · perfil DoT

Standard

sin adblock · la misma evasión · DNSSEC · zero-logs

Webhttps://xdp.es
DNS85.208.114.52   2a0e:97c0:c40::52
DoHhttps://lite.xdp.es/dns-query
DoTlite.xdp.es · puerto 853
DoQquic://lite.xdp.es:853
iOS / macOSperfil DoH · perfil DoT

Qué es esto

A veces un operador no bloquea un dominio: bloquea la IP. En Cloudflare anycast esa misma dirección la comparten cientos de sitios, así que el corte es indiscriminado — cae lo que tocaba y lo que no. evade-proxy detecta esas IPs y, en la respuesta DNS, las sustituye por otra del mismo prefijo que no está cortada.

Tres piezas:

evade-proxy Proxy DNS en Rust. Reescribe en el paquete las IPs anycast bloqueadas.
Lista de IPs Cada pocos segundos actualiza qué direcciones están cortadas y se lo pasa al proxy.
Sonda residencial Un equipo en casa confirma IPv6 y CDNs que no son anycast. El servidor en datacenter no ve el bloqueo; la línea del abonado sí.

Cómo se lo salta

cliente → Blocky / DoH / DoT → evade-proxy :5335 → Unbound :5336
                                   │
                                   ├─ blocked_ips.txt       ← lista pública + sonda IPv4
                                   ├─ blocked_ipv6.txt      ← sonda IPv6
                                   ├─ cloudflare_prefixes   ← AS13335
                                   └─ redirects.txt         ← sonda (GitHub / Fastly / Akamai)
  1. Unbound responde con la IP real (DNSSEC).
  2. Si un A, AAAA o hint HTTPS/SVCB está en la blocklist y en un prefijo Cloudflare, el proxy la cambia por un vecino del mismo prefijo que no esté listado, y pone TTL 30 s (EVADE_REWRITE_TTL; 0 restaura el comportamiento anterior, sin caché en el cliente).
  3. Fuera de Cloudflare no se toca nada. En CDNs no-anycast la sonda fija un redirect a una IP verificada desde casa y desde el servidor.

La reescritura es in-place: punteros de compresión, flags y orden de registros se conservan.

Compilar

Rust estable (1.82+):

cargo test --locked
cargo build --release --locked
./target/release/evade-proxy --help

Modo prueba (convive con producción: :15335 / :15337, métricas :15339):

./target/release/evade-proxy --test \
  --redirect example.com=203.0.113.7

--redirect solo se acepta con --test.

Instalar el servidor

Debian/Ubuntu, como root, desde el clone:

sudo ./scripts/install.sh

Instala el binario en /usr/local/bin/evade-proxy, el árbol en /opt/xdp-dns-evadeproxy, escribe /etc/evade-proxy.env y arranca el proxy + el timer de la lista de IPs.

sudo editor /etc/evade-proxy.env    # PROBE_TOKEN=…
sudo systemctl enable --now xdp-probe-server

Exponer el ingest de la sonda con TLS (Caddy):

handle /probe/* {
    reverse_proxy 127.0.0.1:8090
}

No ejecutar a la vez que un evade_proxy en Python: mismos puertos.

Docker

Alternativa a install.sh para quien prefiera contenedores. El stack de ejemplo levanta evade-proxy, un unbound recursivo con validación DNSSEC (su upstream en 127.0.0.1:5336/:5338) y el bucle que sincroniza blocklist + prefijos Cloudflare:

cp evade-proxy.env.example evade-proxy.env   # PROBE_TOKEN=… si usas la sonda
docker compose up -d --build

unbound y blocklist-updater se unen al network namespace de evade-proxy (network_mode: "service:evade-proxy") porque el proxy siempre resuelve su upstream en 127.0.0.1 (ver tabla de puertos más abajo) — no hay forma de apuntarlo a otro contenedor por nombre de servicio.

Para ponerlo delante de un servidor DNS que ya use network_mode: host en el mismo host (p. ej. AdGuard Home), añade network_mode: host al servicio evade-proxy, quita su bloque ports:, y apunta el DNS upstream de ese servidor a 127.0.0.1:5335.

Lista de IPs bloqueadas

scripts/update-blocked-ips.sh, timer cada 15 s:

  1. Descarga el listado público IPv4 (BLOCKLIST_URL)
  2. Se queda solo con direcciones IPv4
  3. Une las IPs que confirmó la sonda
  4. Escribe /etc/unbound/blocked_ips.txt — evade-proxy lo recarga cada 5 s
  5. Une IPv6 de la sonda en /etc/unbound/blocked_ipv6.txt
  6. Actualiza prefijos Cloudflare AS13335 (una vez al día)

No hace falta vaciar la caché del resolver: el proxy reescribe a la salida, también las respuestas ya cacheadas.

Sonda residencial

Cubre IPv6 y CDNs no-anycast. Pide objetivos, sondea TCP:443 + TLS(SNI) + HTTP HEAD y reporta. El servidor solo marca bloqueo si sirve en el datacenter y no en casa, con histéresis (3 rondas para añadir, 2 para quitar).

En probe/domains.json:

En casa (Raspberry Pi / mini-PC):

sudo ./probe/agent/install-agent.sh https://dns.xdp.es/probe <TOKEN> mi-casa

Solo conexiones salientes (funciona detrás del NAT). Detalle: probe/README.md.

Puertos

Escucha Upstream Uso
127.0.0.1:5335 UDP/TCP :5336 camino principal
127.0.0.1:5337 UDP/TCP :5338 segundo camino (Lite)
127.0.0.1:5339 HTTP — /metrics y stats JSON
127.0.0.1:8090 HTTP — ingest de la sonda

Variables: evade-proxy.env.example (EVADE_REWRITE_TTL incluido). Redirects temporales de producción (/run/evade-proxy/redirects.txt):

ejemplo.es=104.18.13.102 1787609000

Layout

src/main.rs                              evade-proxy
scripts/update-blocked-ips.sh            lista de IPs + sonda
scripts/update-cloudflare-prefixes.py    AS13335
probe/probe-server.py                    ingest + diferencial
probe/domains.json                       objetivos
probe/agent/                             sonda de casa
systemd/                                 unidades

Oihalitz con mateodd1 · xdp.es · MIT

xdp-dns-evadeproxy (Oihalitz/xdp-dns-evadeproxy)

Searching Database…

这是什么东西?一个用 Rust 写的 DNS 代理,用来绕过运营商一刀切的 IP 封锁:当运营商把一个被数百个 Cloudflare 网站共享的 anycast 地址整个切断时,它会把 DNS 应答里的这个 IP 改写成同前缀下另一个没被封的地址。
这是要装在我自己服务器上的东西,还是能让我的设备直接指向的在线服务?两者都是。作者运营着公共解析器——dns.xdp.es 和 lite.xdp.es——可以通过纯 IP、DoH、DoT 和 DoQ(端口 853)访问,直接用它们就行;如果你想自己部署,这个仓库就是服务端。
自己跑一个实例需要做些什么?用 Rust 1.82+ 构建,然后在 Debian/Ubuntu 服务器上以 root 身份运行安装脚本:它会把二进制放到 /usr/local/bin/evade-proxy,把目录结构放到 /opt/xdp-dns-evadeproxy,并启动代理和屏蔽列表定时任务。也可以改用 Docker compose 整套部署。
除了这个代理本身,完整部署还需要什么?示例部署把它和一个做 DNSSEC 校验的 unbound 递归解析器以及一个屏蔽列表更新循环搭配在一起。要完整覆盖 IPv6 和非 anycast CDN,还需要在家里的宽带上跑住宅探测程序来上报数据。
这种改写能救回所有被封的网站吗?不能——只改写 Cloudflare 的 anycast IP,这些前缀之外的一切都原样不动。GitHub、Fastly、Akamai 这类非 anycast CDN 走的是经过探测验证的重定向;另外它没法和旧版 Python evadeproxy 同时运行,因为两者要占用相同的端口。
这一切实际运行在哪里?服务端面向 Debian/Ubuntu(Docker 也可以),只监听本机地址:DNS 用 5335 和 5337,指标用 5339,探测数据接收用 8090。住宅探测程序则是给家里 NAT 后面的树莓派或小主机用的,只发出对外连接。
在公共解析器上,我的查询会怎样被处理?xdp.es 的解析器宣称支持 DNSSEC 校验、零日志,并内置广告和恶意软件过滤。自己部署则一切都在你自己的机器上,代理只监听本机地址。
DNS 应答里到底改动了什么?如果一条 A、AAAA 或 HTTPS/SVCB 记录既在屏蔽列表上、又落在 Cloudflare 的前缀内,代理就会把这个 IP 换成同前缀下另一个没被封的地址,并把 TTL 设为 30 秒——可通过 EVADEREWRITETTL 调整,设为 0 则恢复原来的行为。改写是原地进行的,压缩指针、标志位和记录顺序都保持不变。
有了屏蔽列表,为什么还要一个住宅探测程序?因为机房里的服务器看不到家庭宽带用户看到的结果。放在家里的一个小盒子会通过 TCP:443、TLS(SNI) 和 HTTP HEAD 去探测目标并上报;只有当一个网站在机房访问正常、在家里却访问失败时,服务器才标记为被封,并且带迟滞机制:连续 3 轮才加入 IP,连续 2 轮才移除。
为什么要改写 IP,而不是直接换一个解析器?因为封锁打在地址上,而不是域名上:换任何解析器,返回的仍然是那个被数百个网站共享、同样被封的 anycast IP。把它换成同一 Cloudflare 前缀里一个还活着的邻居地址,就能恢复这条地址上所有网站的访问。
运营商增加或解除封锁时,它怎么跟上变化?一个脚本按 15 秒的定时器运行:下载公开的被封 IP 列表,只保留 IPv4 条目,合并你家探测程序确认的结果,写入 /etc/unbound/blockedips.txt,代理每 5 秒重新加载一次。Cloudflare 前缀数据每天刷新一次。
Creator
Oihalitz
Size
0.2 MB
Stars
131
Updated
CommitOct 15
Age
1mo
Commits · 90 Days