Skip to content

Commit

Permalink
Fix InetAddress-wrapping of long AFSocketAddresses
Browse files Browse the repository at this point in the history
Long socket addresses, such as non-ASCII addresses in the Abstract
Namespace close to the maximum length of 108 bytes may not be
representable by our custom address wrapping representation used for
InetAddress, resulting in an exception upon bind, etc.

This is caused by URL-encoding any non-printable characters, resulting
in three UTF-8 characters per byte (3*108+x > 255, an internal limit).

Introduce a fixed-length hex-encoding, which is recognizable by a
wrapped-hostname string starting with "[%%", followed by a sequence of
2-character hex values (2*108+2+x <= 255).
  • Loading branch information
kohlschuetter committed Oct 5, 2022
1 parent f8f280c commit ef283bb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Objects;

/**
Expand Down Expand Up @@ -87,6 +88,7 @@ class AFInetAddress {
};

private static final char PREFIX = '[';
private static final String MARKER_HEX_ENCODING = "%%";
static final String INETADDR_SUFFIX = ".junixsocket";

/**
Expand All @@ -111,6 +113,23 @@ static final String createUnresolvedHostname(byte[] socketAddress, AFAddressFami
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
sb.append('.');
sb.append(af.getJuxString());
sb.append(INETADDR_SUFFIX);

String str = sb.toString();

if (str.length() < 64 || str.getBytes(StandardCharsets.UTF_8).length <= 255) {
return str;
}

sb.setLength(0);
sb.append(PREFIX);
sb.append(MARKER_HEX_ENCODING);
for (int i = 0, n = socketAddress.length; i < n; i++) {
sb.append(String.format(Locale.ENGLISH, "%02x", socketAddress[i]));
}

sb.append('.');
sb.append(af.getJuxString());
sb.append(INETADDR_SUFFIX);
Expand Down Expand Up @@ -185,11 +204,26 @@ static final byte[] unwrapAddress(String hostname, AFAddressFamily<?> af) throws
}

String encodedHostname = hostname.substring(1, domDot);
try {
return URLDecoder.decode(encodedHostname, StandardCharsets.ISO_8859_1.toString()).getBytes(
StandardCharsets.ISO_8859_1);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
if (encodedHostname.startsWith(MARKER_HEX_ENCODING)) {
// Hex-only encoding
int len = encodedHostname.length();
if ((len & 1) == 1) {
throw new IllegalStateException("Length of hex-encoded wrapping must be even");
}
byte[] unwrapped = new byte[(len - 2) / 2];
for (int i = 2, n = encodedHostname.length(), o = 0; i < n; i += 2, o++) {
int v = Integer.parseInt(encodedHostname.substring(i, i + 2), 16);
unwrapped[o] = (byte) v;
}
return unwrapped;
} else {
// URL-encoding
try {
return URLDecoder.decode(encodedHostname, StandardCharsets.ISO_8859_1.toString()).getBytes(
StandardCharsets.ISO_8859_1);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,12 @@ public void testBindTrailingZeroes() throws Exception {
// any sequence of 0's -> null
testBind(AFUNIXSocketAddress.of(new byte[] {0, 0, 0}), null);
}

@Test
public void testBindLongAbstractAddress() throws Exception {
byte[] addr = new byte[108];
addr[1] = '1';
addr[79] = 'X';
testBind(AFUNIXSocketAddress.of(addr));
}
}

0 comments on commit ef283bb

Please sign in to comment.