From ab6a286b96c75f7a30df5208cff17bdef6dbe6ff Mon Sep 17 00:00:00 2001 From: Yubi Lee Date: Fri, 21 Jan 2022 10:30:11 +0900 Subject: [PATCH 1/3] HADOOP-18087. fix bugs when looking up record from upstream DNS servers. - add chained CNAME records to answer section - distinguish between NXDOMAIN and NOERROR + empty answer --- .../registry/server/dns/LookupTask.java | 8 ++- .../registry/server/dns/RegistryDNS.java | 64 ++++++++++++++----- .../registry/server/dns/TestRegistryDNS.java | 8 +++ 3 files changed, 60 insertions(+), 20 deletions(-) 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..b678ef47e73b2 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 @@ -1126,20 +1126,34 @@ private byte remoteLookup(Message response, Name name, int type, type = Type.NS; } - // Always add any CNAMEs to the response first + // Support for CNAME chaining if (type != Type.CNAME) { - Record[] cnameAnswers = getRecords(name, Type.CNAME); - if (cnameAnswers != null) { + Name targetName = name; + while (iterations < 6) { + Record[] cnameAnswers = getRecords(targetName, Type.CNAME).answers; + if (cnameAnswers == null) { + break; + } for (Record cnameR : cnameAnswers) { if (!response.findRecord(cnameR)) { response.addRecord(cnameR, Section.ANSWER); + targetName = ((CNAMERecord) cnameR).getTarget(); } } + iterations++; + } + if (iterations < 6 && !targetName.equals(name)) { + return remoteLookup(response, targetName, type, iterations + 1); } } // Forward lookup to primary DNS servers - Record[] answers = getRecords(name, type); + RemoteAnswer ra = getRecords(name, type); + Record[] answers = ra.answers; + // no answer + if (answers == null) { + return (byte)ra.rcode; + } try { for (Record r : answers) { if (!response.findRecord(r)) { @@ -1149,12 +1163,6 @@ private byte remoteLookup(Message response, Name name, int type, response.addRecord(r, Section.ANSWER); } } - if (r.getType() == Type.CNAME) { - Name cname = r.getName(); - if (iterations < 6) { - remoteLookup(response, cname, type, iterations + 1); - } - } } } catch (NullPointerException e) { return Rcode.NXDOMAIN; @@ -1169,20 +1177,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(), 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, Rcode.NXDOMAIN); } finally { executor.shutdown(); } @@ -1779,4 +1799,14 @@ public void close() { lock.unlock(); } } + + public static class RemoteAnswer { + public Record[] answers; + public int rcode; + + public RemoteAnswer(Record[] answers, int rcode) { + this.answers = answers; + 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..868b25e5590bf 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 @@ -703,6 +703,14 @@ public void testUpstreamFault() throws Exception { 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("CNAME record for example.com. should be null.", ra.answers); + assertEquals("The result of DNS query for example.com. should be NOERROR.", Rcode.NOERROR, ra.rcode); + } + public RegistryDNS getRegistryDNS() { return registryDNS; } From ac890695552e0275bc4abc46c9c581e28cb948e1 Mon Sep 17 00:00:00 2001 From: Yubi Lee Date: Mon, 28 Feb 2022 15:20:27 +0900 Subject: [PATCH 2/3] HADOOP-18087 support both CNAME and DNAME chaining - There is no way to figure out the type of alias from dnsjava's lookup. As a workaround, query CNAME first and then DNAME. - dnsjava use "dnsjava.lookup.max_iterations" property in order to limit follow chaining. Default 16. Therefore, I think "iterations" var. in remoteLookup() is not necessary. --- .../registry/server/dns/RegistryDNS.java | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) 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 b678ef47e73b2..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,55 +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; } - // Support for CNAME chaining - if (type != Type.CNAME) { - Name targetName = name; - while (iterations < 6) { - Record[] cnameAnswers = getRecords(targetName, Type.CNAME).answers; - if (cnameAnswers == null) { - break; + // 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; } - for (Record cnameR : cnameAnswers) { - if (!response.findRecord(cnameR)) { - response.addRecord(cnameR, Section.ANSWER); - targetName = ((CNAMERecord) cnameR).getTarget(); + if (answers != null) { + for (Record r : answers) { + if (!response.findRecord(r)) { + response.addRecord(r, Section.ANSWER); + } } } - iterations++; - } - if (iterations < 6 && !targetName.equals(name)) { - return remoteLookup(response, targetName, type, iterations + 1); } } - - // Forward lookup to primary DNS servers - RemoteAnswer ra = getRecords(name, type); Record[] answers = ra.answers; // no answer if (answers == null) { return (byte)ra.rcode; } - 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); - } + 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; } @@ -1197,12 +1186,12 @@ protected RemoteAnswer getRecords(Name name, int type) { LOG.warn("Unexpected result from lookup: {} type: {} error: {}", name, Type.string(type), lookup.getErrorString()); break; } - return new RemoteAnswer(lookup.getAnswers(), rcode); + 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 new RemoteAnswer(null, Rcode.NXDOMAIN); + return new RemoteAnswer(null, null, Rcode.NXDOMAIN); } finally { executor.shutdown(); } @@ -1802,10 +1791,12 @@ public void close() { public static class RemoteAnswer { public Record[] answers; + public Name[] aliases; public int rcode; - public RemoteAnswer(Record[] answers, int rcode) { + public RemoteAnswer(Record[] answers, Name[] aliases, int rcode) { this.answers = answers; + this.aliases = aliases; this.rcode = rcode; } } From 683b944943662ca2af3a5953ecd7428768ec4173 Mon Sep 17 00:00:00 2001 From: Yubi Lee Date: Wed, 19 Nov 2025 09:07:42 +0900 Subject: [PATCH 3/3] HADOOP-18087. fix bugs on TestRegistryDNS.java --- .../hadoop/registry/server/dns/TestRegistryDNS.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 868b25e5590bf..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,7 +699,7 @@ 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"); } @@ -707,8 +707,8 @@ public void testUpstreamFault() throws Exception { public void testNODATA() throws Exception { Name name = Name.fromString("example.com."); RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.CNAME); - assertNull("CNAME record for example.com. should be null.", ra.answers); - assertEquals("The result of DNS query for example.com. should be NOERROR.", Rcode.NOERROR, ra.rcode); + 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() {