Android VpnService Neden Trafiğin Bir Kısmını Yakalar, Tamamını Değil
Rotalar, DNS kayıtları ve uygulama başına kapsam hangi paketlerin tun aygıtına ulaştığını, yerel aygıtların neden kaybolduğunu ve oluşturucunun neyi reddettiğini belirler.
VpnService içinde hiçbir şey trafiği kendiliğinden yakalamaz. Sistemden bir tun arayüzü ister, o arayüze bir dizi adres ve rota verir ve o andan itibaren çekirdek bu rotalarla eşleşen her paketi uygulamanın okuyabileceği bir dosya tanımlayıcısına kopyalar. Uygulama kodu rotaların seçmediği paketleri asla görmez, bu yüzden bir tünelin kapsamı programlama sorusu olmadan önce yönlendirme tablosu sorusudur. Bu yüzden aynı hizmet uygulaması bir telefonda her akışı yutabilirken diğerinde yalnızca bir kısmını yutabilir ve bu yüzden bir rota eklemek bazen bozuk görünen bir tüneli onarır. Aldığınız şey, beyan ettiğiniz şeydir, oluşturucunun sessizce reddettiği her şey çıkarıldığında.
Hangi paketlerin geldiğini rotalar belirler
Builder.addRoute(prefix, prefixLength) VPN ağının yönlendirme tablosuna bir önek yerleştirir. Sistem bu ağı kapsamdaki uygulamalar için varsayılan olarak değerlendirir, bu yüzden kayıtları fiziksel ağın varsayılan rotasından önce bakılır ve eşleşen bir önek bir akışı saptırmaya yeter. Bu yüzden 0.0.0.0/0 için bir rota IPv4'ün tamamını alır; yazıcı, cast hedefi ve yönlendiricinin yönetim sayfası dahil.
Fiziksel varsayılan kaydı silmeden bu kapsamı isteyen istemciler bunun yerine 0.0.0.0/1 ve 128.0.0.0/1 çiftini kullanır. Daha belirli iki rota varsayılan bir rotayı yener, birlikte tüm adres alanını kapsar ve telefonun kendi varsayılan kaydı hâlâ fiziksel ağa bağlı soketler için tabloda kalır.
Adresler ve DNS kayıtları aynı oluşturucudan gelir ve başka bir soruyu yanıtlar. addAddress arayüze bir önek uzunluğuyla adres verir ve addDnsServer kapsamdaki uygulamaların arayüz üzerinden sorgulayacağı bir çözümleyici kurar. İki aile de tek bir arayüzde oturabilir, bu yüzden yalnızca IPv4 rota kümesinin bir IPv6 adresinin yanında olması doğru okunan ve yine de sızdıran bir yapılandırmadır. Arayüzün adresi olmayan bir aileyi yönlendirirseniz çekirdeğin o paketler için kaynak adresi olmaz ve bu paketler tanımlayıcıda asla görünmez.
establish() ne döndürür
establish() bir ParcelFileDescriptor döndürür veya uygulama yetkili değilse null döndürür. Null bir ağ hatası değil, bir onay durumudur: VpnService.prepare() zaten null döndürmüş olmalı ya da kullanıcı çağrıdan önce sistem iletişim penceresini onaylamış olmalıdır. Onay hizmet çalışırken geri alınabilir ve arayüz okuma döngünüze herhangi bir geri çağrı olmadan ayaklarınızın altında kapanır.
Aksini söylemezseniz tanımlayıcı engellemez, bu yüzden bir okuma iş parçacığını park etmek yerine veri olmadan hemen döner. Engelleyen bir soket için yazılmış bir döngü bir çekirdeği yakar ve boş bir okumayı ölümcül sayan bir döngü tüneli boş bir saniyede yırtar. Builder.setBlocking(true) bu davranışı değiştirir ve bedeli okumanın içinde bekleyen bir iş parçacığıdır.
Rota ve adres argümanları LinkAddress değerleri olarak doğrulanır ve 224.0.0.0/4 gibi multicast hedefleri doğrudan reddedilir. Noktadan noktaya bir tun arayüzünün de yayın alanı yoktur, bu yüzden üzerinden multicast keşfi bir rota daha değil, farklı bir tasarım gerektirir. Kontrol edilecek liste VpnService.Builder olup, bir çağrının yok sayıldığı sonucuna varmadan önce bakılmalıdır.
Uygulama başına kapsam kümeyi daraltır, tüneli değil
API 21'den itibaren oluşturucu addAllowedApplication ve addDisallowedApplication kabul eder ve iki liste tek bir oluşturucu içinde birbirini dışlar. İzin listesi tüneli o paketler için var ederken diğer her şey fiziksel ağı korur; yasak listesi adı geçen paketler dışında her şeyi yakalar, bir istemcinin bölünmüş tünelleme olarak sunduğu şey budur. API 21 öncesinde hiçbir platform mekanizması yoktur ve uygulama başına davranış, kendi yönlendiricileri içinde UID'ye göre filtreleyen üçüncü taraf istemcilerden geliyordu. Bu ayrım hata ayıklarken önemlidir, çünkü tek paketlik izin listesi olan uygulama başına bir tünel neredeyse hiç trafik üretmez ve bu doğru davranıştır, bozuk bir rota değil.
Kapsam ne olursa olsun, uygulamanızın VPN sunucusuna açtığı soket kurmakta olduğu tünelden geçmemelidir. VpnService.protect(socket) o soketi alttaki ağa bağlar, böylece paketleri tun aygıtını atlar. Çağrıyı atlarsanız el sıkışma onu kaldırması gereken arayüz tarafından yutulur.
VpnService.setUnderlyingNetworks tüneli hangi fiziksel ağın taşıdığını sisteme söyleyerek döngüyü kapatır. Bu değer VPN'in diğer uygulamalara bağlantıyı nasıl bildirdiğini belirler ve null ya da eski bir değer, telefonun geri kalanının çevrimdışı saydığı bağlı bir tünelin olağan nedenidir. Alttaki ağ değiştiğinde güncelleyin, yalnızca başlangıçta değil.
Sağlama toplamları ve MTU: doğru bir rotanın yine de başarısız olduğu yer
Paketler geldikten sonra, paket düzeyindeki iki ayrıntı bir şeyin uçtan uca çalışıp çalışmadığını belirler. Birincisi kaynak adresidir: birden çok arayüz adresiyle çekirdek ilkini taşıyan paketler gönderebilir, bu yüzden başlıkları yeniden yazan bir yönlendirici adresi ve onu kapsayan sağlama toplamını düzeltmelidir.
İkincisi sağlama toplamının kapsamıdır. Uygulama TCP veya UDP paketlerini kendisi oluşturduğunda sağlama toplamı kaynak adresi, hedef adresi, protokol numarası ve taşıma uzunluğunu tutan bir sözde başlığı kapsar ve bunlardan birini atlamak gelip düşürülen paketler verir. Bu başarısızlık hiç gelmeyen bir yanıttan sonra zaman aşımı gibi görünür ve bu çoğu kişiyi rotalara geri gönderir. setMtu arayüzün MTU'sunu sabitler ve her okuma tam olarak bir eksiksiz IP paketi döndürür, bu yüzden bayt akışı için yazılmış bir tampon paketi değil ayrıştırmanızı parçalar.
Katmanları ayıran bir doğrulama turu
Kapsamın nerede yanlış gittiğini bulmak için katmanları sırayla test edin. Cihaza VPN ağının gerçekte hangi rotaları tuttuğunu sorun, sonra bilinen bir adrese giden akışın tanımlayıcıda bir okuma olarak görünüp görünmediğini kontrol edin, sonra yönlendiricinizin gönderdiği paketin iyi biçimlendirilmiş olup olmadığını kontrol edin. Bir rota sorunu tanımlayıcıda hiçbir şey göstermez, oysa bir sağlama toplamı sorunu gelip kaybolan bir paket gösterir.
Tanımlayıcıya hiçbir şey ulaşmıyorsa şüpheli okuyan değil rota kümesidir: önekleri doğrulayın, aynı ailede bir adres olduğunu doğrulayın ve uygulamanın belirlediğiniz kapsam içinde olduğunu doğrulayın. Paketler tanımlayıcıya ulaşıyor ama hiçbir şey geri dönmüyorsa, tekrar bir rotaya dokunmadan önce protect() ve alttaki ağın değerini inceleyin. Uzak taraf bozuk paketler bildiriyorsa sağlama toplamı ve MTU bakılacak yerlerdir. Katman başına bir sonda bir öğleden sonra tahmin tasarrufu sağlar.