
مراسل مشفر نظير لنظير مكتوب بلغة Rust مع Noise IK و UDP NAT hole punching
محادثة ند-لند مشفرة من طرف إلى طرف عبر UDP. لا حسابات، ولا خادم مركزي يقوم بتوجيه/تخزين الرسائل، ولا وسيط. فقط نظيران، اتصال مباشر، وتشفير بروتوكول Noise.
https://github.com/user-attachments/assets/939e96d3-45e3-4484-9a27-28c3a0457b05
شخصان يقومان بتشغيل punchline connect <peer> على أجهزتهما. يقوم punchline باختراق NAT الخاص بهما، وإجراء مصافحة مشفرة، وإسقاطهما في محادثة خاصة - كل ذلك في بضع ميلي ثوانٍ. تقوم خوادم STUN والإشارة المضمنة باكتشاف الاتصال ثم تختفي من الطريق.

cargo build --release
قم بتشغيل الخوادم (على جهاز يمكن لكلا النظيرين الوصول إليه)، أو استخدم خوادمي العامة المستضافة على 64.225.107.28 (STUN: المنفذ 3478، الإشارة: المنفذ 8743):
punchline-stund # خادم STUN - يخبر النظائر بعنوان IP العام الخاص بهم
punchline-signald # خادم الإشارة - يطابق النظائر الذين يريدون التحدث
على جهاز كل نظير:
# إنشاء هويتك (زوج مفاتيح X25519)
punchline keygen
# شارك مفتاحك العام مع نظيرك
punchline pubkey
# احفظ مفتاحهم
punchline peers add alice a1b2c3d4...64_hex_chars
# الاتصال (يقوم كلا النظيرين بتشغيل هذا، مستهدفين بعضهما البعض)
punchline connect alice --stun <server>:3478 --signal <server>:8743
يبدأ واجهة TUI مع عرض حي لتقدم الاتصال:
اكتشاف STUN - حل عنوانك الخارجي عبر punchline-stund
خادم الإشارة - الاتصال بـ punchline-signald
انتظار النظير - خادم الإشارة يطابق كلا النظيرين
اختراق NAT - إنشاء مسار UDP المباشر
مصافحة Noise - تبادل المفاتيح المشفر
بمجرد الاكتمال، تكون في المحادثة. اكتب ثم اضغط Enter. اضغط Esc للخروج.
يتكون النظام بأكمله من ثلاثة ملفات تنفيذية، كلها مضمنة في هذا المستودع:
| الملف التنفيذي | الدور | متى يُستخدم |
|---|---|---|
بعد الإعداد الأولي، لا يتم الاتصال بخوادم STUN والإشارة مرة أخرى. كل شيء يتدفق مباشرة بين النظيرين.
punchlineالأعلام العامة:
| العلم | الوصف |
|---|---|
-v | زيادة مستوى تفصيل السجل (-v = تصحيح، -vv = تتبع). |
-q, --quiet | إخفاء جميع مخرجات السجل. |
punchline-stundpunchline-signaldبدلاً من تمرير --stun و --signal في كل مرة، أنشئ ~/.config/punchline/config.toml:
stun_server = "203.0.113.10:3478"
signal_server = "203.0.113.10:8743"
punchline peers # سرد الكل
punchline peers add alice a1b2c3d4... # إضافة
punchline peers remove alice # إزالة
يتم تخزين الأسماء المستعارة في ~/.punchline/known_peers.toml. يمكنك أيضًا الاتصال مباشرة باستخدام مفتاح سداسي عشري خام بطول 64 حرفًا.
punchline status
يظهر هويتك وإعداداتك وإمكانية الوصول إلى الخوادم (يرسل اختبار STUN حقيقي واتصال TCP) وعدد النظائر.
كلا الخادمين يدعمان -v (تصحيح)، -vv (تتبع)، -q (صمت)، --address، و --port:
punchline-stund -v --port 3478
punchline-signald -v --port 8743
قم بتخصيص TUI عبر ~/.config/punchline/style.toml
الأنماط المستخدمة في الفيديو:
[colors]
my_text = "#ebdbb2"
peer_text = "#bdae93"
input_text = "#ebdbb2"
border = "#ebdbb2"
sidebar_key = "#ebdbb2"
sidebar_value = "#bdae93"
[padding]
chat_horizontal = 2
chat_vertical = 1
جميع الألوان هي RGB سداسي عشري. إذا كان الملف غير موجود، يتم استخدام الألوان الافتراضية للمحطة الطرفية.
punchline completions bash > ~/.local/share/bash-completion/completions/punchline
punchline completions zsh > ~/.zfunc/_punchline
punchline completions fish > ~/.config/fish/completions/punchline.fish
اسم البروتوكول الكامل: Noise_IK_25519_ChaChaPoly_SHA256
| المكون | الدور |
|---|---|
| Noise IK | نمط المصافحة - يعرف البادئ المفتاح العام للمستجيب. يكتمل في رسالتين. |
يعني نمط IK أن البادئ يعرف المفتاح العام الثابت للمستجيب قبل بدء المصافحة. كلا النظيرين لديهما بالفعل مفاتيح بعضهما البعض (تم تبادلها خارج النطاق أو عبر سجل النظائر)، لذا لا حاجة إلى الثقة عند أول استخدام.
يحدد Punchline البادئ بشكل حتمي بمقارنة أول 8 بايتات من المفتاح العام لكل نظير كعدد صحيح u64 كبير النهاية. النظير ذو القيمة الأصغر يصبح البادئ. يقوم كلا الجانبين بحساب هذا بشكل مستقل.
الهوية هي مفتاح سري X25519 بطول 32 بايت في ~/.punchline/id_x25519 مع أذونات Unix 0600. المفتاح العام مشتق عند التحميل. يستخدم إنشاء المفاتيح x25519-dalek مع OsRng.
البايت الأول من كل حزمة UDP يحدد نوعها:
ينفذ كلا النظيرين نفس الخوارزمية في وقت واحد:
PROBE (0x00) كل 200ms إلى عنوان النظير الخارجي.PROBE، قم بالتبديل إلى إرسال ACK (0x01).ACK، أرسل ACK نهائيًا واحدًا وأعلن النجاح.تحمل الرسائل (0x02) حمولات مشفرة بـ Noise بترميز UTF-8. الـ Keepalives (0x03) هي حمولات فارغة مشفرة تُرسل كل 10 ثوانٍ للحفاظ على مزامنة عداد nonce الخاص بالتشفير. 30 ثانية دون أي حزمة تؤدي إلى قطع الاتصال.
JSON فوق WebSocket:
// طلب الاقتران (عميل -> خادم)
{ "external_addr": "203.0.113.5:48291", "public_key": "a1b2...", "target_public_key": "d4e5..." }
// رد الاقتران (خادم -> عميل)
{ "target_external_addr": "198.51.100.7:51003", "target_public_key": "d4e5..." }
يتبع RFC 5389 (مبسط): طلب/رد الربط مع XOR-MAPPED-ADDRESS. IPv4 فقط.
مساحة عمل Cargo مع أربع حاويات:
crates/
├── proto/ # مكتبة مشتركة: تشفير، أنواع STUN والإشارة، سمة النقل
├── client/ # عميل P2P: CLI، TUI، منطق الاتصال، إدارة النظائر
├── signald/ # خادم الإشارة: مطابقة WebSocket للنظائر
└── stund/ # خادم STUN: اكتشاف العنوان الخارجي
cargo install punchline # عميل TUI
cargo install punchline-signald # خادم الإشارة
cargo install punchline-stund # خادم STUN
المتطلبات الأساسية: إصدار Rust 2024 (rustc 1.85+)
git clone https://github.com/michal-pielka/punchline.git
cd punchline
cargo build --release
توضع الملفات التنفيذية في target/release/:
punchlinepunchline-signaldpunchline-stundcargo test
تغطي الاختبارات العمليات التشفيرية، ترميز/فك STUN، تسلسل بروتوكول الإشارة، تحليل الإعدادات، إدارة النظائر، تنسيق الألوان، ومصافحة Noise IK.
MIT - انظر LICENSE.
punchline-stund |
| خادم STUN (UDP) - يرد بعنوان IP العام للعميل:المنفذ |
| أثناء الإعداد فقط |
punchline-signald | خادم الإشارة (WebSocket) - يطابق النظائر ويتبادل العناوين | أثناء الإعداد فقط |
punchline | برنامج المراسلة نفسه - CLI، TUI، تشفير، اختراق NAT | دائمًا |
| الأمر | الوصف |
|---|
keygen [--force] [-i path] | إنشاء زوج مفاتيح هوية X25519 جديد. استخدم --force للكتابة فوق دون تأكيد. استخدم -i لتحديد مسار الإخراج. |
pubkey [-i path] | طباعة مفتاحك العام (64 حرفًا سداسيًا عشريًا). استخدم -i لاستخلاصه من ملف مفتاح محدد. |
connect <peer> [-i path] [--stun addr] [--signal addr] | الاتصال بنظير باستخدام اسم مستعار أو مفتاح سداسي عشري خام. استخدم -i لتحديد مفتاح الهوية. يفتح TUI. |
peers | سرد جميع النظائر المعروفة. |
peers add <name> <key> | حفظ المفتاح العام لنظير تحت اسم مستعار. |
peers remove <name> | إزالة نظير بالاسم المستعار. |
config path | طباعة مسار ملف الإعدادات. |
config show | عرض قيم الإعدادات الحالية. |
status | عرض الهوية والإعدادات وإمكانية الوصول إلى الخوادم وعدد النظائر. |
completions <shell> | إنشاء إكمالات أوامر shell (bash، zsh، أو fish). |
| العلم | الوصف |
|---|
--address <addr> | عنوان الربط (الافتراضي: 0.0.0.0). |
--port <port> | منفذ الربط (الافتراضي: 3478). |
-v / -vv | تسجيل التصحيح / التتبع. |
-q | وضع الصمت. |
| العلم | الوصف |
|---|
--address <addr> | عنوان الربط (الافتراضي: 0.0.0.0). |
--port <port> | منفذ الربط (الافتراضي: 8743). |
-v / -vv | تسجيل التصحيح / التتبع. |
-q | وضع الصمت. |
| X25519 | تبادل مفاتيح Diffie-Hellman على المنحنى الإهليلجي (RFC 7748). أمان 128 بت، وقت ثابت. |
| ChaCha20-Poly1305 | تشفير AEAD لتشفير الرسائل (RFC 8439). نفس التشفير المستخدم في TLS 1.3 و WireGuard. |
| SHA-256 | يُستخدم داخليًا بواسطة Noise لاستخلاص المفاتيح وتجزئة المصافحة. |
| البادئة | النوع | المرحلة | الوصف |
|---|
0x00 | PROBE | اختراق NAT | يُرسل كل 200ms لفتح ثقب NAT |
0x01 | ACK | اختراق NAT | يؤكد استلام PROBE |
| (لا يوجد) | مصافحة | مصافحة | حمولة المصافحة المشفرة بـ Noise الخام |
0x02 | رسالة | نقل | رسالة محادثة مشفرة |
0x03 | Keepalive | نقل | حمولة فارغة مشفرة (نبض القلب) |
| الحاوية | الغرض |
|---|
snow | إطار عمل بروتوكول Noise (مصافحة + تشفير النقل) |
x25519-dalek | إنشاء واستخلاص مفاتيح X25519 |
ratatui | إطار عمل واجهة المستخدم الطرفية |
crossterm | معالجة أحداث الطرفية |
clap | تحليل وسيطات سطر الأوامر + إكمالات shell |
tungstenite | عميل/خادم WebSocket |
tracing | تسجيل منظم |