Estoy tratando de obtener las direcciones de los servidores DNS actualmente utilizados en mi aplicación, ya sea que esté conectado a través de Wifi o un dispositivo móvil. El objeto DhcpInfo debería proporcionar esto, pero ¿cómo puedo obtener un objeto válido DhcpInfo?¿Cómo se obtienen los servidores DNS actuales para Android?
Respuesta
android.net.ConnectivityManager
le entregará una matriz de NetworkInfo utilizando getAllNetworkInfo()
. Luego use android.net.NetworkUtils.runDhcp()
para obtener un DhcpInfo
para cualquier interfaz de red dada - la estructura DhcpInfo tiene la dirección IP para dns1
y dns2
para esa interfaz (que son valores enteros que representan la dirección IP).
En caso de que se preguntan cómo diablos se van a transformar el número entero en una dirección IP, se puede hacer esto:
/**
* Convert int IP adress to String
* cf. http://teneo.wordpress.com/2008/12/23/java-ip-address-to-integer-and-back/
*/
private String intToIp(int i) {
return (i & 0xFF) + "." +
((i >> 8) & 0xFF) + "." +
((i >> 16) & 0xFF) + "." +
((i >> 24) & 0xFF);
}
Editar
También puede obtener un objeto DchcpInfo
haciendo algo como esto:
WiFiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
DhcpInfo info = wifi.getDhcpInfo();
recomiendo dnsjava para su uso en DNS complejo Android. Veamos cómo dnsjava determina el servidor DNS activo actual para la conexión. From dnsjava ResolverConfig.java:428:
/**
* Parses the output of getprop, which is the only way to get DNS
* info on Android. getprop might disappear in future releases, so
* this code comes with a use-by date.
*/
private void
findAndroid() {
// This originally looked for all lines containing .dns; but
// http://code.google.com/p/android/issues/detail?id=2207#c73
// indicates that net.dns* should always be the active nameservers, so
// we use those.
String re1 = "^\\d+(\\.\\d+){3}$";
String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";
try {
ArrayList lserver = new ArrayList();
ArrayList lsearch = new ArrayList();
String line;
Process p = Runtime.getRuntime().exec("getprop");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
StringTokenizer t = new StringTokenizer(line, ":");
String name = t.nextToken();
if (name.indexOf("net.dns") > -1) {
String v = t.nextToken();
v = v.replaceAll("[ \\[\\]]", "");
if ((v.matches(re1) || v.matches(re2)) &&
!lserver.contains(v))
lserver.add(v);
}
}
configureFromLists(lserver, lsearch);
} catch (Exception e) {
// ignore resolutely
}
}
Advertencia: este código puede causar bloqueos en Runtime.getRuntime(). Exec() – Nappy
Llamada para el getRuntime().exec
puede hang su aplicación.
android.net.NetworkUtils.runDhcp()
causan solicitudes de red innecesarias.
así que prefiero hacer esto:
Class<?> SystemProperties = Class.forName("android.os.SystemProperties");
Method method = SystemProperties.getMethod("get", new Class[] { String.class });
ArrayList<String> servers = new ArrayList<String>();
for (String name : new String[] { "net.dns1", "net.dns2", "net.dns3", "net.dns4", }) {
String value = (String) method.invoke(null, name);
if (value != null && !"".equals(value) && !servers.contains(value))
servers.add(value);
}
Si está trabajando en AOSP (aplicación del sistema o biblioteca), puede importar directamente 'android.os.SystemProperties' y usar' public static String get (String key, String def) ' – Cyctemic
Parece que esto ya no está permitido en Android Oreo. ¿Alguna actualización aquí? – atsakiridis
Sí, esto ya no está permitido en oreo – Hades
Una alternativa nativa es:
char dns1[PROP_VALUE_MAX];
__system_property_get("net.dns1", dns1);
O mejor aún para obtener una lista completa:
for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
char prop_name[PROP_NAME_MAX];
snprintf(prop_name, sizeof(prop_name), "net.dns%d", i);
__system_property_get(prop_name, dns);
}
Hay algunas ventajas para hacerlo de esta manera:
- runDHCP es realmente lento. Puede tomar hasta 5-10 segundos. Esto puede causar una caída importante cuando se usa incorrectamente.
- runDCHP no parece funcionar para 3G/4G.
- Dado que runDCHP es una API oculta, está sujeta a cambios. De hecho, sí cambió en ICS. En ICS se necesita un nuevo DhcpInfoInternal, por lo que tendrá que crear dos diferentes para admitir todos los teléfonos.
__system_property_get() la función se elimina en Android L –
primero Añadir JAR externos layoutlib.jar a su trayectoria de la estructura, el archivo layoutlib.jar en SDK_PATH $/plataformas/android-xxx/data /, entonces
String dnsStr1 = android.os.SystemProperties.get("net.dns1");
String dnsStr2 = android.os.SystemProperties.get("net.dns2");
también se puede ver todos los bienes en adb shell con el comando $ getprop.
funciona con 'getprop net.dns1' en termux. – Ben
Puede usar la reflexión de java.ejemplo:
ConnectivityManager mgr =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Method getLinkPropeties;
try{
getLinkPropeties = mgr.getClass().getMethod("getLinkProperties", int.class);
}catch (InvocationTargetException e) {
e.printStackTrace();
}
Los siguientes trabajos para API 21 y superior. Devuelve servidores dns correctos para las interfaces WiFi y Celular. He verificado los valores devueltos con utilidad de shell 'GetProp'
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if (networkInfo.isConnected()) {
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
Log.d("DnsInfo", "iface = " + linkProperties.getInterfaceName());
Log.d("DnsInfo", "dns = " + linkProperties.getDnsServers());
return linkProperties.getDnsServers();
}
}
Esta fue una mina de oro por proporcionar mi propia solución que maneja todas las versiones. Por favor revisa mi respuesta. ¡Gracias de nuevo! –
Desafortunadamente la mayoría de las soluciones presentadas ya no funcionan en Android 8.0
Android Oficial del Estado la documentación esto muy claramente en el artículo de Android 8.0 Cambios de comportamiento. Las propiedades del sistema net.dns1, net.dns2, net.dns3 y net.dns4 ya no están disponibles, un cambio que mejora la privacidad en la plataforma.
https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri
biblioteca Dnsjava también se lado afecto y los métodos de detección utilizados en dnsjava no son conscientes de los cambios de Oreo.
La solución de Varun Anand funciona en Oreo pero tiene una debilidad al no manejar la conexión con las rutas predeterminadas. Debido a esto, el resultado puede ser envenenado con servidores DNS no válidos que entran primero en el resultado y la persona que llama puede pasar mucho tiempo iterando la lista y tratando de conectarse a servidores DNS ilegibles. Esto fue arreglado en mi solución. Otro problema con la solución Varun Anand es que esto solo funciona para API 21 y superior. Pero debo decir que fue oro mío para mí escribir mi propia solución. ¡Así que gracias!
Para su comodidad proporcioné una clase de detector de servidores DNS completa que puede usar que funciona en cualquier versión de Android. Se incluyen comentarios completos para responder a por qué y cómo.
/**
* DNS servers detector
*
* IMPORTANT: don't cache the result.
*
* Or if you want to cache the result make sure you invalidate the cache
* on any network change.
*
* It is always better to use a new instance of the detector when you need
* current DNS servers otherwise you may get into troubles because of invalid/changed
* DNS servers.
*
* This class combines various methods and solutions from:
* Dnsjava http://www.xbill.org/dnsjava/
* Minidns https://github.com/MiniDNS/minidns
*
* Unfortunately both libraries are not aware of Orero changes so new method was added to fix this.
*
* Created by Madalin Grigore-Enescu on 2/24/18.
*/
public class DnsServersDetector {
private static final String TAG = "DnsServersDetector";
/**
* Holds some default DNS servers used in case all DNS servers detection methods fail.
* Can be set to null if you want caller to fail in this situation.
*/
private static final String[] FACTORY_DNS_SERVERS = {
"8.8.8.8",
"8.8.4.4"
};
/**
* Properties delimiter used in exec method of DNS servers detection
*/
private static final String METHOD_EXEC_PROP_DELIM = "]: [";
/**
* Holds context this was created under
*/
private Context context;
//region - public //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor
*/
public DnsServersDetector(Context context) {
this.context = context;
}
/**
* Returns android DNS servers used for current connected network
* @return Dns servers array
*/
public String [] getServers() {
// Will hold the consecutive result
String[] result;
// METHOD 1: old deprecated system properties
result = getServersMethodSystemProperties();
if (result != null && result.length > 0) {
return result;
}
// METHOD 2 - use connectivity manager
result = getServersMethodConnectivityManager();
if (result != null && result.length > 0) {
return result;
}
// LAST METHOD: detect android DNS servers by executing getprop string command in a separate process
// This method fortunately works in Oreo too but many people may want to avoid exec
// so it's used only as a failsafe scenario
result = getServersMethodExec();
if (result != null && result.length > 0) {
return result;
}
// Fall back on factory DNS servers
return FACTORY_DNS_SERVERS;
}
//endregion
//region - private /////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Detect android DNS servers by using connectivity manager
*
* This method is working in android LOLLIPOP or later
*
* @return Dns servers array
*/
private String [] getServersMethodConnectivityManager() {
// This code only works on LOLLIPOP and higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
ArrayList<String> priorityServersArrayList = new ArrayList<>();
ArrayList<String> serversArrayList = new ArrayList<>();
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
// Iterate all networks
// Notice that android LOLLIPOP or higher allow iterating multiple connected networks of SAME type
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if (networkInfo.isConnected()) {
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
List<InetAddress> dnsServersList = linkProperties.getDnsServers();
// Prioritize the DNS servers for link which have a default route
if (linkPropertiesHasDefaultRoute(linkProperties)) {
for (InetAddress element: dnsServersList) {
String dnsHost = element.getHostAddress();
priorityServersArrayList.add(dnsHost);
}
} else {
for (InetAddress element: dnsServersList) {
String dnsHost = element.getHostAddress();
serversArrayList.add(dnsHost);
}
}
}
}
}
// Append secondary arrays only if priority is empty
if (priorityServersArrayList.isEmpty()) {
priorityServersArrayList.addAll(serversArrayList);
}
// Stop here if we have at least one DNS server
if (priorityServersArrayList.size() > 0) {
return priorityServersArrayList.toArray(new String[0]);
}
} catch (Exception ex) {
Log.d(TAG, "Exception detecting DNS servers using ConnectivityManager method", ex);
}
}
// Failure
return null;
}
/**
* Detect android DNS servers by using old deprecated system properties
*
* This method is NOT working anymore in Android 8.0
* Official Android documentation state this in the article Android 8.0 Behavior Changes.
* The system properties net.dns1, net.dns2, net.dns3, and net.dns4 are no longer available,
* a change that improves privacy on the platform.
*
* https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri
* @return Dns servers array
*/
private String [] getServersMethodSystemProperties() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// This originally looked for all lines containing .dns; but
// http://code.google.com/p/android/issues/detail?id=2207#c73
// indicates that net.dns* should always be the active nameservers, so
// we use those.
final String re1 = "^\\d+(\\.\\d+){3}$";
final String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";
ArrayList<String> serversArrayList = new ArrayList<>();
try {
Class SystemProperties = Class.forName("android.os.SystemProperties");
Method method = SystemProperties.getMethod("get", new Class[]{String.class});
final String[] netdns = new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"};
for (int i = 0; i < netdns.length; i++) {
Object[] args = new Object[]{netdns[i]};
String v = (String) method.invoke(null, args);
if (v != null && (v.matches(re1) || v.matches(re2)) && !serversArrayList.contains(v)) {
serversArrayList.add(v);
}
}
// Stop here if we have at least one DNS server
if (serversArrayList.size() > 0) {
return serversArrayList.toArray(new String[0]);
}
} catch (Exception ex) {
Log.d(TAG, "Exception detecting DNS servers using SystemProperties method", ex);
}
}
// Failed
return null;
}
/**
* Detect android DNS servers by executing getprop string command in a separate process
*
* Notice there is an android bug when Runtime.exec() hangs without providing a Process object.
* This problem is fixed in Jelly Bean (Android 4.1) but not in ICS (4.0.4) and probably it will never be fixed in ICS.
* https://stackoverflow.com/questions/8688382/runtime-exec-bug-hangs-without-providing-a-process-object/11362081
*
* @return Dns servers array
*/
private String [] getServersMethodExec() {
// We are on the safe side and avoid any bug
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
try {
Process process = Runtime.getRuntime().exec("getprop");
InputStream inputStream = process.getInputStream();
LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(inputStream));
Set<String> serversSet = methodExecParseProps(lineNumberReader);
if (serversSet != null && serversSet.size() > 0) {
return serversSet.toArray(new String[0]);
}
} catch (Exception ex) {
Log.d(TAG, "Exception in getServersMethodExec", ex);
}
}
// Failed
return null;
}
/**
* Parse properties produced by executing getprop command
* @param lineNumberReader
* @return Set of parsed properties
* @throws Exception
*/
private Set<String> methodExecParseProps(BufferedReader lineNumberReader) throws Exception {
String line;
Set<String> serversSet = new HashSet<String>(10);
while ((line = lineNumberReader.readLine()) != null) {
int split = line.indexOf(METHOD_EXEC_PROP_DELIM);
if (split == -1) {
continue;
}
String property = line.substring(1, split);
int valueStart = split + METHOD_EXEC_PROP_DELIM.length();
int valueEnd = line.length() - 1;
if (valueEnd < valueStart) {
// This can happen if a newline sneaks in as the first character of the property value. For example
// "[propName]: [\n…]".
Log.d(TAG, "Malformed property detected: \"" + line + '"');
continue;
}
String value = line.substring(valueStart, valueEnd);
if (value.isEmpty()) {
continue;
}
if (property.endsWith(".dns") || property.endsWith(".dns1") ||
property.endsWith(".dns2") || property.endsWith(".dns3") ||
property.endsWith(".dns4")) {
// normalize the address
InetAddress ip = InetAddress.getByName(value);
if (ip == null) continue;
value = ip.getHostAddress();
if (value == null) continue;
if (value.length() == 0) continue;
serversSet.add(value);
}
}
return serversSet;
}
/**
* Returns true if the specified link properties have any default route
* @param linkProperties
* @return true if the specified link properties have default route or false otherwise
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private boolean linkPropertiesHasDefaultRoute(LinkProperties linkProperties) {
for (RouteInfo route : linkProperties.getRoutes()) {
if (route.isDefaultRoute()) {
return true;
}
}
return false;
}
//endregion
}
- 1. ¿Qué algoritmos usan los servidores DNS para búsquedas más rápidas?
- 2. Consultar DNS usando servidores DNS específicos en .NET
- 3. Obtenga mediante programación servidores DNS del host
- 4. Especificación de diferentes servidores DNS para dominios diferentes
- 5. ¿Cómo obtienen los datos de los mashups de craigslist?
- 6. Creando emuladores para los teléfonos con Android actuales
- 7. Android: Flush DNS
- 8. ¿Cómo se obtienen los bloques de servidor <% %> para formatear bien en Visual Studio?
- 9. ¿Cómo se obtienen los iconos de shell32.dll?
- 10. ¿Cómo se obtienen los hijos de un widget en Qt?
- 11. ¿Cómo se obtienen los datos de la RAM?
- 12. Recibe notificaciones actuales de Android
- 13. ¿Cómo funcionan los servidores web?
- 14. Especifique qué servidores DNS usar para resolver nombres de host en .NET
- 15. cómo obtener los minutos actuales php
- 16. obtener los límites latlng actuales?
- 17. No se puede hacer la búsqueda DNS inversa en Android
- 18. DNS- ¿Enruta el DNS para la subcarpeta a otro servidor?
- 19. cómo se administran las contraseñas de root de los servidores
- 20. Configurar Android IP, DNS, configuración GATEWAY programáticamente
- 21. ¿Cómo se obtienen los métodos S3 para trabajar con objetos S4?
- 22. ¿Cómo se obtienen los comentarios XML para que aparezcan en un proyecto diferente (dll)?
- 23. ¿Cómo se obtienen los subrayados dobles para mostrar en el descuento?
- 24. Comprender el MECHNISM búsqueda DNS
- 25. ¿El DNS de Android necesita calentamiento?
- 26. Los archivos fuente CUDA obtienen una extensión .cu. ¿Qué obtienen los archivos de cabecera?
- 27. ¿Cómo evitan los servidores web TIME_WAIT?
- 28. Deje que git bash se lance en los repositorios actuales
- 29. ¿Los argumentos de constructor obtienen GC'ed?
- 30. ¿Cómo funcionan varios servidores en sincronización para la aplicación web?
Pero no es android.net.NetworkUtils.runDhcp() una función nativa? ¿Cómo accedo? – John
Ok, obtener el DhcpInfo de Wifi es sencillo, pero ¿cómo lo haces para el móvil? (UMTS, etc.) ¿Tengo que cargar alguna biblioteca nativa para obtener acceso a android.net.NetworkUtils.runDhcp()? – John
@John: publiqué una solución nativa que funciona para redes móviles. Echar un vistazo. – Grimmace