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:
| Field | Type | توضیح |
|---|---|---|
name | string | نام دلخواه نود؛ باید داخل config یکتا باشد. |
type | string | باید دقیقاً "TrojanServer" باشد. |
settings | object | تنظیمات Trojan server؛ نباید خالی باشد. |
next | string | لازم است؛ ترافیک پذیرفتهشده Trojan به این نود فرستاده میشود. |
باید دقیقاً یکی از روشهای authentication را انتخاب کنید.
تنظیمات Local Authentication
برای local authentication، auth-client-node-name را حذف کنید و حداقل یک raw password تنظیم کنید.
| Field | Type | توضیح |
|---|---|---|
password | string | یک raw Trojan password. |
pass | string | alias برای password. فقط یکی از password یا pass را استفاده کنید. |
passwords | array of strings | چند raw Trojan password. |
users | array | password stringها یا objectهایی با password یا pass. objectها میتوانند username داشته باشند. |
clients | array | alias برای users. فقط یکی از users یا clients را استفاده کنید. |
string مربوط به password نباید خالی باشد. تکرار یک password خطایی fatal در config است، حتی اگر entryهای تکراری usernameهای متفاوتی داشته باشند.
تنظیمات Database Authentication
| Field | Type | توضیح |
|---|---|---|
auth-client-node-name | string | نام یک نود موجود AuthenticationClient داخل همان config file. |
نود اشارهشده باید در config وجود داشته باشد، از نوع AuthenticationClient باشد و به خود TrojanServer اشاره نکند. در
حالت database نیز نباید password، pass، passwords، users یا clients را تنظیم کنید.
تنظیمات اختیاری
| Field | Default | توضیح |
|---|---|---|
connect | true | Trojan TCP CONNECT با command 0x01 را فعال میکند. |
udp | true | Trojan UDP ASSOCIATE با command 0x03 را فعال میکند. |
verbose | false | جزئیات بیشتری از روند authentication را log میکند. |
fallback-node-name | تنظیم نشده | branch جایگزین برای probeهای نامعتبر و احراز هویتنشده. نامهای fallback-node و fallback هم پذیرفته میشوند. |
fallback-intentional-delay-ms | 7 | تأخیر payloadهای upstream که به fallback میروند؛ مقدار 0 آن را غیرفعال میکند و مقدار منفی مجاز نیست. |
fallback-intentional-delay-jitter-ms | 1 | jitter تصادفی برای زمانبندی payloadهای fallback؛ با delay صفر نادیده گرفته میشود و نباید منفی باشد. |
sweep-interval-ms | 1000 | در حالت 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:
- password hash را بررسی میکند
- destination درخواستی را میخواند
- destination را داخل
line->routing_context.dest_ctxمینویسد - credentialهای local یا database را برای routing downstream روی line record میکند
- نود
nextرا مقداردهی اولیه میکند - byteهای TCP body را که همراه request header رسیدهاند میفرستد
- 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 نود
| Property | Value |
|---|---|
| Node flag | kNodeFlagChainHead |
| Previous node | مجاز، در استفاده عادی required |
| Next node | required |
| Layer group | kNodeLayerAnything |
required_padding_left | 263 |
| Line state | authentication 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 آدرس مقصد خودش را حمل میکند.