Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8322243

Parsing of resolv.conf fails for IPv6 in mixed hexidecimal and dot decimial

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      macOS 14.2 with 1.8.0_391, 17.0.9, 21.01, 22 (latest eap) and 23 (latest eap).

      Code is shared with Linux, so should reproduce on Linux as well.

      A DESCRIPTION OF THE PROBLEM :
      The sun.net.dns.ResolverConfigurationImpl#resolvconf(String,int,int) method identifies non-BSD (non-RFC3986) IPv6 addresses with:

      if (val.indexOf(':') >= 0 &&
          val.indexOf('.') < 0 && // skip for IPv4 literals with port
          val.indexOf('[') < 0 &&
          val.indexOf(']') < 0 ) {
          // IPv6 literal, in non-BSD-style.
          val = "[" + val + "]";
      }

      When mixed hexidecimal and dot-decimal format is used, as is recommended for IPv6-mapped IPv4 addresses (e.g. ::1111:1.1.1.1 or ::1111:8.8.8.8), the address is passed as an IPv4 value to com.sun.jndi.toolkit.url.Uri#parseCompat and the first colon misinterpreted as indicating that a port follows, resulting in a failure ot parse the port with a NumberFormatException.

      The failing parsing code was introduced in JDK-6991580, which added IPv6 nameserver support.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      IPv6-mapped IPv4 addresses written in mixed hexidecimal and dot decimal notation such as ::1111:1.1.1.1 in /etc/resolv.conf and use javax.naming.InitialContext to attempt a resolution using java.naming.provider.url set to `dns:`.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      IPv6-mapped IPv4 addresses written in mixed hexidecimal and dot decimal notation such as ::1111:1.1.1.1 in /etc/resolv.conf should be parsed as IPv6 addresses and be used successfully in DNS lookups.
      ACTUAL -
      Any mixed hexidecimal and dot decimal addresses in /etc/resolv.conf will be mis-parsed as IPv4 addresses, and a NumberFormatException will be thrown, preventing DNS lookups from succeeding.

      ---------- BEGIN SOURCE ----------
      package com.coruscations.example;

      //import com.sun.jndi.dns.DnsContext;

      import javax.naming.InitialContext;
      import javax.naming.directory.Attribute;
      import javax.naming.directory.Attributes;
      import javax.naming.directory.InitialDirContext;
      import java.util.Hashtable;
      import java.util.stream.Stream;

      public class TestJndiIpv6 {
          public static void main(final String[] args) {
              //testStream().forEach(TestJndiIpv6::testDnsContext);
              testStream().forEach(TestJndiIpv6::testInitialContext);
              testStream().forEach(TestJndiIpv6::testInitialDirContext);
          }

          private static Stream<String> testStream() {
              return Stream.of(
                      "1.1.1.1", // IPv4 address
                      "2606:4700:4700::1111", // IPv6 address
                      "[2606:4700:4700::1111]", // BSD-syle IPv6 address
                      "::ffff:1.1.1.1", // IPv6-mapped IPv4 address in format 3
                      "[::ffff:1.1.1.1]", // BSD-style IPv6-mapped IPv4 address in format 3
                      "::ffff:101:101", // BSD-style IPv6-mapped IPv4 address
                      "[::ffff:101:101]", // IPv6-mapped IPv4 address
                      // Passing an empty string will use the configuration in /etc/resolv.conf.
                      // To test the failure case, either convert an existing IPv6 address to the y:y:y:y:y:y:x.x.x.x format
                      // or use an IPv6-mapped IPv4 address -- e.g. add `nameserver ::1111:1.1.1.1` or `nameserver ::1111:8.8.8.8`.
                      ""
              );
          }

          // /**
          // * Tests DnsContext directly, but requires `--add-opens jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED` when
          // * executed in JDK 9+.
          // */
          // private static void testDnsContext(final String server) {
          // final Hashtable<Object, Object> env = new Hashtable<>();
          // env.put("java.naming.provider.url", "dns:");
          // env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
          // try {
          // final DnsContext ctx = new DnsContext(".", new String[]{server}, env);
          // ctx.lookup("example.com");
          // System.out.println("[Direct use of com.sun.jndi.dns.DnsContext] Server IP `" + server + "` succeeds.");
          // } catch (final Exception e) {
          // System.out.println("[Direct use of com.sun.jndi.dns.DnsContext] Server IP `" + server + "` fails with: " + e);
          // }
          // }

          private static void testInitialContext(final String server) {
              final Hashtable<Object, Object> env = new Hashtable<>();
              env.put("java.naming.provider.url", "dns://" + server);
              env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
              try {
                  final InitialContext ctx = new InitialContext(env);
                  ctx.lookup("example.com");
                  System.out.println("[Use of javax.naming.InitialContext]: Server IP `" + server + "` succeeds.");
              } catch (final Exception e) {
                  System.out.println("[Use of javax.naming.InitialContext]: Server IP `" + server + "` fails with: " + e);
                  e.printStackTrace();
              }
          }

          private static void testInitialDirContext(final String server) {
              final Hashtable<Object, Object> env = new Hashtable<>();
              env.put("java.naming.provider.url", "dns://" + server);
              env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
              try {
                  final InitialDirContext dirContext = new InitialDirContext(env);
                  final Attributes attributes = dirContext.getAttributes("example.com", new String[]{"A"});
                  final Attribute attribute = attributes.get("A");
                  System.out.println("[Use of javax.naming.directory.InitialDirContext]: Server IP `" + server + "` succeeds.");
              } catch (final Exception e) {
                  System.out.println("[Use of javax.naming.directory.InitialDirContext]: Server IP `" + server + "` fails with: " + e);
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Manually alter /etc/resolv.conf to use pure hexidecimal notation -- e.g. use ::1111:101:101 instead of ::1111:1.1.1.1.

      FREQUENCY : always


            michaelm Michael McMahon
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: