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

protect() چه چیزی را از تونل حذف می‌کند

VpnService.protect() یک فراخوان به‌ازای هر سوکت است. سوکت یا توصیفگری را که تونل را حمل می‌کند به آن می‌دهید و اندروید آن سوکت را علامت می‌زند تا ترافیکش از شبکه زیرین به جای رابط VPN استفاده کند. هر چیز دیگری که برنامه می‌فرستد همچنان مسیر عادی VPN را دنبال می‌کند.

همین دامنه باریک نکته اصلی است. سوکت محافظت‌شده تغییری در نحوهٔ حل نام‌ها توسط کلاینت HTTP شما، رابطی که فراخوان‌های تحلیلی‌تان استفاده می‌کند، یا آنچه بر سر اتصال دومی که بعداً باز می‌شود نمی‌دهد.

سه شرطی که دامنه را تعیین می‌کند

شرط اول این است که آیا فقط انتقال تونل باید خارج شود. اگر بقیه ترافیک برنامه باید همچنان از VPN عبور کند، محافظت از سوکت دامنه درست است. شرط دوم این است که آیا ایجاد سوکت را در کنترل دارید. کتابخانه‌ای که سوکت خودش را در عمق باز می‌کند جایی برای شما نمی‌گذارد که protect() را فراخوانی کنید، مگر اینکه قلابی ارائه دهد یا سوکتی از پیش ساخته را بپذیرد. شرط سوم این است که آیا برنامه باید مستقیماً به شبکه محلی یا captive portal برسد، که الزامی متفاوت از زنده نگه داشتن تونل است.

حذف برنامه با addDisallowedApplication() ابزار بی‌ظرافتی است. هر اتصالی که برنامه برقرار می‌کند را از VPN حذف می‌کند، از جمله آن‌هایی که می‌خواستید بررسی کنید، و در بعضی دستگاه‌ها رفتار کشف محلی را هم تغییر می‌دهد.

گزینه سوم این است که انتقال را به شبکه‌ای انتخابی مقید کنید با bindProcessToNetwork() یا دستگیره شبکه در سطح سوکت. این وقتی مفید است که دستگاه هم‌زمان Wi-Fi و شبکه موبایل دارد و می‌خواهید تونل از یک بالاگذر مشخص برود.

آن را وقتی انتقال در حال ساخته شدن است فراخوانی کنید

فراخوانی کنید protect() را در همان بلوکی که انتقال را می‌سازد، پیش از connect() یا send(). اگر فراخوان false برگرداند، سوکت را ببندید و راه‌اندازی را شکست دهید؛ ادامه دادن شما را با انتقالی رها می‌کند که بسته‌هایش ممکن است دوباره به رابط خودتان وارد شوند.

شکل به‌قدری کوچک است که در یک جا بماند:

DatagramSocket transport = new DatagramSocket();
if (!protect(transport)) {
    transport.close();
    throw new IOException("transport not protected");
}
transport.connect(serverAddress);

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

مسیر مسدود را آزمایش کنید، نه فقط مسیر خوش‌بینانه را

با تونل برپا بررسی کنید، چون تنها حالتی است که دو مسیر می‌توانند متفاوت باشند. یک درخواست را از انتقال محافظت‌شده بفرستید و یکی را از مسیر کدی که هرگز protect() را صدا نزده است، سپس آنچه را انتهای دور می‌بیند مقایسه کنید: اتصال محافظت‌شده باید با شبکه زیرین به عنوان مبدأ برسد، در حالی که اتصال بدون محافظت نشانی خود تونل را نشان می‌دهد و شمارنده‌های بایت تونل را حرکت می‌دهد. روی دستگاه،ss یا netstat همان شکاف را پیش از خروج هر چیز از رادیو نشان می‌دهد.

پس‌گرفتن را جداگانه آزمایش کنید، چون تغییر رضایت رابط را فرو می‌ریزد بی‌آنکه کد سوکت شما را لمس کند. رضایت VPN را پس بگیرید یا سرویس را متوقف کنید، انتقال را از نو بسازید و تأیید کنید که protect() هنوز true برمی‌گرداند و انتقال پس از دادن دوباره رضایت دوباره وصل می‌شود.

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

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

مقالات مرتبط