Using Java JNDI for DNS

I used to have a Java class that created sockets, connected to a specified DNS server on port 53, setup streams and then did DNS queries and parsed the responses. It worked, but much ado about DNS from Java.

Enter JNDI.

It seems that JNDI has a DNS "Service Provider" and thus JNDI can query DNS just as any other directory. As the Sun JNDI/DNS service provider states The provider presents the DNS namespace as a tree of JNDI directory contexts, and DNS resource records as JNDI attributes.

Many of you I am sure are already aware of this nifty feature, but I was not. I do not normally use JNDI or any type of directory services, but I probably should.

When I again needed to use DNS from within a Java app (I need to query MX records for domains that have bounced email in an app that is written with JavaMail API, also very cool stuff) I set out to find the old socket DNS class. Then just on a whim I decided to poke around a bit online because certainly what I needed to do must be quite common.

I found the JNDI/DNS docs and read through them. Then I found this simple Lookup class using JNDI/DNS. Then I created my own very simple derivative:

import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;

public class Lookup   
{           
    // vars 
    static final String DNS_SERVER = "192.168.200.1";
    static final String MX_TYPE = "MX"; 
    static final String A_TYPE = "A";
    static final String NS_TYPE = "NS"; 

    /**
     * <br />Simple EXAMPLE of how getRecord can be implemented.  
     * Create return such as ArrayList for real use. 
     *
     **/
    public static void getRecord(String domainName, String recordType) 
        { 
            try 
                {  
                    Hashtable env = new Hashtable(); 
                    env.put("java.naming.factory.initial", 
				"com.sun.jndi.dns.DnsContextFactory");
                    env.put("java.naming.provider.url", 
				"dns://" + DNS_SERVER + "/");
                    DirContext ictx = new InitialDirContext(env);
                    Attributes a = ictx.getAttributes(domainName, 
				new String[] { recordType });
                    NamingEnumeration all = a.getAll();
                    while (all.hasMore()) 
                        {
                            Attribute attr = (Attribute)all.next();
                            System.out.println("Attribute: " 
                                    + attr.getID());
                            NamingEnumeration values = attr.getAll(); 
                            while (values.hasMore())
                                {  
                                    // obviously you RETURN here 
				    // example print
                                    System.out.println("Value: " 
					+ values.next()); 
                                } 
                        } 
                }     
            catch (Exception e) 
		{
			System.out.println("Lookup.getRecord() ERROR " 
				+ e.getMessage());
		}
    

    /**
     * <br />Simple main() for test purposes.  
     * Args 1 = domain | Args 2 = record type
     *
     **/	
    public static void main (String[] args) 
    {                  
        System.out.println("calling getMX for " 
		+ args[0] + " and record type " + args[1]);
        Lookup.getRecord(args[0], args[1]);
    } 
} 

Using this ultra simple class that makes use of JNDI/DNS I was able to replace a much more complicated socket and stream and manual DNS process.

This is good stuff, try it. Make sure that the jars for dns, jndi and providerutil are in your classpath and compile it. Then simple run it via command line as "Lookup yahoo.com MX" where the args are obviously domain and type. Use if from within other apps very simply by calling the static Lookup.getRecord(domain, type) method. Props to Java and to cee.hw.ac.uk.

Comments

There are caveats, too

If you omit the java.naming.provider.url parameter, Java will try to deduct some defaults from the OS environment (on UNIX, /etc/resolv.conf).

This fails badly, however, with IPv6. An IPv6 server address causes exception:

java.lang.NumberFormatException: For input string: "db8::1"

where db8 is the second word of the DNS server IP address. Brackets do not work, either.

This might have been addressed in Java bug 5042453.

--Marcin

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.