پرش به مطلب اصلی

TrojanServer

TrojanServer پیاده‌سازی سمت server پروتکل Trojan در WaterWall است. stream مربوط به Trojan را از نود قبلی می‌خواند، درستی hash استاندارد SHA224 برای password را بررسی می‌کند، مقصد TCP یا UDP درخواستی را بیرون می‌کشد و ترافیک پذیرفته‌شده را به next می‌فرستد.

برای authentication می‌توانید از فهرست محلی passwordها یا کاربران AuthenticationClient استفاده کنید. fallback اختیاری هم برای probeهای نامعتبر و احراز هویت‌نشده در دسترس است.

این نود جایگزین setup قدیمی دو نودی TrojanAuthServer و TrojanSocksServer شده است.

جایگاه رایج

Trojan server عادی:

TcpListener -> TlsServer -> TrojanServer -> TcpUdpConnector

خروجی فقط TCP:

TcpListener -> TlsServer -> TrojanServer -> TcpConnector

routing بعد از authentication:

TcpListener -> TlsServer -> TrojanServer -> Router

TrojanServer خودش TLS را terminate نمی‌کند. در deployment عمومی Trojan، TlsServer را پیش از آن قرار دهید؛ در غیر این صورت hash مربوط به password و metadata مقصد روی wire دیده می‌شوند.

نمونه Minimal با Local Password

[
{
"name": "tls-in",
"type": "TlsServer",
"settings": {
"cert-file": "/etc/waterwall/fullchain.pem",
"key-file": "/etc/waterwall/privkey.pem"
},
"next": "trojan-server"
},
{
"name": "trojan-server",
"type": "TrojanServer",
"settings": {
"password": "secret-password",
"connect": true,
"udp": true,
"verbose": false
},
"next": "outbound"
},
{
"name": "outbound",
"type": "TcpUdpConnector",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port"
}
}
]

چند User محلی

{
"name": "trojan-server",
"type": "TrojanServer",
"settings": {
"users": [
"secret-password",
{
"username": "alice",
"password": "another-secret"
}
],
"connect": true,
"udp": true
},
"next": "outbound"
}

در حالت allowlist محلی، TrojanServer password خام متناظر را روی line نگه می‌دارد تا Router بتواند ruleهای مربوط به password را بررسی کند. اگر object انتخاب‌شده username داشته باشد، همان username نیز برای مسیریابی روی line ثبت می‌شود.

حالت AuthenticationClient

{
"name": "trojan-server",
"type": "TrojanServer",
"settings": {
"auth-client-node-name": "auth-client",
"connect": true,
"udp": true,
"verbose": false
},
"next": "outbound"
}

در این حالت، AuthenticationClient منبع اصلی authentication است. password مربوط به Trojan را به‌صورت plaintext در فیلد password هر user قرار دهید؛ AuthenticationClient داده لازم برای lookup بر اساس SHA224 را در داخل آماده می‌کند. فیلد name کاربر، account name است و خود Trojan password نیست.

با تنظیم auth-client-node-name دیگر نمی‌توانید password محلی تعریف کنید. TrojanServer خودش یک UserController داخلی پیش از نود outbound قرار می‌دهد؛ بنابراین UserController دیگری را دستی و مستقیم بعد از آن نگذارید.

نمونه Fallback

{
"name": "trojan-server",
"type": "TrojanServer",
"settings": {
"password": "secret-password",
"fallback-node-name": "fallback-service",
"fallback-intentional-delay-ms": 7,
"fallback-intentional-delay-jitter-ms": 1,
"connect": true,
"udp": true
},
"next": "outbound"
}

Fallback برای مقاومت در برابر active probing است. به‌جای بستن فوری ترافیک نامعتبر یا احراز هویت‌نشده، می‌توان آن را به نود دیگری سپرد.

فیلدهای اجباری

فیلدهای top-level:

FieldTypeتوضیح
namestringنام دلخواه نود؛ باید داخل config یکتا باشد.
typestringباید دقیقاً "TrojanServer" باشد.
settingsobjectتنظیمات Trojan server؛ نباید خالی باشد.
nextstringلازم است؛ ترافیک پذیرفته‌شده Trojan به این نود فرستاده می‌شود.

باید دقیقاً یکی از روش‌های authentication را انتخاب کنید.

تنظیمات Local Authentication

برای local authentication، auth-client-node-name را حذف کنید و حداقل یک raw password تنظیم کنید.

FieldTypeتوضیح
passwordstringیک raw Trojan password.
passstringalias برای password. فقط یکی از password یا pass را استفاده کنید.
passwordsarray of stringsچند raw Trojan password.
usersarraypassword stringها یا objectهایی با password یا pass. objectها می‌توانند username داشته باشند.
clientsarrayalias برای users. فقط یکی از users یا clients را استفاده کنید.

string مربوط به password نباید خالی باشد. تکرار یک password خطایی fatal در config است، حتی اگر entryهای تکراری usernameهای متفاوتی داشته باشند.

تنظیمات Database Authentication

FieldTypeتوضیح
auth-client-node-namestringنام یک نود موجود AuthenticationClient داخل همان config file.

نود اشاره‌شده باید در config وجود داشته باشد، از نوع AuthenticationClient باشد و به خود TrojanServer اشاره نکند. در حالت database نیز نباید password، pass، passwords، users یا clients را تنظیم کنید.

تنظیمات اختیاری

FieldDefaultتوضیح
connecttrueTrojan TCP CONNECT با command 0x01 را فعال می‌کند.
udptrueTrojan UDP ASSOCIATE با command 0x03 را فعال می‌کند.
verbosefalseجزئیات بیشتری از روند authentication را log می‌کند.
fallback-node-nameتنظیم نشدهbranch جایگزین برای probeهای نامعتبر و احراز هویت‌نشده. نام‌های fallback-node و fallback هم پذیرفته می‌شوند.
fallback-intentional-delay-ms7تأخیر payloadهای upstream که به fallback می‌روند؛ مقدار 0 آن را غیرفعال می‌کند و مقدار منفی مجاز نیست.
fallback-intentional-delay-jitter-ms1jitter تصادفی برای زمان‌بندی payloadهای fallback؛ با delay صفر نادیده گرفته می‌شود و نباید منفی باشد.
sweep-interval-ms1000در حالت database، این تنظیم اختیاری به UserController داخلی داده می‌شود.

حداقل یکی از connect یا udp باید فعال باشد.

فرمت Request

درخواست قابل قبول Trojan:

password:     56 ASCII hex bytes, hex(SHA224(password))
separator: CRLF
command: 01 CONNECT or 03 UDP ASSOCIATE
destination: ATYP + address + port
separator: CRLF
body: TCP stream bytes or Trojan UDP packets

فرمت destination:

ATYP 01: IPv4 address, 4 bytes, then 2-byte big-endian port
ATYP 03: domain length, domain bytes, then 2-byte big-endian port
ATYP 04: IPv6 address, 16 bytes, then 2-byte big-endian port

فرمت Trojan UDP packet:

destination:  ATYP + address + port
length: 2 bytes big-endian
separator: CRLF
payload: length bytes

جریان Authentication

clientهای Trojan مقدار hex(SHA224(password)) را به‌شکل ۵۶ بایت ASCII hex می‌فرستند. TrojanServer آن را decode و با روش authentication انتخاب‌شده بررسی می‌کند.

در حالت محلی، server مقدار SHA224 هر password خام را از قبل محاسبه می‌کند. در حالت database از API جست‌وجوی SHA224 در AuthenticationClient استفاده می‌شود و پس از خواندن درخواست، user handle برگشتی روی line ثبت می‌شود.

hash کامل ۵۶ بایتی password باید در نخستین callback مربوط به upstream payload حاضر باشد. در غیر این صورت line یک probe نامعتبر و احراز هویت‌نشده در نظر گرفته می‌شود: اگر fallback وجود داشته باشد byteها به آن می‌روند وگرنه line بسته می‌شود. پس از دریافت کامل hash، بخش‌های بعدی درخواست مانند CRLF، command، destination و byteهای ابتدایی body می‌توانند در callbackهای بعدی برسند.

حالت Trojan بدون authentication وجود ندارد.

رفتار Runtime برای TCP CONNECT

برای command 0x01، server:

  1. password hash را بررسی می‌کند
  2. destination درخواستی را می‌خواند
  3. destination را داخل line->routing_context.dest_ctx می‌نویسد
  4. credentialهای local یا database را برای routing downstream روی line record می‌کند
  5. نود next را مقداردهی اولیه می‌کند
  6. byteهای TCP body را که همراه request header رسیده‌اند می‌فرستد
  7. downstream Est را فقط پس از برقرار شدن مسیر outbound انتخاب‌شده می‌فرستد

نود next معمولاً TcpConnector، TcpUdpConnector، Router یا نود دیگری است که destination context را می‌شناسد.

رفتار Runtime برای UDP ASSOCIATE

برای command 0x03، آدرس داخل request اولیه فقط metadata مربوط به association است. مقصد واقعی remote داخل هر Trojan UDP packet حمل می‌شود.

برای هر destination یکتای UDP packet، TrojanServer یک backend UDP line داخلی ایجاد یا reuse می‌کند. آن backend line destination packet را داخل line->routing_context.dest_ctx می‌گیرد، credentialهای authenticated user را حمل می‌کند، و payload خام UDP را به next می‌فرستد.

replyهای backend UDP lineها دوباره داخل Trojan UDP packet framing wrap می‌شوند و به stream اصلی Trojan client برمی‌گردند. در نتیجه یک Trojan UDP association می‌تواند با چند endpoint مختلف UDP صحبت کند.

UDP packet header خراب، domain name با طول صفر، port missing، CRLF نامعتبر، یا UDP payload بزرگ‌تر از 8192 بایت باعث بسته شدن Trojan line مربوطه می‌شود. pending downstream reply data تا 1 MiB محدود است.

رفتار Fallback

Fallback فقط قبل از authentication موفق استفاده می‌شود. بعد از موفق شدن authentication، داده Trojan protocol خراب باعث close شدن line می‌شود و به fallback replay نمی‌شود.

Fallback ممکن است در این حالت‌ها انتخاب شود:

  • invalid password prefix bytes
  • password hash که در اولین upstream payload split شده باشد
  • password CRLF نامعتبر قبل از authentication
  • password hex نامعتبر قبل از authentication
  • lookup ناموفق password
  • آماده نبودن AuthenticationClient
  • prefix ناقص unauthenticated که از initial-buffer limit بزرگ‌تر شود

وقتی fallback انتخاب شود:

  • fallback branch بلافاصله Init دریافت می‌کند
  • byteهای ابتدایی ذخیره‌شده و payloadهای بعدی upstream به fallback فرستاده می‌شوند
  • upstream fallback payloadها می‌توانند با fallback-intentional-delay-ms به علاوه jitter delay شوند
  • upstream Finish تا تحویل payloadهای delayed fallback صبر می‌کند
  • پاسخ‌های downstream در fallback عمداً به تأخیر نمی‌افتند

تأخیر پیش‌فرض fallback عمداً کوتاه است. delay و jitter را بر اساس رفتار سرویس عمومی‌ای تنظیم کنید که fallback قرار است شبیه آن باشد؛ این‌ها mitigation هستند، نه اثبات indistinguishability زمانی.

رفتار Finish

TrojanServer پیش از فرستادن Finish واقعی، line state خود را از بین می‌برد.

client stream line توسط adapter قبلی ساخته شده و TrojanServer آن را destroy نمی‌کند. backend UDP lineهای داخلی توسط TrojanServer ساخته می‌شوند؛ این نود مالک آن lineهاست و هنگام بسته شدن client stream یا backend UDP line، آن‌ها را امن از بین می‌برد.

Padding

TrojanServer ممکن است بزرگ‌ترین Trojan UDP reply header را prepend کند:

required_padding_left = 263

این مقدار ATYP + domain length + 255-byte domain + port + payload length + CRLF را پوشش می‌دهد.

Metadata نود

PropertyValue
Node flagkNodeFlagChainHead
Previous nodeمجاز، در استفاده عادی required
Next noderequired
Layer groupkNodeLayerAnything
required_padding_left263
Line stateauthentication state، phase، read stream، pending queueها، fallback state، map مربوط به UDP backend lineها

قابلیت‌های پشتیبانی‌نشده

این پیاده‌سازی موارد زیر را ایجاد یا مدیریت نمی‌کند:

  • TLS termination
  • WebSocket، HTTP، gRPC یا transport wrapperهای دیگر
  • composition قدیمی TrojanAuthServer به علاوه TrojanSocksServer
  • extensionهای غیر استاندارد Trojan

وقتی به این layerها نیاز دارید، از نودهای جداگانه WaterWall مثل TlsServer، HttpServer، MuxServer، TcpUdpConnector یا Router استفاده کنید.

اشتباه‌های رایج

  • TrojanServer را مستقیماً روی TCP listener عمومی قرار ندهید، مگر اینکه عمداً Trojan را به‌صورت plain روی wire بخواهید؛ برای حالت عادی قبل از آن TlsServer بگذارید.
  • local passwordها را همراه auth-client-node-name تنظیم نکنید.
  • next را روی یک UserController دستی نگذارید؛ database mode خودش UserController داخلی می‌سازد.
  • برای configهای جدید از node nameهای قدیمی TrojanAuthServer و TrojanSocksServer استفاده نکنید.
  • انتظار نداشته باشید آدرس اولیه UDP ASSOCIATE مقصد نهایی UDP را تعیین کند؛ هر Trojan UDP packet آدرس مقصد خودش را حمل می‌کند.