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"
}
فیلدها
| فیلد | نوع | اجباری | توضیح |
|---|---|---|---|
type | string | بله | باید DomainResolver باشد. |
settings | object | خیر | object تنظیمات اختیاری؛ اگر نوشته شود باید از نوع object باشد. |
next | string | معمولاً | 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. |
verbose | false | آغاز resolve را در لاگ debug ثبت میکند. آدرس resolveشده همچنان در logger عادی debug مربوط به DNS ثبت میشود. |
strategy میتواند string یا یکی از مقادیر داخلی مورد قبول parser مشترک domain-strategy باشد.
جریان اجرا
هنگام دریافت Init از upstream:
- state مربوط به line آماده میشود.
dest_ctxبررسی میشود- اگر نیازی به DNS نباشد،
Initدر جهت upstream بهnextمیرود. - اگر DNS لازم باشد، node وارد state مربوط به resolving میشود و callback برمیگردد.
- پس از پایان DNS، آدرس انتخابشده در
dest_ctxنوشته میشود. Initمنتظرمانده در جهت upstream عبور داده میشود.- 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 flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayerAnything |
layer_group_prev_node | kNodeLayerSameAsNext |
layer_group_next_node | kNodeLayerSameAsPrev |
required_padding_left | 0 bytes |