Routing VPN su Android: le regole di policy prima della tabella main
Android sceglie una tabella di routing con regole di uid e di marchio prima di qualsiasi ricerca della destinazione, quindi una rotta aggiunta a main può non essere mai consultata.
Una rotta aggiunta alla tabella main su Android appare corretta in ogni elenco e tuttavia non trasporta il traffico. Il motivo è che la tabella main è una sola opzione fra diverse e non viene consultata per prima. Il servizio di rete di Android costruisce regole di policy che scelgono una tabella di routing usando informazioni che l'indirizzo di destinazione non contiene — l'uid dell'applicazione, un marchio sul pacchetto, l'interfaccia da cui è arrivato — e la ricerca della destinazione avviene dopo, dentro la tabella che quelle regole hanno scelto.
Tre decisioni in un ordine fisso
Un pacchetto in uscita prende tre decisioni separate. Primo, una regola di policy stabilisce quale tabella di routing vale. Secondo, una rotta dentro quella tabella stabilisce il salto successivo e l'interfaccia di uscita. Terzo, gli hook di netfilter decidono se il pacchetto sopravvive, viene modificato o rediretto.
L'ordine conta perché ogni fase può rispondere solo alla propria domanda. Una regola di firewall che accetta un pacchetto non sceglie una tabella, e una rotta aggiunta a una tabella che nessuna regola sceglie è inerte. Gran parte della confusione sulle VPN Android nasce dal correggere una delle tre e non osservare alcun cambiamento, perché il guasto era in un'altra.
| Stage | Selector | What it cannot decide |
|---|---|---|
| Policy rule | uid range, mark, incoming interface | Which route exists inside the table |
| Route lookup | Destination prefix, longest match | Whether the packet is allowed out |
| Netfilter hook | Chain position, match conditions | Which table was selected |
I marchi sono un campo impacchettato, non un'etichetta che possiedi
Android impacchetta diversi fatti nello stesso valore di marchio: quale rete è stata scelta, se un'applicazione ha scelto esplicitamente una rete, se un socket è protetto dalla VPN e bit legati ai permessi. L'intestazione fwmark di AOSP definisce quella disposizione per l'albero corrente, e la disposizione è un dettaglio interno della piattaforma che cambia fra le versioni.
Per questo scrivere un valore di marchio intero con iptables -j MARK --set-mark è pericoloso su Android. Non aggiunge un'etichetta; sostituisce la scelta di rete che il sistema ha già fatto. Il pacchetto finisce quindi per corrispondere ad altre regole, il che può sembrare che la VPN abbia iniziato a funzionare, o che un'applicazione non correlata abbia perso la connettività, a seconda dei bit sovrascritti.
Se devi toccare i marchi, leggi prima il valore corrente e usa una maschera in modo che vengano modificati solo i bit che comprendi:
ip rule show
ip route show table all | head -40
ip route get 10.20.4.11Un marchio di connessione è un oggetto separato da un marchio di pacchetto, e nessuno dei due è una rotta. Ripristinare il marchio sui pacchetti di risposta è un passo distinto dallo scegliere una tabella in uscita, ed è per questo che le correzioni unidirezionali producono connessioni che si aprono e poi si bloccano.
Chi possiede le regole e le tabelle
Il servizio di rete di Android, netd, crea le regole e le tabelle per rete. Il AOSP RouteController è il punto in cui quelle regole vengono assemblate per VPN, reti fisiche e intervalli di uid, e il suo ciclo di vita è legato a eventi di rete anziché a un file di configurazione.
Ne seguono due conseguenze. Primo, le priorità e i numeri di tabella che trovi su un telefono sono dettagli interni della build, non un'interfaccia: numeri dall'aspetto identico su un'altra versione di Android possono significare tutt'altro. Secondo, lo stato viene ricostruito quando le reti cambiano, quindi una regola inserita oggi da una shell root può essere sparita dopo il successivo passaggio Wi-Fi.
Questa sparizione viene spesso riportata come un sistema che ignora una rotta. Quello che è successo davvero è che la regola che sceglieva la tabella non esiste più, e la rotta dentro la tabella ora è irraggiungibile dal punto di vista del pacchetto. Controlla l'elenco delle regole, non quello delle rotte, quando una configurazione che funzionava smette di funzionare dopo una riconnessione.
Le domande sull'ordine degli hook non hanno risposta universale
La domanda se iptables venga eseguito prima del routing VPN non ha risposta senza nominare il percorso del pacchetto. Un pacchetto generato localmente attraversa l'hook output, dove un cambio di marchio innesca un controllo di rerouting — una seconda ricerca, non una modifica retroattiva della prima. Un pacchetto che arriva da un client in tethering attraversa il percorso prerouting e viene invece inoltrato, e le catene che lo vedono sono altre.
La stessa regola può quindi essere efficace per il traffico di un'applicazione e invisibile al traffico in tethering, e un contatore che resta a zero ti dice quale percorso ha preso il pacchetto, non se la regola è sbagliata. Usa i contatori per stabilire il percorso prima di cambiare qualsiasi condizione di corrispondenza.
Questa è anche la fase in cui un errore di policy routing diventa difficile da vedere. Instradare verso una tabella che esiste ma non contiene la destinazione produce un rete irraggiungibile che sembra un drop del firewall, mentre un drop del firewall produce un timeout che sembra un buco nero di routing.
Diagnostica dentro il sistema, o lascialo stare
Per una revisione autorizzata, stabilisci quattro fatti prima di toccare qualsiasi cosa: l'uid e il profilo dell'applicazione, la rete che Android ha scelto per essa, se la VPN include quell'applicazione e se il problema esiste per entrambe le famiglie di indirizzi. Un'esclusione per applicazione spiega moltissime segnalazioni di VPN che non funziona senza alcun guasto di routing.
Poi leggi le regole, le maschere e le tabelle realmente in vigore, e tieni un cambio di rete dentro la finestra di osservazione. Se il comportamento cambia durante una riconnessione, stai guardando un ciclo di vita gestito, non una rotta mancante.
Per requisiti ordinari, usa i controlli supportati: inclusione ed esclusione per applicazione nell'applicazione VPN, e la selezione di rete propria della piattaforma per tutto ciò che richiede un percorso specifico. Se un'integrazione privilegiata deve davvero cooperare con la macchina di routing, punta all'implementazione della versione esatta di Android che supporti e mantieni il suo ciclo di vita tramite il componente che la possiede. Svuotare le catene della piattaforma o inserire una regola ad alta priorità trasforma una diagnosi in un secondo gestore di rete, e il telefono si comporterà di conseguenza.