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 معتبر باشد.
فیلدهای ضروری
فیلدهای سطح بالا:
| فیلد | نوع | توضیح |
|---|---|---|
name | string | نام دلخواه نود. باید داخل فایل config یکتا باشد. |
type | string | باید دقیقاً "TcpUdpConnector" باشد. |
settings | object | تنظیمات مشترک هر دو connector داخلی؛ باید objectی غیرخالی باشد. |
TcpUdpConnector یک chain end است. نباید next داشته باشد.
تنظیمات destination لازم:
| سبک | فیلدهای لازم | توضیح |
|---|---|---|
| مقصد تکی | address و port | هر connector داخلی که انتخاب شود از همین مقصد استفاده میکند. |
| مقصدهای weighted | addresses | مقصد هر line از یک فهرست وزندار انتخاب میشود. connectorهای داخلی spelling قدیمی adresses را هم میپذیرند، اما در configهای جدید از addresses استفاده کنید. |
addresses را با address یا port top-level ترکیب نکنید.
تنظیمات مشترک connector
object مربوط به settings باید هنگام راهاندازی برای هر دو connector داخلی معتبر باشد. حتی اگر قرار است در زمان اجرا فقط از یک protocol استفاده کنید، این نکته همچنان مهم است؛ چون wrapper موقع خواندن config هر دو connector را میسازد.
| گزینه | روی کدام child اثر دارد | توضیح |
|---|---|---|
address | TCP و UDP | آدرس ثابت، domain، "src_context->address" یا "dest_context->address". |
port | TCP و UDP | پورت ثابت، "src_context->port" یا "dest_context->port". |
addresses | TCP و UDP | لیست weighted destination. |
domain-strategy | TCP و UDP | استراتژی انتخاب نتیجه DNS برای مقصدهای domain. |
large-send-buffer | TCP و UDP | تنظیم SO_SNDBUF در صورت پشتیبانی. |
large-recv-buffer | TCP و UDP | تنظیم SO_RCVBUF در صورت پشتیبانی. |
fwmark | TCP و UDP | اعمال socket mark به سبک Linux در صورت پشتیبانی. |
interface | TCP و UDP | محدود کردن socketهای خروجی به یک network device در صورت پشتیبانی. |
source-ip | TCP و UDP | bind کردن socketهای خروجی به یک source IP محلی مشخص. |
nodelay | TCP child | فعالسازی TCP_NODELAY روی TCP socketهای خروجی. |
fastopen | TCP child | درخواست TCP_FASTOPEN در صورت پشتیبانی. |
balance-mode | UDP 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 را تغییر دهد، انتخاب اولیه عوض نمیشود.
ترتیب انتخاب:
| مرحله | رفتار |
|---|---|
| 1 | line->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-connectorUdpConnectorبا نامی شبیه<node-name>.udp-connector
هر دو نود داخلی زیر wrapper در chain قرار میگیرند. callbackها در زمان اجرا این مسیر را طی میکنند:
- نود قبلی upstream
Initرا بهTcpUdpConnectorمیفرستد - wrapper یکی از connectorهای داخلی را انتخاب و مقداردهی اولیه میکند
- callbackهای upstream مربوط به payload، pause، resume، establishment و finish به همان connector فرستاده میشوند
- callbackهای downstream آن connector به
TcpUdpConnectorبرمیگردند - wrapper آنها را در جهت downstream به نود قبلی میفرستد
مالکیت line
TcpUdpConnector هیچ connection lineای نمیسازد و از بین نمیبرد. مالک line همان adapter یا bridge قبلی است که آن را ساخته است.
این wrapper فقط connector انتخابشده را در یک per-line state کوچک نگه میدارد و پیش از فرستادن Finish واقعی در هر جهت، آن state را پاک میکند. lineDestroy() هیچوقت از این نود فراخوانی نمیشود.
متادیتای نود
| ویژگی | مقدار |
|---|---|
| Node flag | kNodeFlagChainEnd |
| نود قبلی | لازم است |
| نود بعدی | مجاز نیست |
| layer group | kNodeLayerAnything |
required_padding_left | 0 |
| line state | child 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 مشخص نمیکند.