[
https://issues.apache.org/jira/browse/HADOOP-20020?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18127006#comment-18127006
]
ASF GitHub Bot commented on HADOOP-20020:
-----------------------------------------
smengcl commented on code in PR #8820:
URL: https://github.com/apache/hadoop/pull/8820#discussion_r4269044786
##########
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/DNS.java:
##########
@@ -89,7 +91,12 @@ public static String reverseDns(InetAddress hostIp,
@Nullable String ns)
ictx.close();
}
- String hostname = attribute.get("PTR").get().toString();
+ Attribute ptr = attribute.get("PTR");
+ if (ptr == null) {
+ // The server answered, but without a PTR record.
+ throw new NameNotFoundException("No PTR record for " + reverseIP);
+ }
+ String hostname = ptr.get().toString();
Review Comment:
Done in ae72666ac6b: an empty PTR attribute now throws the same
NameNotFoundException.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
##########
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestDNS.java:
##########
@@ -222,6 +226,52 @@ public void testReverseDnsIPv6WithInvalidServer() throws
Exception {
.isInstanceOf(NamingException.class);
}
+ /**
+ * Test that the reverse lookup fails with a NamingException, which the
+ * callers handle, when the DNS server answers without a PTR record.
+ */
+ @Test
+ public void testReverseDnsWithoutPtrRecord() throws Exception {
+ try (DatagramSocket server = new DatagramSocket(0,
InetAddress.getByName("127.0.0.1"))) {
+ Thread responder = new Thread(() -> answerWithoutRecords(server));
+ responder.setDaemon(true);
+ responder.start();
+ String ns = "127.0.0.1:" + server.getLocalPort();
+ for (String ip : new String[] {"192.0.2.1", "2001:db8::1"}) {
+ assertThatThrownBy(() -> DNS.reverseDns(InetAddress.getByName(ip), ns))
+ .isInstanceOf(NameNotFoundException.class)
+ .hasMessageContaining("No PTR record");
+ }
+ }
+ }
+
+ /**
+ * Answers every DNS query with NOERROR and no records, until the socket
+ * is closed.
+ */
+ private static void answerWithoutRecords(DatagramSocket server) {
+ byte[] buf = new byte[512];
+ try {
+ while (true) {
+ DatagramPacket query = new DatagramPacket(buf, buf.length);
+ server.receive(query);
+ // Keep the header and the question, drop anything after the question.
+ int end = 12;
+ while (buf[end] != 0) {
+ end += buf[end] + 1;
+ }
+ end += 5; // the root label, QTYPE and QCLASS
+ byte[] answer = Arrays.copyOf(buf, end);
Review Comment:
Done in ae72666ac6b: the label loop is bounded by the packet length and
malformed packets are skipped. Compression is not handled since the JDK DNS
client never compresses the question in a query.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
##########
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestDNS.java:
##########
@@ -222,6 +226,52 @@ public void testReverseDnsIPv6WithInvalidServer() throws
Exception {
.isInstanceOf(NamingException.class);
}
+ /**
+ * Test that the reverse lookup fails with a NamingException, which the
+ * callers handle, when the DNS server answers without a PTR record.
+ */
+ @Test
+ public void testReverseDnsWithoutPtrRecord() throws Exception {
+ try (DatagramSocket server = new DatagramSocket(0,
InetAddress.getByName("127.0.0.1"))) {
+ Thread responder = new Thread(() -> answerWithoutRecords(server));
+ responder.setDaemon(true);
+ responder.start();
+ String ns = "127.0.0.1:" + server.getLocalPort();
+ for (String ip : new String[] {"192.0.2.1", "2001:db8::1"}) {
+ assertThatThrownBy(() -> DNS.reverseDns(InetAddress.getByName(ip), ns))
+ .isInstanceOf(NameNotFoundException.class)
+ .hasMessageContaining("No PTR record");
+ }
+ }
+ }
+
+ /**
+ * Answers every DNS query with NOERROR and no records, until the socket
+ * is closed.
+ */
+ private static void answerWithoutRecords(DatagramSocket server) {
+ byte[] buf = new byte[512];
+ try {
+ while (true) {
+ DatagramPacket query = new DatagramPacket(buf, buf.length);
+ server.receive(query);
+ // Keep the header and the question, drop anything after the question.
+ int end = 12;
+ while (buf[end] != 0) {
+ end += buf[end] + 1;
+ }
+ end += 5; // the root label, QTYPE and QCLASS
+ byte[] answer = Arrays.copyOf(buf, end);
+ answer[2] = (byte) 0x81; // QR and RD
+ answer[3] = (byte) 0x80; // RA, RCODE 0
+ Arrays.fill(answer, 6, 12, (byte) 0); // no answer, authority or
additional records
+ server.send(new DatagramPacket(answer, end, query.getSocketAddress()));
+ }
+ } catch (IOException closed) {
+ // The test closed the socket.
+ }
Review Comment:
Done in ae72666ac6b: the IOException is only swallowed when the socket is
closed, otherwise it is rethrown as UncheckedIOException.
_🤖 Addressed by [Claude Code](https://claude.com/claude-code)_
> DNS.reverseDns throws NullPointerException when the answer has no PTR record
> ----------------------------------------------------------------------------
>
> Key: HADOOP-20020
> URL: https://issues.apache.org/jira/browse/HADOOP-20020
> Project: Hadoop Common
> Issue Type: Sub-task
> Reporter: Siyao Meng
> Assignee: Siyao Meng
> Priority: Major
> Labels: pull-request-available
>
> {{DNS.reverseDns}} reads {{attribute.get("PTR").get()}} without a null check.
> When the DNS server answers the reverse query with NOERROR but no PTR record
> (a NODATA answer), JNDI returns no PTR attribute and {{reverseDns}} throws
> {{NullPointerException}}.
> The callers, {{DNS.getHosts}} and {{DNSDomainNameResolver.getHostnameByIP}},
> only catch {{NamingException}}, so the exception escapes instead of falling
> back. Through {{getHostnameByIP}} it reaches
> {{SecurityUtil.getServerPrincipal(String, InetAddress)}} and
> {{ServiceAuthorizationManager.authorize}}. A name that does not exist
> (NXDOMAIN) already fails with {{NameNotFoundException}} and is handled.
> Throw {{NameNotFoundException}} when the answer has no PTR record. This
> applies to IPv4 and IPv6 addresses alike. It was seen with a resolver that
> answers NODATA for the {{ip6.arpa}} name of {{::}}.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]