1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Copyright (c) 2005 Brian Wellington (bwelling@xbill.org)
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.xbill.DNS.spi;
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.reflect.InvocationHandler;
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.reflect.Method;
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.InetAddress;
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.UnknownHostException;
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.StringTokenizer;
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.AAAARecord;
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.ARecord;
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.ExtendedResolver;
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.Lookup;
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.Name;
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.PTRRecord;
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.Record;
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.Resolver;
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.ReverseMap;
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.TextParseException;
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.xbill.DNS.Type;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This class implements a Name Service Provider, which Java can use
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * (starting with version 1.4), to perform DNS resolutions instead of using
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the standard calls.
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p>
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This Name Service Provider uses dnsjava.
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p>
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * To use this provider, you must set the following system property:
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <b>sun.net.spi.nameservice.provider.1=dns,dnsjava</b>
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Brian Wellington
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Paul Cowan (pwc21@yahoo.com)
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class DNSJavaNameService implements InvocationHandler {
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static final String nsProperty = "sun.net.spi.nameservice.nameservers";
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static final String domainProperty = "sun.net.spi.nameservice.domain";
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static final String v6Property = "java.net.preferIPv6Addresses";
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean preferV6 = false;
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a DNSJavaNameService instance.
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p>
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Uses the
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <b>sun.net.spi.nameservice.nameservers</b>,
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <b>sun.net.spi.nameservice.domain</b>, and
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <b>java.net.preferIPv6Addresses</b> properties for configuration.
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprotected
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenDNSJavaNameService() {
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String nameServers = System.getProperty(nsProperty);
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String domain = System.getProperty(domainProperty);
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String v6 = System.getProperty(v6Property);
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (nameServers != null) {
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		StringTokenizer st = new StringTokenizer(nameServers, ",");
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		String [] servers = new String[st.countTokens()];
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		int n = 0;
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		while (st.hasMoreTokens())
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			servers[n++] = st.nextToken();
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		try {
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			Resolver res = new ExtendedResolver(servers);
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			Lookup.setDefaultResolver(res);
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (UnknownHostException e) {
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			System.err.println("DNSJavaNameService: invalid " +
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					   nsProperty);
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (domain != null) {
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		try {
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			Lookup.setDefaultSearchPath(new String[] {domain});
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (TextParseException e) {
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			System.err.println("DNSJavaNameService: invalid " +
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					   domainProperty);
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (v6 != null && v6.equalsIgnoreCase("true"))
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		preferV6 = true;
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Object
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Cheninvoke(Object proxy, Method method, Object[] args) throws Throwable {
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (method.getName().equals("getHostByAddr")) {
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return this.getHostByAddr((byte[]) args[0]);
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else if (method.getName().equals("lookupAllHostAddr")) {
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			InetAddress[] addresses;
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			addresses = this.lookupAllHostAddr((String) args[0]);
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			Class returnType = method.getReturnType();
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (returnType.equals(InetAddress[].class)) {
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				// method for Java >= 1.6
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return addresses;
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			} else if (returnType.equals(byte[][].class)) {
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				// method for Java <= 1.5
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				int naddrs = addresses.length;
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				byte [][] byteAddresses = new byte[naddrs][];
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				byte [] addr;
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				for (int i = 0; i < naddrs; i++) {
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					addr = addresses[i].getAddress();
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					byteAddresses[i] = addr;
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return byteAddresses;
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	} catch (Throwable e) {
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		System.err.println("DNSJavaNameService: Unexpected error.");
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		e.printStackTrace();
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw e;
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	throw new IllegalArgumentException(
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					"Unknown function name or arguments.");
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Performs a forward DNS lookup for the host name.
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param host The host name to resolve.
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return All the ip addresses found for the host name.
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic InetAddress []
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenlookupAllHostAddr(String host) throws UnknownHostException {
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Name name = null;
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		name = new Name(host);
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (TextParseException e) {
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new UnknownHostException(host);
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Record [] records = null;
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (preferV6)
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		records = new Lookup(name, Type.AAAA).run();
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (records == null)
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		records = new Lookup(name, Type.A).run();
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (records == null && !preferV6)
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		records = new Lookup(name, Type.AAAA).run();
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (records == null)
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new UnknownHostException(host);
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	InetAddress[] array = new InetAddress[records.length];
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	for (int i = 0; i < records.length; i++) {
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Record record = records[i];
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (records[i] instanceof ARecord) {
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			ARecord a = (ARecord) records[i];
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			array[i] = a.getAddress();
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		} else {
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			AAAARecord aaaa = (AAAARecord) records[i];
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			array[i] = aaaa.getAddress();
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return array;
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Performs a reverse DNS lookup.
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param addr The ip address to lookup.
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The host name found for the ip address.
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic String
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetHostByAddr(byte [] addr) throws UnknownHostException {
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Name name = ReverseMap.fromAddress(InetAddress.getByAddress(addr));
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Record [] records = new Lookup(name, Type.PTR).run();
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (records == null)
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new UnknownHostException();
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return ((PTRRecord) records[0]).getTarget().toString();
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
177