package org.jgroups.protocols.dns; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import org.jgroups.Address; import org.jgroups.logging.Log; import org.jgroups.logging.LogFactory; import org.jgroups.stack.IpAddress; class DefaultDNSResolver implements DNSResolver { private static final Pattern SRV_REGEXP = Pattern.compile("\\d+ \\d+ \\d+ ([\\w+.-]+)\\."); private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); final String dnsContextFactory; final String dnsAddress; final DirContext dnsContext; /** * @deprecated Implemented for testing. */ @Deprecated DefaultDNSResolver(DirContext direcoryContextForTests) { this.dnsContext = direcoryContextForTests; dnsAddress = null; dnsContextFactory = null; } public DefaultDNSResolver(String dnsContextFactory, String dnsAddress) { this.dnsContextFactory = dnsContextFactory; this.dnsAddress = dnsAddress; dnsContext = getDnsContext(); } private final DirContext getDnsContext() { try { log.trace("Initializing DNS Context with factory: %s and url: %s" + dnsContextFactory, dnsAddress); Hashtable env = new Hashtable(); env.put("java.naming.factory.initial", dnsContextFactory); env.put("java.naming.provider.url", "dns://" + dnsAddress); return new InitialDirContext(env); } catch (NamingException e) { throw new IllegalStateException("Wrong DNS Context", e); } } @Override public List<Address> resolveIps(String dnsQuery, DNSRecordType recordType) { log.trace("Resolving DNS Query: %s of a type: %s", dnsQuery, recordType.toString()); switch (recordType) { case A: return resolveAEntries(dnsQuery); case SRV: return resolveSRVEntries(dnsQuery); default: throw new IllegalStateException("Not implemented"); } } private List<Address> resolveSRVEntries(String dnsQuery) { List<Address> addresses = new ArrayList<>(); try { // We are parsing this kind of structure: // {srv=SRV: 10 100 8888 9089f34a.jgroups-dns-ping.myproject.svc.cluster.local.} // The frst attribute is the type of record. We are not interested in this. Next are addresses. Attributes attributes = dnsContext.getAttributes(dnsQuery, new String[]{DNSRecordType.SRV.toString()}); if(attributes != null && attributes.getAll().hasMoreElements()) { NamingEnumeration<?> namingEnumeration = attributes.get(DNSRecordType.SRV.toString()).getAll(); while (namingEnumeration.hasMoreElements()) { try { String srvEntry = namingEnumeration.nextElement().toString(); Matcher matcher = SRV_REGEXP.matcher(srvEntry); if(matcher.find()) { String srcDNSRecord = matcher.group(1); // The implementation here is not optimal but it's easy to read. SRV discovery will be performed // extremely rare only when a fine grained discovery using ports is needed. addresses.addAll(resolveAEntries(srcDNSRecord)); } } catch (Exception e) { log.trace("Non critical DNS resolution error", e); continue; } } } } catch (NamingException e) { log.trace("No DNS records for query: " + dnsQuery); } return addresses; } private List<Address> resolveAEntries(String dnsQuery) { List<Address> addresses = new ArrayList<>(); try { // We are parsing this kind of structure: // {a=A: 172.17.0.2, 172.17.0.7} // The frst attribute is the type of record. We are not interested in this. Next are addresses. Attributes attributes = dnsContext.getAttributes(dnsQuery, new String[]{DNSRecordType.A.toString()}); if(attributes != null && attributes.getAll().hasMoreElements()) { NamingEnumeration<?> namingEnumeration = attributes.get(DNSRecordType.A.toString()).getAll(); while (namingEnumeration.hasMoreElements()) { try { addresses.add(new IpAddress(namingEnumeration.nextElement().toString())); } catch (Exception e) { log.trace("Non critical DNS resolution error", e); continue; } } } } catch (NamingException e) { log.trace("No DNS records for query: " + dnsQuery); } return addresses; } }