سؤال

The program below performs a DNS lookup. It works good except for one particular combination of host name and dns:

import javax.naming.directory.InitialDirContext;
import javax.naming.NamingException;
import java.util.Hashtable;

public final class StackOverflow {
 public static void main(String args[]) throws NamingException {
  Hashtable<String, Object> env = new Hashtable<String, Object>();
  env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
  env.put("java.naming.provider.url", "dns://ns.dnssek.org");
  System.out.println(new InitialDirContext(env).getAttributes("dnsseccert.us", new String[]{"NS","A"}));
 }
}

I tried to set timeout:

env.put("com.sun.jndi.dns.timeout.initial", "220");

however it behaves strange. It works sometimes for small values when it throws:

DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out];

but for most of the times the program just freezes and hangs in the memory.

Have someone else had the same problem and solved it? Are there any other settings I could try to prevent it? Is there some other alternative java.naming.factory.initial which I could try?

هل كانت مفيدة؟

المحلول

It took me a few hours but I finally found an acceptable solution. I downloaded sources of the package com.sun.jndi.dns and added one line into the class DnsClient:

...
Tcp(InetAddress server, int port, int timeout) throws IOException {
    sock = new Socket(server, port);
    sock.setSoTimeout(timeout);  // <-- missing timeout
    sock.setTcpNoDelay(true);
    out = new java.io.BufferedOutputStream(sock.getOutputStream());
    in = new java.io.BufferedInputStream(sock.getInputStream());
}
...

I set timout of the socket. I actually also added a parameter into the Tcp constructor and modified its calls so it is now initialized by the value from com.sun.jndi.dns.timeout.initial.

نصائح أخرى

Please try setting both the com.sun.jndi.dns.timeout.initial and com.sun.jndi.dns.timeout.retries values. For example, I see consistent timeout with the following:

$ cat StackOverflow.java 
import javax.naming.directory.InitialDirContext;
import javax.naming.NamingException;
import java.util.Hashtable;

public final class StackOverflow {
 public static void main(String args[]) throws NamingException {
  Hashtable<String, Object> env = new Hashtable<String, Object>();
  env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
  env.put("java.naming.provider.url", "dns://ns.dnssek.org");

  env.put("com.sun.jndi.dns.timeout.initial", "220");
  env.put("com.sun.jndi.dns.timeout.retries", "1");

  System.out.println(new InitialDirContext(env).getAttributes("dnsseccert.us", new String[]{"NS","A"}));
 }
}

$ java -version
java version "11" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11+28)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode)

$ java StackOverflow
Exception in thread "main" javax.naming.CommunicationException: DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out]; remaining name    'dnsseccert.us'
    at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:313)
    at jdk.naming.dns/com.sun.jndi.dns.Resolver.query(Resolver.java:81)
    at jdk.naming.dns/com.sun.jndi.dns.DnsContext.c_getAttributes(DnsContext.java:434)
    at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:235)
    at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:141)
    at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:129)
    at java.naming/javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:142)
    at StackOverflow.main(StackOverflow.java:14)
    Caused by: java.net.SocketTimeoutException: Receive timed out
    at java.base/java.net.PlainDatagramSocketImpl.receive0(Native Method)
    at java.base/java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:181)
    at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:814)
    at jdk.naming.dns/com.sun.jndi.dns.DnsClient.doUdpQuery(DnsClient.java:423)
    at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:212)
    ... 7 more

You will of course want to configure timeout and retry values that make sense in your own environment. The above values are just for demonstration purposes.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top