ipipou: повеќе од обичен нешифриран тунел

Што му велиме на Богот на IPv6?

ipipou: повеќе од обичен нешифриран тунел
Така е, истото ќе му го кажеме и на богот на шифрирањето денес.

Овде ќе зборуваме за нешифриран IPv4 тунел, но не за „топла светилка“, туку за модерна „LED“. И тука трепкаат и сирови приклучоци, а во тек е работа со пакети во корисничкиот простор.

Постојат N протоколи за тунелирање за секој вкус и боја:

  • стилски, модерен, младешки WireGuard
  • мултифункционален, како швајцарски ножеви, OpenVPN и SSH
  • стар и не злобен GRE
  • наједноставниот, брз, целосно нешифриран IPIP
  • активно се развива GЕНЕВЕ
  • многу други.

Но, јас сум програмер, така што ќе го зголемам N само за дел и ќе го оставам развојот на вистински протоколи на развивачите на Комерсант.

Во едно неродено нацртОна што го правам сега е да дојдам до домаќините зад NAT однадвор. Користејќи протоколи со криптографија за возрасни за ова, не можев да го попуштам чувството дека тоа е како да пукаш врапчиња од топ. Бидејќи тунелот во најголем дел се користи само за пробивање дупки во NAT-e, внатрешниот сообраќај обично е исто така шифриран, но тие сепак се дават во HTTPS.

Додека истражував различни протоколи за тунелирање, вниманието на мојот внатрешен перфекционист беше привлечено кон IPIP одново и одново поради минималните трошоци. Но, има еден и пол значајни недостатоци за моите задачи:

  • бара јавни IP од двете страни,
  • и нема автентикација за вас.

Затоа, перфекционистот бил вратен назад во темниот агол на черепот, или каде и да седне таму.

И тогаш еден ден, додека читате статии на природно поддржани тунели во Linux наидов на FOU (Foo-over-UDP), т.е. што и да е, завиткано во UDP. Досега се поддржани само IPIP и GUE (Generic UDP Encapsulation).

„Еве го сребрениот куршум! Едноставен IPIP е доволен за мене“. - Јас мислев.

Всушност, се покажа дека куршумот не е целосно сребрен. Енкапсулацијата во UDP го решава првиот проблем - можете да се поврзете со клиенти зад NAT однадвор користејќи претходно воспоставена врска, но тука половина од следниот недостаток на IPIP процвета во ново светло - секој од приватна мрежа може да се скрие зад видливото јавна IP и клиентска порта (во чиста IPIP овој проблем не постои).

За да се реши овој еден и пол проблем, се роди комуналните услуги ипипу. Имплементира домашен механизам за автентикација на далечински хост, без нарушување на работата на кернелот 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 — ИП на клиентот доделена на интерфејсот 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 IP и портата на клиентот не се секогаш познати и често се непредвидливи или променливи (во зависност од типот NAT). Ако испуштите encap-dport на страната на серверот, тунелот нема да работи, не е доволно паметен да ја земе портата за далечинско поврзување. Во овој случај, може да помогне и ipipou, или WireGuard и други слични на него може да ви помогнат.

Како тоа функционира?

Клиентот (кој обично е зад NAT) отвора тунел (како во примерот погоре) и испраќа пакет за автентикација до серверот така што тој го конфигурира тунелот на негова страна. Во зависност од поставките, ова може да биде празен пакет (само за да може серверот да ја види јавната IP: порта за поврзување) или со податоци со кои серверот може да го идентификува клиентот. Податоците може да бидат едноставна лозинка во јасен текст (аналогијата со HTTP Basic Auth ми доаѓа на ум) или специјално дизајнирани податоци потпишани со приватен клуч (слично на HTTP Digest Auth само посилна, видете ја функцијата client_auth во кодот).

На серверот (страната со јавната IP), кога ќе се стартува ipipou, тој создава управувач за nfqueue queue и го конфигурира netfilter така што потребните пакети се испраќаат таму каде што треба да бидат: пакети што ја иницијализираат врската со nfqueue редот и [речиси] сите останати одат директно кај слушателот ФОУ.

За оние кои не знаат, nfqueue (или NetfilterQueue) е посебна работа за аматери кои не знаат како да развиваат кернел модули, кои со користење на netfilter (nftables/iptables) ви овозможуваат да ги пренасочите мрежните пакети во корисничкиот простор и да ги обработите таму користејќи примитивни средства при рака: изменете (опционално ) и вратете го на јадрото или отфрлете го.

За некои програмски јазици има врски за работа со nfqueue, за bash немаше (хех, не е изненадувачки), морав да користам python: ipipou користи NetfilterQueue.

Ако перформансите не се критични, користејќи ја оваа работа, можете релативно брзо и лесно да ја смислите сопствената логика за работа со пакети на прилично ниско ниво, на пример, да креирате експериментални протоколи за пренос на податоци или да тролате локални и далечински услуги со нестандардно однесување.

Необработените приклучоци работат рака под рака со nfqueue, на пример, кога тунелот е веќе конфигуриран и FOU слуша на саканата порта, нема да можете да испратите пакет од истата порта на вообичаен начин - тој е зафатен, но може да земете и да испратите случајно генериран пакет директно до мрежниот интерфејс користејќи необработен приклучок, иако за генерирање на таков пакет ќе треба малку повеќе да се помешате. Вака се креираат пакетите со автентикација во ipipou.

Бидејќи ipipou ги обработува само првите пакети од врската (и оние што успеале да протечат во редот пред да се воспостави врската), перформансите скоро и да не страдаат.

Штом серверот ipipou прими автентициран пакет, се креира тунел и сите последователни пакети во врската се веќе обработени од кернелот заобиколувајќи го nfqueue. Ако врската не успее, тогаш првиот пакет од следниот ќе биде испратен во редот nfqueue, во зависност од поставките, ако не е пакет со автентикација, туку од последната запаметена IP и клиентска порта, може или да се пренесе на или отфрлени. Ако автентициран пакет доаѓа од нова IP и порта, тунелот е реконфигуриран да ги користи.

Вообичаениот IPIP-over-FOU има уште еден проблем при работа со NAT - невозможно е да се создадат два IPIP тунели инкапсулирани во UDP со иста IP, бидејќи модулите FOU и IPIP се прилично изолирани еден од друг. Оние. пар клиенти зад истата јавна IP адреса нема да можат истовремено да се поврзат на истиот сервер на овој начин. Во иднина, можеби, ќе се реши на ниво на јадрото, но тоа не е сигурно. Во меѓувреме, NAT проблемите може да се решат со NAT - ако се случи пар IP адреси веќе да бидат окупирани од друг тунел, ipipou ќе направи NAT од јавна на алтернативна приватна IP, voila! - можете да креирате тунели додека не се потрошат пристаништата.

Бидејќи Не се потпишани сите пакети во врската, тогаш оваа едноставна заштита е ранлива на MITM, па ако на патот помеѓу клиентот и серверот демне некој негативец кој може да го слуша сообраќајот и да манипулира со него, тој може да ги пренасочи автентицираните пакети преку друга адреса и креирајте тунел од недоверлив домаќин.

Ако некој има идеи за тоа како да го поправите ова додека го оставате најголемиот дел од сообраќајот во јадрото, не двоумете се да зборувате.

Патем, инкапсулацијата во UDP се покажа многу добро. Во споредба со инкапсулацијата преку IP, таа е многу постабилна и често побрза и покрај дополнителните трошоци на насловот на UDP. Ова се должи на фактот дека повеќето хостови на Интернет работат добро само со трите најпопуларни протоколи: TCP, UDP, ICMP. Опипливиот дел може целосно да отфрли сè друго, или да го обработи побавно, бидејќи е оптимизиран само за овие три.

На пример, ова е причината зошто QUICK, на кој се базира HTTP/3, е создаден на врвот на UDP, а не на врвот на IP.

Па, доволно зборови, време е да видиме како функционира во „реалниот свет“.

Битка

Се користи за имитација на реалниот свет iperf3. Во однос на степенот на блискост со реалноста, ова е приближно исто како и емулирањето на реалниот свет во Minecraft, но засега тоа ќе го направи.

Учесници на натпреварот:

  • референтен главен канал
  • херојот на оваа статија е ипипу
  • OpenVPN со автентикација, но без шифрирање
  • OpenVPN во сеопфатен режим
  • WireGuard без PresharedKey, со MTU=1440 (од само IPv4)

Технички податоци за гиковите
Метриката се зема со следните команди:

на клиентот:

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 латентност

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"

Конфигурација на тунел

ипипу
сервер
/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 (со шифрирање, автентикација, преку UDP, сè како што се очекуваше)
Конфигуриран со користење openvpn-управувај

жица
сервер
/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

Наоди

Влажен грд знак
Оптоварувањето на процесорот на серверот не е многу индикативно, бидејќи... Има многу други услуги кои работат таму, понекогаш тие јадат ресурси:

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

ipipou: повеќе од обичен нешифриран тунел

ipipou: повеќе од обичен нешифриран тунел

канал на 1 оптимистички Gbps

ipipou: повеќе од обичен нешифриран тунел

ipipou: повеќе од обичен нешифриран тунел

Во сите случаи, ipipou е доста блиску во перформансите до основниот канал, што е одлично!

Нешифрираниот openvpn тунел се однесуваше прилично чудно и во двата случаи.

Ако некој ќе го тестира, ќе биде интересно да се слушне повратна информација.

Нека IPv6 и NetPrickle бидат со нас!

Извор: www.habr.com

Додадете коментар