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

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 انتخاب‌شده انجام می‌شود.

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

فیلدنوعتوضیح
settingsobjectاجباری است و نباید خالی باشد.
settings.address / settings.target-address / settings.targetstringآدرس مقصد نهایی SOCKS. می‌تواند IP یا domain ثابت، dest_context->address یا line->dest_ctx->address باشد.
settings.portnumber یا stringپورت مقصد نهایی. عدد 1 تا 65535، یا dest_context->port / line->dest_ctx->port.
nextstringاجباری است و به transport سمت SOCKS proxy اشاره می‌کند.

فیلدهای اختیاری

فیلدپیش‌فرضتوضیح
settings.protocol / settings.prototcpمقدارهای مجاز: 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-strategydo-not-resolve-domainsتعیین می‌کند domain پیش از درخواست SOCKS به‌صورت local resolve شود یا همان domain ارسال گردد.
settings.verbosefalselogهای 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-domainsdomain بدون تغییر در درخواست SOCKS5 نوشته می‌شود تا SOCKS server آن را resolve کند.
resolve-domains-with-core-settingsاز تنظیم DNS داخل core.json استفاده می‌کند.
resolve-domains-and-accept-dns-returned-orderاولین نتیجه قابل استفاده DNS را می‌گیرد.
resolve-domains-and-prefer-ipv4IPv4 را ترجیح می‌دهد و در صورت نبود، IPv6 را استفاده می‌کند.
resolve-domains-and-prefer-ipv6IPv6 را ترجیح می‌دهد و در صورت نبود، IPv4 را استفاده می‌کند.
resolve-domains-and-use-only-ipv4فقط IPv4؛ اگر نتیجه IPv4 نباشد line بسته می‌شود.
resolve-domains-and-use-only-ipv6فقط IPv6؛ اگر نتیجه IPv6 نباشد line بسته می‌شود.

رفتار TCP

در حالت TCP، lifecycle به این ترتیب است:

  1. upstream Init، line state مربوط به Socks5Client را مقداردهی اولیه می‌کند و Init را به transport بعدی می‌فرستد.
  2. transport بعدی اتصال proxy را برقرار می‌کند و downstream Est می‌فرستد.
  3. Socks5Client greeting مربوط به methodهای SOCKS5 را ارسال می‌کند.
  4. اگر credential تنظیم شده باشد و server روش username/password را انتخاب کند، درخواست احراز هویت فرستاده می‌شود.
  5. نود برای مقصد تنظیم‌شده دستور CONNECT می‌فرستد.
  6. پس از پاسخ موفق، downstream Est به نود قبلی اعلام می‌شود.
  7. 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 دارند برای احتیاط نادیده گرفته می‌شوند.

متادیتای نود

ویژگیمقدار
flagkNodeFlagNone
previous nodeمجاز
next nodeاجباری
layer groupkNodeLayerAnything
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 همچنان جداگانه لازم است.