diff --git a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/LookupTask.java b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/LookupTask.java index c2fc4a97df022..2b56b307c2cc4 100644 --- a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/LookupTask.java +++ b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/LookupTask.java @@ -22,7 +22,7 @@ import org.xbill.DNS.Name; import org.xbill.DNS.Record; -public class LookupTask implements Callable { +public class LookupTask implements Callable { private Name name; private int type; @@ -33,7 +33,9 @@ public LookupTask(Name name, int type) { } @Override - public Record[] call() throws Exception { - return new Lookup(name, type).run(); + public Lookup call() throws Exception { + Lookup lookup = new Lookup(name, type); + lookup.run(); + return lookup; } } diff --git a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java index e99c49f7dc6a8..803b58b57921e 100644 --- a/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java +++ b/hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java @@ -1101,7 +1101,7 @@ byte[] generateReply(Message query, Socket s) LOG.debug("calling addAnswer"); byte rcode = addAnswer(response, name, type, dclass, 0, flags); if (rcode != Rcode.NOERROR) { - rcode = remoteLookup(response, name, type, 0); + rcode = remoteLookup(response, name, type); response.getHeader().setRcode(rcode); } addAdditional(response, flags); @@ -1119,47 +1119,44 @@ byte[] generateReply(Message query, Socket s) /** * Lookup record from upstream DNS servers. */ - private byte remoteLookup(Message response, Name name, int type, - int iterations) { + private byte remoteLookup(Message response, Name name, int type) { // If retrieving the root zone, query for NS record type if (name.toString().equals(".")) { type = Type.NS; } - // Always add any CNAMEs to the response first - if (type != Type.CNAME) { - Record[] cnameAnswers = getRecords(name, Type.CNAME); - if (cnameAnswers != null) { - for (Record cnameR : cnameAnswers) { - if (!response.findRecord(cnameR)) { - response.addRecord(cnameR, Section.ANSWER); + // Forward lookup to primary DNS servers + RemoteAnswer ra = getRecords(name, type); + + // Support for CNAME/DNAME chaining + if (ra.aliases != null) { + for (Name targetName : ra.aliases) { + Record[] answers = getRecords(targetName, Type.CNAME).answers; + if (answers == null) { + answers = getRecords(targetName, Type.DNAME).answers; + } + if (answers != null) { + for (Record r : answers) { + if (!response.findRecord(r)) { + response.addRecord(r, Section.ANSWER); + } } } } } - - // Forward lookup to primary DNS servers - Record[] answers = getRecords(name, type); - try { - for (Record r : answers) { - if (!response.findRecord(r)) { - if (r.getType() == Type.SOA) { - response.addRecord(r, Section.AUTHORITY); - } else { - response.addRecord(r, Section.ANSWER); - } - } - if (r.getType() == Type.CNAME) { - Name cname = r.getName(); - if (iterations < 6) { - remoteLookup(response, cname, type, iterations + 1); - } + Record[] answers = ra.answers; + // no answer + if (answers == null) { + return (byte)ra.rcode; + } + for (Record r : answers) { + if (!response.findRecord(r)) { + if (r.getType() == Type.SOA) { + response.addRecord(r, Section.AUTHORITY); + } else { + response.addRecord(r, Section.ANSWER); } } - } catch (NullPointerException e) { - return Rcode.NXDOMAIN; - } catch (Throwable e) { - return Rcode.SERVFAIL; } return Rcode.NOERROR; } @@ -1169,20 +1166,32 @@ private byte remoteLookup(Message response, Name name, int type, * * @param name - query string * @param type - type of DNS record to lookup - * @return DNS records + * @return DNS records and return code from remote DNS server */ - protected Record[] getRecords(Name name, int type) { - Record[] result = null; + protected RemoteAnswer getRecords(Name name, int type) { ExecutorService executor = Executors.newSingleThreadExecutor(); - Future future = executor.submit(new LookupTask(name, type)); + Future future = executor.submit(new LookupTask(name, type)); try { - result = future.get(1500, TimeUnit.MILLISECONDS); - return result; + Lookup lookup = future.get(1500, TimeUnit.MILLISECONDS); + int result = lookup.getResult(); + int rcode = Rcode.NXDOMAIN; + switch (result) { + case Lookup.SUCCESSFUL: + case Lookup.TYPE_NOT_FOUND: + rcode = Rcode.NOERROR; + break; + case Lookup.HOST_NOT_FOUND: + break; + default: + LOG.warn("Unexpected result from lookup: {} type: {} error: {}", name, Type.string(type), lookup.getErrorString()); + break; + } + return new RemoteAnswer(lookup.getAnswers(), lookup.getAliases(), rcode); } catch (InterruptedException | ExecutionException | TimeoutException | NullPointerException | ExceptionInInitializerError e) { LOG.warn("Failed to lookup: {} type: {}", name, Type.string(type), e); - return result; + return new RemoteAnswer(null, null, Rcode.NXDOMAIN); } finally { executor.shutdown(); } @@ -1779,4 +1788,16 @@ public void close() { lock.unlock(); } } + + public static class RemoteAnswer { + public Record[] answers; + public Name[] aliases; + public int rcode; + + public RemoteAnswer(Record[] answers, Name[] aliases, int rcode) { + this.answers = answers; + this.aliases = aliases; + this.rcode = rcode; + } + } } diff --git a/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/server/dns/TestRegistryDNS.java b/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/server/dns/TestRegistryDNS.java index 17e9e7b96fcb7..23602dd80e2ca 100644 --- a/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/server/dns/TestRegistryDNS.java +++ b/hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/server/dns/TestRegistryDNS.java @@ -637,7 +637,7 @@ public void testSplitReverseZoneNames() throws Exception { @Test public void testExampleDotCom() throws Exception { Name name = Name.fromString("example.com."); - Record[] records = getRegistryDNS().getRecords(name, Type.SOA); + Record[] records = getRegistryDNS().getRecords(name, Type.SOA).answers; assertNotNull(records, "example.com exists:"); } @@ -699,10 +699,18 @@ public void testMultiARecord() throws Exception { @Timeout(value = 5) public void testUpstreamFault() throws Exception { Name name = Name.fromString("19.0.17.172.in-addr.arpa."); - Record[] recs = getRegistryDNS().getRecords(name, Type.CNAME); + Record[] recs = getRegistryDNS().getRecords(name, Type.CNAME).answers; assertNull(recs, "Record is not null"); } + @Test + public void testNODATA() throws Exception { + Name name = Name.fromString("example.com."); + RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.CNAME); + assertNull(ra.answers, "CNAME record for example.com. should be null."); + assertEquals(Rcode.NOERROR, ra.rcode, "The result of DNS query for example.com. should be NOERROR."); + } + public RegistryDNS getRegistryDNS() { return registryDNS; }