Проблема и цель
Наличие пакетов в конверте WireGuard (UDP-пакеты, транспортирующие зашифрованную полезную нагрузку) не подвергается туннельной инкапсуляции, несмотря на использование того же IP внутри туннеля, что и вне туннеля.
метод
Поскольку стек маршрутизации (ip route, ip rule ...) работает на уровне 3 (IP), а не на уровне 4 (UDP, используется конвертом), это невозможно решить только с помощью стека маршрутизации без дополнительной помощи. отличать пакеты конверта от пакетов данных.
К счастью, можно пометить пакет с пометкой (чисто внутри, на skbuff пакета, конечно, не на проводе). Затем тег можно повторно использовать в качестве fwmark для стека маршрутизации. Средства (я знаю), способные пометить пакеты, - это iptables, nftables ... и сам WireGuard.
Поскольку Wireguard, тем не менее, может маркировать пакеты после инкапсуляции, нет необходимости использовать iptables/nftables в качестве дополнительной помощи для маршрутизации.
В настоящее время существует раздражающее ограничение в wireguard (которое, безусловно, существует по уважительным причинам, связанным, вероятно, с обработкой маршрутизации): я не смог найти способ установить два одноранговых узла с одинаковыми значениями allow-ips. Так что невозможно просто установить:
AllowedIps = 172.29.244.0/25,172.29.248.128/25
на каждой конечной точке. Попытка этого удалит разрешенные ips на предыдущих конечных точках с тем же значением. Установка любого другого перекрывающегося диапазона (например, изменение маски) будет принята, но не позволит работать некоторым перекрывающимся узлам. Разумеется, работает только IP-адрес единственной удаленной конечной точки. Это единственный способ для правильной работы всей сетки.
Решение
Различают пакеты-конверты и туннелированные пакеты с пометкой. Нет даже необходимости указывать, каким UDP-портом он должен быть, WireGuard обрабатывает эту часть. Используйте эту отметку, чтобы сделать "исключение из исключения" для выбора маршрута.
Выбор сделан
Согласно комментарию OP, пересылка пакетов не требуется, поэтому пересылка не тестировалась.
Сделанный здесь выбор заключается в том, чтобы пометить пакеты, которые не будут входить в туннель, с помощью WireGuard (другое рабочее решение, использующее iptables вместо WireGuard для маркировки пакетов, могло бы сделать обратное и пометить пакеты, поступающие в туннель).
инструкции
Пример конфигурации:
# ip -4 -br addr show dev ens160
ens160@if7 UP 172.29.248.132/25
# ip route
default via 10.0.3.1 dev eth0
10.0.3.0/24 dev eth0 proto kernel scope link src 10.0.3.147
172.29.244.0/25 via 172.29.248.129 dev ens160
172.29.248.128/25 dev ens160 proto kernel scope link src 172.29.248.132
# wg show wg0
interface: wg0
public key: 7FsVTBuIDNQsWj9flHWwMt+kCaE8urEE9bCwcvz6CBM=
private key: (hidden)
listening port: 51820
peer: +NJdQr+piwid1iuC58rbnXFgGo/vZ9d8Gs3xvl3/TxI=
endpoint: 172.29.248.134:51820
allowed ips: (none)
transfer: 14.74 KiB received, 34.35 KiB sent
peer: KrZWEupjHGoHTywwWhg4XXQSyFl/disav7/pyhOK/1Q=
endpoint: 172.29.244.20:51820
allowed ips: (none)
transfer: 11.06 KiB received, 15.65 KiB sent
Поскольку, в конце концов, все может пройти через туннель, используя те же IP-адреса, сеть 192.168.2.0/24 больше не используется. Поскольку ни одно правило маршрутизации не будет ссылаться на эти IP-адреса, их даже можно удалить: у wg0 будет нулевой IP-адрес (все еще можно сохранить их при желании):
# ip addr flush dev wg0
Сконфигурируйте wg0 для маркировки пакетов конвертов с произвольно выбранным значением (здесь 9):
# wg set wg0 fwmark 9
Сконфигурируйте каждый хост WireGuard для принятия IP-адреса конечной точки в туннеле, вот цель:
# wg show wg0|awk 'BEGIN { RS="\n\n" } /^peer/ { printf "wg set wg0 peer %s allowed-ips %s\n",$2,$4 }'|cut -d: -f1 | sh
Который сейчас дает:
# wg show wg0
interface: wg0
public key: 7FsVTBuIDNQsWj9flHWwMt+kCaE8urEE9bCwcvz6CBM=
private key: (hidden)
listening port: 51820
fwmark: 0x9
peer: +NJdQr+piwid1iuC58rbnXFgGo/vZ9d8Gs3xvl3/TxI=
endpoint: 172.29.248.134:51820
allowed ips: 172.29.248.134/32
transfer: 14.74 KiB received, 34.35 KiB sent
peer: KrZWEupjHGoHTywwWhg4XXQSyFl/disav7/pyhOK/1Q=
endpoint: 172.29.244.20:51820
allowed ips: 172.29.244.20/32
transfer: 11.06 KiB received, 15.65 KiB sent
Добавьте маршруты в (произвольно выбранную) таблицу 200 маршрутизации, указав IP-адрес хоста в качестве источника (чтобы избежать, к сожалению, выбора IP-адреса из несвязанного интерфейса) ...
... или только один раз, маршруты для обеих локальных сетей, но для этого потребуется использование WireGuard для любого IP-трафика с любым узлом в локальных сетях:
# localip=$(ip -4 -br addr show dev ens160|awk '{ print $3 }'|cut -d/ -f1)
# ip route add 172.29.244.0/25 dev wg0 table 200 src $localip
# ip route add 172.29.248.128/25 dev wg0 table 200 src $localip
Который дает:
# ip route show table 200
172.29.244.0/25 dev wg0 scope link src 172.29.248.132
172.29.248.128/25 dev wg0 scope link src 172.29.248.132
... либо добавьте на одноранговые маршруты:
# localip=$(ip -4 -br addr show dev ens160|awk '{ print $3 }'|cut -d/ -f1)
# wg show wg0|awk 'BEGIN { RS="\n\n" } /^peer/ { printf "ip route add %s dev wg0 table 200 src %s\n",gensub(":.*$","",1,$4),localip }' localip=$localip | sh
Что дает вместо здесь:
# ip route show table 200
172.29.244.20 dev wg0 scope link src 172.29.248.132
172.29.248.134 dev wg0 scope link src 172.29.248.132
Заранее исправьте проблемы типа «курица и яйцо», которые будут введены правилом после этого, используя непосредственно основную таблицу маршрутизации для пакетов, помеченных WireGuard (эти пакеты 51820/UDP):
# ip rule add priority 32000 fwmark 9 lookup main
"Вставить" после просмотра таблицы 200. На самом деле будут совпадать только пакеты с маршрутами, указанными выше для WireGuard, и они будут использовать туннель через wg0, остальные пакеты продолжат (обычную) основную таблицу:
# ip rule add priority 32100 lookup 200
Это правило 32100 и таблица 200, которые заменяют обычную маршрутизацию, выполняемую внутри wg0, когда для него установлены IP-адреса.
Который сейчас дает:
# ip rule
0: from all lookup local
32000: from all fwmark 0x9 lookup main
32100: from all lookup 200
32766: from all lookup main
32767: from all lookup default
Увы, теперь фильтр обратного пути запускается для входящего трафика, отличного от WireGuard, поступающего из обычного интерфейса (здесь ens160), когда теперь ожидается wg0. Это включает пакеты ответа ARP, необходимые для нахождения одноранговых узлов в одной и той же локальной сети, а также шлюза в другую локальную сеть (у меня нет хорошего объяснения этому). Поэтому для обычного интерфейса rp_filter должен быть установлен в свободный режим (здесь ens160):
echo 2 > /proc/sys/net/ipv4/conf/ens160/rp_filter
С этими настройками, повторенными для других одноранговых узлов, теперь все одноранговые узлы могут обмениваться данными друг с другом, используя свой собственный IP, как если бы не было туннеля (в сетке, потенциально использующей до n * (n-1)/2 туннелей).
Пример: хост получает один пинг и отвечает:
# tcpdump -n -s0 -i wg0 -p
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wg0, link-type RAW (Raw IP), capture size 262144 bytes
05:22:51.553463 IP 172.29.244.20 > 172.29.248.132: ICMP echo request, id 2083, seq 1, length 64
05:22:51.553525 IP 172.29.248.132 > 172.29.244.20: ICMP echo reply, id 2083, seq 1, length 64
В то время как на маршрутизаторе зашифрованный трафик виден (с некоторыми издержками после, вероятно, потому что не было никакой недавней активности):
# tcpdump -n -s0 -i br248 -p
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br248, link-type EN10MB (Ethernet), capture size 262144 bytes
05:22:51.553317 ARP, Request who-has 172.29.248.132 tell 172.29.248.129, length 28
05:22:51.553358 ARP, Reply 172.29.248.132 is-at 2e:02:6e:cf:6d:4f, length 28
05:22:51.553383 IP 172.29.244.20.51820 > 172.29.248.132.51820: UDP, length 128
05:22:51.553583 IP 172.29.248.132.51820 > 172.29.244.20.51820: UDP, length 128
05:22:51.554112 IP 172.29.248.132.51820 > 172.29.244.20.51820: UDP, length 148
05:22:51.555198 IP 172.29.244.20.51820 > 172.29.248.132.51820: UDP, length 92
05:22:51.555748 IP 172.29.248.132.51820 > 172.29.244.20.51820: UDP, length 32