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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11647629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:55:02  来源:igfitidea点击:

How to configure hostname resolution to use a custom DNS server in Java?

javanetworkingdns

提问by Pacerier

java.net.InetAddressresolves hostnames using the local machine's default host-name resolver by default:

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

Host name-to-IP address resolution is accomplished through the use of a combination of local machine configuration information and network naming services such as the Domain Name System (DNS) and Network Information Service(NIS). The particular naming services(s) being used is by default the local machine configured one. For any host name, its corresponding IP address is returned. [source]

主机名到 IP 地址的解析是通过结合使用本地机器配置信息和网络命名服务(例如域名系统 (DNS) 和网络信息服务 (NIS))来完成的。默认情况下,使用的特定命名服务是本地机器配置的一个。对于任何主机名,都会返回其对应的 IP 地址。[来源]

How can we configure this behavior without modifying the local machine's default hostname resolver?

我们如何在不修改本地机器的默认主机名解析器的情况下配置此行为?

For example, is there anyway to configure java.net.InetAddresssuch that it resolves host names through OpenDNS (208.67.222.222, 208.67.220.220) or Google Public DNS (2001:4860:4860::8888, 2001:4860:4860::8844)?

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

Or is the only solution to explicitly create DNS packet requests, send them to the servers through either java.net.DatagramSocketor java.net.Socket, and parse the responses?

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

采纳答案by Pace

Java 9 removed this capability. You will need to use a third party DNS client library.

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

If you are using Java 8 or older you can do:

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

You can set the system property sun.net.spi.nameservice.nameserversas documented by this site.

您可以sun.net.spi.nameservice.nameservers按照本站点的文档设置系统属性

回答by Yves Martin

For Java versions up to 8, here is the code I wrote to hard-code a foosystem name DNS resolution in Java for test cases to pass. Its avantage is to append your specific entrie(s) to default Java runtime DNS resolution.

对于高达 8 的 Java 版本,这里是我编写的代码foo,用于在 Java 中硬编码系统名称 DNS 解析以通过测试用例。它的优点是将您的特定条目附加到默认的 Java 运行时 DNS 解析。

I recommend not to run it in production. Forced reflective access and Java runtime non-public implementation classes are used !

我建议不要在生产中运行它。使用了强制反射访问和 Java 运行时非公共实现类!

private static final String FOO_IP = "10.10.8.111";

/** Fake "foo" DNS resolution */
@SuppressWarnings("restriction")
public static class MyHostNameService implements sun.net.spi.nameservice.NameService {
    @Override
    public InetAddress[] lookupAllHostAddr(String paramString) throws UnknownHostException {
        if ("foo".equals(paramString) || "foo.domain.tld".equals(paramString)) {
            final byte[] arrayOfByte = sun.net.util.IPAddressUtil.textToNumericFormatV4(FOO_IP);
            final InetAddress address = InetAddress.getByAddress(paramString, arrayOfByte);
            return new InetAddress[] { address };
        } else {
            throw new UnknownHostException();
        }
    }
    @Override
    public String getHostByAddr(byte[] paramArrayOfByte) throws UnknownHostException {
        throw new UnknownHostException();
    }
}

static {
    // Force to load fake hostname resolution for tests to pass
    try {
        List<sun.net.spi.nameservice.NameService> nameServices =
            (List<sun.net.spi.nameservice.NameService>)
            org.apache.commons.lang3.reflect.FieldUtils.readStaticField(InetAddress.class, "nameServices", true);
        nameServices.add(new MyHostNameService());
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

Hope this helps, but again, to be used with care !

希望这会有所帮助,但同样要小心使用!

回答by SkateScout

with the following Interface and allowing access to java.net.* it is possible to use own DNS provider with JDK8 and JDK9. The new Provider is installed via "INameService.install(new MyNameService());"

使用以下接口并允许访问 java.net.* 可以使用带有 JDK8 和 JDK9 的自己的 DNS 提供程序。新的 Provider 是通过“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());
        }
    }
}