diff --git a/src/java/org/jivesoftware/multiplexer/net/DNSUtil.java b/src/java/org/jivesoftware/multiplexer/net/DNSUtil.java index df2cde3..0c78759 100644 --- a/src/java/org/jivesoftware/multiplexer/net/DNSUtil.java +++ b/src/java/org/jivesoftware/multiplexer/net/DNSUtil.java @@ -3,7 +3,7 @@ * $Revision: $ * $Date: $ * - * Copyright (C) 2006 Jive Software. All rights reserved. + * Copyright (C) 2007 Jive Software. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. @@ -11,12 +11,16 @@ package org.jivesoftware.multiplexer.net; +import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.Log; import javax.naming.directory.Attributes; -import javax.naming.directory.InitialDirContext; import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; /** * Utilty class to perform DNS lookups for XMPP services. @@ -27,11 +31,22 @@ private static DirContext context; + /** + * Internal DNS that allows to specify target IP addresses and ports to use for domains. + * The internal DNS will be checked up before performing an actual DNS SRV lookup. + */ + private static Map dnsOverride; + static { try { Hashtable env = new Hashtable(); env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); context = new InitialDirContext(env); + + String property = JiveGlobals.getXMLProperty("dnsutil.dnsOverride"); + if (property != null) { + dnsOverride = decode(property); + } } catch (Exception e) { Log.error(e); @@ -56,13 +71,21 @@ * server can be reached at for the specified domain. */ public static HostAddress resolveXMPPServerDomain(String domain, int defaultPort) { + // Check if there is an entry in the internal DNS for the specified domain + if (dnsOverride != null) { + HostAddress hostAddress = dnsOverride.get(domain); + if (hostAddress != null) { + return hostAddress; + } + } if (context == null) { return new HostAddress(domain, defaultPort); } String host = domain; int port = defaultPort; try { - Attributes dnsLookup = context.getAttributes("_xmpp-server._tcp." + domain); + Attributes dnsLookup = + context.getAttributes("_xmpp-server._tcp." + domain, new String[]{"SRV"}); String srvRecord = (String)dnsLookup.get("SRV").get(); String [] srvRecordEntries = srvRecord.split(" "); port = Integer.parseInt(srvRecordEntries[srvRecordEntries.length-2]); @@ -71,13 +94,16 @@ catch (Exception e) { // Attempt lookup with older "jabber" name. try { - Attributes dnsLookup = context.getAttributes("_jabber._tcp." + domain); + Attributes dnsLookup = + context.getAttributes("_jabber._tcp." + domain, new String[]{"SRV"}); String srvRecord = (String)dnsLookup.get("SRV").get(); String [] srvRecordEntries = srvRecord.split(" "); port = Integer.parseInt(srvRecordEntries[srvRecordEntries.length-2]); host = srvRecordEntries[srvRecordEntries.length-1]; } - catch (Exception e2) { } + catch (Exception e2) { + // Do nothing + } } // Host entries in DNS should end with a ".". if (host.endsWith(".")) { @@ -87,6 +113,57 @@ } /** + * Returns the internal DNS that allows to specify target IP addresses and ports + * to use for domains. The internal DNS will be checked up before performing an + * actual DNS SRV lookup. + * + * @return the internal DNS that allows to specify target IP addresses and ports + * to use for domains. + */ + public static Map getDnsOverride() { + return dnsOverride; + } + + /** + * Sets the internal DNS that allows to specify target IP addresses and ports + * to use for domains. The internal DNS will be checked up before performing an + * actual DNS SRV lookup. + * + * @param dnsOverride the internal DNS that allows to specify target IP addresses and ports + * to use for domains. + */ + public static void setDnsOverride(Map dnsOverride) { + DNSUtil.dnsOverride = dnsOverride; + JiveGlobals.setXMLProperty("dnsutil.dnsOverride", encode(dnsOverride)); + } + + private static String encode(Map internalDNS) { + if (internalDNS == null) { + return ""; + } + StringBuilder sb = new StringBuilder(100); + for (String key : internalDNS.keySet()) { + if (sb.length() > 0) { + sb.append(","); + } + sb.append("{").append(key).append(","); + sb.append(internalDNS.get(key).getHost()).append(":"); + sb.append(internalDNS.get(key).getPort()).append("}"); + } + return sb.toString(); + } + + private static Map decode(String encodedValue) { + Map answer = new HashMap(); + StringTokenizer st = new StringTokenizer(encodedValue, "{},:"); + while (st.hasMoreElements()) { + String key = st.nextToken(); + answer.put(key, new HostAddress(st.nextToken(), Integer.parseInt(st.nextToken()))); + } + return answer; + } + + /** * Encapsulates a hostname and port. */ public static class HostAddress {