Obtens un shell al dispositiu, llegeixes /etc/resolv.conf o desenterres un valor antic de net.dns1, i obtens una adreça. L’app que tens davant resol per una cosa completament diferent. En una versió actual d’Android el resolutor és per xarxa: el sistema manté una política per a cada Network i l’aplica al socket que va fer la petició. El fitxer i la propietat heretada són restes, i cap dels dos no descriu el camí que realment va seguir la teva consulta.

Aquest buit apareix durant els desplegaments de split tunnel i DNS privat, on dues apps del mateix telèfon poden veure respostes diferents de manera legítima. Aquest recorregut comença en la consulta errònia o absent i retrocedeix fins a la configuració a la qual pertany.

El resolutor pertany a una xarxa, no al dispositiu

La resolució de noms a Android 9 i posteriors passa per un resolutor del sistema que es basa en la Network a la qual està vinculat un socket. Cada xarxa porta les seves pròpies LinkProperties, i aquestes propietats contenen la llista de servidors DNS, els dominis de cerca i l’estat del DNS privat només per a aquella xarxa. Res d’aquest model no es correspon amb una llista única per a tot el dispositiu que puguis llegir d’un fitxer.

Una VPN fa òbvia la separació. Quan puja el túnel, l’app de VPN forneix servidors DNS registrats a la xarxa pròpia de la VPN, així que les apps encaminades per ella resolen contra aquests servidors mentre les apps excloses continuen usant la xarxa subjacent. Un dispositiu, dos camins de resposta, cap contradicció.

Llegir la instantània des de dins de l’app afectada

Pregunta a la pròpia app. Un mètode que tingui un Context i el permís normal android.permission.ACCESS_NETWORK_STATE pot llegir la instantània sense tocar propietats del sistema:

val cm = getSystemService(ConnectivityManager::class.java) ?: return
val network = cm.activeNetwork
val links = network?.let { cm.getLinkProperties(it) }

val dnsServers = links?.dnsServers
val privateDnsActive = links?.isPrivateDnsActive
val privateDnsName = links?.privateDnsServerName

activeNetwork és la xarxa predeterminada del teu procés, no l’única del dispositiu, i pot ser null quan el cridador no té una predeterminada utilitzable. Una VPN predeterminada bloquejada és el motiu habitual. isPrivateDnsActive et diu si les consultes en aquella xarxa van per TLS a un resolutor amb nom, cosa que canvia què mostrarà una sonda UDP 53 simple. La superfície d’API està documentada a LinkProperties, i cada valor que conté és una instantània de configuració, no la prova que una consulta concreta arribés a un servidor concret.

Quan la xarxa predeterminada no és la que treballa

La instantània només respon per la predeterminada. Una app pot vincular el seu procés o un sol socket a una altra xarxa, i llavors la consulta segueix aquesta elecció mentre el teu diagnòstic continua informant de la predeterminada. Un navegador que porta el seu propi resolutor DNS-over-HTTPS no consulta mai la llista del sistema, així que les seves respostes no diuen res de la resta del dispositiu. Una app de perfil de treball s’executa sota un usuari a part amb la seva pròpia política. Comprova la unió abans de culpar els servidors.

La integració amb VPN és l’altra meitat. Rebre una línia dhcp-option DNS en un perfil d’OpenVPN i registrar aquesta adreça a la xarxa VPN d’Android són dos passos diferents, i una ruta absent cap al servidor falla amb la mateixa discreció que una adreça equivocada. Des d’una màquina de desenvolupament, adb shell dumpsys connectivity imprimeix les mateixes propietats d’enllaç per xarxa quan la compilació ho permet, cosa que confirma la llista sense escriure codi.

Comparar la configuració amb una consulta que puguis fer

Tria un nom que s’hagi de resoldre dins de l’espai privat i un nom públic, i anota tots dos resultats al costat de la instantània: xarxa, servidors configurats, estat del DNS privat i el text exacte de l’error. Una consulta directa a un servidor amb nom demostra que aquell servidor et respon; no demostra que la resolució normal de l’aplicació l’hagi triat. Una resposta en memòria cau no és una prova nova, així que buida la memòria cau o usa un nom que ningú hagi consultat avui.

Si el resolutor només serveix clients d’una xarxa d’accés concreta, el que veu després de la sortida de la VPN pot decidir el resultat, i això és una qüestió de política per a qui l’opera i no la prova que els operadors bloquin l’UDP 53. On el DNS privat és actiu, un nom d’amfitrió no qualificat es pot rebutjar per disseny mentre el mateix servidor respon amb normalitat a noms públics. Llegir les propietats et diu quin mode està vigent, així deixes d’endevinar filtres de paquets.

Corregir la capa a la qual pertany la discrepància

Treballa cap amunt en lloc d’editar l’estat global. Si l’app està vinculada a la xarxa equivocada, corregeix la unió. Si el perfil porta l’opció DNS equivocada, corregeix el perfil. Si el DNS privat és estricte en una xarxa el resolutor de la qual no pot servir la teva zona privada, això és una decisió de gestió del dispositiu i no una raó per desactivar la funció a tot arreu.

Forçar resolutors públics en un hook de DHCP o en una propietat del sistema és la reparació que no deixa de causar incidents: els noms privats deixen de resoldre’s, el canvi sobreviu a la sessió de VPN i la següent persona al dispositiu troba una adreça obsoleta sense propietari. Mantén el canvi dins de la VPN, de l’app o de la capa de gestió a la qual pertany la discrepància, i després torna a llegir la instantània per confirmar que la llista de servidors ha canviat de debò.

El que vols al final és una petició d’app lligada a una xarxa, una llista de resolutors i un estat de DNS privat. Un cop puguis mostrar aquesta cadena, una adreça coneguda en un fitxer deixa de ser prova de res.

Articles relacionats