Skip to content

Commit dad60e7

Browse files
author
이유비
committed
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
1 parent dae33cf commit dad60e7

File tree

3 files changed

+64
-22
lines changed

3 files changed

+64
-22
lines changed

hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/LookupTask.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.xbill.DNS.Name;
2323
import org.xbill.DNS.Record;
2424

25-
public class LookupTask implements Callable<Record[]> {
25+
public class LookupTask implements Callable<Lookup> {
2626

2727
private Name name;
2828
private int type;
@@ -33,7 +33,9 @@ public LookupTask(Name name, int type) {
3333
}
3434

3535
@Override
36-
public Record[] call() throws Exception {
37-
return new Lookup(name, type).run();
36+
public Lookup call() throws Exception {
37+
Lookup lookup = new Lookup(name, type);
38+
lookup.run();
39+
return lookup;
3840
}
3941
}

hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/server/dns/RegistryDNS.java

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,20 +1125,34 @@ private byte remoteLookup(Message response, Name name, int type,
11251125
type = Type.NS;
11261126
}
11271127

1128-
// Always add any CNAMEs to the response first
1128+
// Support for CNAME chaining
11291129
if (type != Type.CNAME) {
1130-
Record[] cnameAnswers = getRecords(name, Type.CNAME);
1131-
if (cnameAnswers != null) {
1130+
Name targetName = name;
1131+
while (iterations < 6) {
1132+
Record[] cnameAnswers = getRecords(targetName, Type.CNAME).answers;
1133+
if (cnameAnswers == null) {
1134+
break;
1135+
}
11321136
for (Record cnameR : cnameAnswers) {
11331137
if (!response.findRecord(cnameR)) {
11341138
response.addRecord(cnameR, Section.ANSWER);
1139+
targetName = ((CNAMERecord) cnameR).getTarget();
11351140
}
11361141
}
1142+
iterations++;
1143+
}
1144+
if (iterations < 6 && !targetName.equals(name)) {
1145+
return remoteLookup(response, targetName, type, iterations + 1);
11371146
}
11381147
}
11391148

11401149
// Forward lookup to primary DNS servers
1141-
Record[] answers = getRecords(name, type);
1150+
RemoteAnswer ra = getRecords(name, type);
1151+
Record[] answers = ra.answers;
1152+
// no answer
1153+
if (answers == null) {
1154+
return (byte)ra.rcode;
1155+
}
11421156
try {
11431157
for (Record r : answers) {
11441158
if (!response.findRecord(r)) {
@@ -1148,12 +1162,6 @@ private byte remoteLookup(Message response, Name name, int type,
11481162
response.addRecord(r, Section.ANSWER);
11491163
}
11501164
}
1151-
if (r.getType() == Type.CNAME) {
1152-
Name cname = r.getName();
1153-
if (iterations < 6) {
1154-
remoteLookup(response, cname, type, iterations + 1);
1155-
}
1156-
}
11571165
}
11581166
} catch (NullPointerException e) {
11591167
return Rcode.NXDOMAIN;
@@ -1168,20 +1176,32 @@ private byte remoteLookup(Message response, Name name, int type,
11681176
*
11691177
* @param name - query string
11701178
* @param type - type of DNS record to lookup
1171-
* @return DNS records
1179+
* @return DNS records and return code from remote DNS server
11721180
*/
1173-
protected Record[] getRecords(Name name, int type) {
1174-
Record[] result = null;
1181+
protected RemoteAnswer getRecords(Name name, int type) {
11751182
ExecutorService executor = Executors.newSingleThreadExecutor();
1176-
Future<Record[]> future = executor.submit(new LookupTask(name, type));
1183+
Future<Lookup> future = executor.submit(new LookupTask(name, type));
11771184
try {
1178-
result = future.get(1500, TimeUnit.MILLISECONDS);
1179-
return result;
1185+
Lookup lookup = future.get(1500, TimeUnit.MILLISECONDS);
1186+
int result = lookup.getResult();
1187+
int rcode = Rcode.NXDOMAIN;
1188+
switch (result) {
1189+
case Lookup.SUCCESSFUL:
1190+
case Lookup.TYPE_NOT_FOUND:
1191+
rcode = Rcode.NOERROR;
1192+
break;
1193+
case Lookup.HOST_NOT_FOUND:
1194+
break;
1195+
default:
1196+
LOG.warn("Unexpected result from lookup: {} type: {} error: {}", name, Type.string(type), lookup.getErrorString());
1197+
break;
1198+
}
1199+
return new RemoteAnswer(lookup.getAnswers(), rcode);
11801200
} catch (InterruptedException | ExecutionException |
11811201
TimeoutException | NullPointerException |
11821202
ExceptionInInitializerError e) {
11831203
LOG.warn("Failed to lookup: {} type: {}", name, Type.string(type), e);
1184-
return result;
1204+
return new RemoteAnswer(null, Rcode.NXDOMAIN);
11851205
} finally {
11861206
executor.shutdown();
11871207
}
@@ -1778,4 +1798,14 @@ public void close() {
17781798
lock.unlock();
17791799
}
17801800
}
1801+
1802+
public static class RemoteAnswer {
1803+
public Record[] answers;
1804+
public int rcode;
1805+
1806+
public RemoteAnswer(Record[] answers, int rcode) {
1807+
this.answers = answers;
1808+
this.rcode = rcode;
1809+
}
1810+
}
17811811
}

hadoop-common-project/hadoop-registry/src/test/java/org/apache/hadoop/registry/server/dns/TestRegistryDNS.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,8 @@ public void testSplitReverseZoneNames() throws Exception {
642642
@Test
643643
public void testExampleDotCom() throws Exception {
644644
Name name = Name.fromString("example.com.");
645-
Record[] records = getRegistryDNS().getRecords(name, Type.SOA);
645+
RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.SOA);
646+
Record[] records = ra.answers;
646647
assertNotNull("example.com exists:", records);
647648
}
648649

@@ -703,10 +704,19 @@ public void testMultiARecord() throws Exception {
703704
@Test(timeout=5000)
704705
public void testUpstreamFault() throws Exception {
705706
Name name = Name.fromString("19.0.17.172.in-addr.arpa.");
706-
Record[] recs = getRegistryDNS().getRecords(name, Type.CNAME);
707+
RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.CNAME);
708+
Record[] recs = ra.answers;
707709
assertNull("Record is not null", recs);
708710
}
709711

712+
@Test
713+
public void testNODATA() throws Exception {
714+
Name name = Name.fromString("example.com.");
715+
RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.CNAME);
716+
assertNull("CNAME record for example.com. should be null.", ra.answers);
717+
assertEquals("The result of DNS query for example.com. should be NOERROR.", Rcode.NOERROR, ra.rcode);
718+
}
719+
710720
public RegistryDNS getRegistryDNS() {
711721
return registryDNS;
712722
}

0 commit comments

Comments
 (0)