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

DomainResolver

DomainResolver یک node داخلی برای کاربردهای پیشرفته است که پیش از عبور دادن Init، نام domain مقصد line را به IP تبدیل می‌کند.

در config‌های معمول لازم نیست این node را دستی اضافه کنید. node‌های سطح بالاتری مانند TcpConnector، UdpConnector، Router، Socks5Client، VlessClient و TrojanClient در صورت نیاز آن را داخل خودشان می‌سازند و تنظیم می‌کنند. ابتدا از تنظیمات عمومی همان node‌ها استفاده کنید، مگر اینکه عمداً chain سفارشی‌ای می‌سازید که خودش line->routing_context.dest_ctx را مقداردهی می‌کند.

کاری که انجام می‌دهد​

DomainResolver فقط context آدرس مقصد را می‌خواند و به‌روزرسانی می‌کند:

line->routing_context.dest_ctx

اگر مقصد از ابتدا IP باشد یا قبلاً resolve شده باشد، Init بی‌درنگ عبور داده می‌شود. اگر مقصد نام domain باشد، درخواست DNS به‌صورت async روی worker فعلی انجام می‌شود؛ سپس strategy انتخاب آدرس اعمال و IP برگزیده در dest_ctx نوشته می‌شود و در پایان Init که منتظر مانده بود عبور می‌کند.

این node:

  • socket باز نمی‌کند
  • line جدید نمی‌سازد
  • payload را تغییر نمی‌دهد
  • بایتی از پروتکل به buffer اضافه نمی‌کند
  • src_ctx را resolve نمی‌کند

جایگاه رایج​

استفاده دستی از این node برای سناریوهای پیشرفته است. آن را پس از node‌ای قرار دهید که dest_ctx را روی یک domain تنظیم می‌کند و پیش از node‌ای که به IP واقعی نیاز دارد.

TcpListener -> Socks5Server -> DomainResolver -> TcpConnector

در بیشتر config‌های عادی نیازی به این کار نیست، زیرا connector یا node پروتکل resolver داخلی خود را می‌سازد.

نمونه تنظیمات​

{
"name": "resolve-domain",
"type": "DomainResolver",
"settings": {
"strategy": "prefer-ipv4",
"verbose": false
},
"next": "outbound"
}

فیلدها​

فیلدنوعاجباریتوضیح
typestringبلهباید DomainResolver باشد.
settingsobjectخیرobject تنظیمات اختیاری؛ اگر نوشته شود باید از نوع object باشد.
nextstringمعمولاًnode‌ای که پس از resolve شدن مقصد، Init را در جهت upstream می‌گیرد.

این node فقط Init در جهت upstream و Est در جهت downstream را می‌پذیرد. Init در جهت downstream و Est در جهت upstream با رفتار پیش‌فرض سازنده رد می‌شوند. payload، Pause/Resume و Finish همچنان در هر دو جهت معنای معمول خود را دارند.

تنظیمات​

گزینهپیش‌فرضتوضیح
strategyمقدار core در dns.domain-strategyروش انتخاب نتیجه DNS. یکی از core-settings، accept-dns-returned-order، prefer-ipv4، prefer-ipv6، only-ipv4 یا only-ipv6.
verbosefalseآغاز resolve را در لاگ debug ثبت می‌کند. آدرس resolve‌شده همچنان در logger عادی debug مربوط به DNS ثبت می‌شود.

strategy می‌تواند string یا یکی از مقادیر داخلی مورد قبول parser مشترک domain-strategy باشد.

جریان اجرا​

هنگام دریافت Init از upstream:

  1. state مربوط به line آماده می‌شود.
  2. dest_ctx بررسی می‌شود
  3. اگر نیازی به DNS نباشد، Init در جهت upstream به next می‌رود.
  4. اگر DNS لازم باشد، node وارد state مربوط به resolving می‌شود و callback برمی‌گردد.
  5. پس از پایان DNS، آدرس انتخاب‌شده در dest_ctx نوشته می‌شود.
  6. Init منتظرمانده در جهت upstream عبور داده می‌شود.
  7. payload‌هایی که هنگام DNS در صف مانده‌اند، به‌ترتیب ارسال می‌شوند.

payload در جهت downstream پس از آغاز Init node بعدی مستقیماً به node قبلی فرستاده می‌شود؛ این شامل پاسخ‌هایی است که در همان callback مربوط به Init دریافت می‌شوند.

Pending Payload​

payload در جهت upstream فقط هنگام DNS، ورودی re-entrant در Init node مجاور یا وجود داده قدیمی‌تر در صف نگه داشته می‌شود. پیش از افزودن داده، هم طول منطقی و هم هزینه حافظه buffer‌ها با سقف 2 MiB برای هر line بررسی می‌شود. سرریز پیش از Init node بعدی فقط سمت prev و پس از آن هر دو جهت بازشده را می‌بندد.

پس از بازشدن مسیر، Est مربوط به transport بدون تأخیر عبور می‌کند. تخلیه صف با ترتیب FIFO و با رعایت Pause مصرف‌کننده انجام می‌شود؛ ورودی re-entrant از دادهٔ قدیمی‌تر جلو نمی‌زند. Pause دریافت‌شده هنگام DNS پس از بازشدن مسیر مجاور نیز معتبر می‌ماند.

اولین ورودی نگهداری‌شده پس از ثبت مالکیت FIFO و حسابداری، فقط source آغازکننده را Pause می‌کند. این دلیل محلیِ انتظار DNS یا ترتیب داده از Pause دریافتی جداست و پیشرفت DNS یا transport در حال Init را متوقف نمی‌کند. این توقف در callback‌های تخلیه نیز حفظ می‌شود و تنها پس از خالی‌شدن FIFO و اجازه مصرف‌کننده مجاور آزاد می‌شود. Pause/Resume re-entrant نمی‌تواند از داده قبلی جلو بزند، دلیل فشار دیگری را پاک کند یا پس از Finish دوباره کار ایجاد کند.

پس از بازگشت Init node بعدی، خالی‌شدن FIFO و تکمیل اعلان‌های فشار محلی، این node برای line معمولی به‌طور دائمی bypass می‌شود. ابتدا تمام state مربوط به resolver، از جمله حافظهٔ آماده‌سازی داخلی، آزاد و صفر می‌شود. مصرف‌کنندگان این حافظه باید دادهٔ لازم را در همان Init مصرف یا کپی کنند؛ پس از آن در دسترس نیست. callbackهای بعدی مستقیماً بین همسایه‌ها عبور می‌کنند و Finish بعدی به resolver نمی‌رسد. lineهای packet دائمی worker همچنان فعال می‌مانند.

رفتار در خطا​

در شرایط زیر line رد می‌شود:

  • مقصد نه آدرس IP باشد و نه domain معتبر.
  • ثبت درخواست async DNS شکست بخورد.
  • DNS برای strategy تنظیم‌شده هیچ آدرس قابل استفاده‌ای برنگرداند
  • صف payload‌های pending از سقف تعیین‌شده بگذرد.

DomainResolver خودش درخواست DNS را دوباره امتحان نمی‌کند. این کار باید در node سطح بالاتر یا در طراحی transport انجام شود.

متادیتای نود​

DomainResolver یک node پشتیبان شفاف و داخلی است: state هر line را نگه می‌دارد، اما line ایجاد یا نابود نمی‌کند و بایت‌های payload را تغییر نمی‌دهد.

metadata برگرفته از کد منبع:

ویژگیمقدار
node flagskNodeFlagSupportsSplice
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayerAnything
layer_group_prev_nodekNodeLayerSameAsNext
layer_group_next_nodekNodeLayerSameAsPrev
required_padding_left0 bytes