پرش به محتویات

مشخصات پروتکل Hysteria 2

Hysteria یک پروکسی TCP و UDP مبتنی بر QUIC است که برای سرعت، امنیت و مقاومت در برابر سانسور طراحی شده است. این سند پروتکل مورد استفاده Hysteria از نسخه 2.0.0 به بعد را توصیف می‌کند که گاهی به صورت داخلی با نام پروتکل «v4» شناخته می‌شود. از اینجا به بعد آن را «پروتکل» یا «پروتکل Hysteria» می‌نامیم.

اصطلاحات

کلمات کلیدی «باید» (MUST)، «نباید» (MUST NOT)، «الزامی است» (REQUIRED)، «خواهد بود» (SHALL)، «نخواهد بود» (SHALL NOT)، «توصیه می‌شود» (SHOULD)، «توصیه نمی‌شود» (SHOULD NOT)، «پیشنهادی» (RECOMMENDED)، «ممکن است» (MAY) و «اختیاری» (OPTIONAL) در این سند باید مطابق با RFC 2119 تفسیر شوند.

پروتکل زیربنایی و قالب سیمی

پروتکل Hysteria باید بر روی پروتکل انتقال استاندارد QUIC RFC 9000 با افزونه دیتاگرام غیرقابل اعتماد پیاده‌سازی شود.

تمام اعداد چندبایتی از قالب Big Endian استفاده می‌کنند.

تمام اعداد صحیح با طول متغیر («varint») مطابق تعریف QUIC (RFC 9000) کدگذاری/رمزگشایی می‌شوند.

احراز هویت و ظاهرسازی HTTP/3

یکی از ویژگی‌های کلیدی پروتکل Hysteria این است که برای یک طرف سوم بدون اعتبارنامه‌های احراز هویت مناسب (چه یک واسطه یا یک کاوشگر فعال)، سرور پروکسی Hysteria دقیقاً مانند یک وب‌سرور استاندارد HTTP/3 رفتار می‌کند. علاوه بر این، ترافیک رمزنگاری‌شده بین کلاینت و سرور از ترافیک عادی HTTP/3 قابل تمایز نیست.

بنابراین، سرور Hysteria باید یک سرور HTTP/3 (مطابق RFC 9114) پیاده‌سازی کرده و درخواست‌های HTTP را مانند هر وب‌سرور استاندارد دیگری پردازش کند. برای جلوگیری از شناسایی الگوهای پاسخ رایج سرورهای Hysteria توسط کاوشگرهای فعال، پیاده‌سازی‌ها توصیه می‌شود به کاربران پیشنهاد دهند که محتوای واقعی میزبانی کنند یا آن را به عنوان پروکسی معکوس برای سایت‌های دیگر تنظیم کنند.

یک کلاینت واقعی Hysteria، هنگام اتصال، باید درخواست HTTP/3 زیر را به سرور ارسال کند:

:method: POST
:path: /auth
:host: hysteria
Hysteria-Auth: [string]
Hysteria-CC-RX: [uint]
Hysteria-Padding: [string]

Hysteria-Auth: اعتبارنامه‌های احراز هویت.

Hysteria-CC-RX: حداکثر نرخ دریافت کلاینت بر حسب بایت در ثانیه. مقدار 0 به معنای ناشناخته است.

Hysteria-Padding: یک رشته پرکننده تصادفی با طول متغیر.

سرور Hysteria باید این درخواست ویژه را شناسایی کند و به جای تلاش برای ارائه محتوا یا ارسال آن به سایت بالادستی، باید کلاینت را با استفاده از اطلاعات ارائه‌شده احراز هویت کند. در صورت موفقیت احراز هویت، سرور باید پاسخ زیر را ارسال کند (کد وضعیت HTTP 233):

:status: 233 HyOK
Hysteria-UDP: [true/false]
Hysteria-CC-RX: [uint/"auto"]
Hysteria-Padding: [string]

Hysteria-UDP: آیا سرور از ارسال UDP پشتیبانی می‌کند.

Hysteria-CC-RX: حداکثر نرخ دریافت سرور بر حسب بایت در ثانیه. مقدار 0 به معنای نامحدود است؛ «auto» به معنای آن است که سرور از ارائه مقدار امتناع می‌کند و از کلاینت می‌خواهد که خود با استفاده از کنترل ازدحام نرخ را تعیین کند.

Hysteria-Padding: یک رشته پرکننده تصادفی با طول متغیر.

برای اطلاعات بیشتر درباره نحوه استفاده از مقادیر Hysteria-CC-RX، بخش کنترل ازدحام را ببینید.

Hysteria-Padding اختیاری است و فقط برای مبهم‌سازی الگوی درخواست/پاسخ در نظر گرفته شده است. هر دو طرف توصیه می‌شود آن را نادیده بگیرند.

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

کلاینت باید کد وضعیت را بررسی کند تا موفقیت احراز هویت را تعیین کند. اگر کد وضعیت چیزی غیر از 233 باشد، کلاینت باید احراز هویت را ناموفق تلقی کرده و از سرور قطع اتصال شود.

پس از (و فقط پس از) عبور کلاینت از احراز هویت، سرور باید این اتصال QUIC را به عنوان یک اتصال پروکسی Hysteria در نظر بگیرد. سپس باید پردازش درخواست‌های پروکسی از کلاینت را مطابق بخش بعدی آغاز کند.

درخواست‌های پروکسی

TCP

برای هر اتصال TCP، کلاینت باید یک جریان دوطرفه QUIC جدید ایجاد کرده و پیام TCPRequest زیر را ارسال کند:

[varint] 0x401 (TCPRequest ID)
[varint] Address length
[bytes] Address string (host:port)
[varint] Padding length
[bytes] Random padding

سرور باید با پیام TCPResponse پاسخ دهد:

[uint8] Status (0x00 = OK, 0x01 = Error)
[varint] Message length
[bytes] Message string
[varint] Padding length
[bytes] Random padding

اگر وضعیت OK باشد، سرور باید ارسال داده بین کلاینت و آدرس TCP مشخص‌شده را تا زمانی که یکی از طرفین اتصال را ببندد آغاز کند. اگر وضعیت Error باشد، سرور باید جریان QUIC را ببندد.

UDP

بسته‌های UDP باید در قالب UDPMessage زیر کپسوله شده و از طریق دیتاگرام غیرقابل اعتماد QUIC ارسال شوند (هم از کلاینت به سرور و هم از سرور به کلاینت):

[uint32] Session ID
[uint16] Packet ID
[uint8] Fragment ID
[uint8] Fragment count
[varint] Address length
[bytes] Address string (host:port)
[bytes] Payload

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

پروتکل روش صریحی برای بستن یک جلسه UDP ارائه نمی‌دهد. اگرچه کلاینت می‌تواند یک Session ID را به طور نامحدود نگه‌داری و استفاده مجدد کند، توصیه می‌شود سرور پورت مرتبط با Session ID را پس از یک دوره عدم فعالیت یا معیارهای دیگر آزاد و مجدداً اختصاص دهد. اگر کلاینت یک بسته UDP به Session ID ای ارسال کند که دیگر توسط سرور شناخته نمی‌شود، سرور باید آن را به عنوان یک جلسه جدید در نظر بگیرد و پورت جدیدی اختصاص دهد.

اگر سرور از ارسال UDP پشتیبانی نمی‌کند، توصیه می‌شود تمام پیام‌های UDP دریافتی از کلاینت را بی‌صدا کنار بگذارد.

تکه‌تکه‌سازی

به دلیل محدودیت اعمال‌شده توسط کانال دیتاگرام غیرقابل اعتماد QUIC، هر بسته UDP که از حداکثر اندازه دیتاگرام QUIC فراتر رود باید تکه‌تکه شود یا کنار گذاشته شود.

برای بسته‌های تکه‌تکه‌شده، هر تکه باید Packet ID منحصر به فرد یکسانی را حمل کند. Fragment ID، که از 0 شروع می‌شود، شاخص از کل Fragment Count را نشان می‌دهد. هم سرور و هم کلاینت باید قبل از پردازش، منتظر رسیدن تمام تکه‌های یک بسته تکه‌تکه‌شده باشند. اگر یک یا چند تکه از یک بسته گم شود، کل بسته باید کنار گذاشته شود.

برای بسته‌هایی که تکه‌تکه نشده‌اند، Fragment Count باید روی 1 تنظیم شود. در این حالت، مقادیر Packet ID و Fragment ID اهمیتی ندارند.

کنترل ازدحام

یک ویژگی منحصر به فرد Hysteria، قابلیت تنظیم نرخ tx/rx (آپلود/دانلود) در سمت کلاینت است. در طول احراز هویت، کلاینت نرخ rx خود را از طریق هدر Hysteria-CC-RX به سرور ارسال می‌کند. سرور می‌تواند از این اطلاعات برای تعیین نرخ ارسال خود به کلاینت استفاده کند و بالعکس، با بازگرداندن نرخ rx خود به کلاینت از طریق همان هدر.

سه حالت خاص وجود دارد:

  • اگر کلاینت 0 ارسال کند، نرخ rx خود را نمی‌داند. سرور باید از یک الگوریتم کنترل ازدحام (مانند BBR، Cubic) برای تنظیم نرخ ارسال خود استفاده کند.
  • اگر سرور با 0 پاسخ دهد، محدودیت پهنای باند ندارد. کلاینت ممکن است با هر نرخی که بخواهد ارسال کند.
  • اگر سرور با «auto» پاسخ دهد، ترجیح می‌دهد نرخی مشخص نکند. کلاینت باید از یک الگوریتم کنترل ازدحام برای تنظیم نرخ ارسال خود استفاده کند.

مبهم‌سازی «Salamander»

پروتکل Hysteria از یک لایه مبهم‌سازی اختیاری با نام رمزی «Salamander» پشتیبانی می‌کند.

«Salamander» تمام بسته‌های QUIC را در قالب زیر کپسوله می‌کند:

[8 bytes] Salt
[bytes] Payload

برای هر بسته QUIC، مبهم‌ساز باید هش BLAKE2b-256 یک salt تصادفی 8 بایتی الحاق‌شده به یک کلید از پیش به اشتراک گذاشته‌شده توسط کاربر را محاسبه کند.

hash = BLAKE2b-256(key + salt)

سپس هش برای مبهم‌سازی بار مفید با استفاده از الگوریتم زیر به کار می‌رود:

for i in range(0, len(payload)):
    payload[i] ^= hash[i % 32]

رمزگشا باید از همان الگوریتم‌ها برای محاسبه هش نمکی و رفع مبهم‌سازی بار مفید استفاده کند. هر بسته نامعتبر باید کنار گذاشته شود.