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

با آنچه صفحه تنظیمات نشان می‌دهد شروع کنید

فهرست VPN دفتری از پروفایل‌هایی است که سیستم یا کلاینت سازنده نصب کرده است: PPTP، L2TP/IPsec، IKEv2 و هر ردیفی که یک برنامه OEM یا یک MDM هل داده باشد. هر ردیف یک نشانی سرور، اعتبارنامه و پیاده‌سازی پروتکلی را حمل می‌کند که بیرون از فرایند شما زندگی می‌کند. وقتی کاربر آنجا روی اتصال ضربه می‌زند، کلاینت پلتفرم تونل را بالا می‌آورد، نه کد شما. به همین دلیل ردیف پس از راه‌اندازی مجدد باقی می‌ماند و به همین دلیل حذف برنامه شما هرگز آن را برنمی‌دارد.

از سمت کاربر، فهرست مثل یک سطح API به نظر می‌رسد، جایی که افزودن VPN باید یک intent فاصله داشته باشد. این‌طور نیست. تنها نقاط ورود عمومی که به آن دست می‌زنند intentهای ناوبری هستند، و هر چیزی که در آن می‌نویسد متعلق به پلتفرم یا یک مؤلفه دارای امتیاز است.

پیامد عملی: اگر متن پشتیبانی به کاربران بگوید پروفایل را در تنظیمات اضافه کنند، برنامه شما اصلاً بخشی از آن جریان نیست.

VpnService واقعاً چه چیزی به شما می‌دهد

VpnService و VpnService.Builder یک تونل را توصیف می‌کنند که مالکش برنامه شماست. نشانی‌ها، مسیرها، سرورهای DNS و یک MTU اضافه می‌کنید، ترافیک را با addAllowedApplication() یا addDisallowedApplication() محدود می‌کنید، و سپس establish() یک ParcelFileDescriptor برای رابط TUN برمی‌گرداند. از آن لحظه برنامه بسته‌های IP را می‌خواند و پاسخ می‌نویسد، یعنی پروتکل متعلق به شماست که پیاده‌سازی یا جاسازی کنید: OpenVPN، WireGuard، یک انتقال سفارشی.

هیچ‌چیز در آن توالی به PPTP، L2TP/IPsec یا IKEv2 حرف نمی‌زند. Builder هیچ کلیدی ندارد که بگوید از کلاینت L2TP سیستم استفاده کن، و هیچ callbackی وجود ندارد که به شما اجازه دهد پروفایلی را که پلتفرم از قبل مالک آن است هدایت کنید. این مرز واقعی است، و مرز طراحی است نه شکاف در مجوزها.

پس یک برنامه کاملاً می‌تواند در اندروید کلاینت VPN باشد. فقط نمی‌تواند مدیر کلاینت‌هایی باشد که همراه گوشی می‌آیند.

دیالوگ رضایت تزئینی نیست

چون تونل شما می‌تواند ترافیک برنامه‌های دیگر را بگیرد، سیستم کاربر را مجبور می‌کند آن را صریحاً تأیید کند. prepare() یک Intent برمی‌گرداند که باید اجرا کنید، تأیید به بسته شما گره خورده است، و تا وقتی تونل بالاست نوار وضعیت نشانگر دائمی نشان می‌دهد. VPN دوم که بالا بیاید اولی را غیرفعال می‌کند، چون اندروید هر بار یک VPN فعال اجرا می‌کند.

قاعده یک فعال در آزمون مردم را به اشتباه می‌اندازد. تونلتان را بالا می‌آورید در حالی که کلاینت شرکتی وصل است و نتیجه می‌گیرید کدتان خراب است، در حالی که پلتفرم فقط از کلاینت دیگر تغییر کرده است. تأییدها بعداً قابل لغو هستند، و prepare() می‌تواند در دستگاه‌هایی که فعالیت رضایت در آن‌ها نیست null برگرداند، پس establish() هنوز باید شکست را مدیریت کند.

APIهای پنهان و intentهای تنظیمات

پاسخ‌های قدیمی‌تر به کلاس‌های com.android.internal و رابط‌های AIDL اشاره می‌کنند که کلاینت داخلی از آن‌ها استفاده می‌کند. آن‌ها در SDK نیستند، بین نسخه‌ها بدون اطلاع تغییر می‌کنند و فروشگاه‌های برنامه چنین دسترسی را ریسک می‌دانند. روت کردن دستگاه هم آن‌ها را پایدار نمی‌کند، چون روت و دسترسی به APIهای پنهان دو مشکل بی‌ربط هستند.

راهنمای ناوبری پشتیبانی‌شده Settings.ACTION_VPN_SETTINGS است که مقدارش android.net.vpn.SETTINGS است. پیش از اجرا آن را resolve کنید، چون بعضی بیلدهای OEM آن فعالیت را ندارند، و وقتی resolve شکست خورد به مراحل نوشتاری برگردید. کاربر را به صفحه می‌برد و چیزی پیکربندی نمی‌کند.

مسیرهای مالک دستگاه و MDM همان استثنایی هستند که مردم معمولاً منظورشان است. DevicePolicyManager می‌تواند یک بسته VPN همیشه‌فعال تعیین کند، و پیکربندی‌های مدیریت‌شده می‌توانند تنظیمات را برای کلاینتی که از آن‌ها پشتیبانی می‌کند از پیش بارگذاری کنند، اما این هنوز همان SDK عمومی نیست که پروفایل PPTP بنویسد.

تصمیم را از سمت کاربر مرور کنید

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

آن تصمیم را پیش از نوشتن کد بنویسید، چون سه مسیر بعد از اولین اسپرینت تقریباً هیچ وجه مشترکی ندارند.

یک بررسی آخر پیش از شروع: آیا نیازمندی می‌گوید برنامه ما وصل می‌شود یا دستگاه وصل می‌شود؟ اولی VpnService است، دومی پروفایلی است که نمی‌توانید بسازید. درست نوشتن آن جمله از هر بازسازی ارزان‌تر است.

مقالات مرتبط