Не проходит соединение xray dokodemo-door + wireguard

Вариантов много:

  • использовать защиту dns на шлюзе сети (самое надежное и гарантированно защищает от “особенностей” разных ОС), то есть ловить любые исходящие на 53 и делать redirect на локальный сервис DoH/DNSCrypt
  • использовать локальный DNS-сервис на самом серваке - можно просто системный (то есть dns-запрос делается на выходе обращений из direct)
  • можно завернуть udp/53 в xray и использовать его встроенный резолвер и кэш DNS (через outbound “dns”)
{
	"dns": {
    	"hosts": {
		},
    	"servers": [
    		{
        		"address": "127.0.0.53","skipFallback": false
    		},
    		{
        		"address": "127.0.2.1","skipFallback": false
    		}
    	],
		"queryStrategy": "UseIPv4",
		"disableCache": false,
		"disableFallback": false,
		"disableFallbackIfMatch": true,
		"tag": "dns-srv"
	}
}

{
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom"
    },
    {
      "tag": "dns-out",
      "protocol": "dns",
      "settings": {
        "address":"127.0.0.1",
        "comment": "на DNS хоста идут прочие запросы кроме A/CNAME, A/CNAME идут в встроенный dns xray",
        "port": 53,
        "nonIPQuery": "skip"
      }
    }
  ]
}

{
  "routing": {
	"rules": [
		{
			"protocol": "dns",
			"outboundTag": "dns-out",
			"ruleTag": "dns"
		}
       ]
 }
  • можно использовать fake-dns, он позволяет перехватывать только dns запросы вместо всего трафика и выдавать на него адреса из указанного вами диапазона, затем дотстаточно заворачивать на nftables в tproxy только эти адреса и использовать снифер fakedns - xray будет сам подставлять вместо них правильные и отправлять запрос дальше

Самое простое конечно - перехватывать udp/53 с локальной сети и просто отправлять на EU VPS, но здесь есть ряд проблем:

  • надо использовать адреса dns-серверов, которые явно не выйдут через RU-сервер, спалив всю схему
  • нет никакой гарантии, что приложения не лазят к своим серверам игноря системные настройки. Например приложения гугля на телефонах всегда стараются ломиться на 8.8.8.8 и 8.8.4.4 и плюют на то, что андроид получил по dhcp. FIrefox, например, даже если у него указано использовать socks-proxy v5 и dns через него, все равно пытается разрешить DNS через полученный от dhcp DNS-сервер (роутер) и это бесит…
  • cам сервер с xray будет слать запросы в открытом виде к указаным на нем DNS (провайдерским например), перехват трафика с самого сервера в tproxy тоже можно сделать, но это более запутанная схема через цепочку с приоритетом routing и можно оторвать себе доступ к серваку

Вы прямо кладезь информации!

Пробую идти по первому варианту. В nat prerouting

    ip saddr != 127.0.0.1 udp dport 53 redirect to 1053
    ip saddr != 127.0.0.1 tcp dport 53 redirect to 1053

Dnscrypt запущен на :1053.

./dnscrypt-proxy -config dnscrypt-proxy.toml
[2025-04-14 20:51:53] [NOTICE] dnscrypt-proxy 2.1.8
[2025-04-14 20:51:53] [NOTICE] Network connectivity detected
[2025-04-14 20:51:53] [NOTICE] Now listening to 127.0.0.1:1053 [UDP]
[2025-04-14 20:51:53] [NOTICE] Now listening to 127.0.0.1:1053 [TCP]
[2025-04-14 20:51:53] [NOTICE] Source [public-resolvers] loaded
[2025-04-14 20:51:53] [NOTICE] Source [relays] loaded
[2025-04-14 20:51:53] [NOTICE] Firefox workaround initialized
[2025-04-14 20:51:59] [NOTICE] [quad9-dnscrypt-ip4-filter-ecs-pri] should upgrade to XChaCha20 for encryption
[2025-04-14 20:51:59] [NOTICE] [quad9-dnscrypt-ip4-filter-ecs-pri] OK (DNSCrypt) - rtt: 43ms
[2025-04-14 20:51:59] [NOTICE] [quad9-dnscrypt-ip4-filter-ecs-pri] OK (DNSCrypt) - rtt: 43ms - additional certificate
[2025-04-14 20:51:59] [NOTICE] [dnscry.pt-fremont-ipv4] OK (DNSCrypt) - rtt: 165ms
[2025-04-14 20:51:59] [NOTICE] [blahdns-de-dnscrypt-v4] OK (DNSCrypt) - rtt: 40ms
[2025-04-14 20:51:59] [NOTICE] [dnscry.pt-tbilisi-ipv4] OK (DNSCrypt) - rtt: 74ms
[2025-04-14 20:51:59] [NOTICE] Sorted latencies:
[2025-04-14 20:51:59] [NOTICE] -    40ms blahdns-de-dnscrypt-v4
[2025-04-14 20:51:59] [NOTICE] -    43ms quad9-dnscrypt-ip4-filter-ecs-pri
[2025-04-14 20:51:59] [NOTICE] -    74ms dnscry.pt-tbilisi-ipv4
[2025-04-14 20:51:59] [NOTICE] -   165ms dnscry.pt-fremont-ipv4
[2025-04-14 20:51:59] [NOTICE] Server with the lowest initial latency: blahdns-de-dnscrypt-v4 (rtt: 40ms)
[2025-04-14 20:51:59] [NOTICE] dnscrypt-proxy is ready - live servers: 4

Запросы dns с самого сервера (пробовал dig @127.0.0.1:1053) работают. Запросы dns с пиров wireguard, подключенных к серверу, не проходят. По tcpdump вижу

tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:54:42.519376 wgserv0 In  IP 10.70.90.3.61067 > one.one.one.one.domain: 27784+ [1au] A? ya.ru. (34)
20:54:42.522054 eth0  Out IP VPS RU.43670 > one.one.one.one.domain: 21202+ PTR? 1.1.1.1.in-addr.arpa. (38)
20:54:42.524727 eth0  In  IP one.one.one.one.domain > VPS RU.43670: 21202 1/0/0 PTR one.one.one.one. (67)
20:54:42.524889 eth0  Out IP VPS RU.39291 > one.one.one.one.domain: 60704+ PTR? 3.90.70.10.in-addr.arpa. (41)
20:54:42.529163 eth0  In  IP one.one.one.one.domain > VPS RU.39291: 60704 NXDomain 0/0/0 (41)
20:54:42.625060 eth0  Out IP VPS RU.37157 > one.one.one.one.domain: 27627+ PTR? 6.145.87.194.in-addr.arpa. (43)
20:54:43.188401 eth0  In  IP one.one.one.one.domain > VPS RU.37157: 27627 NXDomain 0/1/0 (106)
20:54:43.519113 wgserv0 In  IP 10.70.90.3.62976 > one.one.one.one.domain: 27784+ [1au] A? ya.ru. (34)
20:54:43.561040 eth0  Out IP VPS RU.37519 > one.one.one.one.domain: 65369+ PTR? 1.0.0.1.in-addr.arpa. (38)
20:54:43.563909 eth0  In  IP one.one.one.one.domain > VPS RU.37519: 65369 1/0/0 PTR one.one.one.one. (67)
20:54:44.515686 wgserv0 In  IP 10.70.90.3.62580 > dns9.quad9.net.domain: 27784+ [1au] A? ya.ru. (34)
20:54:44.601068 eth0  Out IP VPS RU.38622 > one.one.one.one.domain: 55166+ PTR? 9.9.9.9.in-addr.arpa. (38)
20:54:44.605281 eth0  In  IP one.one.one.one.domain > VPS RU.38622: 55166 1/0/0 PTR dns9.quad9.net. (66)
^C
13 packets captured
17 packets received by filter
0 packets dropped by kernel

Если судить по дампу, пакеты из wg вообще не попадают в redirect, а проходят nat и вылетают с адреса сервера. Не могу навскидку сказать, почему так, вероятно после декапсуляции из wireguard пакеты считаются локальными для сервера и проходят только output.

Теоретически это можно проверить через nftrace
Добавить маркирование пакетов:

ip saddr != 127.0.0.1 udp dport 53 meta nftrace set 1
ip saddr != 127.0.0.1 udp dport 53 redirect to 1053
ip saddr != 127.0.0.1 tcp dport 53 redirect to 1053

Затем запустить nft -nn monitor trace и смотреть, для каждого пакета будут записи с уникальным id, которые будут показывать весь путь. Если в трассировке ничего нет, значит действительно prerouting пакеты не проходят.

Но вообще есть более простой путь организовать клиентам DNS-сервер. Просто добавьте на сервер еще один адрес из подсети wireguard, который будет клиентам доступен. Например вы раздаете им адреса 192.168.10.0/24. Навесьте на сервер адрес 192.168.10.254 - прямо на loopback:

ip address add 192.168.10.254/24 dev lo

Лучше даже использовать маску /32, главное, чтобы не было конфликта с интерфейсом wg и адрес был доступен клиентам.
Если хостер использует netplan, то примерно вот так:

network:
  ethernets:
    lo:
      renderer: networkd
      match:
        name: lo
      addresses:
        - 127.0.0.1/8
        - 192.168.10.254
  version: 2

После этого можете этот адрес отдавать клиентам как DNS, и на нем навесить любой резолвер: unbound, dnsmasq, dnscrypt. Даже можно сделать xray inbound dokodemo 192.168.10.254:53 и направлять куда угодно, хоть в внутренний сервер xray (через routing в outbound dns), хоть в тот же 127.0.0.1:1053

ЕЯПП, способ с просто назначением адреса лупбэк интерфейсу и установкой его в качестве адреса резолвера по функции = назначению в качестве резволвера wireguard адреса сервера (10.70.90.1). Он будет обрататывать только те запросы, которые направлены к нему как к DNS серверу (например, указаны в DNS wireguard конфига пира), но при этом не будет работать перехватчиком всего трафика на порт 53 и перенаправлением его на локальный DNSCrypt. Поправьте меня, если я не прав.

Такую организацию я уже сделал, и она, безусловно, полезна, спасибо что напомнили про dnscrypt. Но если какие-то программы или сама ОСь шлет запросы на захардкоженные DNS серверы типо гугла или КФ, это не может, так ведь? Все равно нужен механизм переадресации на локальный DNSCrypt.

Я еще разбираюсь с редиректом в nftables. Никогда не сталкивался. В output цепочку его нельзя, ругается не недопустимость там redirect дерективы.

P. S. Или вы имели ввиду, что нужно организовать редирект на назначенный лупбэку адрес из другой подсети, попутно разрешив форвардинг с wireguard интерфейса сервера на lo сервера?

Для перехвата всего трафика (в том числе dns) нужно использовать правило для tproxy. Для самого сервера это тоже вариант, но более сложный в настройке. Я просто прописываю в настройках сервера локальный unbound или dnscrypt (для systemd-resolved это можно сделать в файле /etc/systemd/resolved