VmessServer
VmessServer درخواستهای VMess AEAD را دریافت میکند، حساب کاربر را با UUID احراز هویت میکند
و ترافیک TCP، UDP با مقصد ثابت یا packetaddr را پس از رمزگشایی به next میفرستد. این node مستقل از
transport است. برای TLS یا WebSocket، nodeهای TlsServer یا HttpServer را پیش از آن قرار دهید.
احراز هویت
یکی از دو روش را انتخاب کنید:
- کاربران محلی: از
uuid/id/user-id، آرایهuuidsیاusers/clientsاستفاده کنید. هر شیء کاربر یکuuidیاid/user-idو در صورت نیازusernameدارد. این روش به پایگاه AuthenticationClient نیاز ندارد. - کاربران مدیریتشده:
auth-client-node-nameرا تنظیم و تمام اعتبارنامههای محلی را حذف کنید. UUID کاربر در فیلدpasswordحساب AuthenticationServer قرار میگیرد. این node از جدول همگامشده حافظه AuthenticationClient استفاده میکند و یکUserControllerداخلی پیش از outbound میگذارد؛ روی همین مسیر یک UserController دیگر بهصورت دستی اضافه نکنید.
اعتبارنامه محلی UUID هگز دقیق با خط تیره یا فشرده، یا رشته UTF-8 غیرخالی با طول
۱ تا ۳۰ بایت است. شناسه کوتاه مانند Xray با UUIDv5 و namespace صفر نگاشت میشود:
waterwall برابر 106b9dde-356b-5769-b2f6-7ea4193ec5f7 است. رشته trim، case-fold یا
Unicode-normalize نمیشود. UUIDهای یکسان پس از نگاشت حساب تکراریاند و startup رد میشود.
در روش مدیریتشده، password باید UUID canonical حاصل را داشته باشد؛ نمایههای مشترک
AuthenticationClient برای VMess نام کوتاه را بهطور خصوصی تبدیل نمیکنند.
روش مدیریتشده از پذیرش حساب، ثبت مصرف، محدودیت اتصال و IP، سهمیه و shaping تنظیمشده کاربر استفاده میکند. پس از اولین همگامسازی معتبر، قطع معمول شبکه کنترل باعث استفاده از آخرین جدول پذیرفتهشده میشود. نبود جدول اولیه یا رد صریح اعتبارنامه AuthenticationClient پذیرش جدید را میبندد. تغییرات مدیر پس از refresh معتبر اعمال میشوند. محدودیت cache محلی تضمین reservation سراسری بین چند AuthenticationClient قطعشده نیست.
VMess بهجای UUID آشکار، AuthID رمزشده میفرستد. شناسایی AuthID تازه در بدترین حالت
به جستجوی O(N) بین N کلید نامزدِ دارای UUID نیاز دارد. کلید فرمان و کلید AuthID
از پیش محاسبه میشوند و جدول آنها بین workerهای همین node مشترک است. حسابهای دارای
UUID پیش از بررسی شرایط پذیرش در فهرست نامزدها قرار میگیرند؛ تطبیق کلید بهتنهایی
مجوز پذیرش حساب غیرفعال نیست. پس از تطبیق رمزنگاری، در روش مدیریتشده هویت فعلی حساب
و شرایط پذیرش آن با lookup نمایهدار AuthenticationClient دوباره بررسی میشود.
کار احراز هویت در نوبتهای محدود event loop انجام میشود و کارهای منتظر و cache اعتبارنامه بودجه محدود دارند. کلید cacheشده مجوز حساب حذفشده یا جایگزینشده نیست. این محدودیتها برای کار و حافظهاند و نرخ انتقال داده برنامه را محدود نمیکنند.
پشتیبانی پروتکل
| security بدنه در کلاینت | TCP | UDP |
|---|---|---|
aes-128-gcm | پشتیبانی میشود | پشتیبانی میشود |
chacha20-poly1305 | پشتیبانی میشود | پشتیبانی میشود |
none با chunk framing | پشتیبانی میشود | پشتیبانی میشود |
zero یا none بدون framing | پشتیبانی میشود | رد میشود |
در همه حالتها، header درخواست و پاسخ AEAD است و alterId باید صفر باشد. حالتهای
none و zero بدنه برنامه را رمز یا احراز اصالت نمیکنند؛ اگر محرمانگی بدنه لازم است،
transport محافظ مناسب را جداگانه انتخاب کنید. zero تنظیم کلاینت است و روی wire به
none بدون chunk تبدیل میشود؛ stream بدون framing مرز datagramهای UDP را نگه نمیدارد.
در درخواست عادی، IPv4، IPv6 و دامنه غیرخالی پذیرفته میشود. UDP عادی یک backend برای
مقصد ثابت دارد؛ رکورد خالی پایان پروتکل است و پاسخ UDP محلی خالی کنار گذاشته میشود.
packetaddr فقط marker دقیق sp.packet-addr.v2fly.arpa را با فرمان UDP و پورت بیرونی صفر
پس از احراز هویت میپذیرد؛ marker هرگز به DNS یا connector فرستاده نمیشود. هر رکورد یک
envelope آدرس IP و پورت (۷ بایت IPv4، ۱۹ بایت IPv6) و یک datagram دارد. دامنه و پورت مقصد
صفر در envelope رد میشوند. envelope بدون payload یک datagram خالی واقعی است.
هر مقصد یک backend متعلق به همین node و روی همان worker دارد. سقف آن با
packetaddr-max-destinations محدود میشود؛ در ظرفیت کامل فقط datagram مقصد تازه drop
میشود و مقصدهای موجود ادامه میدهند. Finish هر backend ورودی دقیق آن را حذف میکند و
ورودی بعدی میتواند آن را دوباره بسازد. بستن carrier و shutdown همه backendهای owned را
drain میکند. پاسخ صفشده بایتهای مستقل و مقصد مبدأ immutable خود را دارد. ترافیک
رمزگشاییشده در روش مدیریتشده دقیقاً یک بار از UserController میگذرد.
سقف payload بدنه ۶۵۵۳۵ بایت، بهعلاوه ۱۶ بایت برای authenticated-length، منهای tag رمزنگاری ۱۶ بایتی و در صورت فعال بودن global padding منهای allowance برابر ۶۳ بایت است. packetaddr دوباره اندازه دقیق envelope یعنی ۷ یا ۱۹ بایت را کم میکند. datagram شکسته نمیشود؛ پاسخ بزرگتر drop میشود. این حدود سقف UDP/IP زیرین را افزایش نمیدهد.
هر جهت رمزشده شمارنده ۱۶ بیتی از صفر دارد. پیشفرض encrypted-counter-policy: "wrap"
همه ordinalهای 0..65535 را برای داده میپذیرد و سپس بدون reset کلید، IV یا SHAKE از صفر
ادامه میدهد. wrap باعث تکرار nonce AEAD با همان کلید session میشود؛ rekey نیست و
یکتایی nonce را حفظ نمیکند. این انتخاب با ادامه اتصال در پیادهسازیهای رایج سازگار است.
در strict داده خروجی فقط 0..65534 را مصرف میکند و 65535 برای EOF رزرو است؛ داده
ورودی معتبر در 65535 تحویل میشود و سپس اتصال پیش از استفاده مجدد بسته میشود.
بدنه و طول احرازشده ordinal یکسان دارند. NONE/zero این محدودیت رمزشده را ندارند.
send-termination: false رکورد خالی خروجی اختیاری را حذف و مسیر full-close موجود را
استفاده میکند. EOF معتبر ورودی همواره پذیرفته میشود و EOF رمزشده ابتدا احراز میشود.
Finish در حالت idle درخواستی نمیسازد؛ zero خام EOF framed ندارد. سیاست شمارنده، allow-list
و termination محلیاند و بیت negotiation تازهای ندارند؛ endpoint strict ممکن است peer
دارای wrap را در سقف خودش ببندد.
allowed-security حالت واقعی بدنه را پس از parse احرازشده و پیش از Init محافظتشده یا
ساخت backend بررسی میکند. حالت ردشده به fallback نمیرود. auto انتخاب محلی کلاینت است
و حالت wire در این فهرست نیست. برای پرهیز از رمزنگاری دوباره، اپراتور برای TCP داخل TLS
خودش zero و برای UDP داخل TLS خودش none دارای framing را انتخاب میکند؛ VMess
TLS را تشخیص نمیدهد و خودکار security را تغییر نمیدهد.
header قدیمی VMess و alter ID، AES-CFB، Mux.Cool، XUDP و فرمان reverse پشتیبانی نمیشوند. AES-CTR نیز خارج از پشتیبانی است. framing سفارشی WaterWall Mux با Mux.Cool سازگار نیست و interoperability چندجریانی VMess خارجی را فراهم نمیکند. TLS، WebSocket و HTTP مسئولیت nodeهای خودشان هستند؛ VmessServer تنظیمات یا تشخیص داخلی این transportها ندارد. این node splice را برای chain غیرفعال میکند، چون parser و رمزنگاری به buffer عادی حافظه نیاز دارند.
چیدمان و مثال
TcpListener -> VmessServer -> TcpUdpConnector
TcpListener -> TlsServer -> VmessServer -> TcpUdpConnector
TcpListener -> HttpServer (WebSocket) -> VmessServer -> TcpUdpConnector
TcpListener -> TlsServer -> HttpServer (WebSocket) -> VmessServer -> TcpUdpConnector
کاربر محلی:
{
"name": "vmess",
"type": "VmessServer",
"settings": {
"users": [
{"username": "alice", "uuid": "5783a3e7-e373-51cd-8642-c83782b807c5"}
],
"connect": true,
"udp": true
},
"next": "outbound"
}
کاربر مدیریتشده:
{
"name": "vmess",
"type": "VmessServer",
"settings": {"auth-client-node-name": "auth-client"},
"next": "outbound"
}
connector خروجی معمولاً "address": "dest_context->address" و
"port": "dest_context->port" دارد. برای TCP از TcpConnector، برای UDP از
UdpConnector و برای هر دو از TcpUdpConnector استفاده کنید.
تنظیمات
| تنظیم | پیشفرض | کاربرد |
|---|---|---|
uuid / id / user-id | ندارد | UUID یا ID کوتاه محلی؛ فقط یک alias. |
uuids | ندارد | آرایه رشته UUID/ID کوتاه یا شیء کاربر. |
users / clients | ندارد | آرایه رشته UUID/ID کوتاه یا شیء کاربر؛ یکی از دو نام را انتخاب کنید. |
auth-client-node-name | ندارد | نام AuthenticationClient؛ با تنظیمات کاربر محلی همزمان مجاز نیست. |
connect | true | اجازه درخواست TCP. |
udp | true | اجازه UDP دارای framing؛ حداقل یکی از TCP و UDP باید فعال باشد. |
handshake-timeout-ms | 10000 | مهلت قطعی handshake درخواست؛ دریافت داده آن را تمدید نمیکند. |
auth-max-pending | 4096 | بیشترین تعداد کار احراز هویت منتظر در node. |
auth-pending-max-bytes | 67108864 | بودجه مشترک بایت منطقی ورودی کارهای احراز هویت منتظر. |
auth-cache-max-bytes | 67108864 | بودجه حافظه cache اعتبارنامه و احراز هویت، برحسب بایت. |
replay-max-entries | 262144 | بیشترین ورودی زنده در هر یک از جدولهای replay مربوط به AuthID و session. |
fallback-node-name | ندارد | شاخه اختیاری برای ترافیک واجد شرایط پیش از احراز هویت. |
fallback-intentional-delay-ms | 7 | تأخیر عمدی fallback؛ صفر آن را غیرفعال میکند. |
fallback-intentional-delay-jitter-ms | 1 | jitter افزوده؛ با تأخیر صفر نادیده گرفته میشود. |
encrypted-counter-policy | wrap | wrap یا strict مستقل برای هر جهت رمزشده. |
allowed-security | هر چهار حالت | آرایه غیرخالی و یکتای aes-128-gcm، chacha20-poly1305، none، zero؛ UDP-only با فقط zero نامعتبر است. |
send-termination | true | ارسال EOF framed اختیاری به سمت wire باز. |
packetaddr | true | پذیرش packetaddr احرازشده؛ udp: false همه شکلهای UDP را رد میکند. |
packetaddr-max-destinations | 64 | عدد صحیح 1..1024 برای تعداد backend زنده هر carrier. |
verbose | false | reason-code بدون اعتبارنامه یا label مقصد؛ حداکثر یک پیام در ثانیه برای هر node. |
محدودیتهای احراز هویت و timeout باید عدد صحیح در بازه 1..2147483647 باشند؛ اندازه جدول
replay نیز باید در ظرفیت قابل نمایش میزبان جا شود. تنظیم نامعتبر startup را رد میکند.
تنظیمات جدید نوع اشتباه، کلید تکراری، مقدار ناشناخته، NUL داخلی، UTF-8 خراب و حدود کسری یا خارج از بازه را رد میکنند.
پر شدن ظرفیت درخواست تازه مربوط را رد میکند؛ برای باز کردن جا هیچ علامت replay منقضینشدهای حذف نمیشود.
پیش از پایان احراز هویت، هر اتصال حداکثر ۶۵۵۳۶ بایت منطقی ورودی در ۲۵۶ buffer نگه میدارد. صف ورودی و صف پاسخ، هر کدام سقف ۲ MiB بایت منطقی، ۸ MiB هزینه تخصیص buffer و ۱۰۲۴ ورودی دارند؛ buffer فعالِ خارجشده از صف تا آزاد شدن همچنان حساب میشود. این سقفهای ثابت مکمل بودجه مشترک احراز هویتاند و تضمین سقف RSS یا کل حافظه فرایند نیستند.
Fallback و جلوگیری از replay
با fallback-node-name یک شاخه stream موجود را برای اعتبارنامه ناشناخته یا احراز هویت
در دسترسنبودنی انتخاب کنید. prefix بررسیشده و بقیه بایتها دقیق و به همان ترتیب بازپخش
میشوند. هویت ردشده به شاخه fallback منتشر نمیشود و UserController داخلی در این مسیر نیست.
پس از شناسایی احراز هویت VMess، fallback دیگر مجاز نیست. AuthID تکراری یا منقضی، session تکراری، tag نامعتبر، header احرازشده خراب، فرمان پشتیبانینشده پس از احراز هویت، رد منابع یا پایان مهلت handshake اتصال مربوط را میبندند و به fallback تبدیل نمیشوند.
جدول replay بین همه workerهای این node مشترک است. بازه پذیرش زمان AuthID برابر ۱۲۰ ثانیه در هر جهت با احتساب مرزهاست؛ علامت آن تا پایان تمام بازه اعتبار، حتی برای timestamp آینده، باقی میماند. عقب رفتن ساعت نمیتواند درخواست منقضیشده را دوباره معتبر کند. هویت session شامل UUID، کلید بدنه درخواست و IV است و بازه replay آن سه دقیقه است. هر نمونه جداگانه VmessServer دامنه replay مستقل دارد.
آمار فقط خواندنی
عملیات ثبتشده stats فقط شیء JSON خالی تا ۶۴ بایت با احتساب whitespace میپذیرد.
مجوز عادی APIServer برای این node و operation لازم است؛ callback تاریخی بهتنهایی آن
را منتشر نمیکند. پاسخ JSON schema ثابت دارد. در اشغال بودن lock snapshot احراز/replay،
خطای محدود busy برمیگردد. deadline، سقف response و هزینه واقعی تخصیص pool بررسی میشود؛
حداقل ۴۶۰۸ بایت working allowance بهعلاوه هزینه buffer خروجی رزرو کنید.
پاسخ تنظیمات مؤثر encrypted_counter_policy، allowed_security، send_termination،
packetaddr، packetaddr_max_destinations، connect، udp، verbose و managed را دارد.
approximate برابر true است. همه شمارندهها رشته دهدهی با دقت کامل uint64 هستند.
applications association احرازشده، carriers خط ورودی borrowed زنده شامل pending/fallback
و backends خط مقصد UDP owned زنده را میشمارد. شمارندههای تجمعی شامل tx_records،
rx_records، tx_application_bytes، rx_application_bytes، tx_wire_bytes، rx_wire_bytes،
wrap_events و strict_exhaustion هستند. بایت برنامه، upload رمزگشاییشده ارائهشده به
شاخه محافظتشده و payload پاسخ پذیرفتهشده، بدون envelope است. بایت wire ورودی دریافتی و
پاسخ framed تحویلشده، شامل handshake است. پاسخ UDP عادی خالی/بزرگ dropشده بایت پاسخ
برنامه اضافه نمیکند. records عملیات موفق framed را میشمارد؛ zero خام stream بدون framing
است. snapshot بین workerها و شمارندهها تقریبی است.
pending_auth، pending_auth_bytes، auth_cache_bytes، authid_marks و session_marks
occupancy نگهداشتهشده را نشان میدهند؛ علامت منقضی ممکن است منتظر reclamation عادی باشد.
شیء ثابت reasons شامل close عادی، mismatch/unavailable/expired AuthID، replay-or-capacity،
header خراب، شکست بدنه/طول، command/security ردشده، timeout، admission، UDP بزرگ، packetaddr
خراب، ظرفیت مقصد و strict exhaustion است. شکست بدنه/طول میتواند parser/geometry باشد و
فقط خطای tag نیست. دلیل terminal یک بار در carrier و drop برای هر datagram شمرده میشود.
UUID، password، شناسه کاربر و label مقصد منتشر نمیشود. خواندن از atomic و try-lock محدود
است و خط یا map زنده worker دیگر پیمایش نمیشود. reset یا mutation وجود ندارد.
اعتبارسنجی
peerهای pinned مستقل V2Ray 5.53.0، Xray 25.6.8 و sing-box 1.12.0 در هر دو جهت endpoint
با اعلام صریح cellهای پشتیبانینشده بررسی میشوند. stop-and-wait طولانی بیش از ۶۵۵۳۶ رکورد
را روی یک اتصال transport شمارششده عبور میدهد. native Debug/Release دو wrap واقعی،
checkpoint مستقل، مالکیت/حدود packetaddr، strict، mutation parser، stats و replay را بررسی
میکند. فرمانها در tests/cases/vmess_interop/README.md و بخش ۶ راهنمای توسعه آمدهاند.
متادیتای node
متادیتای برگرفته از tunnels/VmessServer/instance/node.c:
| ویژگی | مقدار |
|---|---|
| node flags | kNodeFlagBlocksSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 0 بایت |