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

TrojanClient

TrojanClient پیاده‌سازی سمت client پروتکل Trojan در WaterWall است. hash مربوط به password، command درخواست و header مقصد را با فرمت استاندارد Trojan می‌نویسد و سپس ترافیک application را از نود stream-facing بعدی عبور می‌دهد.

هر دو حالت TCP CONNECT و UDP ASSOCIATE در Trojan پشتیبانی می‌شوند. خود نود TLS ایجاد نمی‌کند و اتصال به server راه دور را هم باز نمی‌کند.

جایگاه رایج

Trojan client برای TCP:

TcpListener -> TrojanClient -> TlsClient -> TcpConnector

Trojan client برای UDP:

UdpListener -> TrojanClient -> TlsClient -> TcpConnector

مقصد پویا از proxy یا router:

Socks5Server -> TrojanClient -> TlsClient -> TcpConnector
SniffRouter -> TrojanClient -> TlsClient -> TcpConnector

TcpConnector معمولاً به address و port سرور Trojan وصل می‌شود. مقصد واقعی سرویس در درخواست Trojan یا در هر Trojan UDP packet قرار می‌گیرد.

نمونه TCP

[
{
"name": "trojan-client",
"type": "TrojanClient",
"settings": {
"password": "secret-password",
"address": "example.com",
"port": 443,
"protocol": "tcp",
"domain-strategy": "do-not-resolve-domains",
"verbose": false
},
"next": "tls-client"
},
{
"name": "tls-client",
"type": "TlsClient",
"settings": {
"sni": "trojan.example.net",
"verify": true
},
"next": "server-out"
},
{
"name": "server-out",
"type": "TcpConnector",
"settings": {
"address": "trojan.example.net",
"port": 443,
"nodelay": true
}
}
]

این request به این شکل ارسال می‌شود:

hex(SHA224("secret-password")) CRLF
command 01
destination example.com:443
CRLF

نمونه Dynamic Destination

{
"name": "trojan-client",
"type": "TrojanClient",
"settings": {
"sha224": "7e240de74fb1ed08fa08d38063f6a6a91462a815c15d3f6abf1d7e0b",
"address": "dest_context->address",
"port": "dest_context->port",
"protocol": "dest_context->protocol"
},
"next": "tls-client"
}

اگر نمی‌خواهید password خام در config نوشته شود، از sha224 استفاده کنید. مقدار آن باید digest شانزدهی ۵۶ کاراکتری SHA224 باشد.

نمونه UDP

{
"name": "trojan-client-udp",
"type": "TrojanClient",
"settings": {
"password": "secret-password",
"address": "dest_context->address",
"port": "dest_context->port",
"protocol": "udp"
},
"next": "tls-client"
}

در حالت UDP، نود قبلی همچنان با UDP کار می‌کند. TrojanClient یک TCP carrier line داخلی می‌سازد، درخواست Trojan UDP ASSOCIATE را روی آن می‌فرستد و هر UDP payload محلی را با framing مخصوص Trojan UDP حمل می‌کند.

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

فیلدهای top-level:

FieldTypeتوضیح
namestringنام دلخواه نود؛ باید داخل config یکتا باشد.
typestringباید دقیقاً "TrojanClient" باشد.
settingsobjectتنظیمات Trojan client؛ نباید خالی باشد.
nextstringنود stream-facing که byteهای پروتکل Trojan را حمل می‌کند؛ در استفاده معمول لازم است.

فیلدهای اجباری داخل settings:

Fieldنام‌های قابل قبولتوضیح
password materialpassword, pass, sha224, password-sha224, password_sha224یا password خام بدهید یا مقدار hex آماده SHA224؛ استفاده هم‌زمان از هر دو مجاز نیست.
target addresstarget-address, address, targetمقصد نهایی host/IP، یا "dest_context->address" / "line->dest_ctx->address".
target portportپورت مقصد نهایی، یا "dest_context->port" / "line->dest_ctx->port". پورت ثابت باید در بازه 1..65535 باشد.

password و pass مقدار خام password در Trojan هستند. TrojanClient مقدار SHA224(password) را محاسبه و به‌شکل hex با حروف کوچک ارسال می‌کند. مقدار aliasهای sha224 باید دقیقاً ۵۶ کاراکتر hexadecimal باشد؛ حروف بزرگ به‌طور خودکار به حروف کوچک تبدیل می‌شوند.

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

FieldDefaultتوضیح
protocol"tcp"Trojan command را انتخاب می‌کند. alias آن proto است.
verbosefalseجزئیات بیشتری از tunnel را log می‌کند.
domain-strategy"do-not-resolve-domains"مشخص می‌کند domain مقصد پیش از نوشتن درخواست به‌صورت محلی resolve شود یا نه.

مقادیر قابل قبول protocol:

Valueرفتار
"tcp" یا "connect"Trojan command 0x01 برای TCP CONNECT ارسال می‌شود.
"udp" یا "udp-associate"Trojan command 0x03 برای UDP ASSOCIATE ارسال می‌شود و UDP datagramها روی carrier داخلی TCP حمل می‌شوند.
"dest_context->protocol" یا "line->dest_ctx->protocol"protocol از destination context ورودی خوانده می‌شود. TCP دقیق 0x01 و UDP دقیق 0x03 را انتخاب می‌کند.

اگر با انتخاب dest_context->protocol، protocol ورودی وجود نداشته باشد، مبهم باشد یا TCP/UDP نباشد، client یک warning در log می‌نویسد و TCP را انتخاب می‌کند.

Domain Strategy

domain-strategy تعیین می‌کند آدرس نهایی در درخواست Trojan و headerهای UDP packet چگونه نوشته شود.

Valueرفتار
"do-not-resolve-domains"نام domain بدون تغییر می‌ماند تا سمت Trojan server آن را resolve کند.
"resolve-domains-and-accept-dns-returned-order"resolve محلی انجام می‌شود و نخستین پاسخ قابل استفاده DNS انتخاب می‌شود.
"resolve-domains-and-prefer-ipv4"پس از resolve محلی، IPv4 در اولویت است و در صورت نیاز IPv6 استفاده می‌شود.
"resolve-domains-and-prefer-ipv6"پس از resolve محلی، IPv6 در اولویت است و در صورت نیاز IPv4 استفاده می‌شود.
"resolve-domains-and-use-only-ipv4"فقط IPv4 پذیرفته می‌شود؛ نبودن پاسخ IPv4 باعث بسته شدن line است.
"resolve-domains-and-use-only-ipv6"فقط IPv6 پذیرفته می‌شود؛ نبودن پاسخ IPv6 باعث بسته شدن line است.
"resolve-domains-with-core-settings"resolve محلی با تنظیمات dns در core.json انجام می‌شود.

با فعال بودن resolve محلی، TrojanClient یک DomainResolver داخلی می‌سازد. prepare hook آن پیش از DNS lookup، مقصد تنظیم‌شده را اعمال می‌کند. اگر مقصد نهایی Trojan نام domain باشد resolve انجام می‌شود؛ چه مقصد از JSON آمده باشد و چه از destination context. آدرس‌های IP بدون تغییر می‌مانند.

فرمت 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

فرمت 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

در حالت UDP، درخواست اولیه UDP ASSOCIATE از 0.0.0.0:0 به‌عنوان associate address استفاده می‌کند. مقصد واقعی راه دور داخل هر Trojan UDP packet بعدی حمل می‌شود.

فرمت Trojan UDP packet:

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

رفتار TCP در زمان اجرا

در upstream Init، مقصد پیش از راه‌اندازی هسته protocol آماده می‌شود؛ یا از طریق prepare hook مربوط به resolver داخلی، یا در صورت غیرفعال بودن DNS محلی مستقیماً در init خود client. سپس TrojanClient همان line را به نود بعدی می‌فرستد.

وقتی transport سمت downstream established شد، TrojanClient:

  1. Trojan request header را upstream ارسال می‌کند
  2. Trojan stream را established علامت می‌زند
  3. downstream Est را به نود قبلی می‌فرستد
  4. payloadهای upstream موجود در صف را ارسال می‌کند
  5. byteهای downstream را که پیش از برقراری مسیر رسیده‌اند تحویل می‌دهد

Trojan response header موفقیت ندارد، بنابراین client منتظر چنین پاسخی نمی‌ماند.

رفتار UDP در زمان اجرا

در حالت UDP دو line وجود دارد:

Lineکاربرد
UDP app lineline قابل مشاهده برای نود UDP-facing قبلی.
TCP carrier lineline داخلی که TrojanClient می‌سازد و به نود stream-facing بعدی می‌فرستد.

بعد از established شدن carrier:

  • carrier، Trojan password و request مربوط به UDP ASSOCIATE را ارسال می‌کند
  • app line یک downstream Est دریافت می‌کند
  • UDP payloadهای محلی موجود در صف با framing مناسب از carrier عبور می‌کنند
  • Trojan UDP frameهای downstream تجزیه می‌شوند، header آن‌ها حذف می‌شود و payload خام UDP به app line برمی‌گردد

payloadهای محلی UDP بزرگ‌تر از ۸۱۹۲ بایت دور ریخته می‌شوند، بی‌آنکه کل association بسته شود. در مقابل، Trojan UDP frame ورودی بزرگ‌تر از ۸۱۹۲ بایت، header خراب، CRLF نامعتبر یا عبور حجم buffer ورودی از 1 MiB باعث بسته شدن line مربوطه است.

client هنگام انتظار برای برقرار شدن مسیر transport/request، حداکثر 1 MiB از داده upstream application را در صف نگه می‌دارد.

رفتار Finish

TrojanClient پیش از فرستادن Finish واقعی، line state خود را از بین می‌برد. برای lineهای معمولی بیرونی هم lineDestroy() را فراخوانی نمی‌کند.

در حالت UDP، مالک TCP carrier line داخلی‌ای است که خودش ساخته است. بسته شدن app line یا carrier line باعث بسته شدن سمت مقابل و از بین رفتن امن carrier line می‌شود.

Padding

TrojanClient ممکن است بزرگ‌ترین header ممکن برای Trojan UDP packet را به ابتدای payload اضافه کند:

required_padding_left = 263

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

Metadata نود

PropertyValue
Node flagkNodeFlagNone
Previous nodeمجاز، در استفاده عادی required
Next nodeمجاز، در استفاده عادی required
Layer groupkNodeLayerAnything
required_padding_left263
Line statetarget context، phase، read stream، pending queue، لینک‌های UDP app/carrier

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

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

  • TLS
  • WebSocket، HTTP، gRPC یا transport wrapperهای دیگر
  • fallback سمت server
  • extensionهای غیر استاندارد Trojan

وقتی به این layerها نیاز دارید، از نودهای جداگانه WaterWall مثل TlsClient، HttpClient، MuxClient یا TcpConnector استفاده کنید.

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

  • انتظار نداشته باشید TrojanClient خودش به سرور Trojan وصل شود؛ بعد از آن TlsClient و connector بگذارید.
  • در deployment عمومی Trojan، TlsClient را حذف نکنید مگر اینکه عمداً Trojan را به‌صورت plain روی wire بخواهید.
  • آدرس سرور Trojan را با آدرس مقصد نهایی اشتباه نگیرید.
  • حالت UDP را با نود بعدی غیر stream-facing استفاده نکنید.