VPN

Android מספק למפתחים ממשקי API ליצירת רשת וירטואלית פרטית (VPN) ולבסוף על solutions. אחרי שתקראו את המדריך הזה, תוכלו לדעת איך לפתח ולבדוק לקוח VPN פרטי למכשירים מבוססי Android.

סקירה כללית

רשתות VPN מאפשרות למכשירים שלא מחוברים פיזית לרשת לגשת באופן מאובטח עמוקה מאוד,

מערכת Android כוללת לקוח VPN מובנה (PPTP ו-L2TP/IPSec), שלפעמים שנקרא VPN מדור קודם. ב-Android 4.0 (רמת API 14) נוספו ממשקי API כדי שהאפליקציה מפתחים יכולים לספק פתרונות 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 שהמערכת משתמשת בו כדי להפעיל אותו לעצור את ה-VPN ולעקוב אחרי סטטוס החיבור. שירות ה-VPN מקבל בירושה מ- VpnService

השירות גם משמש כמאגר שלכם לחיבורים של שער VPN לממשקי המכשיר המקומיים שלהם. קריאה למופע של השירות שיטות VpnService.Builder ליצירת ממשק מקומי חדש.

איור 1. איך מערכת VpnService מתחברת ל-Android יצירת רישות לשער ה-VPN
תרשים ארכיטקטורה של בלוקים שמראה איך VpnService יוצר TUN מקומי
         בממשק רשת של מערכת.

האפליקציה שלכם מעבירה את הנתונים הבאים כדי לחבר את המכשיר לשער ה-VPN:

  • קריאת חבילות IP יוצאות ממתאר הקובץ של הממשק המקומי, הצפנה ושולח אותם לשער ה-VPN.
  • כותב חבילות נכנסות (שהתקבלו ומפוענחות משער ה-VPN) אל ומתאר הקובץ בממשק המקומי.

יש רק שירות פעיל אחד לכל משתמש או פרופיל. התחלת שירות חדש, יפסיק באופן אוטומטי שירות קיים.

הוספת שירות

כדי להוסיף שירות VPN לאפליקציה, צריך ליצור שירות Android שמקבל בירושה מ- VpnService להצהיר על שירות ה-VPN באפליקציה שלך קובץ מניפסט עם התוספות הבאות:

  • מגינים על השירות באמצעות BIND_VPN_SERVICE כך שרק המערכת תוכל לקשר לשירות שלכם.
  • לפרסם את השירות עם מסנן Intent מסוג "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 שפועל כל הזמן.

הכנת שירות

כדי להכין את האפליקציה להיות שירות ה-VPN הנוכחי של המשתמש, צריך להתקשר VpnService.prepare() אם האדם שמשתמש במכשיר לא כבר ניתנה הרשאה לאפליקציה, השיטה תחזיר Intent לפעילות. הכוונה הזו היא כדי להתחיל פעילות במערכת שמבקשת הרשאה. מציגה תיבת דו-שיח שדומה לתיבות דו-שיח אחרות לגבי הרשאות, כמו גישה למצלמה או לאנשי הקשר. אם האפליקציה כבר מוכנה, השיטה תוחזר null

רק אפליקציה אחת יכולה להיות שירות ה-VPN המוכן הנוכחי. להתקשר תמיד VpnService.prepare() כי יכול להיות שמשתמש הגדיר אחרת בתור שירות ה-VPN מאז הפעם האחרונה שהאפליקציה שלך קראה ל-method. מידע נוסף זמין במאמר הבא: הקטע Service Lifecycle

קישור שירות

לאחר שהשירות יפעל, תוכל ליצור ממשק מקומי חדש שמחובר לשער VPN. כדי לבקש הרשאה ולהתחבר לשירות שלכם כדי שער ה-VPN, תצטרכו להשלים את השלבים לפי הסדר הבא:

  1. התקשרו אל VpnService.prepare() כדי לבקש הרשאה (כאשר נדרש).
  2. צריך להתקשר למספר VpnService.protect() כדי להשאיר את שקע המנהרה של האפליקציה מחוץ לרשת ה-VPN של המערכת ונמנעים מחיבור מעגלי.
  3. צריך להתקשר למספר DatagramSocket.connect() כדי לחבר את המנהרה של האפליקציה שקע לשער ה-VPN.
  4. מפעילים שיטות VpnService.Builder להגדרת נכס מקומי חדש בממשק TUN של המכשיר לתנועת VPN.
  5. קוראים ל-VpnService.Builder.establish() כדי שהמערכת יוצרת את ממשק TUN המקומי ומתחיל לנתב את התנועה דרך גרפי.

שער VPN מציע בדרך כלל הגדרות לממשק TUN המקומי במהלך לחיצת יד. האפליקציה קוראת ל-VpnService.Builder שיטות כדי להגדיר השירות המוצג בדוגמה הבאה:

Kotlin

// 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()

Java

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

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

הדוגמה בקטע VPN לכל אפליקציה מציגה הגדרת IPv6 כולל אפשרויות נוספות. צריך להוסיף את הערכים הבאים של VpnService.Builder לפני שתוכלו ליצור ממשק חדש:

addAddress()
להוסיף לפחות כתובת IPv4 או IPv6 אחת יחד עם מסכה של רשת משנה משויך ככתובת ממשק TUN המקומית. האפליקציה שלך בדרך כלל מקבלת את כתובת ה-IP כתובות ומסכות של רשת משנה משער VPN במהלך לחיצת יד.
addRoute()
צריך להוסיף לפחות נתיב אחד אם רוצים שהמערכת תשלח תנועה דרך ה-VPN גרפי. המסלולים מסננים לפי כתובות יעד. כדי לקבל את כל התנועה, צריך להגדיר נתיב פתוח כמו 0.0.0.0/0 או ::/0.

ה-method establish() מחזירה מופע אחד (ParcelFileDescriptor) שהאפליקציה משתמשת בו כדי לקרוא ולכתוב העברת חבילות נתונים למאגר הנתונים הזמני של הממשק וממנו. establish() הפונקציה מחזירה null אם האפליקציה לא מוכנה או שמישהו מבטל את הרשאה.

מחזור החיים של שירות

האפליקציה צריכה לעקוב אחרי הסטטוס של רשת ה-VPN שנבחרה והמערכת בחיבורים. לעדכן את ממשק המשתמש (UI) של האפליקציה כדי שהאדם שמשתמש המכשיר מודע לשינויים.

הפעלת שירות

אפשר להפעיל את שירות ה-VPN בדרכים הבאות:

  • האפליקציה מפעילה את השירות. לרוב זה קורה כי משתמש הקיש על לחצן התחברות.
  • המערכת מפעילה את השירות כי ה-VPN שפועל כל הזמן מופעל.

האפליקציה שלך מפעילה את שירות ה-VPN על ידי העברת כוונה אל startService() לקבלת מידע נוסף, אפשר לקרוא את המאמר הפעלת .

המערכת מפעילה את השירות ברקע על ידי התקשרות onStartCommand() אבל מערכת Android מגבילה אפליקציות ברקע בגרסה 8.0 (רמת API 26) ואילך. אם התוכנית תומכת מהסוגים האלה רמות API, צריך להעביר את השירות לחזית באמצעות קריאה Service.startForeground() אפשר לקרוא מידע נוסף במאמר הרצת בשירות שפועל בחזית.

הפסקת שירות

אדם שמשתמש במכשיר יכול להפסיק את השירות על ידי שימוש בממשק המשתמש של האפליקציה. הפסקה של שירות במקום לסגור את החיבור. המערכת גם מפסיקה חיבור כשאדם המשתמש במכשיר מבצע את הפעולות הבאות במסך ה-VPN באפליקציית ההגדרות:

  • מנתק או שוכח את אפליקציית ה-VPN
  • משבית את ה-VPN שפועל כל הזמן בשביל חיבור פעיל

המערכת מפעילה את השיטה onRevoke() של השירות, אבל השיחה הזו מתבצעת אולי לא יקרה בשרשור הראשי. כשהמערכת קוראת לשיטה הזו, ממשק הרשת החלופית כבר מנתב את תעבורת הנתונים. אפשר להשליך בבטחה תוכלו להיעזר במקורות המידע הבאים:

  • סגירת שקע המנהרה המוגן לשער ה-VPN באמצעות קריאה DatagramSocket.close()
  • אפשר לסגור את מתאר קובץ החבילה (אין צורך לרוקן אותו) באמצעות קריאה ParcelFileDescriptor.close()

VPN שפועל כל הזמן

מערכת Android יכולה להפעיל שירות VPN בזמן שהמכשיר מופעל, ולהמשיך לפעול בזמן שהמכשיר שהמכשיר מופעל. התכונה הזו נקראת VPN שפועל כל הזמן והיא זמינה Android מגרסה 7.0 (רמת API 24) ואילך. בזמן שהשירות ב-Android מתחזק מחזור החיים שלכם, הוא שירות ה-VPN שאחראי על שער ה-VPN חיבור כזה. VPN שפועל כל הזמן יכול גם לחסום חיבורים שלא משתמשים ב-VPN.

חוויית משתמש

ב-Android מגרסה 8.0 ואילך, המערכת מציגה את תיבות הדו-שיח הבאות כדי: אדם שמשתמש במכשיר מודע ל-VPN שפועל כל הזמן:

  • כשחיבורי VPN שפועלים כל הזמן מתנתקים או לא יכולים להתחבר, אנשים רואים התראה שאי אפשר לסגור. הקשה על ההתראה תציג תיבת דו-שיח מספקת הסבר נוסף. ההתראה תיעלם כשה-VPN יתחבר מחדש או מישהו אחר משביתה את האפשרות 'VPN שפועל כל הזמן'.
  • רשת VPN שפועלת כל הזמן מאפשרת לאדם שמשתמש במכשיר לחסום כל רשת חיבורים שלא משתמשים ב-VPN. כשמפעילים את האפשרות הזו, ההגדרות מוצגת אזהרה לאנשים שאין להם חיבור לאינטרנט לפני ה-VPN עם חיבור. אפליקציית ההגדרות מבקשת מהאדם שמשתמש במכשיר להמשיך או לבטל.

מכיוון שהמערכת (ולא בן אדם) מתחילה ומפסיקה חיבור שפועל כל הזמן, עליכם להתאים את ההתנהגות וממשק המשתמש של האפליקציה:

  1. השבתת כל ממשק משתמש שמנתק את החיבור בגלל שהמערכת וההגדרות שליטה בחיבור.
  2. שומרים את ההגדרות הרצויות בין ההפעלה של כל אפליקציה בנפרד ומגדירים חיבור עם ההגדרות העדכניות ביותר. מאחר שהמערכת מפעילה את האפליקציה על פי דרישה, המשתמש השימוש במכשיר לא תמיד ירצה להגדיר חיבור.

אפשר גם להשתמש בהגדרות מנוהלות כדי להגדיר חיבור כזה. הגדרות מנוהלות עוזרות לאדמין ב-IT להגדיר את ה-VPN מרחוק.

זיהוי מצב פועל כל הזמן

מערכת Android לא כוללת ממשקי API שמאפשרים לאמת אם המערכת הפעילה את ה-VPN לאחר השיפור. אבל כשהאפליקציה מסמנת מופעי שירות כלשהם שהיא מתחילה, אפשר להניח שהמערכת הפעילה שירותים לא מסומנים עבור VPN שפועל כל הזמן. הנה דוגמה:

  1. יוצרים מכונה של Intent כדי להפעיל את שירות ה-VPN.
  2. מסמנים את שירות ה-VPN על ידי הוספת תוספת ל-Intent.
  3. בשיטה onStartCommand() של השירות, מחפשים את בתוספות של הארגומנט intent.

חיבורים חסומים

אדם שמשתמש במכשיר (או אדמין ב-IT) יכול לאלץ את כל תעבורת הנתונים להשתמש ב-VPN. המערכת חוסמת את כל התנועה ברשת שלא משתמשת ב-VPN. אנשים שמשתמשים ב המכשיר יכול למצוא את המתג חסימת חיבורים ללא VPN באפשרויות ה-VPN בחלונית 'הגדרות'.

ביטול ההצטרפות למצב 'פועל כל הזמן'

אם האפליקציה לא יכולה לתמוך כרגע ב-VPN שפועל כל הזמן, אפשר לבטל את ההסכמה לכך (ב-Android) 8.1 ואילך) על ידי הגדרה של SERVICE_META_DATA_SUPPORTS_ALWAYS_ON המטא-נתונים של השירות ל-false. הדוגמה הבאה לקובץ המניפסט של האפליקציה מראה איך להוסיף רכיב המטא-נתונים:

<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. אפשר ליצור רשימת היתרים או רשימה אסורה, אבל לא את שניהם. אם לא תיצרו רשימות מותרות או אסורות, המערכת תשלח את כל התנועה ברשת דרך ה-VPN.

אפליקציית ה-VPN צריכה להגדיר את הרשימות לפני יצירת החיבור. אם צריך לשנות את הרשימות וליצור חיבור VPN חדש. האפליקציה חייבת להיות מותקנות במכשיר כשמוסיפים אותו לרשימה.

Kotlin

// 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()

Java

// The apps that will have access to the VPN.
String[] appPackages = {
    "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.
VpnService.Builder builder = new VpnService.Builder();
PackageManager packageManager = getPackageManager();
for (String appPackage: appPackages) {
  try {
    packageManager.getPackageInfo(appPackage, 0);
    builder.addAllowedApplication(appPackage);
  } catch (PackageManager.NameNotFoundException e) {
    // The app isn't installed.
  }
}

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

אפליקציות מורשות

כדי להוסיף אפליקציה לרשימת ההיתרים, צריך להתקשר VpnService.Builder.addAllowedApplication() אם המיקום אם הרשימה כוללת אפליקציה אחת או יותר, רק האפליקציות שברשימה משתמשות ב-VPN. כל שאר האפליקציות (שלא מופיעות ברשימה) משתמשות ברשתות המערכת כאילו רשת ה-VPN לא פועלת. כשרשימת ההיתרים ריקה, כל האפליקציות משתמשות ב-VPN.

אפליקציות שאסורות לשימוש

כדי להוסיף אפליקציה לרשימת האפליקציות האסורות, יש להתקשר VpnService.Builder.addDisallowedApplication() אפליקציות אסורות משתמשות ברשת של המערכת כאילו ה-VPN לא פועל – כל שאר אפליקציות משתמשות ב-VPN.

מעקף ל-VPN

רשת ה-VPN שלך יכולה לאפשר לאפליקציות לעקוף את ה-VPN ולבחור רשת משלהן. שפת תרגום לעקוף את ה-VPN, קוראים לפונקציה VpnService.Builder.allowBypass() יצירת ממשק VPN. לא ניתן לשנות את הערך הזה אחרי שמתחילים שירות VPN. אם אפליקציה לא מקשרת את התהליך או socket לנכס ספציפי הרשת של האפליקציה, התנועה ברשת של האפליקציה ממשיכה דרך ה-VPN.

לאפליקציות שמקושרות לרשת ספציפית אין חיבור כשמישהו שחוסמת תנועה שלא עוברת דרך ה-VPN. כדי להפנות תנועה דרך רשת, שיטות להתקשרות של אפליקציות, ConnectivityManager.bindProcessToNetwork() או Network.bindSocket() לפני שמחברים את השקע.

קוד לדוגמה

פרויקט הקוד הפתוח של Android כולל אפליקציה לדוגמה בשם ToyVPN. באפליקציה הזו מוסבר איך להגדיר שירות VPN ולחבר אותו.