[ 
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]

Reply via email to