سنتحدث هنا عن نفق IPv4 غير مشفر، ولكن ليس عن "المصباح الدافئ"، ولكن عن "LED" الحديث. وهناك أيضًا وميض مآخذ خام هنا، والعمل جارٍ مع الحزم الموجودة في مساحة المستخدم.
لكنني مبرمج، لذلك سأزيد N فقط بكسر، وترك تطوير البروتوكولات الحقيقية لمطوري Kommersant.
في واحد لم يولد بعد مشروعما أفعله الآن هو الوصول إلى المضيفين خلف NAT من الخارج. باستخدام بروتوكولات التشفير للبالغين لهذا الغرض، لم أستطع التخلص من الشعور بأن الأمر كان مثل إطلاق عصافير من مدفع. لأن يتم استخدام النفق في معظم الأحيان فقط لإحداث ثغرات في NAT-e، وعادةً ما تكون حركة المرور الداخلية مشفرة أيضًا، لكنها لا تزال غارقة في HTTPS.
أثناء البحث في العديد من بروتوكولات الأنفاق، انجذب انتباه منشد الكمال بداخلي إلى IPIP مرارًا وتكرارًا بسبب الحد الأدنى من الحمل. لكن لديها عيبًا ونصفًا كبيرًا بالنسبة لمهامتي:
يتطلب عناوين IP عامة على كلا الجانبين،
ولا مصادقة بالنسبة لك.
لذلك، تم إرجاع الباحث عن الكمال إلى الزاوية المظلمة من الجمجمة، أو أينما كان يجلس هناك.
ثم ذات يوم أثناء قراءة المقالات الأنفاق المدعومة محليا في Linux، صادفت FOU (Foo-over-UDP)، أي. أيا كان، ملفوفة في UDP. حتى الآن، يتم دعم IPIP وGUE (تغليف UDP العام) فقط.
"هذه هي الرصاصة الفضية! IPIP البسيط يكفي بالنسبة لي. - اعتقدت.
في الواقع، تبين أن الرصاصة ليست فضية بالكامل. التغليف في UDP يحل المشكلة الأولى - يمكنك الاتصال بالعملاء خلف NAT من الخارج باستخدام اتصال محدد مسبقًا، ولكن هنا يزدهر نصف العيب التالي لـ IPIP في ضوء جديد - يمكن لأي شخص من شبكة خاصة الاختباء خلف المرئي IP العام ومنفذ العميل (في IPIP النقي لا توجد هذه المشكلة).
لحل هذه المشكلة ونصف، ولدت الأداة المساعدة ipipou. إنه يطبق آلية محلية الصنع لمصادقة مضيف بعيد، دون تعطيل تشغيل kernel FOU، والتي ستقوم بمعالجة الحزم بسرعة وكفاءة في مساحة kernel.
نحن لسنا بحاجة إلى النص الخاص بك!
حسنًا، إذا كنت تعرف المنفذ العام وعنوان 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 الخاص بالعميل: المنفذ كما هو - فسيظل حيًا، وإذا تغير - فسوف ينقطع.
أسهل طريقة لإعادة كل شيء إلى الوراء هي إلغاء تحميل وحدات kernel: 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، و [تقريبًا] كل الباقي يذهب مباشرة إلى المستمع FOU.
بالنسبة لأولئك الذين لا يعرفون، يعد nfqueue (أو NetfilterQueue) أمرًا خاصًا للهواة الذين لا يعرفون كيفية تطوير وحدات kernel، والتي يسمح لك استخدام netfilter (nftables/iptables) بإعادة توجيه حزم الشبكة إلى مساحة المستخدم ومعالجتها هناك باستخدام الوسائل البدائية في متناول اليد: تعديل (اختياري ) وإعادته إلى النواة، أو تجاهله.
بالنسبة لبعض لغات البرمجة، هناك روابط للعمل مع nfqueue، بالنسبة لباش لم يكن هناك أي ارتباطات (هيه، ليس من المستغرب)، اضطررت إلى استخدام بايثون: يستخدم ipipou NetfilterQueue.
إذا لم يكن الأداء أمرًا بالغ الأهمية، فباستخدام هذا الشيء، يمكنك إنشاء منطقك الخاص بسرعة وسهولة نسبيًا للعمل مع الحزم عند مستوى منخفض إلى حد ما، على سبيل المثال، إنشاء بروتوكولات نقل بيانات تجريبية، أو الاستفادة من الخدمات المحلية والبعيدة بسلوك غير قياسي.
تعمل المقابس الأولية جنبًا إلى جنب مع nfqueue، على سبيل المثال، عندما يتم تكوين النفق بالفعل وتستمع FOU إلى المنفذ المطلوب، فلن تتمكن من إرسال حزمة من نفس المنفذ بالطريقة المعتادة - إنه مشغول، ولكن يمكنك أخذ وإرسال حزمة تم إنشاؤها عشوائيًا مباشرةً إلى واجهة الشبكة باستخدام مقبس خام، على الرغم من أن إنشاء مثل هذه الحزمة سيتطلب المزيد من الترقيع. هذه هي الطريقة التي يتم بها إنشاء الحزم ذات المصادقة في ipipou.
نظرًا لأن ipipou يعالج فقط الحزم الأولى من الاتصال (وتلك التي تمكنت من التسرب إلى قائمة الانتظار قبل إنشاء الاتصال)، فإن الأداء لا يتأثر تقريبًا.
بمجرد أن يتلقى خادم ipipou حزمة مصادق عليها، يتم إنشاء نفق وتتم بالفعل معالجة جميع الحزم اللاحقة في الاتصال بواسطة kernel لتجاوز nfqueue. إذا فشل الاتصال، فسيتم إرسال الحزمة الأولى من الحزمة التالية إلى قائمة انتظار nfqueue، اعتمادًا على الإعدادات، إذا لم تكن حزمة مع مصادقة، ولكن من آخر IP ومنفذ العميل الذي تم تذكره، فيمكن إما تمريرها على أو التخلص منها. إذا كانت الحزمة التي تمت مصادقتها تأتي من عنوان IP ومنفذ جديدين، تتم إعادة تكوين النفق لاستخدامهما.
يواجه IPIP-over-FOU المعتاد مشكلة أخرى عند العمل مع NAT - من المستحيل إنشاء أنفاق IPIP مغلفة في UDP بنفس IP، لأن وحدات FOU وIPIP معزولة تمامًا عن بعضها البعض. أولئك. لن يتمكن زوج من العملاء خلف نفس عنوان IP العام من الاتصال بنفس الخادم بهذه الطريقة في نفس الوقت. في المستقبل، ربماسيتم حلها على مستوى النواة، لكن هذا غير مؤكد. في غضون ذلك، يمكن حل مشكلات NAT بواسطة NAT - إذا حدث أن زوجًا من عناوين IP مشغول بالفعل بواسطة نفق آخر، فسوف يقوم ipipou بإجراء NAT من عنوان IP عام إلى عنوان IP خاص بديل، فويلا! - يمكنك إنشاء الأنفاق حتى نفاد المنافذ.
لأن لا يتم توقيع جميع الحزم في الاتصال، فهذه الحماية البسيطة معرضة لـ 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", чтобы лишние пакеты не плодить и не портить производительность.
علامة قبيحة رطبة
تحميل وحدة المعالجة المركزية للخادم ليس مؤشرا للغاية، لأن ... هناك العديد من الخدمات الأخرى التي تعمل هناك، وفي بعض الأحيان تستهلك الموارد:
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 ميجابت في الثانية
قناة لكل 1 جيجابت في الثانية متفائلة
في جميع الحالات، أداء ipipou قريب جدًا من القناة الأساسية، وهو أمر رائع!
تصرف نفق openvpn غير المشفر بشكل غريب جدًا في كلتا الحالتين.
إذا كان أي شخص سيختبره، فسيكون من المثير للاهتمام سماع التعليقات.