Skip to content

Commit ab6a286

Browse files
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 c5b2c34 commit ab6a286

File tree

3 files changed

+60
-20
lines changed

3 files changed

+60
-20
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
@@ -1126,20 +1126,34 @@ private byte remoteLookup(Message response, Name name, int type,
11261126
type = Type.NS;
11271127
}
11281128

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

11411150
// Forward lookup to primary DNS servers
1142-
Record[] answers = getRecords(name, type);
1151+
RemoteAnswer ra = getRecords(name, type);
1152+
Record[] answers = ra.answers;
1153+
// no answer
1154+
if (answers == null) {
1155+
return (byte)ra.rcode;
1156+
}
11431157
try {
11441158
for (Record r : answers) {
11451159
if (!response.findRecord(r)) {
@@ -1149,12 +1163,6 @@ private byte remoteLookup(Message response, Name name, int type,
11491163
response.addRecord(r, Section.ANSWER);
11501164
}
11511165
}
1152-
if (r.getType() == Type.CNAME) {
1153-
Name cname = r.getName();
1154-
if (iterations < 6) {
1155-
remoteLookup(response, cname, type, iterations + 1);
1156-
}
1157-
}
11581166
}
11591167
} catch (NullPointerException e) {
11601168
return Rcode.NXDOMAIN;
@@ -1169,20 +1177,32 @@ private byte remoteLookup(Message response, Name name, int type,
11691177
*
11701178
* @param name - query string
11711179
* @param type - type of DNS record to lookup
1172-
* @return DNS records
1180+
* @return DNS records and return code from remote DNS server
11731181
*/
1174-
protected Record[] getRecords(Name name, int type) {
1175-
Record[] result = null;
1182+
protected RemoteAnswer getRecords(Name name, int type) {
11761183
ExecutorService executor = Executors.newSingleThreadExecutor();
1177-
Future<Record[]> future = executor.submit(new LookupTask(name, type));
1184+
Future<Lookup> future = executor.submit(new LookupTask(name, type));
11781185
try {
1179-
result = future.get(1500, TimeUnit.MILLISECONDS);
1180-
return result;
1186+
Lookup lookup = future.get(1500, TimeUnit.MILLISECONDS);
1187+
int result = lookup.getResult();
1188+
int rcode = Rcode.NXDOMAIN;
1189+
switch (result) {
1190+
case Lookup.SUCCESSFUL:
1191+
case Lookup.TYPE_NOT_FOUND:
1192+
rcode = Rcode.NOERROR;
1193+
break;
1194+
case Lookup.HOST_NOT_FOUND:
1195+
break;
1196+
default:
1197+
LOG.warn("Unexpected result from lookup: {} type: {} error: {}", name, Type.string(type), lookup.getErrorString());
1198+
break;
1199+
}
1200+
return new RemoteAnswer(lookup.getAnswers(), rcode);
11811201
} catch (InterruptedException | ExecutionException |
11821202
TimeoutException | NullPointerException |
11831203
ExceptionInInitializerError e) {
11841204
LOG.warn("Failed to lookup: {} type: {}", name, Type.string(type), e);
1185-
return result;
1205+
return new RemoteAnswer(null, Rcode.NXDOMAIN);
11861206
} finally {
11871207
executor.shutdown();
11881208
}
@@ -1779,4 +1799,14 @@ public void close() {
17791799
lock.unlock();
17801800
}
17811801
}
1802+
1803+
public static class RemoteAnswer {
1804+
public Record[] answers;
1805+
public int rcode;
1806+
1807+
public RemoteAnswer(Record[] answers, int rcode) {
1808+
this.answers = answers;
1809+
this.rcode = rcode;
1810+
}
1811+
}
17821812
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,14 @@ public void testUpstreamFault() throws Exception {
703703
assertNull(recs, "Record is not null");
704704
}
705705

706+
@Test
707+
public void testNODATA() throws Exception {
708+
Name name = Name.fromString("example.com.");
709+
RegistryDNS.RemoteAnswer ra = getRegistryDNS().getRecords(name, Type.CNAME);
710+
assertNull("CNAME record for example.com. should be null.", ra.answers);
711+
assertEquals("The result of DNS query for example.com. should be NOERROR.", Rcode.NOERROR, ra.rcode);
712+
}
713+
706714
public RegistryDNS getRegistryDNS() {
707715
return registryDNS;
708716
}

0 commit comments

Comments
 (0)