Socks5Client
Socks5Client یک tunnel میانی stream است که سمت client پروتکل SOCKS5 را پیاده
میکند. این نود از transport بعدی برای اتصال به SOCKS proxy استفاده میکند،
روش ارتباط را مذاکره میکند، در صورت نیاز با username/password احراز هویت
میشود و سپس برای مقصد نهایی تنظیمشده درخواست CONNECT یا UDP ASSOCIATE
میفرستد.
مقصد نوشتهشده در تنظیمات Socks5Client همان مقصد نهایی داخل درخواست SOCKS
است. آدرس خود SOCKS proxy باید در connector بعدی تنظیم شود؛ معمولاً
TcpConnector برای TCP یا TcpUdpConnector در حالتی که relay مربوط به UDP لازم
است.
جایگاه رایج
برای TCP:
TcpListener -> Socks5Client -> TcpConnector
برای TCP و UDP از یک SOCKS server:
TcpUdpListener -> Socks5Client -> TcpUdpConnector
در چیدمان دوم، connector باید برای control connection از TCP استفاده کند و
relay address برگشتی از UDP ASSOCIATE را از طریق UDP در دسترس قرار دهد.
نمونه پایه
{
"name": "socks-client",
"type": "Socks5Client",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port",
"protocol": "tcp",
"user": "alice",
"pass": "secret",
"domain-strategy": "do-not-resolve-domains",
"verbose": false
},
"next": "proxy-transport"
}
proxy-transport باید نودی باشد که به SOCKS5 server متصل میشود؛ برای مثال یک
TcpConnector که آدرس و port مربوط به proxy در آن تنظیم شده است.
پروتکل پویا
اگر line ورودی از قبل protocol مقصد را مشخص کرده است، میتوانید از
dest_context->protocol استفاده کنید تا client همان protocol را دنبال کند.
{
"name": "socks-client",
"type": "Socks5Client",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port",
"protocol": "dest_context->protocol"
},
"next": "proxy-transport"
}
اگر destination context دقیقاً TCP باشد، CONNECT فرستاده میشود و اگر دقیقاً
UDP باشد، UDP ASSOCIATE انجام خواهد شد. در نبود flag مناسب، در حالت مبهم یا
برای protocolی غیر از TCP/UDP، یک warning ثبت میشود و نود به TCP برمیگردد.
مقصد ثابت
اگر میخواهید مقصد SOCKS را بهصورت ثابت در JSON بنویسید:
{
"name": "socks-client",
"type": "Socks5Client",
"settings": {
"address": "example.com",
"port": 443,
"protocol": "tcp",
"domain-strategy": "resolve-domains-and-prefer-ipv4"
},
"next": "proxy-transport"
}
با فعال بودن resolve محلی domain، DomainResolver داخلی پیش از فرستادن درخواست
SOCKS، example.com را resolve میکند. اگر پاسخ IPv4 موجود باشد، همان آدرس در
درخواست SOCKS قرار میگیرد؛ در غیر این صورت fallback مطابق strategy انتخابشده
انجام میشود.
فیلدهای اجباری
| فیلد | نوع | توضیح |
|---|---|---|
settings | object | اجباری است و نباید خالی باشد. |
settings.address / settings.target-address / settings.target | string | آدرس مقصد نهایی SOCKS. میتواند IP یا domain ثابت، dest_context->address یا line->dest_ctx->address باشد. |
settings.port | number یا string | پورت مقصد نهایی. عدد 1 تا 65535، یا dest_context->port / line->dest_ctx->port. |
next | string | اجباری است و به transport سمت SOCKS proxy اشاره میکند. |
فیلدهای اختیاری
| فیلد | پیشفرض | توضیح |
|---|---|---|
settings.protocol / settings.proto | tcp | مقدارهای مجاز: tcp, connect, udp, udp-associate, dest_context->protocol, line->dest_ctx->protocol. |
settings.user / settings.username | تنظیم نشده | نام کاربری SOCKS5. باید همراه pass / password بیاید. |
settings.pass / settings.password | تنظیم نشده | رمز SOCKS5. باید همراه user / username بیاید. |
settings.domain-strategy | do-not-resolve-domains | تعیین میکند domain پیش از درخواست SOCKS بهصورت local resolve شود یا همان domain ارسال گردد. |
settings.verbose | false | logهای debug بیشتری فعال میکند. |
username و password باید غیرخالی باشند و هر کدام حداکثر ۲۵۵ بایت طول داشته باشند. اگر فقط یکی از آنها تنظیم شود، ساخت نود شکست میخورد.
Domain strategy
Socks5Client پیش از اجرای منطق SOCKS، target تنظیمشده را آماده میکند و
protocol انتخابشده را روی line اصلی client و line->dest_ctx نگه میدارد.
اگر domain-strategy resolve محلی را فعال کند، client یک DomainResolver داخلی
میسازد که prepare hook آن پیش از DNS resolution، target تنظیمشده را اعمال
میکند. این کار هم برای domain ثابت و هم برای مقداری که از
dest_context->address کپی شده انجام میشود؛ IPهای ثابت دستنخورده میمانند.
| مقدار | رفتار |
|---|---|
do-not-resolve-domains | domain بدون تغییر در درخواست SOCKS5 نوشته میشود تا SOCKS server آن را resolve کند. |
resolve-domains-with-core-settings | از تنظیم DNS داخل core.json استفاده میکند. |
resolve-domains-and-accept-dns-returned-order | اولین نتیجه قابل استفاده DNS را میگیرد. |
resolve-domains-and-prefer-ipv4 | IPv4 را ترجیح میدهد و در صورت نبود، IPv6 را استفاده میکند. |
resolve-domains-and-prefer-ipv6 | IPv6 را ترجیح میدهد و در صورت نبود، IPv4 را استفاده میکند. |
resolve-domains-and-use-only-ipv4 | فقط IPv4؛ اگر نتیجه IPv4 نباشد line بسته میشود. |
resolve-domains-and-use-only-ipv6 | فقط IPv6؛ اگر نتیجه IPv6 نباشد line بسته میشود. |
رفتار TCP
در حالت TCP، lifecycle به این ترتیب است:
- upstream
Init، line state مربوط بهSocks5Clientرا مقداردهی اولیه میکند وInitرا به transport بعدی میفرستد. - transport بعدی اتصال proxy را برقرار میکند و downstream
Estمیفرستد. Socks5Clientgreeting مربوط به methodهای SOCKS5 را ارسال میکند.- اگر credential تنظیم شده باشد و server روش username/password را انتخاب کند، درخواست احراز هویت فرستاده میشود.
- نود برای مقصد تنظیمشده دستور
CONNECTمیفرستد. - پس از پاسخ موفق، downstream
Estبه نود قبلی اعلام میشود. - payloadهای upstream که در انتظار بودند روی اتصال proxy فرستاده میشوند.
اگر پیش از موفق شدن درخواست SOCKS، payload upstream برسد، در صف میماند. صف اولیه ظرفیت ۸ buffer دارد و مجموع payloadهای صفشده حداکثر ۱ MiB است. buffer مربوط به handshake نیز به ۴۰۹۶ بایت محدود میشود.
اگر proxy همه methodها را رد کند، authentication شکست بخورد، پاسخ command نامعتبر باشد یا command با خطا تمام شود، tunnel آن line را میبندد.
رفتار UDP
در حالت UDP، line اصلی همان مسیر application است و Socks5Client دو line داخلی میسازد:
| line داخلی | کاربرد |
|---|---|
| UDP control line | یک line TCP که به SOCKS proxy وصل میشود و UDP ASSOCIATE را با مقصد 0.0.0.0:0 میفرستد. |
| UDP relay line | یک line UDP که به relay address برگشتی از proxy وصل میشود. |
line application تنها پس از آماده شدن هم control association و هم relay line
برقرار اعلام میشود. تا آن زمان datagramهای upstream با همان محدودیت ۱ MiB در
صف میمانند. سپس Socks5Client یک header مربوط به SOCKS5 UDP و شامل مقصد نهایی
به ابتدای هر datagram اضافه میکند و آن را از relay line میفرستد. پاسخهای
relay اعتبارسنجی میشوند، header از آنها برداشته میشود و فقط payload به نود
قبلی برمیگردد.
fragmentهای SOCKS5 UDP دوباره سرهم نمیشوند؛ datagramهایی که FRAG != 0
دارند برای احتیاط نادیده گرفته میشوند.
متادیتای نود
| ویژگی | مقدار |
|---|---|
| flag | kNodeFlagNone |
| previous node | مجاز |
| next node | اجباری |
| layer group | kNodeLayerAnything |
required_padding_left | بدترین حالت هدر SOCKS5 UDP: 4 + 1 + 255 + 2 بایت |
این مقدار padding اجازه میدهد header مربوط به SOCKS5 UDP بدون نقض قرارداد buffer به ابتدای datagram افزوده شود. اگر buffer ورودی باز هم فضای کافی در سمت چپ نداشته باشد، tunnel یک buffer جایگزین میگیرد و پیش از افزودن header، payload را در آن کپی میکند.
اشتباههای رایج
- آدرس proxy را داخل
settings.addressننویسید؛ این فیلد مقصد نهایی داخل request SOCKS است. - حالت UDP را با connector فقط-TCP به کار نبرید؛ این حالت هم control line از نوع TCP و هم relay line از نوع UDP میخواهد.
domain-strategyروی IP literal اثری ندارد.- وقتی از
dest_context->addressاستفاده میکنید،portهمچنان جداگانه لازم است.