- test_netns_stand.py — 8 тестов: топология и линки, policy routing по fwmark, правила меток и kill-switch, готовность мока и детектора, доставка handshake из LAN и из шлюза с ростом счётчика метки, имитация недоступности провайдера (mode=drop), положительный контроль утечки и блокировка при kill-switch. Тесты пропускаются вне run.sh, чтобы не падать при случайном pytest-прогоне; - README.md харнесса — схема топологии, состав файлов, таблица тестов, переменные окружения и pitfalls (root/CAP_NET_ADMIN, rp_filter, отсутствие nft и ping в alpine-образе). Refs #21 Refs #15
7.4 KiB
tests/netns — сетевой тестовый стенд
Задача #21, используется тестами split-tunnel (#40, #41, #43).
Цель: проверять маршрутизацию, policy routing, метки трафика и fail-closed без реального VPN-провайдера и без доступа к продакшн-сети.
Топология
client ns gw ns (шлюз awg-dash) uplink ns («ISP»)
10.213.0.2/24 ──veth──► 10.213.0.1/24 10.214.0.1/24 ──veth──► 10.214.0.2/24
(LAN-устройство) ip_forward=1, ip rule fwmark 51820 мок-endpoint udp/51820
→ table 51820 → default via uplink детектор утечки
198.51.100.9:9999
| Namespace | По умолчанию | Роль | Адреса |
|---|---|---|---|
awgt21-client |
AWG_NS_CLIENT |
LAN-устройство за шлюзом | 10.213.0.2/24 |
awgt21-gw |
AWG_NS_GW |
хост со шлюзом: forwarding, policy routing, netfilter | 10.213.0.1/24, 10.214.0.1/24 |
awgt21-uplink |
AWG_NS_UPLINK |
«ISP»: мок WireGuard-endpoint + детектор утечки | 10.214.0.2/24, 198.51.100.9/32 |
Правила в gw: ip rule fwmark 51820 lookup 51820 + table 51820 default via 10.214.0.2
(как в wg-quick), метки ставит netfilter на исходящий трафик шлюза (OUTPUT) и на
транзитный трафик LAN (FORWARD). Kill-switch — правило DROP в FORWARD для трафика
LAN, уходящего напрямую в «публичную» сеть 198.51.100.0/24 (RFC 5737 TEST-NET-2).
Адрес детектора утечки поднят на lo аплинка: если при включённом kill-switch пакет
дошёл до детектора — тест падает.
Запуск
make test-netns # поднять стенд, прогнать тесты, снести стенд
make test-netns-keep # оставить топологию и логи для отладки
make test-netns NETNS_ARGS="--no-tests" # только поднять стенд
make test-netns-ci # то же в привилегированном контейнере (путь для CI)
bash tests/netns/topology.sh status # состояние топологии
bash tests/netns/topology.sh down # снести топологию вручную
bash tests/netns/topology.sh killswitch on # включить fail-closed правило
Требования: Linux, root (или CAP_NET_ADMIN + CAP_SYS_ADMIN), ip, python3;
backend netfilter — nft или iptables (в alpine-образе приложения есть только
iptables, на Debian/Ubuntu — оба). Код возврата 3 означает «заблокировано
окружением»: нет прав на создание netns.
Состав
| Файл | Назначение |
|---|---|
run.sh |
точка входа: preflight → топология → мок → тесты → снос |
lib.sh |
конфигурация стенда + правила netfilter (nft/iptables) |
topology.sh |
up/down/status/`killswitch on |
mock_wg_endpoint.py |
мок WireGuard-endpoint: отвечает на handshake initiation |
leak_sink.py |
детектор утечки: UDP+TCP 198.51.100.9:9999 |
probe.py |
генератор тестового трафика из указанного netns |
netns_common.py |
утилиты для тестов (ns_exec, счётчики правил, JSONL-логи) |
run_tests.py |
прогон unittest + JSON-отчёт |
test_netns_stand.py |
8 интеграционных тестов стенда |
Что проверяют тесты (test_netns_stand.py)
test_01— netns и veth-пары созданы, адреса выданы,ip_forward=1.test_02— policy routing:ip rule fwmark 51820→table 51820→ аплинк.test_03— правила меток (OUTPUT/FORWARD) и DROP kill-switch на месте.test_04— мок-endpoint и детектор утечки слушают и залогировалиlisten.test_05— handshake initiation из LAN доходит до мока, мок отвечает (148 → 92 байта), счётчик правила метки растёт.test_06— то же для трафика, инициированного самим шлюзом (OUTPUT-метка).test_07— режимdropмока имитирует недоступность провайдера: ответа нет, пакеты фиксируются; возврат вrespondвосстанавливает стенд.test_08— kill-switch: при выключенном правиле трафик доходит до детектора (положительный контроль), при включённом — утечки нет.
Параметры (переменные окружения)
| Переменная | По умолчанию | Назначение |
|---|---|---|
AWG_NETNS_PREFIX |
awgt21 |
префикс имён namespace/veth |
AWG_NS_CLIENT / AWG_NS_GW / AWG_NS_UPLINK |
awgt21-* |
имена namespace |
AWG_MOCK_PORT |
51820 |
порт мока WireGuard-endpoint |
AWG_LEAK_IP / AWG_LEAK_PORT |
198.51.100.9 / 9999 |
адрес и порт детектора утечки |
AWG_FWMARK / AWG_ROUTE_TABLE |
51820 / 51820 |
метка и таблица policy routing |
AWG_FW_BACKEND |
auto |
nft, iptables или автоопределение |
AWG_NETNS_WORKDIR |
mktemp -d |
каталог логов и отчёта стенда |
Pitfalls
ip netns addв контейнере требует--privileged(CAP_SYS_ADMIN) — иначеrun.shзавершится кодом 3 с сообщением «заблокировано окружением».- rp_filter в шлюзе выставлен в
2(loose): маркированная политика даёт асимметрию reverse-пути, strict-режим молча дропает ответы. - Мок не умеет криптографию: он повторяет раскладку сообщений WireGuard (тип и длины), но не выполняет Noise IK handshake. Годится для топологии, меток, policy routing и fail-closed — не для проверки шифрования, MTU и пропускной способности.
nftв alpine-образе нет: в контейнере используетсяiptables(nft-backend). Стенд поддерживает оба backend; при отладке форсируйтеAWG_FW_BACKEND=iptables.pingв образе нет (пакетiputilsне установлен) — тесты не используют ICMP: связность проверяется UDP-трафиком через мок и детектор утечки.- Остатки после падения:
bash tests/netns/topology.sh downиip netns list.