[Настройка Linux, Open source, Python, *nix, Сетевые технологии] ipipou: больше чем просто нешифрованный туннель
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Что мы говорим богу IPv6?
Верно, и богу шифрования сегодня скажем то же.
Здесь будет о нешифрованном IPv4 туннеле, но не о «тёплом ламповом», а о модерновом «светодиодном». А ещё тут мелькают сырые сокеты, и идёт работа с пакетами в пространстве пользователя.
Есть N протоколов туннелирования на любой вкус и цвет:
- стильный, модный, молодёжный WireGuard
- мультифункциональные, как швейцарские ножи, OpenVPN и SSH
- старый и не злой GRE
- максимально простой, шустрый, совсем не шифрованный IPIP
- активно развивающийся GENEVE
- множество других.
Но яжпрограммист, поэтому увеличу N лишь на толику, а разработку настоящих протоколов оставлю Ъ-девелоперам.
В одном ещё не родившемся проекте, которым сейчас занимаюсь, надо достучаться до хостов за NAT-ом извне. Используя для этого протоколы со взрослой криптографией, меня никак не покидало ощущение, что это как из пушки по воробьям. Т.к. туннель используется по большей части только для проковыривания дырки в NAT-e, внутренний трафик обычно тоже зашифрован, все же топят за HTTPS.
Исследуя различные протоколы туннелирования внимание моего внутреннего перфекциониста раз за разом привлекал IPIP из-за его минимальных накладных расходов. Но у него есть полтора существенных недостатка для моих задач:
- он требует публичные IP на обеих сторонах,
- и никакой тебе аутентификации.
Поэтому перфекционист загонялся обратно в тёмный угол черепной коробки, или где он там сидит.
И вот как-то раз читая статьи по нативно поддерживаемым туннелям в Linux наткнулся на FOU (Foo-over-UDP), т.е. что-попало, завёрнутое в UDP. Пока из чего-попало поддерживаются только IPIP и GUE (Generic UDP Encapsulation).
«Вот она серебряная пуля! Мне и простого IPIP за глаза.» — думал я.
На деле пуля оказалась не до конца серебряной. Инкапсуляция в UDP решает первую проблему — к клиентам за NAT-ом можно подключаться снаружи используя заранее установленное соединение, но тут половинка следующего недостатка IPIP расцветает в новом свете — за видимыми публичными IP и портом клиента может скрываться кто угодно из приватной сети (в чистом IPIP этой проблемы нет).
Для решения этой полуторной проблемы и родилась утилита ipipou. В ней реализован самопальный механизм аутентификации удалённого хоста, при этом не нарушая работы ядрёного FOU, который будет шустро и эффективно обрабатывать пакеты в пространстве ядра.
Не нужон твой скрипт!
Ок, если тебе известны публичные порт и IP клиента (например за ним все свои, куда попало не ходют, NAT пытается мапить порты 1-в-1), можешь создать IPIP-over-FOU туннель следующими командами, без всяких скриптов.
на сервере:
# Подгрузить модуль ядра FOU
modprobe fou
# Создать IPIP туннель с инкапсуляцией в FOU.
# Модуль ipip подгрузится автоматически.
ip link add name ipipou0 type ipip \
remote 198.51.100.2 local 203.0.113.1 \
encap fou encap-sport 10000 encap-dport 20001 \
mode ipip dev eth0
# Добавить порт на котором будет слушать FOU для этого туннеля
ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0
# Назначить IP адрес туннелю
ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0
# Поднять туннель
ip link set ipipou0 up
на клиенте:
modprobe fou
ip link add name ipipou1 type ipip \
remote 203.0.113.1 local 192.168.0.2 \
encap fou encap-sport 10001 encap-dport 10000 encap-csum \
mode ipip dev eth0
# Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить.
# peer и peer_port используются для создания соединения сразу при создании FOU-listener-а.
ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0
ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1
ip link set ipipou1 up
где
- ipipou* — имя локального туннельного сетевого интерфейса
- 203.0.113.1 — публичный IP сервера
- 198.51.100.2 — публичный IP клиента
- 192.168.0.2 — IP клиента, назначенный интерфейсу eth0
- 10001 — локальный порт клиента для FOU
- 20001 — публичный порт клиента для FOU
- 10000 — публичный порт сервера для FOU
- encap-csum — опция для добавления контрольной суммы UDP в инкапсулированные UDP пакеты; можно заменить на noencap-csum, чтоб не считать, целостность и так контролируется внешним слоем инкапсуляции (пока пакет находится внутри туннеля)
- eth0 — локальный интерфейс к которому будет привязан ipip туннель
- 172.28.0.1 — IP туннельного интерфейса клиента (приватный)
- 172.28.0.0 — IP туннельного интерфейса сервера (приватный)
Пока живо UDP-соединение, туннель будет в работоспособном состоянии, а как порвётся то, как повезёт — если IP: порт клиента останутся прежними — будет жить, изменятся — порвётся.
Вертать всё взад проще всего выгрузив модули ядра: modprobe -r fou ipip
Даже если аутентификация не требуется публичные IP и порт клиента не всегда известны и часто непредсказуемы или изменчивы (в зависимости от типа NAT). Если опустить encap-dport на стороне сервера, туннель не заработает, не настолько он умный, чтоб брать удалённый порт соединения. В этом случае ipipou тоже может помочь, ну или WireGuard и иже с ним тебе в помощь.
Как это работает?
Клиент (что обычно за NAT-ом) поднимает туннель (как в примере выше), и шлёт пакет с аутентификацией на сервер, чтобы тот настроил туннель со своей стороны. В зависимости от настроек это может быть пустой пакет (просто чтобы сервер увидел публичные IP: порт соединения), или с данными по которым сервер сможет идентифицировать клиента. Данные могут быть простой парольной фразой открытым текстом (в голову приходит аналогия с HTTP Basic Auth) или подписанные приватным ключом специально оформленные данные (по аналогии с HTTP Digest Auth только посильнее, см. функцию client_auth в коде).
На сервере (сторона с публичным IP) при запуске ipipou создаёт обработчик очереди nfqueue и настраивает netfilter так, чтоб нужные пакеты направлялись куда следует: пакеты инициализирующие соединение в очередь nfqueue, а [почти] все остальные прямиком в listener FOU.
Кто не в теме, nfqueue (или NetfilterQueue) — это такая специальная штука для дилетантов, не умеющих разрабатывать модули ядра, которая средствами netfilter (nftables/iptables) позволяет перенаправлять сетевые пакеты в пространство пользователя и обрабатывать их там примитивными подручными средствами: модифицировать (опционально) и отдавать обратно ядру, или отбрасывать.
Для некоторых языков программирования есть биндинги для работы с nfqueue, для bash не нашлось (хех, не удивительно), пришлось использовать python: ipipou использует NetfilterQueue.
Если производительность не критична, с помощью этой штуки можно относительно быстро и просто стряпать собственную логику работы с пакетами на достаточно низком уровне, например ваять экспериментальные протоколы передачи данных, или троллить локальные и удалённые сервисы нестандартным поведением.
Рука об руку с nfqueue работают сырые сокеты (raw sockets), например когда туннель уже настроен, и FOU слушает на нужном порту, обычным способом отправить пакет с этого же порта не получится — занято, зато можно взять и запулить произвольно сгенерированный пакет прямо в сетевой интерфейс используя сырой сокет, хоть над генерацией такого пакета и придётся повозиться чуть больше. Так и создаются в ipipou пакеты с аутентификацией.
Так как ipipou обрабатывает только первые пакеты из соединения (ну и те, которые успели просочиться в очередь до установки соединения) производительность почти не страдает.
Как только ipipou-сервер получает пакет прошедший аутентификацию, туннель создаётся и все последующие пакеты в соединении уже обрабатываются ядром минуя nfqueue. Если соединение протухло, то первый пакет следующего будет направлен в очередь nfqueue, в зависимости от настроек, если это не пакет с аутентификацией, но с последнего запомненного IP и порта клиента, он может быть либо пропущен дальше или отброшен. Если аутентифицированный пакет приходит с новых IP и порта, туннель перенастраивается на их использование.
У обычного IPIP-over-FOU есть ещё одна проблема при работе с NAT — нельзя создать два IPIP туннеля инкапсулированных в UDP с одинаковыми IP, ибо модули FOU и IPIP достаточно изолированы друг от друга. Т.е. пара клиентов за одним публичным IP не сможет одновременно подключиться к одному серверу таким способом. В будущем, возможно, её решат на уровне ядра, но это не точно. А пока проблемы NAT-а можно решить NAT-ом — если случается так, что пара IP адресов уже занята другим туннелем, ipipou сделает NAT с публичного на альтернативный приватный IP, вуаля! — можно создавать туннели пока порты не закончатся.
Т.к. не все пакеты в соединении подписаны, то такая простецкая защита уязвима к MITM, так что если на пути между клиентом и сервером затаился злодей, который может слушать трафик и управлять им, он может перенаправлять пакеты с аутентификацией через другой адрес и создать туннель с недоверенного хоста.
Если у кого есть идеи, как это исправить оставляя основную часть трафика в ядре, не стесняйтесь — высказывайтесь.
К слову сказать инкапсуляция в UDP очень хорошо себя зарекомендовала. По сравнению с инкапсуляцией поверх IP она гораздо стабильнее и чаще быстрее несмотря на дополнительные накладные расходы на заголовок UDP. Это связано с тем, что в Интернете бóльшая часть хостов сносно работает только с тремя наиболее популярными протоколами: TCP, UDP, ICMP. Ощутимая часть может вообще отбрасывать всё остальное, или обрабатывать медленнее, ибо оптимизирована только под эти три.
Например, поэтому QUICK, на базе которого создан HTTP/3, создавался именно поверх UDP, а не поверх IP.
Ну да хватит слов, пора посмотреть как это работает в «реальном мире».
Батл
Для эмуляции реального мира используется iperf3. По степени приближённости к реальности это примерно как эмуляция реального мира в Майнкрафте, но пока сойдёт.
В состязании участвуют:
- эталонный основной канал
- герой этой статьи ipipou
- OpenVPN с аутентификацией, но без шифрования
- OpenVPN в режиме «всё включено»
- WireGuard без PresharedKey, с MTU=1440 (ибо IPv4-only)
Технические данные для гиков
SPL
Метрики снимаются такими командами
на клиенте:
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность.
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"
ICMP latency
ping -c 10 SERVER_IP | tail -1
на сервере (запускается одновременно с клиентом):
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
Конфигурация туннелей
ipipou
сервер
/etc/ipipou/server.conf:
server
number 0
fou-dev eth0
fou-local-port 10000
tunl-ip 172.28.0.0
auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-secret topsecret
auth-lifetime 3600
reply-on-auth-ok
verb 3
systemctl start ipipou@server
клиент
/etc/ipipou/client.conf:
client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3
systemctl start ipipou@client
openvpn (без шифрования, с аутентификацией)
сервер
openvpn --genkey --secret ovpn.key # Затем надо передать ovpn.key клиенту
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
клиент
openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
openvpn (c шифрованием, аутентификацией, через UDP, всё как положено)
Настроено используя openvpn-manage
wireguard
сервер
/etc/wireguard/server.conf:
[Interface]
Address=172.31.192.1/18
ListenPort=51820
PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=
MTU=1440
[Peer]
PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=
AllowedIPs=172.31.192.2/32
systemctl start wg-quick@server
клиент
/etc/wireguard/client.conf:
[Interface]
Address=172.31.192.2/18
PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=
MTU=1440
[Peer]
PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=
AllowedIPs=172.31.192.1/32
Endpoint=SERVER_IP:51820
systemctl start wg-quick@client
Результаты
Сырая страшненькая табличка
SPL
Загрузка CPU сервера не очень показательна, т.к. там крутится много других сервисов иногда они жрут ресурсы:
proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику
# pure
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms
# ipipou
UDP 19.8 98.45 99.47
TCP 18.8 99.56 96.75
ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (auth only, no encryption)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full encryption, auth, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms
# wireguard
UDP 19.3 91.60 94.78
TCP 17.2 96.76 92.87
ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## около-1Gbps канал между VPS Европы и США (1 core)
# pure
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (auth only, no encryption)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
канал на 20 Mbps
канал на 1 оптимистичный Gbps
Во всех случаях ipipou довольно близок по показателям к базовому каналу, и это прекрасно!
Нешифрованный туннель openvpn повёл себя довольно странно в обоих случаях.
Если кто соберётся потестить, будет интересно услышать отзывы.
Да пребудет с нами IPv6 и NetPrickle!
===========
Источник:
habr.com
===========
Похожие новости:
- [Настройка Linux, Программирование, Разработка под Linux] Знакомимся с семафорами в Linux (перевод)
- [Патентование, Сетевое оборудование, Сетевые технологии, Финансы в IT] Суд обязал Cisco выплатить $1,9 млрд за нарушение патентов
- [Биотехнологии, Медгаджеты, Здоровье] Исследователи опубликовали проект бионической ноги со свободной лицензией
- [Agile, DevOps, Git, Open source] Приглашаем на Live-Вебинар — Автоматизация процессов с GitLab CI/CD — 29 Окт., 15:00 -16:00 (MST)
- [*nix, Настройка Linux, Системное администрирование] fork() может глюкануть: это важно (перевод)
- Выпуск языка программирования Python 3.9
- [Python] Выход стабильной версии Python 3.9.0
- [Python, Машинное обучение, Искусственный интеллект, TensorFlow] Подборка статей о машинном обучении: кейсы, гайды и исследования за сентябрь 2020
- Ubuntu RescuePack, Live-дистрибутив для борьбы с компьютерными вирусами
- [Разработка веб-сайтов, Python, Django] Отношение один к одному: связывание модели пользователя с кастомной моделью профиля в Django (перевод)
Теги для поиска: #_nastrojka_linux (Настройка Linux), #_open_source, #_python, #_*nix, #_setevye_tehnologii (Сетевые технологии), #_ipip, #_fou, #_nfqueue, #_linux, #_tunnelirovanie (туннелирование), #_autentifikatsija (аутентификация), #_setevoe_programmirovanie (сетевое программирование), #_setevye_tehnologii (сетевые технологии), #_nastrojka_linux (
Настройка Linux
), #_open_source, #_python, #_*nix, #_setevye_tehnologii (
Сетевые технологии
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 04:58
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Что мы говорим богу IPv6? Верно, и богу шифрования сегодня скажем то же. Здесь будет о нешифрованном IPv4 туннеле, но не о «тёплом ламповом», а о модерновом «светодиодном». А ещё тут мелькают сырые сокеты, и идёт работа с пакетами в пространстве пользователя. Есть N протоколов туннелирования на любой вкус и цвет:
Но яжпрограммист, поэтому увеличу N лишь на толику, а разработку настоящих протоколов оставлю Ъ-девелоперам. В одном ещё не родившемся проекте, которым сейчас занимаюсь, надо достучаться до хостов за NAT-ом извне. Используя для этого протоколы со взрослой криптографией, меня никак не покидало ощущение, что это как из пушки по воробьям. Т.к. туннель используется по большей части только для проковыривания дырки в NAT-e, внутренний трафик обычно тоже зашифрован, все же топят за HTTPS. Исследуя различные протоколы туннелирования внимание моего внутреннего перфекциониста раз за разом привлекал IPIP из-за его минимальных накладных расходов. Но у него есть полтора существенных недостатка для моих задач:
Поэтому перфекционист загонялся обратно в тёмный угол черепной коробки, или где он там сидит. И вот как-то раз читая статьи по нативно поддерживаемым туннелям в Linux наткнулся на FOU (Foo-over-UDP), т.е. что-попало, завёрнутое в UDP. Пока из чего-попало поддерживаются только IPIP и GUE (Generic UDP Encapsulation). «Вот она серебряная пуля! Мне и простого IPIP за глаза.» — думал я. На деле пуля оказалась не до конца серебряной. Инкапсуляция в UDP решает первую проблему — к клиентам за NAT-ом можно подключаться снаружи используя заранее установленное соединение, но тут половинка следующего недостатка IPIP расцветает в новом свете — за видимыми публичными IP и портом клиента может скрываться кто угодно из приватной сети (в чистом IPIP этой проблемы нет). Для решения этой полуторной проблемы и родилась утилита ipipou. В ней реализован самопальный механизм аутентификации удалённого хоста, при этом не нарушая работы ядрёного FOU, который будет шустро и эффективно обрабатывать пакеты в пространстве ядра. Не нужон твой скрипт! Ок, если тебе известны публичные порт и IP клиента (например за ним все свои, куда попало не ходют, NAT пытается мапить порты 1-в-1), можешь создать IPIP-over-FOU туннель следующими командами, без всяких скриптов. на сервере: # Подгрузить модуль ядра FOU
modprobe fou # Создать IPIP туннель с инкапсуляцией в FOU. # Модуль ipip подгрузится автоматически. ip link add name ipipou0 type ipip \ remote 198.51.100.2 local 203.0.113.1 \ encap fou encap-sport 10000 encap-dport 20001 \ mode ipip dev eth0 # Добавить порт на котором будет слушать FOU для этого туннеля ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0 # Назначить IP адрес туннелю ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0 # Поднять туннель ip link set ipipou0 up на клиенте: modprobe fou
ip link add name ipipou1 type ipip \ remote 203.0.113.1 local 192.168.0.2 \ encap fou encap-sport 10001 encap-dport 10000 encap-csum \ mode ipip dev eth0 # Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить. # peer и peer_port используются для создания соединения сразу при создании FOU-listener-а. ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0 ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1 ip link set ipipou1 up где
Пока живо UDP-соединение, туннель будет в работоспособном состоянии, а как порвётся то, как повезёт — если IP: порт клиента останутся прежними — будет жить, изменятся — порвётся. Вертать всё взад проще всего выгрузив модули ядра: modprobe -r fou ipip Даже если аутентификация не требуется публичные IP и порт клиента не всегда известны и часто непредсказуемы или изменчивы (в зависимости от типа NAT). Если опустить encap-dport на стороне сервера, туннель не заработает, не настолько он умный, чтоб брать удалённый порт соединения. В этом случае ipipou тоже может помочь, ну или WireGuard и иже с ним тебе в помощь. Как это работает? Клиент (что обычно за NAT-ом) поднимает туннель (как в примере выше), и шлёт пакет с аутентификацией на сервер, чтобы тот настроил туннель со своей стороны. В зависимости от настроек это может быть пустой пакет (просто чтобы сервер увидел публичные IP: порт соединения), или с данными по которым сервер сможет идентифицировать клиента. Данные могут быть простой парольной фразой открытым текстом (в голову приходит аналогия с HTTP Basic Auth) или подписанные приватным ключом специально оформленные данные (по аналогии с HTTP Digest Auth только посильнее, см. функцию client_auth в коде). На сервере (сторона с публичным IP) при запуске ipipou создаёт обработчик очереди nfqueue и настраивает netfilter так, чтоб нужные пакеты направлялись куда следует: пакеты инициализирующие соединение в очередь nfqueue, а [почти] все остальные прямиком в listener FOU. Кто не в теме, nfqueue (или NetfilterQueue) — это такая специальная штука для дилетантов, не умеющих разрабатывать модули ядра, которая средствами netfilter (nftables/iptables) позволяет перенаправлять сетевые пакеты в пространство пользователя и обрабатывать их там примитивными подручными средствами: модифицировать (опционально) и отдавать обратно ядру, или отбрасывать. Для некоторых языков программирования есть биндинги для работы с nfqueue, для bash не нашлось (хех, не удивительно), пришлось использовать python: ipipou использует NetfilterQueue. Если производительность не критична, с помощью этой штуки можно относительно быстро и просто стряпать собственную логику работы с пакетами на достаточно низком уровне, например ваять экспериментальные протоколы передачи данных, или троллить локальные и удалённые сервисы нестандартным поведением. Рука об руку с nfqueue работают сырые сокеты (raw sockets), например когда туннель уже настроен, и FOU слушает на нужном порту, обычным способом отправить пакет с этого же порта не получится — занято, зато можно взять и запулить произвольно сгенерированный пакет прямо в сетевой интерфейс используя сырой сокет, хоть над генерацией такого пакета и придётся повозиться чуть больше. Так и создаются в ipipou пакеты с аутентификацией. Так как ipipou обрабатывает только первые пакеты из соединения (ну и те, которые успели просочиться в очередь до установки соединения) производительность почти не страдает. Как только ipipou-сервер получает пакет прошедший аутентификацию, туннель создаётся и все последующие пакеты в соединении уже обрабатываются ядром минуя nfqueue. Если соединение протухло, то первый пакет следующего будет направлен в очередь nfqueue, в зависимости от настроек, если это не пакет с аутентификацией, но с последнего запомненного IP и порта клиента, он может быть либо пропущен дальше или отброшен. Если аутентифицированный пакет приходит с новых IP и порта, туннель перенастраивается на их использование. У обычного IPIP-over-FOU есть ещё одна проблема при работе с NAT — нельзя создать два IPIP туннеля инкапсулированных в UDP с одинаковыми IP, ибо модули FOU и IPIP достаточно изолированы друг от друга. Т.е. пара клиентов за одним публичным IP не сможет одновременно подключиться к одному серверу таким способом. В будущем, возможно, её решат на уровне ядра, но это не точно. А пока проблемы NAT-а можно решить NAT-ом — если случается так, что пара IP адресов уже занята другим туннелем, ipipou сделает NAT с публичного на альтернативный приватный IP, вуаля! — можно создавать туннели пока порты не закончатся. Т.к. не все пакеты в соединении подписаны, то такая простецкая защита уязвима к MITM, так что если на пути между клиентом и сервером затаился злодей, который может слушать трафик и управлять им, он может перенаправлять пакеты с аутентификацией через другой адрес и создать туннель с недоверенного хоста. Если у кого есть идеи, как это исправить оставляя основную часть трафика в ядре, не стесняйтесь — высказывайтесь. К слову сказать инкапсуляция в UDP очень хорошо себя зарекомендовала. По сравнению с инкапсуляцией поверх IP она гораздо стабильнее и чаще быстрее несмотря на дополнительные накладные расходы на заголовок UDP. Это связано с тем, что в Интернете бóльшая часть хостов сносно работает только с тремя наиболее популярными протоколами: TCP, UDP, ICMP. Ощутимая часть может вообще отбрасывать всё остальное, или обрабатывать медленнее, ибо оптимизирована только под эти три. Например, поэтому QUICK, на базе которого создан HTTP/3, создавался именно поверх UDP, а не поверх IP. Ну да хватит слов, пора посмотреть как это работает в «реальном мире». Батл Для эмуляции реального мира используется iperf3. По степени приближённости к реальности это примерно как эмуляция реального мира в Майнкрафте, но пока сойдёт. В состязании участвуют:
Технические данные для гиковSPLМетрики снимаются такими командами
на клиенте: UDP CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность. TCP CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"
ICMP latency ping -c 10 SERVER_IP | tail -1
на сервере (запускается одновременно с клиентом): UDP CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
TCP CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
Конфигурация туннелей ipipou сервер /etc/ipipou/server.conf: server
number 0 fou-dev eth0 fou-local-port 10000 tunl-ip 172.28.0.0 auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI= auth-secret topsecret auth-lifetime 3600 reply-on-auth-ok verb 3 systemctl start ipipou@server клиент /etc/ipipou/client.conf: client
number 0 fou-local @eth0 fou-remote SERVER_IP:10000 tunl-ip 172.28.0.1 # pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI= auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso= auth-secret topsecret keepalive 27 verb 3 systemctl start ipipou@client openvpn (без шифрования, с аутентификацией) сервер openvpn --genkey --secret ovpn.key # Затем надо передать ovpn.key клиенту
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key клиент openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
openvpn (c шифрованием, аутентификацией, через UDP, всё как положено) Настроено используя openvpn-manage wireguard сервер /etc/wireguard/server.conf: [Interface]
Address=172.31.192.1/18 ListenPort=51820 PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ= MTU=1440 [Peer] PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM= AllowedIPs=172.31.192.2/32 systemctl start wg-quick@server клиент /etc/wireguard/client.conf: [Interface]
Address=172.31.192.2/18 PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I= MTU=1440 [Peer] PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk= AllowedIPs=172.31.192.1/32 Endpoint=SERVER_IP:51820 systemctl start wg-quick@client Результаты Сырая страшненькая табличкаSPLЗагрузка CPU сервера не очень показательна, т.к. там крутится много других сервисов иногда они жрут ресурсы:
proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику # pure UDP 20.4 99.80 93.34 TCP 19.2 99.67 96.68 ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms # ipipou UDP 19.8 98.45 99.47 TCP 18.8 99.56 96.75 ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms # openvpn0 (auth only, no encryption) UDP 19.3 99.89 72.90 TCP 16.1 95.95 88.46 ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms # openvpn (full encryption, auth, etc) UDP 19.6 99.75 72.35 TCP 17.0 94.47 87.99 ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms # wireguard UDP 19.3 91.60 94.78 TCP 17.2 96.76 92.87 ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms ## около-1Gbps канал между VPS Европы и США (1 core) # pure UDP 729 73.40 39.93 TCP 363 96.95 90.40 ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms # ipipou UDP 714 63.10 23.53 TCP 431 95.65 64.56 ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms # openvpn0 (auth only, no encryption) UDP 193 17.51 1.62 TCP 12 95.45 92.80 ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms # wireguard UDP 629 22.26 2.62 TCP 198 77.40 55.98 ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms канал на 20 Mbps канал на 1 оптимистичный Gbps Во всех случаях ipipou довольно близок по показателям к базовому каналу, и это прекрасно! Нешифрованный туннель openvpn повёл себя довольно странно в обоих случаях. Если кто соберётся потестить, будет интересно услышать отзывы. Да пребудет с нами IPv6 и NetPrickle! =========== Источник: habr.com =========== Похожие новости:
Настройка Linux ), #_open_source, #_python, #_*nix, #_setevye_tehnologii ( Сетевые технологии ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 04:58
Часовой пояс: UTC + 5