Skip to content

Commit 349792d

Browse files
committed
Address review comments
1 parent bfe7c62 commit 349792d

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

server/src/main/java/org/elasticsearch/common/network/InetAddresses.java

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@
3434
public class InetAddresses {
3535
private static final int IPV4_PART_COUNT = 4;
3636
private static final int IPV6_PART_COUNT = 8;
37+
private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
3738

3839
public static boolean isInetAddress(String ipString) {
39-
XContentString.UTF8Bytes bytes = new Text(ipString).bytes();
40-
return ipStringToBytes(bytes.bytes(), bytes.offset(), bytes.length(), false) != null;
40+
byte[] utf8Bytes = ipString.getBytes(StandardCharsets.UTF_8);
41+
return ipStringToBytes(utf8Bytes, 0, utf8Bytes.length, false) != null;
4142
}
4243

4344
public static String getIpOrHost(String ipString) {
44-
XContentString.UTF8Bytes utf8Bytes = new Text(ipString).bytes();
45-
byte[] bytes = ipStringToBytes(utf8Bytes.bytes(), utf8Bytes.offset(), utf8Bytes.length(), false);
45+
byte[] utf8Bytes = ipString.getBytes(StandardCharsets.UTF_8);
46+
byte[] bytes = ipStringToBytes(utf8Bytes, 0, utf8Bytes.length, false);
4647
if (bytes == null) { // is not InetAddress
4748
return ipString;
4849
}
@@ -67,21 +68,32 @@ public static byte[] encodeAsIpv6(XContentString ipString) {
6768
return CIDRUtils.encode(address);
6869
}
6970

71+
/**
72+
* Converts an IP address string to a byte array.
73+
* <p>
74+
* This method supports both IPv4 and IPv6 addresses, including dotted quad notation for IPv6.
75+
*
76+
* @param ipUtf8 the IP address as a byte array in UTF-8 encoding
77+
* @param offset the starting index in the byte array
78+
* @param length the length of the IP address string
79+
* @param asIpv6 if true, always returns a 16-byte array (IPv6 format), otherwise returns a 4-byte array for IPv4
80+
* @return a byte array representing the IP address, or null if the input is invalid
81+
*/
7082
private static byte[] ipStringToBytes(byte[] ipUtf8, int offset, int length, boolean asIpv6) {
7183
// Make a first pass to categorize the characters in this string.
72-
boolean hasColon = false;
84+
int indexOfLastColon = -1;
7385
boolean hasDot = false;
7486
for (int i = offset; i < offset + length; i++) {
7587
byte c = ipUtf8[i];
76-
if ((c & 0b10000000) != 0) {
88+
if ((c & 0x80) != 0) {
7789
return null; // Only allow ASCII characters.
7890
} else if (c == '.') {
7991
hasDot = true;
8092
} else if (c == ':') {
8193
if (hasDot) {
8294
return null; // Colons must not appear after dots.
8395
}
84-
hasColon = true;
96+
indexOfLastColon = i;
8597
} else if (c == '%') {
8698
if (i == offset + length - 1) {
8799
return null; // Filter out strings that end in % and have an empty scope ID.
@@ -92,9 +104,9 @@ private static byte[] ipStringToBytes(byte[] ipUtf8, int offset, int length, boo
92104
}
93105

94106
// Now decide which address family to parse.
95-
if (hasColon) {
107+
if (indexOfLastColon >= 0) {
96108
if (hasDot) {
97-
ipUtf8 = convertDottedQuadToHex(ipUtf8, offset, length);
109+
ipUtf8 = convertDottedQuadToHex(ipUtf8, offset, length, indexOfLastColon);
98110
if (ipUtf8 == null) {
99111
return null;
100112
}
@@ -108,20 +120,16 @@ private static byte[] ipStringToBytes(byte[] ipUtf8, int offset, int length, boo
108120
return null;
109121
}
110122

111-
private static byte[] convertDottedQuadToHex(byte[] ipUtf8, int offset, int length) {
112-
int quadOffset = -1;
113-
for (int i = 0; i < length; i++) {
114-
if (ipUtf8[i + offset] == ':') {
115-
quadOffset = i + 1;
116-
}
117-
}
123+
private static byte[] convertDottedQuadToHex(byte[] ipUtf8, int offset, int length, int indexOfLastColon) {
124+
int quadOffset = indexOfLastColon - offset + 1; // +1 to include the colon
118125
assert quadOffset >= 0 : "Expected at least one colon in dotted quad IPv6 address";
119126
byte[] quad = textToNumericFormatV4(ipUtf8, offset + quadOffset, length - quadOffset, false);
120127
if (quad == null) {
121128
return null;
122129
}
123-
byte[] penultimate = Integer.toHexString(((quad[0] & 0xff) << 8) | (quad[1] & 0xff)).getBytes(StandardCharsets.US_ASCII);
124-
byte[] ultimate = Integer.toHexString(((quad[2] & 0xff) << 8) | (quad[3] & 0xff)).getBytes(StandardCharsets.US_ASCII);
130+
byte[] penultimate = toHexBytes(((quad[0] & 0xff) << 8) | (quad[1] & 0xff));
131+
byte[] ultimate = toHexBytes(((quad[2] & 0xff) << 8) | (quad[3] & 0xff));
132+
// initialPart + penultimate + ":" + ultimate
125133
byte[] result = new byte[quadOffset + penultimate.length + 1 + ultimate.length];
126134
System.arraycopy(ipUtf8, offset, result, 0, quadOffset);
127135
System.arraycopy(penultimate, 0, result, quadOffset, penultimate.length);
@@ -130,6 +138,17 @@ private static byte[] convertDottedQuadToHex(byte[] ipUtf8, int offset, int leng
130138
return result;
131139
}
132140

141+
static byte[] toHexBytes(int val) {
142+
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
143+
int length = Math.max(((mag + 3) / 4), 1);
144+
byte[] result = new byte[length];
145+
for (int i = length - 1; i >= 0; i--) {
146+
result[i] = (byte) HEX_DIGITS[val & 0xf];
147+
val >>>= 4;
148+
}
149+
return result;
150+
}
151+
133152
private static byte[] textToNumericFormatV4(byte[] ipUtf8, int offset, int length, boolean asIpv6) {
134153
byte[] bytes;
135154
byte octet;

server/src/test/java/org/elasticsearch/common/network/InetAddressesTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.net.UnknownHostException;
2828
import java.nio.charset.StandardCharsets;
2929
import java.util.Enumeration;
30+
import java.util.stream.IntStream;
3031

3132
import static org.hamcrest.Matchers.equalTo;
3233

@@ -259,4 +260,11 @@ public void testEncodeAsIpv6() throws Exception {
259260
InetAddresses.toAddrString(InetAddress.getByAddress(InetAddresses.encodeAsIpv6(new Text("192.168.0.0"))))
260261
);
261262
}
263+
264+
public void testToHexBytes() {
265+
IntStream.generate(ESTestCase::randomInt).limit(256).forEach(i -> {
266+
byte[] bytes = InetAddresses.toHexBytes(i);
267+
assertArrayEquals(Integer.toHexString(i).getBytes(StandardCharsets.US_ASCII), bytes);
268+
});
269+
}
262270
}

0 commit comments

Comments
 (0)