ipipou: چیزی بیش از یک تونل رمزگذاری نشده است

به خدای IPv6 چه می گوییم؟

ipipou: چیزی بیش از یک تونل رمزگذاری نشده است
درست است، ما امروز همین را به خدای رمزگذاری خواهیم گفت.

در اینجا ما در مورد یک تونل IPv4 رمزگذاری نشده صحبت خواهیم کرد، اما نه در مورد یک "لامپ گرم"، بلکه در مورد یک "LED" مدرن. و همچنین سوکت های خام در اینجا چشمک می زند و کار با بسته ها در فضای کاربر در حال انجام است.

پروتکل N تونل زنی برای هر سلیقه و رنگی وجود دارد:

  • شیک، مد روز، جوان WireGuard
  • چند منظوره، مانند چاقوهای سوئیسی، OpenVPN و SSH
  • GRE قدیمی و نه شیطانی
  • ساده ترین، سریع ترین و کاملاً رمزگذاری نشده IPIP
  • به طور فعال در حال توسعه GENEVE
  • بسیاری دیگر.

اما من یک برنامه نویس هستم، بنابراین N را فقط کسری افزایش می دهم و توسعه پروتکل های واقعی را به توسعه دهندگان کومرسانت می سپارم.

در یکی هنوز متولد نشده است پیش نویسکاری که من اکنون انجام می دهم این است که از بیرون به میزبان های پشت NAT دسترسی پیدا کنم. با استفاده از پروتکل‌هایی با رمزنگاری بزرگسالان برای این کار، نمی‌توانستم از این احساس خلاص شوم که شبیه پرتاب گنجشک‌ها از یک توپ است. زیرا تونل در بیشتر موارد فقط برای سوراخ کردن NAT-e استفاده می شود، ترافیک داخلی نیز معمولاً رمزگذاری شده است، اما همچنان در HTTPS غرق می شوند.

در حین تحقیق در مورد پروتکل‌های مختلف تونل‌زنی، توجه کمال‌گرای درونی من به دلیل حداقل سربار آن بارها و بارها به IPIP جلب شد. اما یک و نیم ایراد مهم برای وظایف من دارد:

  • به IP های عمومی در هر دو طرف نیاز دارد،
  • و هیچ احراز هویتی برای شما وجود ندارد.

بنابراین، کمال گرا به گوشه تاریک جمجمه یا هر جایی که آنجا نشسته بود رانده شد.

و سپس یک روز، در حالی که خواندن مقالات در تونل های بومی پشتیبانی شده در لینوکس به FOU (Foo-over-UDP) برخوردم، یعنی. هر چه باشد، در UDP پیچیده شده است. تاکنون فقط IPIP و GUE (Generic UDP Encapsulation) پشتیبانی می شوند.

«اینجا گلوله نقره است! یک IPIP ساده برای من کافی است.» - فکر کردم

در واقع، گلوله کاملاً نقره ای نبود. کپسوله‌سازی در UDP اولین مشکل را حل می‌کند - می‌توانید با استفاده از یک اتصال از پیش تعیین‌شده از بیرون به کلاینت‌های پشت NAT متصل شوید، اما در اینجا نیمی از اشکال بعدی IPIP در یک نور جدید شکوفا می‌شود - هر کسی از یک شبکه خصوصی می‌تواند پشت موارد قابل مشاهده پنهان شود. IP عمومی و پورت مشتری (در IPIP خالص این مشکل وجود ندارد).

برای حل این یک و نیم مشکل، ابزار به وجود آمد ipipou. این یک مکانیسم خانگی برای احراز هویت یک میزبان راه دور، بدون ایجاد اختلال در عملکرد FOU هسته، پیاده‌سازی می‌کند که به سرعت و کارآمدی بسته‌ها را در فضای هسته پردازش می‌کند.

ما به اسکریپت شما نیاز نداریم!

خوب، اگر پورت عمومی و IP کلاینت را می‌دانید (مثلاً هرکسی که پشت آن قرار دارد به جایی نمی‌رود، NAT سعی می‌کند پورت‌های 1-in-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 ایجاد می کند و فیلتر net را پیکربندی می کند تا بسته های لازم در جایی که باید ارسال شوند: بسته هایی که اتصال را به صف nfqueue اولیه می کنند و [تقریبا] بقیه مستقیماً به FOU شنونده می روند.

برای کسانی که نمی دانند، nfqueue (یا NetfilterQueue) یک چیز ویژه برای آماتورهایی است که نمی دانند چگونه ماژول های هسته را توسعه دهند، که با استفاده از netfilter (nftables/iptables) به شما امکان می دهد بسته های شبکه را به فضای کاربر هدایت کنید و آنها را با استفاده از آنجا پردازش کنید. معنای ابتدایی در دسترس است: اصلاح (اختیاری) و برگرداندن آن به هسته، یا دور انداختن آن.

برای برخی از زبان های برنامه نویسی پیوندهایی برای کار با nfqueue وجود دارد، برای bash هیچ کدام وجود نداشت (هه، جای تعجب نیست)، مجبور شدم از پایتون استفاده کنم: 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 است، اما در حال حاضر این کار را انجام خواهد داد.

شرکت کنندگان در مسابقه:

  • کانال اصلی مرجع
  • قهرمان این مقاله ipipou است
  • 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"

پیکربندی تونل

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 (با رمزگذاری، احراز هویت، از طریق UDP، همه چیز همانطور که انتظار می رود)
با استفاده از پیکربندی openvpn-manage

محافظ سیم
سرور
/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

یافته ها

علامت زشت نمناک
بار 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 مگابیت بر ثانیه

ipipou: چیزی بیش از یک تونل رمزگذاری نشده است

ipipou: چیزی بیش از یک تونل رمزگذاری نشده است

کانال در هر 1 گیگابیت بر ثانیه خوش بینانه

ipipou: چیزی بیش از یک تونل رمزگذاری نشده است

ipipou: چیزی بیش از یک تونل رمزگذاری نشده است

در همه موارد، ipipou از نظر عملکرد کاملاً به کانال پایه نزدیک است که عالی است!

تونل openvpn رمزگذاری نشده در هر دو مورد کاملاً عجیب رفتار کرد.

اگر کسی قرار است آن را آزمایش کند، شنیدن بازخورد جالب خواهد بود.

باشد که IPv6 و NetPrickle با ما باشد!

منبع: www.habr.com

اضافه کردن نظر