Skip to content

سازوکار اعمال محدودیت ​

فرق با پنلی که شمارنده را می‌خواند ​

بیشتر پنل‌ها هر چند ثانیه یک شمارنده‌ی بایت را می‌خوانند و وقتی عدد از سقف مشتری گذشت، او را غیرفعال می‌کنند. بین دو بار خواندن، مشتری با سرعت کامل ترافیک جابه‌جا می‌کند. روی لینک 100 مگابیتی این یعنی حدود ۲۵ مگابایت بیشتر از سقف، و روی لینک گیگابیتی ۲۵۰ مگابایت. اگر پلن ۱ گیگابایتی بفروشید، مشتری پرسرعت بی‌صدا ۱٫۲۵ گیگابایت می‌گیرد.

W-UI سقف را در خود کرنل می‌گذارد، به شکل یک شیء quota در nftables که به آدرس مشتری وصل است:

quota q_c14 { over 1073741824 bytes used 402653184 bytes }

کرنل بسته‌ای را که از سقف رد می‌شود دور می‌ریزد. پنل در مسیر داده نیست، پس اضافه‌مصرف یک بسته است، نه به اندازه‌ی فاصله‌ی دو خواندن؛ و فرقی نمی‌کند لینک مشتری 10 مگابیت باشد یا 10 گیگابیت.

پنل هنوز شمارنده‌ها را می‌خواند، ولی فقط برای دیدن مصرف و برای اینکه تصمیم بگیرد کی دستگاهی را از تونل بردارد؛ هیچ‌وقت برای اعمال سقف بایت.

همه‌ی پروتکل‌ها به یک شکل حساب می‌شوند. هر دستگاه، با هر پروتکلی که وصل شود، داخل تونل آدرس خودش را می‌گیرد و کرنل ترافیکش را با همان آدرس می‌شمارد.

هماهنگ‌ساز ​

دیتابیس مرجع حقیقت است. وضعیت کرنل از روی آن ساخته می‌شود و با آن هماهنگ نگه داشته می‌شود، نه اینکه با هر رویداد تکه‌تکه تغییر کند. هر دو ثانیه:

  1. جمع‌آوری: شمارنده‌های nftables یک‌جا خوانده و صفر می‌شوند و مصرف از طریق یک نویسنده‌ی واحد در دیتابیس نوشته می‌شود.
  2. ارزیابی: با SQL تعیین می‌شود کدام مشتری‌ها حالا از سقف یا تاریخ انقضا گذشته‌اند.
  3. اعمال: مجموعه‌ی دستگاه‌های مطلوب و قانون‌های مطلوب به کرنل و تونل‌ها فرستاده می‌شوند.

پس پنل خودش را ترمیم می‌کند. اگر سرور ری‌استارت شود، کسی nftables را دستی پاک کند، یا پنل وسط نوشتن کشته شود، دور بعدی همه چیز را از روی دیتابیس دوباره می‌سازد. ری‌استارت پنل هم کسی را قطع نمی‌کند: درایورها هیچ‌وقت لینک یا دستگاهی را که درست است حذف یا از نو نمی‌سازند.

هر پروتکل را چه چیزی اجرا می‌کند ​

پروتکلاجرا با
WireGuardماژول wireguard خود کرنل، که پنل آن را هدایت می‌کند.
AmneziaWGماژول کرنل amneziawg، یا amneziawg-go در فضای کاربر وقتی ماژول روی این کرنل ساخته نمی‌شود.
OpenVPNبرنامه‌ی openvpn، یک پردازه برای هر اینترفیس.
L2TP/IPsecstrongSwan برای IPsec، و xl2tpd و pppd برای L2TP.
IKEv2strongSwan، همان نمونه‌ای که تونل L2TP روی همین سرور استفاده می‌کند.
OpenConnectocserv.
PPTPسرور PPTP خود W-UI (wui pptpd)، با یک pppd برای هر تماس.

پنل با یک کاربر بدون امتیاز اجرا می‌شود و نمی‌تواند strongSwan، ocserv یا pppd را راه بیندازد. برای چهار پروتکل آخر، پنل تونل را در فایلی در پوشه‌ی داده‌اش توصیف می‌کند و یک عامل با دسترسی root (wui l2tp-agent، که wui-l2tp.service اجرایش می‌کند) آن را انجام می‌دهد. systemd این عامل را همان لحظه که چنین تونلی ساخته شود راه می‌اندازد و وقتی هیچ‌کدام نماند، خودش متوقف می‌شود؛ پس روی سروری که چنین تونلی ندارد چیزی اجرا نمی‌شود و پورتی گرفته نمی‌شود. عامل هر چه را از پوشه‌ی پنل می‌خواند نامطمئن حساب می‌کند و پیش از اینکه چیزی از آن به فایلی برسد، کامل بررسی‌اش می‌کند. عامل گزارش می‌دهد چه کسی وصل است و نشست‌هایی را که پنل بخواهد می‌بندد.

نکته‌های طراحی ​

  • فهرست peerها مقایسه می‌شود، نه جایگزین. WireGuard برای هر peer وضعیت نشست نگه می‌دارد. اگر در هر دور کل فهرست جایگزین شود، دست‌دهی‌های زنده از بین می‌روند و تونل از هر دو طرف وصل به نظر می‌رسد، در حالی که ترافیکی رد نمی‌شود. درایور فقط تغییرها را می‌فرستد.
  • سقف‌ها ترافیک به خود سرور پنل را هم در بر می‌گیرند، نه فقط ترافیکی که از آن رد می‌شود. بسته‌هایی که مقصدشان همین سرور است هیچ‌وقت به hook فوروارد نمی‌رسند. بدون یک قانون ورودی، حل‌کننده‌ی DNS روی همین سرور داده‌ی مشتری را رایگان جابه‌جا می‌کرد و مشتری قطع‌شده هنوز به هر سرویسی روی سرور می‌رسید.
  • دور ریختن سهمیه پیش از شمارنده می‌آید. وگرنه بایت‌های دورریخته به حساب مشتری‌ای نوشته می‌شدند که هرگز آنها را نگرفته.
  • محدودیت سرعت با علامت دسته‌بندی می‌شود، نه با فیلتر. زنجیره‌ی nftables که از قبل برای هر مشتری هست، بسته را با کلاس HTB آن علامت می‌زند؛ پس هزینه‌ی دسته‌بندی با بیشتر شدن مشتری‌ها ثابت می‌ماند.
  • خروجی با مسیریابی سیاستی انجام می‌شود. هر خروجی یک جدول مسیریابی علامت‌دار است. علامت خروجی پیش‌فرض روی هر ترافیکی که با قانونی جور نشود، از جمله DNS، می‌خورد؛ و وقتی آن خروجی از کار بیفتد، ترافیک مشتری‌ها قطع می‌شود، نه اینکه از آدرس خود سرور نشت کند.

آنچه از کرنل لازم است ​

ماژول nft_quota برای سقف دقیق، HTB (sch_htb) برای محدودیت سرعت، و wireguard برای WireGuard کرنلی. AmneziaWG وقتی ماژولش ساخته نشود، به پیاده‌سازی فضای کاربر برمی‌گردد. نصب‌کننده هر کدام را آزمایش می‌کند و نتیجه را می‌گوید، و خط Enforcement در نمای کلی نشان می‌دهد پنل در کدام حالت است.

اشتراک سرور با پروژه‌های دیگر ​

W-UI طوری نوشته شده که مهمان سروری باشد که ممکن است برنامه‌های دیگری هم داشته باشد: یک وب‌سایت پشت nginx، Docker، یک VPN دیگر، یک دیتابیس. به چیزی جز مال خودش دست نمی‌زند، و وقتی چیز دیگری مال او را بردارد، آن را سر جایش برمی‌گرداند.

W-UI چه می‌کندبه چه چیزی دست نمی‌زند
فایروالفقط جدول‌های nftables خودش: inet wui (سقف‌ها)، inet wui_policy (مسیریابی) و ip wui_nat (ترجمه‌ی آدرس تونل‌ها). در ufw یا firewalld، اگر روشن باشد، پورت تونل‌ها را باز می‌کند و فقط چیزی را می‌بندد که خودش باز کرده.هر جدول و زنجیره‌ی دیگر؛ هیچ‌وقت کل قانون‌ها را پاک نمی‌کند. نصب‌کننده فقط در فایروالی که از قبل روشن است پورت باز می‌کند و هیچ‌وقت فایروالی را روشن نمی‌کند.
مسیریابیعلامت‌ها در بازه‌ی 0xa7xxxx، جدول‌ها از 47000، قانون‌ها با اولویت 20000 به بالا.هر قانونی که علامت یا جدولش در این بازه‌ها نباشد؛ چنین قانونی هیچ‌وقت حذف یا پاک نمی‌شود.
محدودیت سرعتیک صف روی دستگاه‌های تونل خودش.کارت شبکه‌ی سرور، و هر دستگاهی که صفش را برنامه‌ی دیگری ساخته.
بازه‌ی تونل‌هاساب‌نت تونل تازه اگر با شبکه‌ای که از قبل روی سرور هست، مثل bridge داکر، یک VPN دیگر یا شبکه‌ی خود سرور، هم‌پوشانی داشته باشد رد می‌شود و پیام رد، نام دستگاه را می‌گوید.
پورت‌هایک پورت آزاد تصادفی برای پنل و سرویس سابسکریپشن. تونل پورتی را که برنامه‌ی دیگری گرفته نمی‌گیرد.پورت‌هایی که برنامه‌های دیگر گرفته‌اند، از جمله پورت 80. نصب خودکاری که ببیند پورت 80 گرفته شده، به جای پرسیدن، گواهی را کنار می‌گذارد.
DNSفقط روی آدرس دروازه‌ی تونل‌های خودش جواب می‌دهد.پورت 53 روی هر آدرس دیگر، از جمله systemd-resolved.
سرویس‌هاstrongSwan، xl2tpd، ocserv و pppd نصب می‌شوند و خاموش می‌مانند؛ عامل آنها را از روی فایل‌های خودش اجرا می‌کند.strongSwan، xl2tpd یا pptpdی که خودتان از قبل اجرا می‌کنید؛ تونلی که پورت آن را لازم داشته باشد با ذکر دلیل رد می‌شود.
PostgreSQLیک نقش و یک دیتابیس به نام wui، و دو خط برای آنها در ابتدای pg_hba.conf.هر دیتابیس، نقش و خط دیگر؛ ورود پروژه‌های دیگر تغییر نمی‌کند.
گواهی‌هاگواهی‌های خودش در acme.sh، از Let's Encrypt که در هر درخواست نامش آورده می‌شود.مرجع پیش‌فرض acme.sh و گواهی پروژه‌های دیگر. پاک‌سازی بعد از درخواست ناموفق به چیزی جز گواهی‌های خود پنل نمی‌رسد.
کرنلفوروارد IPv4 و IPv6، در /etc/sysctl.d/99-wui.conf.هر تنظیم دیگر.
سرویس پنلبا کاربر بدون امتیاز خودش اجرا می‌شود و بقیه‌ی سیستم برایش فقط‌خواندنی است.

برعکسش هم درست است. وقتی برنامه‌ی دیگری روی سرور چیزی را که پنل ساخته بردارد، مثلاً بارگذاری دوباره‌ی فایروالی که پیکربندی‌اش با flush ruleset شروع می‌شود (فایل پیش‌فرض /etc/nftables.conf در دبیان همین‌طور است، پس یک systemctl restart nftables ساده کافی است)، یا VPN دیگری که قانون‌های مسیریابی را از نو می‌چیند، پنل ظرف دو ثانیه متوجه می‌شود، مال خودش را برمی‌گرداند و در لاگ می‌نویسد removed by something else on this server. بدون این، همه‌ی سقف‌ها، همه‌ی مشتری‌های خاموش‌شده و همه‌ی مسیرهای خروج از تونل‌ها بی‌صدا از کار می‌افتادند.

Released under the AGPL-3.0 License.