3434public 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 ;
0 commit comments