-
Bug
-
Resolution: Unresolved
-
P4
-
8, 11, 17, 21, 22
-
generic
-
generic
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 inJDK-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
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
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
- relates to
-
JDK-6991580 IPv6 Nameservers in resolv.conf throws NumberFormatException
-
- Resolved
-