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

SoftIpLimiter

SoftIpLimiter یک tunnel میانی stream است که تعداد source IPهای مجاز برای استفاده هم‌زمان از یک identity اولیه VLESS یا Trojan را محدود می‌کند. این نود به دیتابیس userهای واتروال یا فهرست کاربران VLESS/Trojan نیاز ندارد؛ کلید limit را مستقیماً از بایت‌های identity موجود در TCP connection کاربر به دست می‌آورد.

این نود باید بلافاصله پیش از parser مربوط به protocol خام یا پیش از raw TCP relay به سروری قرار بگیرد که آن parser را اجرا می‌کند:

  • با identifier: vless، پیش از VlessServer یا TCP relay به سرور VLESS بالادستی
  • با identifier: trojan، پیش از TrojanServer یا TCP relay به سرور Trojan بالادستی

این نود فقط به اندازه لازم از بایت‌های ابتدایی را برای تشخیص identity می‌خواند. پس از تشخیص، source IP را در یک table داخلی بررسی می‌کند و همان بایت‌های bufferشده را بدون تغییر می‌فرستد. رفتار پیش‌فرض برای identity تشخیص‌ناپذیر، عبور دادن connection بدون اعمال limit است؛ در deploymentهای سخت‌گیرانه می‌توانید آن را به close تغییر دهید. SoftIpLimiter کاربر را authenticate نمی‌کند، مقصد را تجزیه نمی‌کند، header را تغییر نمی‌دهد و payload را بازنویسی نمی‌کند. احراز هویت واقعی protocol همچنان بر عهده VlessServer یا TrojanServer بعدی است.

جایگاه رایج

VLESS روی TCP خام برای محیط local یا تست:

TcpListener -> SoftIpLimiter(identifier=vless) -> VlessServer -> TcpUdpConnector

VLESS روی TLS برای deployment عمومی:

TcpListener -> TlsServer -> SoftIpLimiter(identifier=vless) -> VlessServer -> TcpUdpConnector

Trojan روی TLS:

TcpListener -> TlsServer -> SoftIpLimiter(identifier=trojan) -> TrojanServer -> TcpUdpConnector

Relay جلوی یک سرور VLESS/Trojan موجود:

TcpListener -> TlsServer -> SoftIpLimiter(identifier=trojan) -> TcpConnector(upstream Trojan server)

SoftIpLimiter را پس از هر لایه encryption یا transportی قرار دهید که بایت‌های VLESS/Trojan را پنهان می‌کند و پیش از server مربوط به protocol یا raw TCP relay بگذارید که آن بایت‌ها را مصرف یا عبور می‌دهد. این نود فقط برای stream است و نباید در packet chain به کار برود.

شکل ترافیک قابل پشتیبانی

SoftIpLimiter باید یک TCP stream ساده ببیند که نخستین بایت‌های application در آن همان identity مربوط به VLESS یا Trojan باشد. clientهای TLS تنها زمانی پشتیبانی می‌شوند که واتروال پیش از این نود، معمولاً با TlsServer، TLS را terminate کرده باشد.

WebSocket، gRPC، XHTTP، wrapperهای مبتنی بر HTTP Host/header، UDP و packet chainها پشتیبانی نمی‌شوند. در این حالت‌ها identity مربوط به VLESS/Trojan در ابتدای TCP stream دیده نمی‌شود و نود قادر به شناسایی کاربر نیست.

نمونه VLESS

در این نمونه هر UUID مربوط به VLESS می‌تواند هم‌زمان حداکثر از دو source IP فعال استفاده شود:

[
{
"name": "listener",
"type": "TcpListener",
"settings": {
"address": "0.0.0.0",
"port": 443
},
"next": "tls-server"
},
{
"name": "tls-server",
"type": "TlsServer",
"settings": {
"cert-file": "/etc/waterwall/fullchain.pem",
"key-file": "/etc/waterwall/privkey.pem"
},
"next": "soft-ip-limit"
},
{
"name": "soft-ip-limit",
"type": "SoftIpLimiter",
"settings": {
"identifier": "vless",
"simultaneous-user-limit": 2,
"tolerance-ms": 30000,
"on-identification-failure": "passthrough",
"verbose": false
},
"next": "vless-server"
},
{
"name": "vless-server",
"type": "VlessServer",
"settings": {
"uuid": "5783a3e7-e373-51cd-8642-c83782b807c5",
"connect": true,
"udp": true
},
"next": "outbound"
},
{
"name": "outbound",
"type": "TcpUdpConnector",
"settings": {
"address": "dest_context->address",
"port": "dest_context->port"
}
}
]

نمونه Trojan

در این نمونه هر identity مربوط به password در Trojan تنها از یک source IP فعال در هر لحظه قابل استفاده است:

[
{
"name": "listener",
"type": "TcpListener",
"settings": {
"address": "0.0.0.0",
"port": 443
},
"next": "tls-server"
},
{
"name": "tls-server",
"type": "TlsServer",
"settings": {
"cert-file": "/etc/waterwall/fullchain.pem",
"key-file": "/etc/waterwall/privkey.pem"
},
"next": "trojan-soft-ip-limit"
},
{
"name": "trojan-soft-ip-limit",
"type": "SoftIpLimiter",
"settings": {
"identifier": "trojan",
"simultaneous-user-limit": 1,
"tolerance-ms": 45000,
"on-identification-failure": "close",
"verbose": true
},
"next": "trojan-server"
},
{
"name": "trojan-server",
"type": "TrojanServer",
"settings": {
"password": "secret-password",
"connect": true,
"udp": true
},
"next": "outbound"
}
]

نمونه حداقلی برای relay، زمانی که سرور دیگری پس از واتروال ترافیک Trojan را تجزیه می‌کند:

{
"name": "trojan-soft-ip-limit",
"type": "SoftIpLimiter",
"settings": {
"identifier": "trojan",
"simultaneous-user-limit": 1,
"tolerance-ms": 3000,
"verbose": false
},
"next": "tcp-connector"
}

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

فیلدهای top-level:

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

تنظیمات الزامی:

FieldTypeتوضیح
identifierstringباید دقیقاً vless یا trojan باشد.
simultaneous-user-limitintegerتعداد source IPهای متفاوتی که اجازه دارند هم‌زمان از یک identity استفاده کنند. مقدار مجاز 1 تا 6 است.
tolerance-msintegerمدت بی‌فعالیتی بر حسب millisecond که پس از آن یک ردیف IP قدیمی محسوب می‌شود. باید دست‌کم 1 باشد.

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

FieldDefaultتوضیح
on-identification-failurepassthroughرفتار با بایت‌هایی که قطعاً برای identifier تنظیم‌شده معتبر نیستند: passthrough، line را بدون IP limit عبور می‌دهد و close آن را رد می‌کند. pass و pass-through نام‌های مستعار passthrough هستند.
verbosefalsewarningهای مربوط به admission ردشده و بسته شدن payloadهای فعال را در log ثبت می‌کند.

استخراج Identity

در mode vless، byteهای upstream باید با این prefix شروع شوند:

version:  1 byte, must be 00
uuid: 16 raw UUID bytes

شانزده بایت UUID با calcHashBytes(uuid, 16) به یک کلید داخلی ۶۴ بیتی تبدیل می‌شوند.

در mode trojan، byteهای upstream باید با hash استاندارد password شروع شوند:

password hash: 56 ASCII hex bytes, hex(SHA224(password))

SoftIpLimiter این ۵۶ نویسه hex را اعتبارسنجی و decode می‌کند، سپس ۲۸ بایت SHA224 را با calcHashBytes(sha224, 28) به یک کلید داخلی ۶۴ بیتی تبدیل می‌کند.

بایت‌های identity نه مصرف می‌شوند و نه بازنویسی. پس از پذیرفته شدن connection، تمام stream ذخیره‌شده در buffer بدون تغییر به نود بعدی می‌رود.

رفتار شکست تشخیص

تا زمانی که بایت‌های موجود برای تصمیم‌گیری کافی نباشند، SoftIpLimiter منتظر می‌ماند. وقتی بایت‌ها قطعاً برای mode تنظیم‌شده نامعتبر باشند، on-identification-failure رفتار بعدی را تعیین می‌کند.

در حالت پیش‌فرض passthrough، نود برای آن line کاملاً شفاف عمل می‌کند: هیچ ردیفی برای identity ساخته نمی‌شود، simultaneous-user-limit و tolerance-ms اعمال نمی‌شوند، بایت‌های bufferشده بدون تغییر روی نود بعدی بازپخش می‌شوند و payloadها و callbackهای بعدی lifecycle به شکل عادی عبور می‌کنند.

اگر VlessServer یا TrojanServer بعدی fallback خودش را دارد، یا chain عمداً probeهای غیر VLESS/Trojan را هم می‌پذیرد، از passthrough استفاده کنید. اگر early data نامعتبر نباید به نود بعدی برسد، close را انتخاب کنید.

رفتار Limit

limit برای هر identity جداگانه است، نه سراسری برای کل نود. اگر simultaneous-user-limit برابر 2 باشد، یک UUID یا password hash مربوط به Trojan می‌تواند هم‌زمان از دو source IP متفاوت استفاده شود. source IP سوم برای همان identity رد می‌شود، اما هر identity دیگر فهرست IP مستقل خودش را دارد.

چند connection با source IP و identity یکسان فقط یک IP محسوب می‌شوند. ردیف مربوط reference count دارد و تا آزاد شدن آخرین line زنده آن source IP یا قدیمی شدن ردیف، باقی می‌ماند.

رفتار Tolerance

tolerance-ms تنها هنگام دسترسی به table بررسی می‌شود:

  • هنگام admission یک connection جدید
  • پیش از فرستادن upstream payload
  • پیش از فرستادن downstream payload
  • هنگام release شدن row توسط یک line

timer پس‌زمینه‌ای وجود ندارد؛ بنابراین ممکن است یک line ساکت بیشتر از tolerance-ms idle بماند. اگر connection یا payload دیگری همان identity را لمس کند و ردیف IP مربوط به line ساکت حذف شود، آن line با payload بعدی خودش بسته خواهد شد.

اگر clientها معمولاً connectionهای idle را مدت زیادی نگه می‌دارند، tolerance را بزرگ‌تر بگذارید. برای آزاد شدن سریع‌تر slotهای IP قدیمی، مقدار کوچک‌تری انتخاب کنید.

با مقدارهای خیلی بزرگ مراقب باشید. با simultaneous-user-limit: 1، اگر tolerance-ms را مثلاً یک ساعت بگذارید، وقتی کاربر از اینترنت گوشی به Wi-Fi جابه‌جا شود، IP قبلی ممکن است تا یک ساعت تنها slot همان identity را نگه دارد. برای clientهای mobile یا کاربرهایی که network عوض می‌کنند، مقدار کوتاهی مثل 3000 تا 5000 ms معمولاً نقطه شروع عملی‌تری است.

نیاز به Source IP

برای identityهای تشخیص‌داده‌شده، SoftIpLimiter به یک source IP معتبر در source context مربوط به line نیاز دارد. listenerهای معمول stream مانند TcpListener این مقدار را فراهم می‌کنند.

اگر source context وجود نداشته باشد یا از نوع IPv4/IPv6 نباشد، connection پذیرفته نمی‌شود.

اگر تشخیص identity شکست بخورد و on-identification-failure برابر passthrough باشد، source-IP row ساخته نمی‌شود و این نیازمندی source IP برای آن line استفاده نمی‌شود.

Logging

این نود به‌طور پیش‌فرض log اضافه‌ای نمی‌نویسد.

وقتی verbose برابر true باشد، admissionهای ردشده و بسته شدن payloadهای فعال همراه mode مربوط به identifier، کلید داخلی ۶۴ بیتی، source IP، worker id، دلیل، تعداد IP فعلی و limit تنظیم‌شده ثبت می‌شوند. UUID خام VLESS و SHA224 خام Trojan هرگز در log نوشته نمی‌شوند.

نکته‌های عملیاتی

  • SoftIpLimiter نود authentication نیست. VlessServer یا TrojanServer بعدی هنوز authentication را انجام می‌دهد.
  • می‌تواند قبل از VlessServer/TrojanServer محلی قرار بگیرد، یا قبل از یک TcpConnector که ترافیک را به سرور VLESS/Trojan بالادستی relay می‌کند.
  • به fail2ban یا limiter خارجی نیاز ندارد؛ table مربوط به identity/IP در خود واتروال نگه‌داری می‌شود.
  • early data نامعتبر یا قابل تشخیص نبودن به‌صورت پیش‌فرض عبور داده می‌شود. برای reject شدن در همین node، on-identification-failure را close بگذارید.
  • این node username را نمی‌شناسد. key فقط از UUID اولیه VLESS یا مقدار SHA224 اولیه Trojan ساخته می‌شود.
  • اگر simultaneous-user-limit برابر 1 باشد، یک identity همچنان می‌تواند چند line هم‌زمان از همان source IP باز کند.
  • اگر clientها بین networkها جابه‌جا می‌شوند، limit را آن‌قدر بالا بگذارید که overlap معمول را پوشش دهد.
  • table در tunnel state قرار دارد، میان workerهای همان tunnel instance مشترک است و با RW lock محافظت می‌شود.
  • وقتی می‌خواهید بفهمید connection به‌خاطر IP limit reject یا active-close شده یا نه، موقتا verbose را فعال کنید.

Metadata نود

PropertyValue
Node flagkNodeFlagNone
Previous nodeRequired
Next nodeRequired
Layer groupkNodeLayer4
Previous node layerkNodeLayer4
Next node layerkNodeLayer4
required_padding_left0

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

  • قرار دادن SoftIpLimiter(identifier=trojan) پیش از TlsServer؛ در آن نقطه بایت‌های Trojan هنوز رمز شده‌اند و limiter نمی‌تواند connection را شناسایی کند.
  • انتظار پشتیبانی از WebSocket، gRPC، XHTTP، یا configهایی که HTTP Host/header دارند.
  • قرار دادن SoftIpLimiter بعد از VlessServer یا TrojanServer. این limiter باید raw protocol identity را قبل از مصرف شدن توسط parser ببیند.
  • انتظار authentication از این node.
  • انتظار اعمال limit روی lineهای pass-through پیش‌فرض؛ این lineها بدون ردیف identity عبور می‌کنند. برای enforcement سخت‌گیرانه از "on-identification-failure": "close" استفاده کنید.
  • تنظیم simultaneous-user-limit بیشتر از 6.
  • استفاده از این node در packet chainها.