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

TcpUdpConnector

TcpUdpConnector یک wrapper در انتهای chain است که TcpConnector و UdpConnector را زیر یک نود جمع می‌کند. با تنظیمات یکسان، یک connector داخلی برای TCP و یکی برای UDP می‌سازد و سپس بر اساس metadata مسیریابی WaterWall، connector مناسب هر line را انتخاب می‌کند.

این نود TCP را داخل UDP کپسوله نمی‌کند و UDP را هم از TCP عبور نمی‌دهد؛ فقط یک wrapper دوپروتکلی برای connectorهاست.

جایگاه رایج

وقتی نود خروجی باید هم TCP و هم UDP را پشتیبانی کند، از TcpUdpConnector استفاده کنید:

Socks5Server -> TcpUdpConnector
TcpUdpListener -> TcpUdpConnector
TcpUdpListener -> SniffRouter -> TcpUdpConnector
PacketsToConnection -> TcpUdpConnector

نود قبلی باید اطلاعات protocol را در destination context یا source context قرار دهد. TcpUdpConnector با همین metadata تصمیم می‌گیرد line را به TcpConnector داخلی بسپارد یا به UdpConnector داخلی.

نمونه ساده

{
"name": "mixed-out",
"type": "TcpUdpConnector",
"settings": {
"address": "198.51.100.10",
"port": 443,
"domain-strategy": "prefer-ipv4",
"nodelay": true,
"fastopen": false,
"large-send-buffer": true,
"large-recv-buffer": true,
"interface": "eth0",
"fwmark": 10,
"balance-mode": "connection"
}
}

هم lineهای TCP و هم lineهای مربوط به peerهای UDP از destination تنظیم‌شده استفاده می‌کنند. TcpConnector داخلی lineهای TCP را مدیریت می‌کند و lineهای UDP به UdpConnector داخلی سپرده می‌شوند.

نمونه dynamic destination

{
"name": "mixed-out",
"type": "TcpUdpConnector",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port",
"domain-strategy": "prefer-ipv4",
"large-send-buffer": true,
"large-recv-buffer": true
}
}

این حالت بعد از نودهایی مثل Socks5Server و SniffRouter مفید است؛ یعنی نودهایی که address، port و protocol مقصد را در routing context قرار می‌دهند.

نمونه weighted destination

{
"name": "mixed-out",
"type": "TcpUdpConnector",
"settings": {
"addresses": [
{
"address": "198.51.100.10",
"port": 443,
"weight": 3
},
{
"address": "198.51.100.20",
"port": 443,
"weight": 1
}
],
"domain-strategy": "prefer-ipv4",
"large-send-buffer": true,
"large-recv-buffer": true,
"balance-mode": "connection"
}
}

آرایه addresses بدون تغییر به هر دو connector داخلی داده می‌شود. اگر امکان انتخاب هر دو protocol وجود دارد، syntax مقصد باید هم برای TcpConnector و هم برای UdpConnector معتبر باشد.

فیلدهای ضروری

فیلدهای سطح بالا:

فیلدنوعتوضیح
namestringنام دلخواه نود. باید داخل فایل config یکتا باشد.
typestringباید دقیقاً "TcpUdpConnector" باشد.
settingsobjectتنظیمات مشترک هر دو connector داخلی؛ باید objectی غیرخالی باشد.

TcpUdpConnector یک chain end است. نباید next داشته باشد.

تنظیمات destination لازم:

سبکفیلدهای لازمتوضیح
مقصد تکیaddress و portهر connector داخلی که انتخاب شود از همین مقصد استفاده می‌کند.
مقصدهای weightedaddressesمقصد هر line از یک فهرست وزن‌دار انتخاب می‌شود. connectorهای داخلی spelling قدیمی adresses را هم می‌پذیرند، اما در configهای جدید از addresses استفاده کنید.

addresses را با address یا port top-level ترکیب نکنید.

تنظیمات مشترک connector

object مربوط به settings باید هنگام راه‌اندازی برای هر دو connector داخلی معتبر باشد. حتی اگر قرار است در زمان اجرا فقط از یک protocol استفاده کنید، این نکته همچنان مهم است؛ چون wrapper موقع خواندن config هر دو connector را می‌سازد.

گزینهروی کدام child اثر داردتوضیح
addressTCP و UDPآدرس ثابت، domain، "src_context->address" یا "dest_context->address".
portTCP و UDPپورت ثابت، "src_context->port" یا "dest_context->port".
addressesTCP و UDPلیست weighted destination.
domain-strategyTCP و UDPاستراتژی انتخاب نتیجه DNS برای مقصدهای domain.
large-send-bufferTCP و UDPتنظیم SO_SNDBUF در صورت پشتیبانی.
large-recv-bufferTCP و UDPتنظیم SO_RCVBUF در صورت پشتیبانی.
fwmarkTCP و UDPاعمال socket mark به سبک Linux در صورت پشتیبانی.
interfaceTCP و UDPمحدود کردن socketهای خروجی به یک network device در صورت پشتیبانی.
source-ipTCP و UDPbind کردن socketهای خروجی به یک source IP محلی مشخص.
nodelayTCP childفعال‌سازی TCP_NODELAY روی TCP socketهای خروجی.
fastopenTCP childدرخواست TCP_FASTOPEN در صورت پشتیبانی.
balance-modeUDP childانتخاب weighted destination در UDP: "connection" یا "packet".

برای جزئیات انتخاب destination، DNS، گزینه‌های socket و balance mode در UDP، به صفحه‌های TcpConnector و UdpConnector مراجعه کنید.

هشدار

UdpConnector از syntax مخصوص UDP مثل "random(x,y)" برای port پشتیبانی می‌کند، اما TcpConnector نه. چون TcpUdpConnector هر دو child connector را می‌سازد، از syntax مخصوص UDP اینجا خودداری کنید مگر اینکه در کد فعلی برای TcpConnector هم معتبر شده باشد.

انتخاب protocol

با دریافت upstream Init، TcpUdpConnector یکی از connectorهای داخلی را انتخاب و آن را در per-line state ذخیره می‌کند. callbackهای بعدی upstream هم به همان connector می‌روند؛ بنابراین حتی اگر نود دیگری بعداً routing context را تغییر دهد، انتخاب اولیه عوض نمی‌شود.

ترتیب انتخاب:

مرحلهرفتار
1line->routing_context.dest_ctx بررسی می‌شود.
2اگر destination context دقیقاً flag مربوط به TCP را داشته باشد، TcpConnector داخلی انتخاب می‌شود.
3اگر destination context دقیقاً flag مربوط به UDP را داشته باشد، UdpConnector داخلی انتخاب می‌شود.
4اگر destination context هیچ protocol flag نداشته باشد، به line->routing_context.src_ctx برمی‌گردد.
5اگر source context دقیقاً flag مربوط به TCP یا UDP را داشته باشد، connector متناظر انتخاب می‌شود.
6اگر protocol مشخصی پیدا نشود، برنامه آن را خطایی fatal در config یا routing در نظر می‌گیرد.

protocol مقصد بر protocol مبدأ اولویت دارد. به این ترتیب، نودهای آگاه از مسیریابی می‌توانند ترافیک inbound را با یک transport بگیرند و transport خروجی را بر اساس مقصد درخواستی انتخاب کنند.

جریان runtime

هنگام راه‌اندازی، TcpUdpConnector دو tunnel داخلی می‌سازد:

  • TcpConnector با نامی شبیه <node-name>.tcp-connector
  • UdpConnector با نامی شبیه <node-name>.udp-connector

هر دو نود داخلی زیر wrapper در chain قرار می‌گیرند. callbackها در زمان اجرا این مسیر را طی می‌کنند:

  1. نود قبلی upstream Init را به TcpUdpConnector می‌فرستد
  2. wrapper یکی از connectorهای داخلی را انتخاب و مقداردهی اولیه می‌کند
  3. callbackهای upstream مربوط به payload، pause، resume، establishment و finish به همان connector فرستاده می‌شوند
  4. callbackهای downstream آن connector به TcpUdpConnector برمی‌گردند
  5. wrapper آن‌ها را در جهت downstream به نود قبلی می‌فرستد

مالکیت line

TcpUdpConnector هیچ connection lineای نمی‌سازد و از بین نمی‌برد. مالک line همان adapter یا bridge قبلی است که آن را ساخته است.

این wrapper فقط connector انتخاب‌شده را در یک per-line state کوچک نگه می‌دارد و پیش از فرستادن Finish واقعی در هر جهت، آن state را پاک می‌کند. lineDestroy() هیچ‌وقت از این نود فراخوانی نمی‌شود.

متادیتای نود

ویژگیمقدار
Node flagkNodeFlagChainEnd
نود قبلیلازم است
نود بعدیمجاز نیست
layer groupkNodeLayerAnything
required_padding_left0
line statechild connector انتخاب‌شده

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

  • از TcpUdpConnector به‌عنوان protocol converter استفاده نکنید؛ کار آن فقط انتخاب بین connector داخلی TCP و UDP است.
  • برای آن next قرار ندهید؛ chain end است.
  • نمی‌توانید برای TCP و UDP دو destination جدا تنظیم کنید؛ settings میان هر دو مشترک است.
  • در config‌هایی که internal TcpConnector هم باید ساخته شود از syntax مخصوص UDP مثل "random(x,y)" استفاده نکنید.
  • آن را بعد از نودی نگذارید که protocol دقیق TCP یا UDP را در metadata مشخص نمی‌کند.