Skip to content

Commit

Permalink
Don't strip scopeId when resolving ipv6 address (#12019)
Browse files Browse the repository at this point in the history
Motivation:

Due a bug we did strip the scopeId of the ipv6 address string when using the DnsNameResolver. This could later then result to things like "No Route to host" exceptions.

Modifications:

- Add new method to NetUtil which will create the InetAddress for an string that contains an ip while still preserve the scopeId.
- Use this new method
- Add unit tests.

Result:

Fixes #11563
  • Loading branch information
normanmaurer committed Jan 19, 2022
1 parent bc946b0 commit e7d5844
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 6 deletions.
53 changes: 53 additions & 0 deletions common/src/main/java/io/netty/util/NetUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,59 @@ public static byte[] createByteArrayFromIpAddressString(String ipAddressString)
return null;
}

/**
* Creates an {@link InetAddress} based on an ipAddressString or might return null if it can't be parsed.
* No error handling is performed here.
*/
public static InetAddress createInetAddressFromIpAddressString(String ipAddressString) {
if (isValidIpV4Address(ipAddressString)) {
byte[] bytes = validIpV4ToBytes(ipAddressString);
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
// Should never happen!
throw new IllegalStateException(e);
}
}

if (isValidIpV6Address(ipAddressString)) {
if (ipAddressString.charAt(0) == '[') {
ipAddressString = ipAddressString.substring(1, ipAddressString.length() - 1);
}

int percentPos = ipAddressString.indexOf('%');
if (percentPos >= 0) {
try {
int scopeId = Integer.parseInt(ipAddressString.substring(percentPos + 1));
ipAddressString = ipAddressString.substring(0, percentPos);
byte[] bytes = getIPv6ByName(ipAddressString, true);
if (bytes == null) {
return null;
}
try {
return Inet6Address.getByAddress(null, bytes, scopeId);
} catch (UnknownHostException e) {
// Should never happen!
throw new IllegalStateException(e);
}
} catch (NumberFormatException e) {
return null;
}
}
byte[] bytes = getIPv6ByName(ipAddressString, true);
if (bytes == null) {
return null;
}
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
// Should never happen!
throw new IllegalStateException(e);
}
}
return null;
}

private static int decimalDigit(String str, int pos) {
return str.charAt(pos) - '0';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -902,10 +902,10 @@ protected void doResolve(String inetHost,
promise.setSuccess(loopbackAddress());
return;
}
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost);
if (bytes != null) {
final InetAddress address = NetUtil.createInetAddressFromIpAddressString(inetHost);
if (address != null) {
// The inetHost is actually an ipaddress.
promise.setSuccess(InetAddress.getByAddress(bytes));
promise.setSuccess(address);
return;
}

Expand Down Expand Up @@ -1004,10 +1004,10 @@ protected void doResolveAll(String inetHost,
promise.setSuccess(Collections.singletonList(loopbackAddress()));
return;
}
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost);
if (bytes != null) {
final InetAddress address = NetUtil.createInetAddressFromIpAddressString(inetHost);
if (address != null) {
// The unresolvedAddress was created via a String that contains an ipaddress.
promise.setSuccess(Collections.singletonList(InetAddress.getByAddress(bytes)));
promise.setSuccess(Collections.singletonList(address));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import java.io.InputStream;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
Expand Down Expand Up @@ -3470,4 +3471,96 @@ private static void assertNotEmptyAndRelease(Future<List<DnsRecord>> recordsFutu
ReferenceCountUtil.release(record);
}
}

@Test
public void testResolveIpv6WithScopeId() throws Exception {
testResolveIpv6WithScopeId0(false);
}

@Test
public void testResolveAllIpv6WithScopeId() throws Exception {
testResolveIpv6WithScopeId0(true);
}

private void testResolveIpv6WithScopeId0(boolean resolveAll) throws Exception {
DnsNameResolver resolver = newResolver().build();
String address = "fe80:0:0:0:1c31:d1d1:4824:72a9";
int scopeId = 15;
String addressString = address + '%' + scopeId;
byte[] bytes = NetUtil.createByteArrayFromIpAddressString(address);
Inet6Address inet6Address = Inet6Address.getByAddress(null, bytes, scopeId);
try {
final InetAddress addr;
if (resolveAll) {
List<InetAddress> addressList = resolver.resolveAll(addressString).getNow();
assertEquals(1, addressList.size());
addr = addressList.get(0);
} else {
addr = resolver.resolve(addressString).getNow();
}
assertEquals(inet6Address, addr);
} finally {
resolver.close();
}
}

@Test
public void testResolveIpv6WithoutScopeId() throws Exception {
testResolveIpv6WithoutScopeId0(false);
}

@Test
public void testResolveAllIpv6WithoutScopeId() throws Exception {
testResolveIpv6WithoutScopeId0(true);
}

private void testResolveIpv6WithoutScopeId0(boolean resolveAll) throws Exception {
DnsNameResolver resolver = newResolver().build();
String addressString = "fe80:0:0:0:1c31:d1d1:4824:72a9";
byte[] bytes = NetUtil.createByteArrayFromIpAddressString(addressString);
Inet6Address inet6Address = (Inet6Address) InetAddress.getByAddress(bytes);
try {
final InetAddress addr;
if (resolveAll) {
List<InetAddress> addressList = resolver.resolveAll(addressString).getNow();
assertEquals(1, addressList.size());
addr = addressList.get(0);
} else {
addr = resolver.resolve(addressString).getNow();
}
assertEquals(inet6Address, addr);
} finally {
resolver.close();
}
}

@Test
public void testResolveIp4() throws Exception {
testResolveIp4(false);
}

@Test
public void testResolveAllIp4() throws Exception {
testResolveIp4(true);
}

private void testResolveIp4(boolean resolveAll) throws Exception {
DnsNameResolver resolver = newResolver().build();
String addressString = "10.0.0.1";
byte[] bytes = NetUtil.createByteArrayFromIpAddressString(addressString);
InetAddress inetAddress = InetAddress.getByAddress(bytes);
try {
final InetAddress addr;
if (resolveAll) {
List<InetAddress> addressList = resolver.resolveAll(addressString).getNow();
assertEquals(1, addressList.size());
addr = addressList.get(0);
} else {
addr = resolver.resolve(addressString).getNow();
}
assertEquals(inetAddress, addr);
} finally {
resolver.close();
}
}
}

0 comments on commit e7d5844

Please sign in to comment.