如何配置主机名解析以使用Java中的自定义DNS服务器?

2022-09-02 12:02:51

java.net.InetAddress 默认使用本地计算机的默认主机名解析器解析主机名:

主机名到 IP 地址解析是通过使用本地计算机配置信息和网络命名服务(如域名系统 (DNS) 和网络信息服务 (NIS))的组合来实现的。默认情况下,正在使用的特定命名服务是本地计算机配置的命名服务。对于任何主机名,将返回其相应的 IP 地址。[来源]

如何在不修改本地计算机的默认主机名解析程序的情况下配置此行为?

例如,是否无论如何都要配置java.net.InetAddress,以便通过OpenDNS(208.67.222.222,208.67.220.220)或Google公共DNS(2001:4860:4860::8888,2001:4860:4860::8844)解析主机名?

或者,唯一的解决方案是显式创建 DNS 数据包请求,通过 java.net.DatagramSocketjava.net.Socket 将它们发送到服务器,然后解析响应?


答案 1

Java 9 删除了此功能。您将需要使用第三方 DNS 客户端库。

如果您使用的是Java 8或更早版本,则可以执行以下操作:

您可以设置此站点记录的系统属性。sun.net.spi.nameservice.nameservers


答案 2

使用以下接口并允许访问 java.net.*,可以将自己的DNS提供商与JDK8和JDK9一起使用。新的提供程序通过“INameService.install(new MyNameService())”安装;

public interface INameService extends InvocationHandler {
    public static void install(final INameService dns) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException {
        final Class<?> inetAddressClass = InetAddress.class;
        Object neu;
        Field nameServiceField;
        try {
            final Class<?> iface = Class.forName("java.net.InetAddress$NameService");
            nameServiceField = inetAddressClass.getDeclaredField("nameService");
            neu = Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { iface }, dns);
        } catch(final ClassNotFoundException|NoSuchFieldException e) {
            nameServiceField = inetAddressClass.getDeclaredField("nameServices");
            final Class<?> iface = Class.forName("sun.net.spi.nameservice.NameService");
            neu = Arrays.asList(Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { iface }, dns));
        }
        nameServiceField.setAccessible(true);
        nameServiceField.set(inetAddressClass, neu);
    }

    /**
     * Lookup a host mapping by name. Retrieve the IP addresses associated with a host
     *
     * @param host the specified hostname
     * @return array of IP addresses for the requested host
     * @throws UnknownHostException  if no IP address for the {@code host} could be found
     */
    InetAddress[] lookupAllHostAddr(final String host) throws UnknownHostException;

    /**
     * Lookup the host corresponding to the IP address provided
     *
     * @param addr byte array representing an IP address
     * @return {@code String} representing the host name mapping
     * @throws UnknownHostException
     *             if no host found for the specified IP address
     */
    String getHostByAddr(final byte[] addr) throws UnknownHostException;

    @Override default public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        switch(method.getName()) {
        case "lookupAllHostAddr": return lookupAllHostAddr((String)args[0]);
        case "getHostByAddr"    : return getHostByAddr    ((byte[])args[0]);
        default                 :
            final StringBuilder o = new StringBuilder();
            o.append(method.getReturnType().getCanonicalName()+" "+method.getName()+"(");
            final Class<?>[] ps = method.getParameterTypes();
            for(int i=0;i<ps.length;++i) {
                if(i>0) o.append(", ");
                o.append(ps[i].getCanonicalName()).append(" p").append(i);
            }
            o.append(")");
            throw new UnsupportedOperationException(o.toString());
        }
    }
}

推荐