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

VlessServer

VlessServer پیاده‌سازی سمت server پروتکل plain VLESS v0 در WaterWall است. request header را از نود stream-facing قبلی می‌خواند، UUID خام ۱۶ بایتی را بررسی می‌کند، مقصد TCP یا UDP درخواستی را بیرون می‌کشد و ترافیک پذیرفته‌شده را به next می‌فرستد.

این نود فقط بخش پایه پروتکل VLESS را پیاده‌سازی می‌کند؛ TLS، REALITY، XTLS Vision، mux، reverse، XUDP و wrapperهای transport باید با نودهای دیگری ساخته شوند.

جایگاه رایج

VLESS server عادی:

TcpListener -> TlsServer -> VlessServer -> TcpUdpConnector

خروجی فقط TCP:

TcpListener -> TlsServer -> VlessServer -> TcpConnector

خروجی با پشتیبانی UDP:

TcpListener -> TlsServer -> VlessServer -> TcpUdpConnector

VlessServer خودش TLS را terminate نمی‌کند. در deployment عمومی VLESS، TlsServer را پیش از آن قرار دهید؛ در غیر این صورت UUID و metadata مقصد روی wire دیده می‌شوند.

نمونه Minimal

[
{
"name": "tls-in",
"type": "TlsServer",
"settings": {
"cert-file": "/etc/waterwall/fullchain.pem",
"key-file": "/etc/waterwall/privkey.pem"
},
"next": "vless-server"
},
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"uuid": "5783a3e7-e373-51cd-8642-c83782b807c5",
"connect": true,
"udp": true,
"verbose": false
},
"next": "outbound"
},
{
"name": "outbound",
"type": "TcpUdpConnector",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port"
}
}
]

چند User محلی

{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"users": [
"5783a3e7-e373-51cd-8642-c83782b807c5",
{
"username": "alice",
"id": "11111111-2222-3333-4444-555555555555"
}
],
"connect": true,
"udp": true
},
"next": "outbound"
}

در حالت allowlist محلی، اگر object فیلد username داشته باشد همان نام روی line ثبت می‌شود. UUID canonical با حروف کوچک هم به‌عنوان password مربوط به line ذخیره می‌شود تا ruleهای Router حتی بدون database کاربران بتوانند credential را بررسی کنند.

حالت AuthenticationClient

{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"auth-client-node-name": "auth-client",
"connect": true,
"udp": true
},
"next": "outbound"
}

در این حالت، UUID روی wire به فرمت canonical، dashed و با حروف کوچک تبدیل می‌شود و سپس به‌عنوان password کاربر از طریق AuthenticationClient بررسی می‌شود.

نمونه user در database:

{
"id": 2001,
"name": "vless-user",
"password": "5783a3e7-e373-51cd-8642-c83782b807c5",
"enabled": true
}

با تنظیم auth-client-node-name دیگر نمی‌توانید UUID محلی تعریف کنید. VlessServer خودش یک UserController داخلی پیش از outbound قرار می‌دهد تا accounting و مسیریابی مبتنی بر user درست کار کنند.

نمونه Fallback

{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"uuid": "5783a3e7-e373-51cd-8642-c83782b807c5",
"fallback-node-name": "fallback-service",
"fallback-intentional-delay-ms": 7,
"fallback-intentional-delay-jitter-ms": 1,
"connect": true,
"udp": true
},
"next": "outbound"
}

Fallback برای مقاومت در برابر active probing است. به‌جای بستن فوری ترافیک نامعتبر یا احراز هویت‌نشده، می‌توان آن را به نود دیگری سپرد.

فیلدهای لازم

فیلدنوعتوضیح
namestringنام یکتای نود داخل config.
typestringباید دقیقاً "VlessServer" باشد.
settingsobjectتنظیمات غیرخالی VLESS server.
nextstringلازم است؛ ترافیک پذیرفته‌شده VLESS به این نود فرستاده می‌شود.

باید دقیقاً یکی از دو روش authentication را انتخاب کنید.

تنظیمات Authentication محلی

برای authentication محلی، auth-client-node-name را حذف کنید و حداقل یک UUID تنظیم کنید.

فیلدنوعتوضیح
uuidstringیک UUID.
idstringalias برای uuid. هم‌زمان uuid و id را استفاده نکنید.
uuidsarray of stringsچند UUID.
usersarrayUUID string یا object با یکی از uuid، id یا user-id. object می‌تواند username داشته باشد.
clientsarrayalias برای users. هم‌زمان users و clients را استفاده نکنید.

UUID می‌تواند به فرمت dashed در RFC4122 یا hex فشرده ۳۲ کاراکتری باشد. UUID تکراری خطایی fatal در config است، حتی اگر usernameهای متفاوتی داشته باشد.

تنظیمات Database Authentication

فیلدنوعتوضیح
auth-client-node-namestringنام یک نود AuthenticationClient موجود در همان config.

در database mode، uuid، id، uuids، users و clients را تنظیم نکنید.

تنظیمات اختیاری

فیلدپیش‌فرضتوضیح
connecttrueVLESS TCP command 0x01 را فعال می‌کند.
udptrueVLESS UDP command 0x02 را فعال می‌کند.
verbosefalseجزئیات بیشتری از رد اتصال و diagnostics را log می‌کند.
fallback-node-nameتنظیم نشدهbranch جایگزین برای probeهای نامعتبر و احراز هویت‌نشده. نام‌های fallback-node و fallback هم پذیرفته می‌شوند.
fallback-intentional-delay-ms7تأخیر payloadهای upstream که به fallback می‌روند؛ مقدار 0 آن را غیرفعال می‌کند.
fallback-intentional-delay-jitter-ms1jitter تصادفی برای زمان‌بندی payloadهای تأخیردار fallback؛ با delay صفر نادیده گرفته می‌شود.

حداقل یکی از connect یا udp باید فعال باشد.

قالب Request و Response

request پذیرفته‌شده:

version:      1 byte, must be 00
user id: 16 raw UUID bytes
addons len: 1 byte, must be 00
command: 01 TCP or 02 UDP
destination: port first, then address
body: TCP raw stream or UDP length-prefixed packets

destination format:

port:          2 bytes big-endian
address type: 01 IPv4, 02 domain, 03 IPv6
address body: IPv4 4 bytes, domain length + bytes, or IPv6 16 bytes

response header:

00 00

response header تنها پس از برقرار شدن مسیر upstream انتخاب‌شده فرستاده می‌شود. در TCP یعنی مسیر outbound برقرار شده و در UDP یعنی backend UDP line داخلی از طریق نود بعدی مقداردهی شده است.

رفتار Runtime در TCP

برای command 0x01، server:

  1. UUID را بررسی می‌کند
  2. destination درخواستی را می‌خواند
  3. destination را داخل line->routing_context.dest_ctx می‌نویسد
  4. نود next را مقداردهی اولیه می‌کند
  5. byteهای TCP body را که همراه request header رسیده‌اند می‌فرستد
  6. بعد از established شدن upstream path، VLESS response header را می‌فرستد

نود next معمولاً TcpConnector، TcpUdpConnector، Router یا نودی است که destination context را می‌شناسد.

رفتار Runtime در UDP

برای command 0x02، destination داخل VLESS request اولیه برای همان VLESS line ثابت می‌ماند. frameهای UDP جداگانه آدرس per-packet ندارند.

UDP frameها:

length:   2 bytes big-endian
payload: length bytes

VlessServer برای destination مورد نظر یک backend UDP line داخلی می‌سازد. frameهای ورودی VLESS UDP پس از خواندن length prefix به آن line می‌روند. پاسخ backend نیز با همان prefix دو بایتی length بسته‌بندی می‌شود و در جهت downstream به client VLESS برمی‌گردد.

UDP frame با length 0 نامعتبر است. buffering ورودی UDP تا 1 MiB محدود است.

رفتار Fallback

Fallback فقط پیش از پذیرفته شدن UUID کاربرد دارد. پس از authentication موفق، addon نامعتبر، command پشتیبانی‌نشده، مقصد خراب یا UDP frame نادرست باعث بسته شدن VLESS line می‌شود و byteهای احراز هویت‌شده دوباره به fallback داده نمی‌شوند.

Fallback ممکن است در این حالت‌ها انتخاب شود:

  • version byte نامعتبر
  • UUID که در اولین upstream payload split شده باشد
  • UUID lookup ناموفق
  • آماده نبودن AuthenticationClient

وقتی fallback تنظیم شده باشد:

  • fallback branch بلافاصله Init می‌گیرد
  • byteهای ابتدایی ذخیره‌شده و payloadهای بعدی upstream به fallback فرستاده می‌شوند
  • payloadهای upstream در fallback می‌توانند به‌اندازه fallback-intentional-delay-ms به‌علاوه jitter تأخیر داشته باشند
  • upstream Finish تا تحویل payloadهای delayed fallback منتظر می‌ماند
  • پاسخ‌های downstream در fallback عمداً به تأخیر نمی‌افتند

کیفیت fallback بخشی از fingerprint عمومی سرویس است. fallback خراب، خطای generic، بسته شدن فوری یا تفاوت در محتوا و timing می‌تواند deployment را لو بدهد. delay و jitter را با رفتار سرویس عمومی خود تنظیم کنید؛ این‌ها فقط ریسک را کم می‌کنند و تضمینی برای پنهان ماندن نیستند.

قانون First Payload برای Authentication

credential کامل VLESS، یعنی byte نسخه به‌علاوه UUID خام ۱۶ بایتی، باید در نخستین callback مربوط به upstream payload حاضر باشد.

اگر نخستین payload credential کامل را نداشته باشد، line مانند یک probe نامعتبر و احراز هویت‌نشده در نظر گرفته می‌شود. در صورت وجود fallback، byteها به آن می‌روند وگرنه line بسته می‌شود. پس از دریافت کامل UUID، فیلدهای باقی‌مانده می‌توانند در callbackهای بعدی برسند.

رفتار Finish

VlessServer پیش از فرستادن Finish واقعی، line state خود را از بین می‌برد.

برای TCP و fallback، Finish در صورت نیاز به branch انتخاب‌شده فرستاده می‌شود. در UDP، نود مالک backend UDP line داخلی‌ای است که خودش ساخته و با بسته شدن هر یک از دو سمت، آن را به‌شکل امن می‌بندد.

Padding

VlessServer ممکن است prefix دو بایتی length در VLESS UDP را به ابتدای reply packet اضافه کند، بنابراین مقدار زیر را اعلام می‌کند:

required_padding_left = 2

متادیتای نود

ویژگیمقدار
Node flagkNodeFlagChainHead
previous nodeمجاز، و در استفاده عادی لازم
next nodeلازم
layer groupkNodeLayerAnything
required_padding_left2
line stateauth state، phase، read stream، pending queues، backend UDP line

قابلیت‌های پشتیبانی‌نشده

پیاده‌سازی فعلی موارد زیر را نمی‌پذیرد:

  • request addons length غیرصفر
  • XTLS Vision flow addons
  • mux command 0x03
  • reverse command 0x04
  • commandهای ناشناخته
  • XUDP و رفتار پیشرفته UDP/mux
  • VLESS روی transportهای non-stream

probeهای invalid و unauthenticated ممکن است به fallback بروند. protocol data بد بعد از authentication بدون نوشتن response header دیگر close می‌شود.

اشتباه‌های رایج

  • VlessServer را بدون TlsServer مستقیماً روی listener عمومی قرار ندهید، مگر اینکه عمداً plain VLESS را روی wire بخواهید.
  • local UUIDها را همراه auth-client-node-name تنظیم نکنید.
  • نود بعدی را دستی UserController نگذارید؛ database mode خودش یک UserController داخلی اضافه می‌کند.
  • انتظار نداشته باشید UDP frameها برای هر packet مقصد جدید انتخاب کنند؛ VLESS request اولیه UDP target را ثابت می‌کند.
  • به featureهای پشتیبانی‌نشده مثل Vision، flow، mux، reverse یا XUDP تکیه نکنید.