چگونه یک برنامه لینوکس را با قواعد UID به VPN سنجاق کنیم
یک قاعده UID فقط سوکتهای محلی را میبیند و استثنای معمول loopback تونل را از کار میاندازد. اول حساب را مسیریابی کنید، سپس هر مرحله را فیلتر و بررسی کنید.
سنجاق کردن یک برنامه به VPN در لینوکس بیشتر یک مسئله مسیریابی است، و قاعده دیوار آتش فقط تصمیم میگیرد بعد از انتخاب مسیر چه اتفاقی بیفتد۔ اگر UID برنامه را در OUTPUT قبل از آنکه تونل مسیر پیشفرض را در اختیار داشته باشد تطبیق دهید، قاعده همان ترافیکی را میاندازد که میخواستید محافظت کنید۔ همان قاعده فرایند resolver را هم که به پرسشهای DNS برنامه پاسخ میدهد نمیبیند۔ ترتیب را درست کنید و یک حساب بدون امتیاز به انتخابگر قابل اعتماد تونل تقسیمشده تبدیل میشود۔
پیش از حکم، به حساب مسیر بدهید
تطبیق مالک به یک پرسش پاسخ میدهد: آیا سوکت محلی متعلق به این UID بسته را ساخته است؟ رابط را انتخاب نمیکند و نمیتواند ترافیکی را که جدول اصلی از قبل از NIC فیزیکی بیرون میفرستد جابهجا کند۔ به همین دلیل قاعده UID بدون مسیر متناظر برنامه را مسدود میکند نه اینکه آن را تغییر مسیر دهد۔
حساب را اول از جدول خودش عبور دهید، سپس بگذارید دیوار آتش نتیجه را تأیید کند۔ این روی میزبانی کار میکند که iproute2 آن uidrange را میفهمد، که ip rule help آن را در یک خط گزارش میکند۔ جدول 100 یک مسیر پیشفرض از تونل را نگه میدارد و قاعده فقط UID 1000 را به آن جدول میفرستد۔ بقیه چیزها روی جدول اصلی میمانند و از پیوند فیزیکی استفاده میکنند۔
ip rule add uidrange 1000-1000 table 100 ip route add default dev tun0 table 100
حساب دومی که به تونل دیگری نیاز دارد جدول 101 و قاعده خودش را میگیرد، چون دو پروفایل نمیتوانند هر دو در یک جدول مالک مسیر پیشفرض باشند۔ پروفایلهای NetworkManager سراسریاند، پس این بخش دستی میماند و قواعد در راهاندازی مجدد ناپدید میشوند مگر چیزی آنها را برگرداند۔ جدولها را در اسکریپت راهاندازی کنار تعریف تونل بنویسید تا اتصال دوباره یک حساب را در مسیر اشتباه رها نکند۔
چرا استثنای loopback تونل را میکشد
بیشتر نسخههای کپیشده قاعده هر بستهای را که از loopback بیرون نرود میاندازند۔ تونل loopback نیست، پس آن شکل ترافیک تونل را هم میاندازد و نتیجه مانند یک VPN مرده به نظر میرسد نه یک خطای دیوار آتش۔
وقتی OUTPUT اجرا میشود، هسته از قبل رابط خروج را انتخاب کرده، پس -o با پاسخ مسیر مقایسه میشود نه با سرآیند بسته۔ تطبیق مالک فقط در OUTPUT و POSTROUTING بررسی میشود و بستههای ارجاعشده سوکتی ندارند که آن را بخواند۔ این ترکیب یعنی استثنا باید رابط تونل را نام ببرد و آن تطبیق را نفی کند، نه اینکه loopback را نفی کند۔
loopback هنوز شایسته ACCEPT خودش بالای DROP است، چون اولین بسته DNS برنامه از طریق lo به استاب محلی میرود۔ دو قاعده را به این ترتیب بگذارید و حساب به استاب میرسد، سپس به تونل، و به هیچ جای دیگر۔
iptables -I OUTPUT 1 -o lo -m owner --uid-owner vpnapp -j ACCEPT iptables -A OUTPUT -m owner --uid-owner vpnapp ! -o tun0 -j DROP
IPv6 مجموعه قواعد جداگانه است و یک جفت فقط برای v4، ip6tables را دستنخورده میگذارد۔ برنامهای که رکوردهای AAAA را ترجیح میدهد آنگاه بدون رسیدن به DROP از پیوند فیزیکی بیرون میرفت۔ هر دو قاعده را در ip6tables بازتاب دهید، یا وقتی تونل هیچ نشانی از v6 ندارد IPv6 را روی میزبان غیرفعال کنید۔ قواعدی که دستی اضافه شدهاند هم در راهاندازی مجدد ناپدید میشوند، پس آنها را با netfilter-persistent save ذخیره کنید یا همان منطق را بهصورت جدول nftables که واحد راهاندازی بار میکند بازسازی کنید۔
پاسخهای DNS از فرایندی دیگر میآیند
پرسش برنامه به 127.0.0.53 از ACCEPT مربوط به loopback میگذرد و همانجاست که تطبیق UID متوقف میشود۔ resolver استاب از حساب سرویس خودش به بالا ارسال میکند، پس قاعدهای که به vpnapp گره خورده هرگز پرسش دوم را نمیبیند۔ اگر resolver برای پیوند یک سرور LAN انتخاب کند، پاسخها از NIC فیزیکی برمیگردند در حالی که بستههای خود برنامه در تونل میمانند۔ نتیجه قابل مشاهده یک تونل کارکننده با نامهای خراب است، یا نامهایی که سروری پاسخ میدهد که شما انتخاب نکردهاید۔
حل نام را روی پیوند تونل درست کنید نه در برنامه۔ به پروفایل تونل یک سرور DNS و یک دامنه مسیریابی بدهید، سپس با resolvectl query و resolvectl status tun0 تأیید کنید که resolver از آن برای نامهای مهم استفاده میکند۔ درون فضای نام شبکه مشکل ناپدید میشود، چون resolver فضا فقط تونل را میشناسد۔
قاعده را از خود حساب بررسی کنید
از هسته بپرسید یک UID چه مسیری میگیرد، سپس بهعنوان آن حساب درخواستی بفرستید و نشانی خروج را با نشانی حساب خودتان مقایسه کنید۔ اگر هر دو یک نشانی را گزارش کنند، قاعده چیزی غیر از ترافیکی که آزمودید را تطبیق میدهد۔ اولین فرمان زیر جستوجوی مسیر را بدون فرستادن بسته نشان میدهد، که خطای مسیریابی را از خطای دیوار آتش جدا میکند۔
ip route get 1.1.1.1 uid 1000 sudo -u vpnapp curl -s https://ifconfig.co
شمارندهها نشان میدهند آیا قاعدهای هرگز شلیک شده است۔ اجرا کنید iptables -vnL OUTPUT، شمار بستهها را کنار هر قاعده بخوانید و صفر کنار DROP پس از ترافیک واقعی را خطای تطبیق بدانید۔
ترافیک ارجاعشده بیرون این طراحی است۔ یک کانتینر یا VM پشت پل هیچ سوکت محلی متعلق به vpnapp ندارد، پس تطبیق مالک هرگز فعال نمیشود و آن بستهها بهجای آن از سیاست FORWARD پیروی میکنند۔ اگر این بار باید پوشش داده شود، جداگانه آزمونش کنید و سیاستی بنویسید که به پل یا نشانی کانتینر گره خورده باشد۔ طراحی زمانی میایستد که جدول، استثنای رابط، resolver و قواعد v6 همه به یک سمت اشاره کنند؛ هر یک را جا بگذارید و حساب یا نشت میکند یا اتصال را از دست میدهد۔