2009-12-02 19 views
18

¿Hay alguna manera de ver/volcar el caché de DNS utilizado por java.net api?Java DNS cache viewer

+0

Mi entendimiento es que tiene que tener un servidor DNS para realizar el almacenamiento en caché - una serie en sí no almacena en caché peticiones DNS. –

+2

No hay cachés de host. De hecho, el JRE (ejecutándose con un administrador de seguridad) y los navegadores "ocultan" las búsquedas de DNS. –

+0

Las bibliotecas de resolución dns generalmente almacenan en caché los resultados de dns para que no tengan que molestar tanto al servidor, y brindan una respuesta más rápida a las llamadas – nos

Respuesta

18

Aquí hay una secuencia de comandos para imprimir la caché de dirección DNS positiva y negativa.

import java.lang.reflect.Field; 
import java.net.InetAddress; 
import java.net.UnknownHostException; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 
import java.util.Map; 
public class DNSCache { 
    public static void main(String[] args) throws Exception { 
    InetAddress.getByName("stackoverflow.com"); 
    InetAddress.getByName("www.google.com"); 
    InetAddress.getByName("www.yahoo.com"); 
    InetAddress.getByName("www.example.com"); 
    try { 
     InetAddress.getByName("nowhere.example.com"); 
    } catch (UnknownHostException e) { 

    } 

    String addressCache = "addressCache"; 
    System.out.println(addressCache); 
    printDNSCache(addressCache); 
    String negativeCache = "negativeCache"; 
    System.out.println(negativeCache); 
    printDNSCache(negativeCache); 
    } 
    private static void printDNSCache(String cacheName) throws Exception { 
    Class<InetAddress> klass = InetAddress.class; 
    Field acf = klass.getDeclaredField(cacheName); 
    acf.setAccessible(true); 
    Object addressCache = acf.get(null); 
    Class cacheKlass = addressCache.getClass(); 
    Field cf = cacheKlass.getDeclaredField("cache"); 
    cf.setAccessible(true); 
    Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache); 
    for (Map.Entry<String, Object> hi : cache.entrySet()) { 
     Object cacheEntry = hi.getValue(); 
     Class cacheEntryKlass = cacheEntry.getClass(); 
     Field expf = cacheEntryKlass.getDeclaredField("expiration"); 
     expf.setAccessible(true); 
     long expires = (Long) expf.get(cacheEntry); 

     Field af = cacheEntryKlass.getDeclaredField("address"); 
     af.setAccessible(true); 
     InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry); 
     List<String> ads = new ArrayList<String>(addresses.length); 
     for (InetAddress address : addresses) { 
      ads.add(address.getHostAddress()); 
     } 

     System.out.println(hi.getKey() + " "+new Date(expires) +" " +ads); 
    } 
    } 
} 
+0

Reflection? – Pacerier

+0

Muestra agradable :-) –

+0

En caso de que alguien quiera ejecutar el código anterior usando un administrador de seguridad (o convertirlo para que se ejecute en un motor de servlet que se ejecuta con un administrador de seguridad), las siguientes entradas en el archivo de política ayudarán: otorgar { permiso java.lang.RuntimePermission "accessClassInPackage.sun.net"; permission java.lang.RuntimePermission "accessDeclaredMembers"; permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; permission java.net.SocketPermission "*", "aceptar, conectar, resolver"; –

17

El java.net.InetAddress utiliza el almacenamiento en caché de las resoluciones de nombres de host exitosas y sin éxito.

Desde su javadoc:

clase El InetAddress tiene una caché para tienda de éxito, así como las resoluciones fallidos de nombre de host.

Por defecto, cuando un administrador de seguridad está instalada , con el fin de protegerse de los ataques de suplantación de DNS , el resultado de resoluciones positivas de nombre de host se almacenan en caché siempre. Cuando no se instala un administrador de seguridad , el comportamiento predeterminado es almacenar en caché entradas para un período de tiempo finito (según la implementación) . El resultado de resolución de nombre de host sin éxito es en caché durante un período muy corto de tiempo (10 segundos) para mejorar el rendimiento.

Si el comportamiento por defecto no es deseada, a continuación, una propiedad de seguridad de Java se puede ajustar a un valor diferente tiempo de vida (TTL) para almacenar en caché positivo. Del mismo modo, un administrador del sistema puede configurar un valor de TTL de almacenamiento en caché negativo diferente cuando sea necesario.

Dos propiedades de seguridad de Java controlan los valores TTL utilizados para positivo y negativo nombre de host de almacenamiento en caché de resolución:

  • networkaddress.cache.ttl
    Indica la política de caché para búsquedas de nombres de éxito el servicio de nombre. El valor se especifica como entero para indicar el número de segundos para almacenar en caché la búsqueda exitosa . La configuración predeterminada es caché para un período de tiempo específico de implementación .

    Un valor de -1 indica "caché para siempre".

  • networkaddress.cache.negative.ttl (por defecto: 10)
    Indica la política de almacenamiento en caché para búsquedas de nombre un-éxito desde el servicio de nombres. El valor es especificado como número entero para indicar el número de segundos para almacenar en caché el error para búsquedas incorrectas.

    Un valor de 0 indica "nunca caché". Un valor de -1 indica "caché para siempre".

Si lo que tiene en mente es vertido las memorias caché (de tipo java.net.InetAddress$Cache) utilizado por java.net.InetAddress, son detalles de implementación interna y por lo tanto private:

/* 
* Cached addresses - our own litle nis, not! 
*/ 
private static Cache addressCache = new Cache(Cache.Type.Positive); 

private static Cache negativeCache = new Cache(Cache.Type.Negative); 

Así que dudo que encuentra algo haciendo esto de la caja y adivina que tendrás que jugar con la reflexión para lograr tu objetivo.

1

La respuesta anterior ya no funciona en Java 8. Aquí una ligera adaptación:

import java.lang.reflect.Field; 
import java.net.InetAddress; 
import java.net.UnknownHostException; 
import java.time.Instant; 
import java.time.temporal.ChronoUnit; 
import java.util.ArrayList; 
import java.util.Date; 
import java.util.List; 
import java.util.Map; 

public class DNSCache { 
    public static void main(String[] args) throws Exception { 
     InetAddress.getByName("stackoverflow.com"); 
     InetAddress.getByName("www.google.com"); 
     InetAddress.getByName("www.yahoo.com"); 
     InetAddress.getByName("www.example.com"); 
     try { 
      InetAddress.getByName("nowhere.example.com"); 
     } catch (UnknownHostException e) { 

     } 

     String addressCache = "addressCache"; 
     System.out.println(addressCache); 
     printDNSCache(addressCache); 
     String negativeCache = "negativeCache"; 
     System.out.println(negativeCache); 
     printDNSCache(negativeCache); 
    } 

    private static void printDNSCache(String cacheName) throws Exception { 
     Class<InetAddress> klass = InetAddress.class; 
     Field acf = klass.getDeclaredField(cacheName); 
     acf.setAccessible(true); 
     Object addressCache = acf.get(null); 
     Class cacheKlass = addressCache.getClass(); 
     Field cf = cacheKlass.getDeclaredField("cache"); 
     cf.setAccessible(true); 
     Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache); 
     for (Map.Entry<String, Object> hi : cache.entrySet()) { 
      Object cacheEntry = hi.getValue(); 
      Class cacheEntryKlass = cacheEntry.getClass(); 
      Field expf = cacheEntryKlass.getDeclaredField("expiration"); 
      expf.setAccessible(true); 
      long expires = (Long) expf.get(cacheEntry); 

      Field af = cacheEntryKlass.getDeclaredField("addresses"); 
      af.setAccessible(true); 
      InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry); 
      List<String> ads = new ArrayList<String>(addresses.length); 
      for (InetAddress address : addresses) { 
       ads.add(address.getHostAddress()); 
      } 

      System.out.println(hi.getKey() + " expires in " 
        + Instant.now().until(Instant.ofEpochMilli(expires), ChronoUnit.SECONDS) + " seconds " + ads); 
     } 
    } 
}