VPN

Android میاناهای برنامه‌سازی کاربردی‌ای برای توسعه‌دهندگان ارائه می‌دهد تا راهکارهای شبکه خصوصی مجازی (VPN) ایجاد کنند. پس‌از خواندن این راهنما، با نحوه توسعه و آزمایش کردن کارخواه VPN خودتان برای دستگاه‌های مجهز به Android آشنا خواهید شد.

نمای کلی

وی‌پی‌ان به دستگاه‌هایی که به‌طور فیزیکی در شبکه نیستند اجازه می‌دهد به‌طور ایمن به شبکه دسترسی داشته باشند.

Android شامل یک کلاینت VPN داخلی (PPTP و L2TP/IPSec) است که گاهی اوقات VPN قدیمی نامیده می‌شود. Android نسخه ۴.۰ (سطح میانای برنامه‌سازی کاربردی ۱۴) میاناهای برنامه‌سازی کاربردی را معرفی کرد تا توسعه‌دهندگان نرم‌افزار بتوانند راهکارهای VPN خود را ارائه دهند. راهکار VPN خود را در برنامه‌ای بسته‌بندی می‌کنید که افراد در دستگاه نصب می‌کنند. توسعه‌دهندگان معمولاً به‌یکی از دلایل زیر برنامه VPN می‌سازند:

  • برای ارائه پروتکل‌های VPN که کارخواه داخلی پشتیبانی نمی‌کند.
  • برای کمک به افراد جهت متصل شدن به سرویس VPN بدون پیکربندی پیچیده.

بقیه این راهنما نحوه توسعه برنامه‌های VPN (ازجمله همیشه‌روشن و VPN برای هر برنامه) را توضیح می‌دهد و کارخواه VPN داخلی را پوشش نمی‌دهد.

تجربه کاربری

Android میانای کاربری (UI) ارائه می‌دهد تا به افراد کمک کند راهکار VPN شما را پیکربندی، شروع، و متوقف کنند. رابط کاربری سیستم همچنین فردی را که از دستگاه استفاده می‌کند از اتصال فعال VPN مطلع می‌کند. Android مؤلفه‌های میانای کاربر زیر را برای اتصال‌های VPN نشان می‌دهد:

  • قبل‌از اینکه برنامه VPN بتواند برای اولین‌بار فعال شود، سیستم کادر گفتگوی درخواست اتصال را نمایش می‌دهد. کادر گفتگویی از فردی که از دستگاه استفاده می‌کند می‌خواهد تأیید کند که به VPN اعتماد دارد و درخواست را بپذیرد.
  • صفحه تنظیمات VPN («تنظیمات» > «شبکه و اینترنت» > VPN) برنامه‌های VPN را که فرد درخواست‌های اتصال آن‌ها را پذیرفته است نشان می‌دهد. دکمه‌ای برای پیکربندی گزینه‌های سیستم یا فراموش کردن VPN وجود دارد.
  • وقتی اتصالی فعال باشد، سینی «تنظیمات فوری» پانل اطلاعاتی را نشان می‌دهد. با تک‌ضرب زدن روی برچسب، کادر گفتگویی با اطلاعات بیشتر و پیوندی به «تنظیمات» نمایش داده می‌شود.
  • نوار وضعیت شامل نماد VPN (کلید) است که نشان‌دهنده اتصال فعال است.

برنامه شما همچنین باید میانای کاربری ارائه دهد تا فردی که از دستگاه استفاده می‌کند بتواند گزینه‌های سرویس شما را پیکربندی کند. برای مثال، ممکن است راهکار شما نیاز داشته باشد تنظیمات اصالت‌سنجی حساب را ضبط کند. برنامه‌ها باید میانای کاربر زیر را نشان دهند:

  • کنترل‌هایی برای شروع و توقف دستی اتصال. وی‌پی‌ان همیشه روشن می‌تواند درصورت نیاز متصل شود، اما به افراد اجازه می‌دهد اتصال را در اولین باری که از وی‌پی‌ان شما استفاده می‌کنند پیکربندی کنند.
  • اعلان بسته‌نشدنی وقتی سرویس فعال است. اعلان می‌تواند وضعیت اتصال را نشان دهد یا اطلاعات بیشتری (مثل آمار شبکه) ارائه دهد. با ضربه زدن روی اعلان، برنامه‌تان به پیش‌زمینه می‌آید. پس‌از غیرفعال شدن سرویس، اعلان را بردارید.

سرویس VPN

برنامه شما شبکه سیستم را برای کاربر (یا نمایه کاری) به درگاه VPN متصل می‌کند. هر کاربر (یا نمایه کاری) می‌تواند برنامه VPN متفاوتی را اجرا کند. شما سرویس VPN ایجاد می‌کنید که سیستم از آن برای شروع و توقف VPN شما و پیگیری وضعیت اتصال استفاده می‌کند. سرویس VPN شما از VpnService ارث‌بری می‌کند.

این سرویس همچنین به‌عنوان محفظه شما برای اتصال‌های درگاه VPN و میاناهای دستگاه محلی آن‌ها عمل می‌کند. نمونه سرویس شما روش‌های VpnService.Builder را برای ایجاد میانای محلی جدید فراخوانی می‌کند.

شکل ۱. نحوه اتصال شبکه‌سازی Android به درگاه VPN توسط VpnService
نمودار معماری بلوکی که نشان می‌دهد VpnService چگونه یک میانای TUN محلی در شبکه سیستم ایجاد می‌کند.

برنامه شما داده‌های زیر را برای متصل کردن دستگاه به درگاه VPN منتقل می‌کند:

  • بسته‌های IP خروجی را از توصیف‌گر فایل میانای محلی می‌خواند، آن‌ها را رمزگذاری می‌کند، و به درگاه VPN ارسال می‌کند.
  • بسته‌های ورودی (دریافت‌شده و رمزگشایی‌شده از دروازه VPN) را در توصیف‌گر فایل میانای محلی می‌نویسد.

فقط یک سرویس فعال برای هر کاربر یا نمایه وجود دارد. شروع سرویس جدید، به‌طور خودکار سرویس موجود را متوقف می‌کند.

افزودن سرویس

برای افزودن سرویس VPN به برنامه‌تان، سرویس Android ایجاد کنید که از VpnService ارث‌بری کند. سرویس VPN را در فایل مانیفست برنامه‌تان با افزودن موارد زیر اعلام کنید:

  • بااجازه BIND_VPN_SERVICE از سرویس محافظت کنید تا فقط سیستم بتواند به سرویس شما متصل شود.
  • سرویس را با فیلتر قصد "android.net.VpnService" تبلیغ کنید تا سیستم بتواند سرویس شما را پیدا کند.

این مثال نشان می‌دهد که چگونه می‌توانید این سرویس را در فایل مانیفست برنامه‌تان اعلام کنید:

<service android:name=".MyVpnService"
         android:permission="android.permission.BIND_VPN_SERVICE">
     <intent-filter>
         <action android:name="android.net.VpnService"/>
     </intent-filter>
</service>

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

آماده کردن سرویس

برای آماده کردن برنامه برای تبدیل شدن به سرویس VPN فعلی کاربر، VpnService.prepare() را فراخوانی کنید. اگر فردی که از دستگاه استفاده می‌کند قبلاً به برنامه شما اجازه نداده باشد، این روش هدف فعالیت را برمی‌گرداند. از این هدف برای شروع فعالیت سیستم که درخواست اجازه می‌کند استفاده می‌کنید. سیستم کادر گفتگویی را نشان می‌دهد که شبیه کادرهای گفتگوی اجازه‌های دیگر است، مثل دسترسی به دوربین یا مخاطبین. اگر برنامه‌تان ازقبل آماده شده باشد، روش null را برمی‌گرداند.

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

متصل کردن سرویس

وقتی سرویس اجرا شد، می‌توانید میانای محلی جدیدی ایجاد کنید که به درگاه VPN متصل است. برای درخواست اجازه و اتصال به سرویس خود به دروازه VPN، باید مراحل را به‌ترتیب زیر تکمیل کنید:

  1. با VpnService.prepare() تماس بگیرید تا اجازه بگیرید (درصورت نیاز).
  2. VpnService.protect() را فراخوانی کنید تا سوکت تونل برنامه‌تان را خارج از VPN سیستم نگه دارید و از اتصال دایره‌ای جلوگیری کنید.
  3. برای متصل کردن سوکت تونل برنامه‌تان به درگاه VPN، DatagramSocket.connect() را فراخوانی کنید.
  4. روش‌های VpnService.Builder را برای پیکربندی میانای TUN محلی جدید در دستگاه برای ترافیک VPN فراخوانی کنید.
  5. VpnService.Builder.establish() را فراخوانی کنید تا سیستم میانای TUN محلی را ایجاد کند و مسیریابی ترافیک را ازطریق میانای مربوطه آغاز کند.

دروازه VPN معمولاً تنظیماتی را برای میانای TUN محلی درطول دست‌دهی پیشنهاد می‌کند. برنامه شما روش‌های VpnService.Builder را برای پیکربندی سرویس فراخوانی می‌کند، همان‌طور که در نمونه زیر نشان داده شده است:

// Configure a new interface from our VpnService instance. This must be done
// from inside a VpnService.
val builder = Builder()

// Create a local TUN interface using predetermined addresses. In your app,
// you typically use values returned from the VPN gateway during handshaking.
val localTunnel = builder
    .addAddress("192.168.2.2", 24)
    .addRoute("0.0.0.0", 0)
    .addDnsServer("192.168.1.1")
    .establish()

مثال موجود در بخش وی‌پی‌ان برای هر برنامه پیکربندی IPv6 را نشان می‌دهد که شامل گزینه‌های بیشتری است. قبل‌از اینکه بتوانید میانای جدیدی ایجاد کنید، باید مقادیر VpnService.Builder زیر را اضافه کنید:

addAddress()
حداقل یک نشانی IPv4 یا IPv6 به‌همراه پوشش زیرشبکه اضافه کنید که سیستم به‌عنوان نشانی میانای TUN محلی اختصاص می‌دهد. برنامه شما معمولاً نشانی‌های IP و پوشش‌های زیرشبکه را درطول دست‌دهی از درگاه VPN دریافت می‌کند.
addRoute()
اگر می‌خواهید سیستم ترافیک را ازطریق میانای VPN ارسال کند، حداقل یک مسیر اضافه کنید. مسیرها براساس نشانی‌های مقصد فیلتر می‌شوند. برای پذیرفتن همه ترافیک، مسیر بازی مثل 0.0.0.0/0 یا ::/0 تنظیم کنید.

روش establish() یک نمونه ParcelFileDescriptor برمی‌گرداند که برنامه‌تان از آن برای خواندن و نوشتن بسته‌ها به و از میانگیر میانجی استفاده می‌کند. اگر برنامه‌تان آماده نباشد یا کسی اجازه را لغو کند، روش establish() مقدار null را برمی‌گرداند.

چرخه حیات سرویس

برنامه شما باید وضعیت VPN انتخاب‌شده سیستم و هرگونه اتصال فعال را ردیابی کند. میانای کاربر (UI) برنامه‌تان را به‌روز کنید تا فردی که از دستگاه استفاده می‌کند از هرگونه تغییر مطلع شود.

شروع کردن سرویس

سرویس VPN شما می‌تواند به روش‌های زیر شروع شود:

  • برنامه شما سرویس را شروع می‌کند—معمولاً به این دلیل که فردی روی دکمه اتصال تک‌ضرب زده است.
  • سیستم سرویس را شروع می‌کند چون وی‌پی‌ان همیشه روشن روشن است.

برنامه شما سرویس VPN را با ارسال یک هدف به startService() شروع می‌کند. برای کسب اطلاعات بیشتر، شروع کردن سرویس را بخوانید.

سیستم سرویس شما را در پس‌زمینه با فراخوانی onStartCommand() شروع می‌کند. بااین‌حال، Android در نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) یا بالاتر، محدودیت‌هایی برای برنامه‌های پس‌زمینه اعمال می‌کند. اگر از این سطوح API پشتیبانی می‌کنید، باید با فراخوانی Service.startForeground()، سرویس خود را به پیش‌زمینه منتقل کنید. برای کسب اطلاعات بیشتر، اجرای سرویس در پیش‌زمینه را بخوانید.

متوقف کردن سرویس

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

  • اتصال برنامه VPN را قطع کند یا آن را فراموش کند
  • وی‌پی‌ان همیشه روشن را برای اتصال فعال خاموش می‌کند

سیستم روش onRevoke() سرویس شما را فراخوانی می‌کند اما این فراخوانی ممکن است در رشته اصلی اتفاق نیفتد. وقتی سیستم این روش را فراخوانی می‌کند، یک میانای شبکه جایگزین ازقبل ترافیک را مسیریابی می‌کند. می‌توانید منابع زیر را با خیال راحت دور بیندازید:

  • با فراخوانی DatagramSocket.close()، سوکت تونل محافظت‌شده به درگاه وی‌پی‌ان را ببندید.
  • توصیف‌گر فایل بسته را با فراخوانی ParcelFileDescriptor.close() ببندید (نیازی به تخلیه آن نیست).

VPN همیشه فعال

Android می‌تواند سرویس VPN را هنگام راه‌اندازی دستگاه شروع کند و آن را درحین روشن بودن دستگاه فعال نگه دارد. این ویژگی VPN همیشه روشن نام دارد و در Android 7.0 (سطح میانای برنامه‌سازی کاربردی ۲۴) یا بالاتر دردسترس است. درحالی‌که Android چرخه حیات سرویس را حفظ می‌کند، سرویس VPN شما مسئول اتصال درگاه VPN است. «VPN همیشه روشن» می‌تواند اتصال‌هایی را که از VPN استفاده نمی‌کنند نیز مسدود کند.

تجربه کاربری

در Android نسخه ۸.۰ یا بالاتر، سیستم کادرهای گفتگوی زیر را نشان می‌دهد تا فردی که از دستگاه استفاده می‌کند از وی‌پی‌ان همیشه روشن مطلع شود:

  • وقتی اتصال‌های وی‌پی‌ان همیشه روشن قطع می‌شود یا نمی‌تواند متصل شود، افراد اعلانی را می‌بینند که نمی‌توانند آن را ببندند. با تک‌ضرب زدن روی اعلان، کادر گفتگویی نشان داده می‌شود که توضیحات بیشتری ارائه می‌دهد. وقتی VPN دوباره متصل شود یا کسی گزینه VPN همیشه روشن را خاموش کند، اعلان ناپدید می‌شود.
  • «وی‌پی‌ان همیشه روشن» به فردی که از دستگاه استفاده می‌کند اجازه می‌دهد هرگونه اتصال شبکه‌ای را که از وی‌پی‌ان استفاده نمی‌کند مسدود کند. وقتی این گزینه روشن باشد، برنامه «تنظیمات» پیش‌از اتصال VPN به افراد هشدار می‌دهد که اتصال اینترنت ندارند. برنامه «تنظیمات» از فردی که از دستگاه استفاده می‌کند می‌خواهد ادامه دهد یا لغو کند.

چون سیستم (و نه شخص) اتصال همیشه روشن را شروع و متوقف می‌کند، باید رفتار و میانای کاربر برنامه‌تان را تطبیق دهید:

  1. هر میانای کاربری را که اتصال را قطع می‌کند غیرفعال کنید زیرا سیستم و برنامه «تنظیمات» اتصال را کنترل می‌کنند.
  2. هر پیکربندی را بین هر شروع برنامه ذخیره کنید و اتصالی را با جدیدترین تنظیمات پیکربندی کنید. چون سیستم برنامه شما را براساس تقاضا راه‌اندازی می‌کند، فردی که از دستگاه استفاده می‌کند ممکن است همیشه نخواهد اتصال را پیکربندی کند.

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

تشخیص همیشه روشن

Android میاناهای برنامه‌سازی کاربردی برای تأیید اینکه سیستم سرویس VPN شما را راه‌اندازی کرده است یا نه ندارد. اما وقتی برنامه‌تان هر نمونه سرویسی را که شروع می‌کند پرچم‌گذاری کند، می‌توانید فرض کنید که سیستم سرویس‌های پرچم‌گذاری‌نشده را برای وی‌پی‌ان همیشه روشن شروع کرده است. مثالی در اینجا آمده است:

  1. برای شروع سرویس VPN، نمونه Intent ایجاد کنید.
  2. سرویس VPN را با قرار دادن یک extra در intent پرچم‌گذاری کنید.
  3. در روش onStartCommand() سرویس، به‌دنبال پرچم در موارد اضافی آرگومان intent بگردید.

اتصال‌های مسدودشده

فردی که از دستگاه استفاده می‌کند (یا سرپرست فناوری اطلاعات) می‌تواند همه ترافیک را مجبور به استفاده از VPN کند. سیستم هرگونه ترافیک شبکه‌ای را که از VPN استفاده نمی‌کند مسدود می‌کند. افرادی که از دستگاه استفاده می‌کنند می‌توانند کلید مسدود کردن اتصال‌های بدون وی‌پی‌ان را در پانل گزینه‌های وی‌پی‌ان در «تنظیمات» پیدا کنند.

انصراف از «همیشه روشن»

اگر برنامه‌تان درحال‌حاضر نمی‌تواند از VPN همیشه روشن پشتیبانی کند، می‌توانید با تنظیم فراداده سرویس SERVICE_META_DATA_SUPPORTS_ALWAYS_ON روی false، از آن انصراف دهید (در Android نسخه ۸.۱ یا بالاتر). نمونه مانیفست برنامه زیر نحوه افزودن عنصر فراداده را نشان می‌دهد:

<service android:name=".MyVpnService"
         android:permission="android.permission.BIND_VPN_SERVICE">
     <intent-filter>
         <action android:name="android.net.VpnService"/>
     </intent-filter>
     <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
             android:value=false/>
</service>

وقتی برنامه‌تان از VPN همیشه روشن انصراف می‌دهد، سیستم کنترل‌های میانای کاربر گزینه‌ها را در «تنظیمات» غیرفعال می‌کند.

وی‌پی‌ان برای هر برنامه

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

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

// The apps that will have access to the VPN.
val appPackages = arrayOf(
    "com.android.chrome",
    "com.google.android.youtube",
    "com.example.a.missing.app"
)

// Loop through the app packages in the array and confirm that the app is
// installed before adding the app to the allowed list.
val builder = Builder()
for (appPackage in appPackages) {
    try {
        packageManager.getPackageInfo(appPackage, 0)
        builder.addAllowedApplication(appPackage)
    } catch (e: PackageManager.NameNotFoundException) {
        // The app isn't installed.
    }
}

// Complete the VPN interface config.
val localTunnel = builder
    .addAddress("2001:db8::1", 64)
    .addRoute("::", 0)
    .establish()

برنامه‌های دارای اجازه

برای افزودن برنامه به فهرست مجاز، VpnService.Builder.addAllowedApplication() را فراخوانی کنید. اگر فهرست شامل یک یا چند برنامه باشد، فقط برنامه‌های موجود در فهرست از VPN استفاده می‌کنند. همه برنامه‌های دیگر (که در فهرست نیستند) از شبکه‌های سیستم استفاده می‌کنند، گویی که وی‌پی‌ان درحال اجرا نیست. وقتی فهرست مجاز خالی باشد، همه برنامه‌ها از VPN استفاده می‌کنند.

برنامه‌های غیرمجاز

برای افزودن برنامه به فهرست غیرمجاز، VpnService.Builder.addDisallowedApplication() را فراخوانی کنید. برنامه‌های غیرمجاز از شبکه سیستم استفاده می‌کنند، گویی VPN درحال اجرا نیست—همه برنامه‌های دیگر از VPN استفاده می‌کنند.

دور زدن VPN

وی‌پی‌ان شما می‌تواند به برنامه‌ها اجازه دهد وی‌پی‌ان را دور بزنند و شبکه خودشان را انتخاب کنند. برای دور زدن VPN، هنگام ایجاد میانای VPN، VpnService.Builder.allowBypass() را فراخوانی کنید. پس‌از شروع سرویس VPN، نمی‌توانید این مقدار را تغییر دهید. اگر برنامه‌ای فرایند یا سوکت خود را به شبکه خاصی متصل نکند، ترافیک شبکه برنامه ازطریق VPN ادامه می‌یابد.

برنامه‌هایی که به شبکه خاصی متصل می‌شوند، وقتی کسی ترافیکی را که از VPN عبور نمی‌کند مسدود کند، اتصال ندارند. برای ارسال ترافیک ازطریق شبکه‌ای خاص، برنامه‌ها پیش‌از اتصال سوکت، روش‌هایی مثل ConnectivityManager.bindProcessToNetwork() یا Network.bindSocket() را فراخوانی می‌کنند.

کدگذاری نمونه

«پروژه منبع باز Android» شامل برنامه نمونه‌ای به نام ToyVPN است. این برنامه نحوه راه‌اندازی و اتصال سرویس VPN را نشان می‌دهد.