Android udostępnia deweloperom interfejsy API do tworzenia rozwiązań wirtualnych sieci prywatnych (VPN). Ten dokument wyjaśnia, jak opracować i przetestować własnego klienta VPN na urządzenia z Androidem.
Przegląd
Sieci VPN umożliwiają urządzeniom, które nie znajdują się fizycznie w sieci, bezpieczny dostęp do niej.
Android zawiera wbudowanego klienta VPN (PPTP i L2TP/IPSec), który czasami jest nazywany starszą siecią VPN. W Androidzie 4.0 (poziom interfejsu API 14) wprowadziliśmy interfejsy API, dzięki którym deweloperzy aplikacji mogą udostępniać własne rozwiązania VPN. Rozwiązanie VPN jest pakowane w aplikację, którą użytkownicy instalują na urządzeniu. Deweloperzy zwykle tworzą aplikacje VPN z jednego z tych powodów:
- aby oferować protokoły VPN, których nie obsługuje wbudowany klient;
- aby umożliwić innym skorzystanie z usługi VPN bez skomplikowanej konfiguracji;
W pozostałej części tego dokumentu opisujemy, jak tworzyć aplikacje VPN (w tym zawsze włączone i dla poszczególnych aplikacji). Nie omawiamy wbudowanego klienta VPN.
Interfejs użytkownika
Android udostępnia interfejs użytkownika, który pomaga skonfigurować, uruchomić i zatrzymać rozwiązanie VPN. Interfejs systemu informuje też osobę korzystającą z urządzenia o aktywnym połączeniu VPN. Android wyświetla te komponenty interfejsu dla połączeń VPN:
- Zanim aplikacja VPN zostanie aktywowana po raz pierwszy, system wyświetli okno z prośbą o połączenie. W oknie pojawi się prośba o potwierdzenie, że użytkownik ufa sieci VPN i akceptuje żądanie.
- Na ekranie ustawień VPN (Ustawienia > Sieć i internet > VPN) wyświetlane są aplikacje VPN, w których użytkownik zaakceptował prośby o połączenie. Jest tam przycisk do konfigurowania opcji systemowych lub zapominania sieci VPN.
- Gdy połączenie jest aktywne, w obszarze Szybkich ustawień wyświetla się panel informacyjny. Kliknięcie etykiety powoduje wyświetlenie okna z dodatkowymi informacjami i linkiem do Ustawień.
- Na pasku stanu znajduje się ikona VPN (klucz), która wskazuje aktywne połączenie.
Aplikacja musi też udostępniać interfejs, aby osoba korzystająca z urządzenia mogła skonfigurować opcje usługi. Na przykład Twoje rozwiązanie może wymagać przechwytywania ustawień uwierzytelniania konta. Uwzględnij w aplikacji te elementy interfejsu:
- Elementy sterujące do ręcznego rozpoczynania i kończenia połączenia. Stały VPN może łączyć się w razie potrzeby, ale pozwól użytkownikom skonfigurować połączenie przy pierwszym użyciu sieci VPN.
- Powiadomienie, którego nie można zamknąć, gdy usługa jest aktywna. Powiadomienie może pokazywać stan połączenia lub zawierać więcej informacji, np. statystyki sieci. Kliknięcie powiadomienia powoduje wyświetlenie aplikacji na pierwszym planie. Usuń powiadomienie, gdy usługa stanie się nieaktywna.
Usługa VPN
Aplikacja łączy sieć systemową użytkownika (lub profilu służbowego) z bramą VPN. Każdy użytkownik (lub profil służbowy) może korzystać z innej aplikacji VPN. Tworzysz usługę VPN, której system używa do uruchamiania i zatrzymywania sieci VPN oraz śledzenia stanu połączenia. Twoja usługa VPN dziedziczy z VpnService.
Usługa działa też jako kontener połączeń bramy VPN i interfejsów urządzeń lokalnych. Instancja usługi wywołuje metody VpnService.Builder, aby ustanowić nowy interfejs lokalny.
VpnService łączy sieć Androida z bramą VPNAby połączyć urządzenie z bramą VPN, aplikacja przesyła te dane:
- Odczytuje wychodzące pakiety IP z deskryptora pliku interfejsu lokalnego, szyfruje je i wysyła do bramy VPN.
- Zapisuje pakiety przychodzące (odebrane i odszyfrowane z bramy VPN) w deskryptorze pliku interfejsu lokalnego.
Na użytkownika lub profil może przypadać tylko 1 aktywna usługa. Rozpoczęcie nowej usługi automatycznie zatrzymuje aktywną usługę.
Dodawanie usługi
Aby dodać usługę VPN do aplikacji, utwórz usługę Androida dziedziczącą z VpnService. Zadeklaruj usługę VPN w pliku manifestu aplikacji, dodając te elementy:
- Zabezpiecz usługę uprawnieniem
BIND_VPN_SERVICE, aby tylko system mógł się z nią powiązać. - Zareklamuj usługę za pomocą filtra intencji
android.net.VpnService, aby system mógł ją znaleźć.
Ten przykład pokazuje, jak zadeklarować usługę w pliku manifestu aplikacji:
<service android:name=".MyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
Teraz, gdy aplikacja deklaruje usługę, system może automatycznie uruchamiać i zatrzymywać usługę VPN aplikacji, gdy jest to konieczne. Na przykład system kontroluje usługę, gdy działa zawsze włączony VPN.
Przygotowanie usługi
Aby przygotować aplikację do roli bieżącej usługi VPN użytkownika, wywołaj VpnService.prepare(). Jeśli osoba korzystająca z urządzenia nie przyznała jeszcze uprawnień Twojej aplikacji, metoda zwraca intencję aktywności.
Używasz tej intencji, aby rozpocząć aktywność systemową, która prosi o uprawnienia. System wyświetla okno podobne do innych okien uprawnień, takich jak dostęp do aparatu lub kontaktów. Jeśli aplikacja jest już przygotowana, metoda zwraca wartość null.
Tylko jedna aplikacja może być aktualnie przygotowaną usługą VPN. Zawsze wywołuj metodę VpnService.prepare(), ponieważ użytkownik mógł ustawić inną aplikację jako usługę VPN od czasu ostatniego wywołania metody przez Twoją aplikację. Więcej informacji znajdziesz w sekcji Cykl życia usługi.
Łączenie usługi
Gdy usługa będzie działać, możesz utworzyć nowy interfejs lokalny połączony z bramą VPN. Aby poprosić o uprawnienia i połączyć usługę z bramą sieci VPN, musisz wykonać te czynności w podanej kolejności:
- Zadzwoń do
VpnService.prepare(), aby poprosić o zgodę (w razie potrzeby). - Wywołaj
VpnService.protect(), aby gniazdo tunelu aplikacji znajdowało się poza systemową siecią VPN i nie dochodziło do połączenia cyklicznego. - Wywołaj
DatagramSocket.connect(), aby połączyć gniazdo tunelu aplikacji z bramą VPN. - Wywołaj metody
VpnService.Builder, aby skonfigurować nowy lokalny interfejs TUN na urządzeniu na potrzeby ruchu VPN. - Wywołaj
VpnService.Builder.establish(), aby system utworzył lokalny interfejs TUN i zaczął kierować przez niego ruch.
Brama VPN zwykle sugeruje ustawienia lokalnego interfejsu TUN podczas uzgadniania. Aplikacja wywołuje metody VpnService.Builder, aby skonfigurować usługę, jak pokazano w tym przykładzie:
// 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()
Przykład w sekcji VPN dla poszczególnych aplikacji pokazuje konfigurację IPv6 z dodatkowymi opcjami. Zanim utworzysz nowy interfejs, musisz dodać te wartości VpnService.Builder:
addAddress()- Dodaj co najmniej 1 adres IPv4 lub IPv6 wraz z maską podsieci, którą system przypisuje jako lokalny adres interfejsu TUN. Aplikacja zwykle otrzymuje adresy IP i maski podsieci z bramy VPN podczas uzgadniania połączenia.
addRoute()- Jeśli chcesz, aby system wysyłał ruch przez interfejs VPN, dodaj co najmniej 1 trasę. Trasy są filtrowane według adresów docelowych. Aby akceptować cały ruch, ustaw otwartą trasę, np.
0.0.0.0/0lub::/0.
Metoda establish() zwraca instancję ParcelFileDescriptor, której aplikacja używa do odczytywania i zapisywania pakietów do i z bufora interfejsu. Jeśli aplikacja nie jest przygotowana lub ktoś wycofa uprawnienia, metoda establish() zwraca wartość null.
Cykl życia usługi
Aplikacja powinna śledzić stan wybranej sieci VPN i wszystkich aktywnych połączeń. Zaktualizuj interfejs aplikacji, aby informować osobę korzystającą z urządzenia o wszelkich zmianach.
uruchamianie usługi,
Usługę VPN można uruchomić na te sposoby:
- Aplikacja uruchamia usługę – zwykle dlatego, że użytkownik kliknął przycisk połączenia.
- System uruchamia usługę, ponieważ stała sieć VPN jest włączona.
Aplikacja uruchamia usługę VPN, przekazując intencję do startService(). Więcej informacji znajdziesz w artykule Uruchamianie usługi.
System uruchamia usługę w tle, wywołując metodę onStartCommand(). Jednak w Androidzie w wersji 8.0 (API na poziomie 26) lub nowszej obowiązują ograniczenia dotyczące aplikacji działających w tle. Jeśli obsługujesz te poziomy interfejsu API, musisz przenieść usługę na pierwszy plan, wywołując metodę Service.startForeground(). Więcej informacji znajdziesz w artykule Uruchamianie usługi na pierwszym planie.
Zatrzymywanie usługi
Osoba korzystająca z urządzenia może zatrzymać usługę za pomocą interfejsu aplikacji. Zatrzymaj usługę, zamiast tylko zamykać połączenie. System zatrzymuje też aktywne połączenie, gdy osoba korzystająca z urządzenia wykona te czynności na ekranie VPN w aplikacji Ustawienia:
- rozłącza się z aplikacją VPN lub ją zapomina,
- wyłącza stały VPN dla aktywnego połączenia,
System wywołuje metodę onRevoke() usługi, ale to wywołanie może nie nastąpić w głównym wątku. Gdy system wywołuje tę metodę, ruch jest już kierowany przez alternatywny interfejs sieciowy. Możesz bezpiecznie usunąć te zasoby:
- Zamknij chronione gniazdo tunelu do bramy VPN, wywołując metodę
DatagramSocket.close(). - Zamknij deskryptor pliku pakietu (nie musisz go opróżniać), wywołując metodę
ParcelFileDescriptor.close().
Stały VPN
Android może uruchomić usługę VPN po włączeniu urządzenia i nie wyłączać jej do momentu, aż urządzenie nie zostanie wyłączone. Ta funkcja nosi nazwę zawsze włączonej sieci VPN i jest dostępna na urządzeniach z Androidem 7.0 (poziom interfejsu API 24) lub nowszym. Android zarządza cyklem życia usługi, ale to usługa VPN odpowiada za połączenie z bramą VPN. Sieć VPN zawsze włączona może też blokować połączenia, które nie korzystają z sieci VPN.
Interfejs użytkownika
W Androidzie 8.0 lub nowszym system wyświetla te okna, aby poinformować osobę korzystającą z urządzenia o zawsze włączonej sieci VPN:
- Gdy połączenie ze stałą siecią VPN zostanie przerwane lub nie można go nawiązać, użytkownicy zobaczą powiadomienie, którego nie można zamknąć. Kliknięcie powiadomienia spowoduje wyświetlenie okna z dodatkowymi informacjami. Powiadomienie zniknie, gdy sieć VPN zostanie ponownie połączona lub ktoś wyłączy opcję stałej sieci VPN.
- Sieć VPN zawsze włączona umożliwia osobie korzystającej z urządzenia blokowanie połączeń sieciowych, które nie korzystają z sieci VPN. Po włączeniu tej opcji aplikacja Ustawienia ostrzega użytkowników, że nie mają połączenia z internetem, zanim połączy się z siecią VPN. Aplikacja Ustawienia wyświetli prośbę o potwierdzenie lub anulowanie działania.
Ponieważ połączenie zawsze włączone jest uruchamiane i zatrzymywane przez system (a nie przez człowieka), musisz dostosować działanie aplikacji i jej interfejs:
- Wyłącz wszystkie elementy interfejsu, które rozłączają połączenie, ponieważ połączeniem steruje system i aplikacja Ustawienia.
- Zapisuj konfigurację między uruchomieniami aplikacji i konfiguruj połączenie z najnowszymi ustawieniami. System uruchamia aplikację na żądanie, więc osoba korzystająca z urządzenia nie zawsze może chcieć skonfigurować połączenie.
Do skonfigurowania połączenia możesz też użyć konfiguracji zarządzanych. Konfiguracje zarządzane pomagają administratorowi IT zdalnie skonfigurować sieć VPN.
Wykrywanie zawsze włączone
Android nie zawiera interfejsów API do potwierdzania, czy system uruchomił usługę VPN. Jeśli jednak aplikacja oznaczy wszystkie uruchamiane przez siebie instancje usługi, możesz założyć, że system uruchomił nieoznaczone usługi na potrzeby zawsze włączonej sieci VPN. Oto przykład:
- Utwórz instancję
Intent, aby uruchomić usługę VPN. - Oznacz usługę VPN, dodając dodatkowe informacje do intencji.
- W metodzie
onStartCommand()usługi poszukaj flagi w dodatkach argumentuintent.
Zablokowane połączenia
Osoba korzystająca z urządzenia (lub administrator IT) może wymusić, aby cały ruch korzystał z sieci VPN. System blokuje cały ruch w sieci, który nie korzysta z sieci VPN. Osoby korzystające z urządzenia mogą znaleźć przełącznik Blokuj połączenia bez VPN w panelu opcji VPN w Ustawieniach.
Rezygnacja z funkcji zawsze włączone
Jeśli Twoja aplikacja nie obsługuje sieci VPN zawsze włączonej, możesz zrezygnować z tej funkcji (w Androidzie 8.1 (poziom interfejsu API 27) lub nowszym), ustawiając metadane usługi SERVICE_META_DATA_SUPPORTS_ALWAYS_ON na false. Ten przykładowy plik manifestu aplikacji pokazuje, jak dodać element metadanych:
<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>
Gdy aplikacja zrezygnuje z funkcji zawsze włączonej sieci VPN, system wyłączy elementy sterujące interfejsu opcji w Ustawieniach.
VPN dla poszczególnych aplikacji
Aplikacje VPN mogą filtrować, które aplikacje instalowane mogą wysyłać ruch przez połączenie VPN. Możesz utworzyć listę dozwolonych lub niedozwolonych, ale nie obie. Jeśli nie utworzysz list dozwolonych lub niedozwolonych, system będzie wysyłać cały ruch w sieci przez VPN.
Aplikacja VPN musi ustawić listy przed nawiązaniem połączenia. Jeśli chcesz zmienić listy, nawiąż nowe połączenie VPN. Aplikacja musi być zainstalowana na urządzeniu, gdy dodajesz ją do listy.
// 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()
Aplikacje dozwolone
Aby dodać aplikację do listy dozwolonych, wywołaj VpnService.Builder.addAllowedApplication(). Jeśli lista zawiera co najmniej 1 aplikację, tylko aplikacje z listy będą korzystać z sieci VPN.
Wszystkie inne aplikacje, których nie ma na liście, korzystają z sieci systemowych tak, jakby sieć VPN nie była uruchomiona. Gdy lista dozwolonych jest pusta, wszystkie aplikacje korzystają z VPN.
Aplikacje niedozwolone
Aby dodać aplikację do listy niedozwolonych, wywołaj VpnService.Builder.addDisallowedApplication().
Niedozwolone aplikacje korzystają z sieci systemowej tak, jakby sieć VPN nie była uruchomiona – wszystkie inne aplikacje korzystają z sieci VPN.
Omijanie sieci VPN
Usługa VPN może zezwalać aplikacjom na jej pomijanie i wybieranie własnej sieci. Aby pominąć VPN, podczas ustanawiania interfejsu VPN wywołaj VpnService.Builder.allowBypass(). Tej wartości nie można zmienić po uruchomieniu usługi VPN. Jeśli aplikacja nie powiąże swojego procesu lub gniazda z określoną siecią, ruch w sieci aplikacji będzie nadal przechodził przez sieć VPN.
Aplikacje, które są powiązane z konkretną siecią, nie mają połączenia, gdy ktoś blokuje ruch, który nie przechodzi przez sieć VPN. Aby wysyłać ruch przez określoną sieć, aplikacje wywołują metody takie jak ConnectivityManager.bindProcessToNetwork() lub Network.bindSocket() przed połączeniem gniazda.
Przykładowy kod
Projekt Android Open Source zawiera przykładową aplikację o nazwie ToyVPN. Ta aplikacja pokazuje, jak skonfigurować i połączyć usługę VPN.