Is there a way to force Java to respect the DNS caching timeout?

We use GSLB for geolocation and load balancing. Each service is assigned a fixed domain name. Through some DNS magic, the domain name is resolved to the IP closest to the server with the least load. In order for load balancing to work, the application server must comply with the TTL from the DNS response and resolve the domain name again after the cache timeout. However, I could not find a way to do this in Java.

The application is in Java 5, running on Linux (Centos 5).

+78
java dns gslb
Aug 10 '09 at 18:49
source share
6 answers

There is some serious weird dns caching behavior in Java. Itโ€™s best to turn off DNS caching or set it to a small amount, for example, 5 seconds.

networkaddress.cache.ttl (default: -1)
Specifies a caching policy for successfully finding names from a name service. The value is specified as an integer to indicate the number of seconds to cache a successful search. A value of -1 indicates "cache forever."

networkaddress.cache.negative.ttl (default: 10)
Specifies a caching policy for failed name lookups from a name service. The value is specified as an integer indicating the number of seconds to cache the error for failed searches. A value of 0 indicates never cache. A value of -1 indicates "cache forever."

+55
Aug 10 '09 at 19:00
source share

In response to a Byron request, you cannot set networkaddress.cache.ttl or networkaddress.cache.negative.ttl as system properties using the -D flag or calling System.setProperty because they are not system properties - they are security properties.

If you want to use the System property to trigger this behavior (so you can use the -D flag or call System.setProperty ), you need to set the following System property:

 -Dsun.net.inetaddr.ttl=0 

This system property will give the desired effect.

But keep in mind: if you do not use the -D flag when starting the JVM process and decide to call it from the code instead:

 java.security.Security.setProperty("networkaddress.cache.ttl" , "0") 

This code must be executed before any other code in the JVM attempts to perform network operations.

This is important because, for example, if you called Security.setProperty in a .war file and deployed this .war for Tomcat, this would not work: Tomcat uses the Java network stack to initialize much earlier than yours. the military code is being executed. Because of this โ€œrace condition," it is usually more convenient to use the -D flag when starting the JVM process.

If you do not use -Dsun.net.inetaddr.ttl=0 or call Security.setProperty , you will need to edit $JRE_HOME/lib/security/java.security and set these security properties in this file, for example.

 networkaddress.cache.ttl = 0 networkaddress.cache.negative.ttl = 0 

But pay attention to the security warnings in the comments related to these properties. Do this only if you are confident that you are not vulnerable to DNS spoofing attacks .

+48
Jun 20 '13 at 16:50
source share

This has obviously been fixed in new versions (SE 6 and 7). I experience a 30 second max caching time when I run the following code snippet while watching port 53 activity using tcpdump.

 /** * http://stackoverflow.com/questions/1256556/any-way-to-make-java-honor-the-dns-caching-timeout-ttl * * Result: Java 6 distributed with Ubuntu 12.04 and Java 7 u15 downloaded from Oracle have * an expiry time for dns lookups of approx. 30 seconds. */ import java.util.*; import java.text.*; import java.security.*; import java.net.InetAddress; import java.net.UnknownHostException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class Test { final static String hostname = "www.google.com"; public static void main(String[] args) { // only required for Java SE 5 and lower: //Security.setProperty("networkaddress.cache.ttl", "30"); System.out.println(Security.getProperty("networkaddress.cache.ttl")); System.out.println(System.getProperty("networkaddress.cache.ttl")); System.out.println(Security.getProperty("networkaddress.cache.negative.ttl")); System.out.println(System.getProperty("networkaddress.cache.negative.ttl")); while(true) { int i = 0; try { makeRequest(); InetAddress inetAddress = InetAddress.getLocalHost(); System.out.println(new Date()); inetAddress = InetAddress.getByName(hostname); displayStuff(hostname, inetAddress); } catch (UnknownHostException e) { e.printStackTrace(); } try { Thread.sleep(5L*1000L); } catch(Exception ex) {} i++; } } public static void displayStuff(String whichHost, InetAddress inetAddress) { System.out.println("Which Host:" + whichHost); System.out.println("Canonical Host Name:" + inetAddress.getCanonicalHostName()); System.out.println("Host Name:" + inetAddress.getHostName()); System.out.println("Host Address:" + inetAddress.getHostAddress()); } public static void makeRequest() { try { URL url = new URL("http://"+hostname+"/"); URLConnection conn = url.openConnection(); conn.connect(); InputStream is = conn.getInputStream(); InputStreamReader ird = new InputStreamReader(is); BufferedReader rd = new BufferedReader(ird); String res; while((res = rd.readLine()) != null) { System.out.println(res); break; } rd.close(); } catch(Exception ex) { ex.printStackTrace(); } } } 
+19
Mar 07 '13 at 21:24
source share

To expand Byron's answer, I believe that you need to edit the java.security file in the %JRE_HOME%\lib\security directory to make this change.

Here is the relevant section:

 # # The Java-level namelookup cache policy for successful lookups: # # any negative value: caching forever # any positive value: the number of seconds to cache an address for # zero: do not cache # # default value is forever (FOREVER). For security reasons, this # caching is made forever when a security manager is set. When a security # manager is not set, the default behavior is to cache for 30 seconds. # # NOTE: setting this to anything other than the default value can have # serious security implications. Do not set it unless # you are sure you are not exposed to DNS spoofing attack. # #networkaddress.cache.ttl=-1 

The documentation in the java.security file java.security here .

+17
Aug 10 '09 at 19:33
source share

To summarize the other answers, in <jre-path>/lib/security/java.security you can set the value of the networkaddress.cache.ttl property to configure DNS query caching. Please note that this is not a system property, but a security property. I was able to install this using:

 java.security.Security.setProperty("networkaddress.cache.ttl", "<value>"); 

This can also be set by the system property -Dsun.net.inetaddr.ttl , although this will not override the security property if set elsewhere.

I would also like to add that if you see this problem with web services in WebSphere, like me, setting networkaddress.cache.ttl will not be enough. You need to set the system property disableWSAddressCaching to true . Unlike the time-to-live property, this can be set as a JVM argument or through System.setProperty ).

IBM has a pretty detailed post about how WebSphere handles DNS caching here . Relevant part above:

To disable address caching for web services, you need to set an additional custom JVM property to disable WSAddressCaching to true. Use this property to disable address caching for web services. If your system usually works with a large number of client threads and you encounter a blocking conflict in the wsAddrCache cache, you can set this custom property to true to prevent caching of web services data.

+4
Jun 03 '15 at 21:12
source share

According to the official properties of oracle java , sun.net.inetaddr.ttl is a property specific to the Sun implementation that "may not be supported in future versions." "The preferred method is to use the security property" networkaddress.cache.ttl .

+1
Oct 07 '17 at 23:44
source share



All Articles