VPN per app su Android: escludere un’app non significa bloccarla
L’elenco per app sullo schermo appartiene a un solo proprietario del tunnel, ed escludere un’app la instrada attorno a quel tunnel invece di toglierla dalla rete. Parti da lì.
Due persone fanno la stessa domanda e ricevono risposte incompatibili, perché si trovano in punti diversi. Una ha aperto la schermata delle impostazioni VPN di sistema e modifica un elenco di applicazioni. L’altra scrive VpnService.Builder.addDisallowedApplication() in un editor. Entrambe la chiamano filtro VPN per app. Solo una delle due possiede il controllo che descrive, e nessuna delle due sta bloccando qualcosa.
Parti dalla schermata che vede l’utente
Apri Impostazioni, trova la voce VPN e guarda la connessione davvero attiva. Se il client offre un elenco per app, quell’elenco appartiene al tunnel del client stesso. La piattaforma non pubblica un’API generale con cui un’app estranea possa leggere o modificare la selezione di applicazioni di un’altra VPN, quindi una seconda app non può sistemare quell’elenco per l’utente.
Questa è la prima biforcazione del percorso. Se la VPN installata non ha quell’impostazione, non c’è nulla da aggirare con il codice: la funzione manca nel prodotto che possiede il tunnel. Se ce l’ha, la correzione giusta è in quella schermata, fatta da chi può aprirla.
Segui il pacchetto dentro un tunnel
Quando la tua app costruisce un tunnel, crea un’interfaccia TUN e dichiara quale traffico delle applicazioni vi entra. Le chiamate di appartenenza avvengono prima che l’interfaccia sia stabilita, e dopo l’insieme di regole è fisso per quella sessione:
val builder = VpnService.Builder()
builder.addAddress("10.8.0.2", 32)
builder.addRoute("0.0.0.0", 0)
builder.addDisallowedApplication("com.example.bypass")
val tun = builder.establish() // membership decided hereQuelle chiamate valgono per il tunnel che la tua app ha appena creato e per nient’altro. Non sono una politica a livello di dispositivo, non persistono per altri client e non possono entrare nella VPN di qualcun altro. Quando una chiamata del builder lancia un’eccezione perché il pacchetto non è risolvibile, l’interfaccia non viene mai stabilita, il che è un fallimento pulito e non silenzioso.
Perché l’esclusione sembrava un blocco
Un’app esclusa viene instradata attorno al tuo tunnel sulla rete sottostante. È l’opposto di bloccarla: il traffico lascia comunque il dispositivo, solo fuori dall’interfaccia che controlli. Un’app in stile firewall fa il contrario. Ammette il traffico dell’applicazione nel proprio tunnel e poi scarta i pacchetti, o rifiuta di inoltrarli, così l’interfaccia è la stessa e la direzione della politica è invertita.
Il lavoro dietro quell’inversione non è un flag di configurazione. Leggi pacchetti IP dal descrittore del tunnel, decidi per flusso e poi li inoltri attraverso un socket protetto oppure li scarti. Tutto ciò che non gestisci semplicemente si ferma, ed è per questo che un tunnel a metà sembra una rete rotta invece di un filtro che funziona. Se l’obiettivo è un blocco, metti in budget gestione dei pacchetti, un servizio in primo piano e una politica scritta per il traffico che non sai classificare.
Cosa si rompe quando lo costruisci da solo
Android in genere consente una sola VPN attiva alla volta, quindi il tuo tunnel di filtraggio e un tunnel per la privacy competono per lo stesso posto, a meno che i prodotti supportino il concatenamento. La VPN sempre attiva con blocco delle connessioni cambia il modo di fallire in una maniera che qui conta: il traffico che non può entrare nel tunnel viene scartato invece di essere inviato direttamente, che è ciò che vuole un progetto anti-fuga e che una sessione di debug raramente si aspetta.
La visibilità dei pacchetti è la seconda trappola. Risolvere il nome del pacchetto di un’app può fallire con NameNotFoundException, e sulle versioni più recenti di Android l’insieme dei pacchetti visibili dipende dalle query che hai dichiarato. Gestisci l’eccezione invece di dare per scontato che ogni nome si risolva, e rileggi l’elenco quando le applicazioni vengono installate o rimosse invece di metterlo in cache per sempre.
I dispositivi gestiti aggiungono un terzo proprietario. Una politica di mobilità aziendale può impostare una VPN per app o un profilo sempre attivo, e un’app comune non può sovrascriverla. Controlla se il dispositivo è gestito prima di fare debug del tuo codice, perché in quel caso l’elenco che stai cercando di cambiare potrebbe non essere modificabile da chi tiene in mano il telefono.
Provalo con un’app che controlli
Non provare con l’app che stai cercando di filtrare. Usa una seconda applicazione di cui puoi osservare il comportamento di rete, e verifica se il suo traffico esce dal tuo tunnel mentre quello del bersaglio no. Se entrambi restano dentro, la politica funziona e il bersaglio è escluso; se nessuno esce, il tunnel stesso è sbagliato e l’elenco delle app non è il problema.
Poi decidi quale delle tre cose stai davvero costruendo. Un tunnel per app è l’API del builder, con l’elenco come parte del tuo profilo. Un firewall del dispositivo è gestione dei pacchetti più un ciclo di vita che puoi difendere. Cambiare la VPN di qualcun altro non è affatto un percorso supportato, e la risposta onesta lì è che l’impostazione appartiene a quel prodotto.