Подтвердить что ты не робот

Java-просмотрщик кэшей DNS

Есть ли способ просмотреть/сбросить DNS-кеширование, используемое java.net api?

4b9b3361

Ответ 1

Вот script для печати положительного и отрицательного кеша DNS-адресов.

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);
    }
  }
}

Ответ 2

java.net.InetAddress использует кеширование успешных и неуспешных разрешений имен хостов.

Из своего javadoc:

В классе InetAddress имеется кеш магазина, а также безуспешные разрешения имен хостов.

По умолчанию, когда диспетчер безопасности установленных для защиты от Атаки подмены DNS, результат положительные разрешения имен хостов кэш навсегда. Когда безопасность менеджер не установлен, по умолчанию поведение - кэшировать записи для конечный (зависит от реализации) период времени. Результат безуспешное разрешение имени хоста кэшируется в течение очень короткого периода времени (10 секунд) для повышения производительности.

Если поведение по умолчанию не желательно, тогда свойство безопасности Java может быть настроено на другое время жизни (TTL) для положительного кэширования. Аналогичным образом администратор системы может настроить значение отрицательного кэширования TTL при необходимости.

Два свойства безопасности безопасности Java значения TTL, используемые для позитивных и отрицательное кэширование разрешения имени хоста:

  • networkaddress.cache.ttl
    Указывает политику кэширования для успешное имя поиска от имени оказание услуг. Значение указано как integer, чтобы указать количество секунд для кэширования успешных Погляди. Значение по умолчанию - кеш для конкретной реализации период времени.

    Значение -1 указывает "кеш навсегда".

  • networkaddress.cache.negative.ttl (по умолчанию: 10)
    Указывает на кеширование политика для неудачных поисков имен от службы имени. Значение задано как целое число, указывающее количество секунд для кэширования неудача для неудачных поисков.

    Значение 0 указывает "никогда не кэшировать". Значение -1 указывает "кеш навсегда".

Если вы имеете в виду сброс кешей (типа java.net.InetAddress$Cache), используемых java.net.InetAddress, они являются внутренними деталями реализации и, таким образом, 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);

Поэтому я сомневаюсь, что вы найдете что-нибудь из этого, и предположите, что вам нужно будет играть с отражением, чтобы достичь своей цели.

Ответ 3

Выше ответ больше не работает на Java 8. Здесь небольшая адаптация:

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);
        }
    }
}