یک توزیع لینوکس را زیر chroot روی گوشی اجرا می‌کنید، یک کلاینت VPN داخلش نصب می‌کنید و پوسته اعلام می‌کند تونل کامل شد. بعد به مرورگر می‌روید و ترافیک از داده همراه بیرون می‌رود، انگار هیچ اتفاقی نیفتاده. یا برعکس: همه برنامه‌های گوشی اتصال را از دست می‌دهند چون کلاینت یک مسیر پیش‌فرض در همان فضای نامی گذاشته که اندروید واقعاً استفاده می‌کند. این دو نشانه از یک قطعه گمشده می‌آیند و هیچ‌کدام باگ کلاینت VPN نیست.

پوسته می‌گوید متصل، برنامه‌ها موافق نیستند

نتیجه اول رایج است. تونلی در فضای کاربر که از chroot باز شده می‌تواند دست‌دادنش را کامل کند، آمارش را چاپ کند و ترافیکی را که همان پوسته تولید می‌کند حمل کند، در حالی که برنامه‌های اندروید همچنان از شبکه پیش‌فرض گوشی استفاده می‌کنند. چیزی جلوی آن‌ها را نمی‌گیرد، چون چیزی به اندروید نگفته که VPN وجود دارد.

نتیجه دوم خطرناک است. اگر chroot فضای نام شبکه اندروید را به اشتراک بگذارد، که به‌طور پیش‌فرض چنین است، فرآیندی با امتیاز کافی می‌تواند مسیرها و یک واسط TUN اضافه کند که کل گوشی را تحت تأثیر قرار دهد. آن‌گاه تونل برای هر برنامه‌ای کار می‌کند، از جمله آن‌هایی که نمی‌خواستید مسیریابی شوند، و اتصال گوشی اکنون به یک دیمن بدون مدیریت چرخه عمر، بدون نشانگر اتصال و بدون سیاست همیشه‌روشن وابسته است.

کدام یک از این دو را گرفته‌اید با یک فرمان قابل پاسخ است. ip route را داخل chroot با همان فرمان از پوسته اندروید بیرون مقایسه کنید. خروجی یکسان یعنی chroot در فضای نام میزبان است: هر تغییر شبکه‌ای که بدهد برای کل گوشی است. خروجی متفاوت یعنی راه‌انداز برایش فضای نامی ساخته و تونلش به‌حکم ساخت برای اندروید نامرئی است.

chroot چه چیزی را عوض کرد و چه چیزی را نه

ObjectEffect of a chroot
Pathname resolutionChanged: lookups start at the new root
Kernel and driversUnchanged: the phone's kernel, its TUN driver, its limits
Network namespaceUnchanged unless the launcher creates one
Android VPN registrationUnchanged: no app consented, no VPN is selected

فراخوان سیستمی chroot یک کار می‌کند: پوشه‌ای را که برای مسیر‌یابی استفاده می‌شود عوض می‌کند. صفحه man صریح می‌گوید این یک مرز امنیتی نیست و درباره واسط‌ها، مسیرها یا وضعیت VPN چیزی نمی‌گوید. هر چیزی که مردم از یک کانتینر لینوکس انتظار دارند — پشته شبکه خصوصی، فایل‌سیستم فیلترشده، محدودیت منابع — از سازوکارهای دیگری می‌آید که راه‌انداز ممکن است به کار برده باشد یا نه.

به همین دلیل ادعاهایی که می‌گویند chroot یک VPN را جدا می‌کند معمولاً به پرسش اشتباه پاسخ می‌دهند. پرسش درست این است که فرآیند در کدام فضای نام اجرا می‌شود و به کدام دامنه SELinux محدود است، و هر دو ویژگی نحوه شروع آن است، نه واژه chroot.

TUN سه چیز می‌خواهد و گره دستگاه فقط یکی است

یک تونل سنتی در فضای کاربر به دستگاه TUN که بتواند بازش کند، پشتیبانی هسته برای آن دستگاه و اجازه پیکربندی واسط و مسیرها نیاز دارد. این‌ها شرط‌های جداگانه‌اند و ساختن یک نام مسیر زیر /dev به‌تنهایی هیچ‌یک را برآورده نمی‌کند:

ls -l /dev/net/tun
ip tuntap add dev tun0 mode tun

در اندروید پشتیبانی TUN معمولاً در هسته کامپایل شده، چون سرویس VPN خود پلتفرم از آن استفاده می‌کند، اما این یعنی فرآیند شما مجاز به استفاده از آن نیست. پیکربندی واسط به توانایی مدیریت شبکه نیاز دارد و SELinux تصمیم می‌گیرد که آیا فرآیند اصلاً به گره دستگاه می‌رسد. رد شدن شبیه خطای دسترسی بدون علت آشکار است و پاسخ در رد پای حسابرسی است:

dmesg | grep avc
logcat -d | grep "avc: denied"

root این را حل نمی‌کند. SELinux فرآیندهای uid 0 را دقیقاً مثل بقیه محدود می‌کند، پس chroot که از پوسته root شروع شده باز هم می‌تواند از دستگاهی که می‌بیند محروم شود. خاموش کردن اجرای اجباری برای کار کردن یک نصب‌کننده قدیمی تصمیمی برای کل گوشی با پیامدهایی بسیار فراتر از تونل است و رفع یک باینری کهنه نیست.

چرا برنامه‌های اندروید تونل شما را نادیده می‌گیرند

مدل پشتیبانی‌شده اندروید یک برنامه VPN است که از طریق سرویس VPN پلتفرم ثبت می‌شود، یک بار از کاربر رضایت می‌گیرد و یک توصیفگر فایل برای تونلش می‌گیرد. سپس پلتفرم ترافیک را به آن توصیفگر می‌فرستد و دامنه برنامه‌ای را که کاربر یا مدیر انتخاب کرده اعمال می‌کند، از همین رو همان سازوکار می‌تواند برای هر برنامه، هر پروفایل و همراه با تنظیمات همیشه‌روشن و مسدودسازی بدون VPN ترکیب شود. راهنمای توسعه VPN اندروید آن دست‌دادن را توصیف می‌کند و نکته کلیدی این است که ثبت است، نه ترفند مسیریابی.

دیمن داخل chroot هرگز ثبت نمی‌شود. نه دیالوگ رضایتی هست، نه نماد کلید در نوار وضعیت، نه فهرست شامل یا خارج کردن برای هر برنامه و نه مشارکتی در سیاست همیشه‌روشن. بنابراین برنامه‌ها همچنان از شبکه پیش‌فرض استفاده می‌کنند و تونل فقط چیزی را حمل می‌کند که خود پوسته می‌فرستد.

جهت مخالف هم کمکی نمی‌کند. هُل دادن مسیرها به فضای نام میزبان همه چیز را می‌گیرد، از جمله ترافیکی که پلتفرم انتظار داشت محلی بماند، و این کار را بدون کنترل هر برنامه و بدون راهی برای دیدن یا لغو کردن آن انجام می‌دهد. تنظیم میانه‌ای وجود ندارد که دیمن chroot ترافیک فقط یک برنامه را مسیریابی کند.

سازگاری باینری دیوار جداست

حتی وقتی سمت شبکه جالب است، فایل اجرایی نیازهای خودش را دارد: معماری پردازنده، بارگذار پویا، کتابخانه C و توانایی‌های هسته‌ای که انتظار دارد. اندروید به‌جای glibc از bionic استفاده می‌کند و یک باینری قدیمی که برای توزیع رومیزی ساخته شده ممکن است کتابخانه‌هایی بخواهد که دیگر روی دستگاه نیست.

پیوند دادن نام یک فایل کتابخانه به نسخه‌ای تازه‌تر سازگاری ABI نمی‌سازد و یک کتابخانه رمزنگاری بایگانی‌شده از بسته‌ای ده ساله مؤلفه‌ای نگهداری‌شده نیست. اگر برنامه به این وابسته باشد، برنامه یعنی اجرای کد بدون نگهداری با امتیازهای شبکه روی گوشی.

آن را در بستر اندروید ثابت کنید و بعد پاک‌سازی کنید

چیزی را که واقعاً برایتان مهم است از سمتی که اهمیت دارد آزمایش کنید: برنامه مشخص را باز کنید، به مقصد خصوصی مشخص برسید، تأیید کنید کدام resolver پاسخ داد، سپس تونل را قطع کنید و رفتار مستند را تأیید کنید. نتیجه‌ای از یک ترمینال داخل chroot شاهدی درباره بستر اجرای همان ترمینال است و نه بیشتر.

اگر در آزمایش مسیرهای میزبان را تغییر دادید، آن‌ها را برگردانید و بنویسید چه تغییری دادید. سپس ببینید گوشی VPN همیشه‌روشن دارد یا نه، چون آزمایشی قدیمی که قاعده‌ای جا گذاشته ممکن است ماه‌ها بعد شبیه نقص پلتفرم به نظر برسد.

برای نیاز واقعی دسترسی از راه دور از کلاینت پشتیبانی‌شده سرویس یا طراحی دروازه تأییدشده استفاده کنید. پرسشی که ارزش پرسیدن دارد این نیست که آیا می‌توان نصب‌کننده‌ای با root را به کار انداخت، بلکه این است که آیا پیاده‌سازی پشتیبانی‌شده برنامه‌های لازم شما را از مرزی که می‌خواستید عبور می‌دهد، بدون جا گذاشتن تغییرات ویژه بدون مالک روی دستگاه.

مقالات مرتبط