1 /*
2  * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.net.util;
27 
28 public class IPAddressUtil {
29     private final static int INADDR4SZ = 4;
30     private final static int INADDR16SZ = 16;
31     private final static int INT16SZ = 2;
32 
33     /*
34      * Converts IPv4 address in its textual presentation form
35      * into its numeric binary form.
36      *
37      * @param src a String representing an IPv4 address in standard format
38      * @return a byte array representing the IPv4 numeric address
39      */
40     @SuppressWarnings("fallthrough")
textToNumericFormatV4(String src)41     public static byte[] textToNumericFormatV4(String src)
42     {
43         byte[] res = new byte[INADDR4SZ];
44 
45         long tmpValue = 0;
46         int currByte = 0;
47         boolean newOctet = true;
48 
49         int len = src.length();
50         if (len == 0 || len > 15) {
51             return null;
52         }
53         /*
54          * When only one part is given, the value is stored directly in
55          * the network address without any byte rearrangement.
56          *
57          * When a two part address is supplied, the last part is
58          * interpreted as a 24-bit quantity and placed in the right
59          * most three bytes of the network address. This makes the
60          * two part address format convenient for specifying Class A
61          * network addresses as net.host.
62          *
63          * When a three part address is specified, the last part is
64          * interpreted as a 16-bit quantity and placed in the right
65          * most two bytes of the network address. This makes the
66          * three part address format convenient for specifying
67          * Class B net- work addresses as 128.net.host.
68          *
69          * When four parts are specified, each is interpreted as a
70          * byte of data and assigned, from left to right, to the
71          * four bytes of an IPv4 address.
72          *
73          * We determine and parse the leading parts, if any, as single
74          * byte values in one pass directly into the resulting byte[],
75          * then the remainder is treated as a 8-to-32-bit entity and
76          * translated into the remaining bytes in the array.
77          */
78         for (int i = 0; i < len; i++) {
79             char c = src.charAt(i);
80             if (c == '.') {
81                 if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
82                     return null;
83                 }
84                 res[currByte++] = (byte) (tmpValue & 0xff);
85                 tmpValue = 0;
86                 newOctet = true;
87             } else {
88                 int digit = Character.digit(c, 10);
89                 if (digit < 0) {
90                     return null;
91                 }
92                 tmpValue *= 10;
93                 tmpValue += digit;
94                 newOctet = false;
95             }
96         }
97         if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
98             return null;
99         }
100         switch (currByte) {
101             // BEGIN Android-changed: Require all four parts to be given for an IPv4 address.
102             /*
103             case 0:
104                 res[0] = (byte) ((tmpValue >> 24) & 0xff);
105             case 1:
106                 res[1] = (byte) ((tmpValue >> 16) & 0xff);
107             case 2:
108                 res[2] = (byte) ((tmpValue >>  8) & 0xff);
109             */
110             case 0:
111             case 1:
112             case 2:
113                 return null;
114             // END Android-changed: Require all four parts to be given for an IPv4 address.
115             case 3:
116                 res[3] = (byte) ((tmpValue >>  0) & 0xff);
117         }
118         return res;
119     }
120 
121     /*
122      * Convert IPv6 presentation level address to network order binary form.
123      * credit:
124      *  Converted from C code from Solaris 8 (inet_pton)
125      *
126      * Any component of the string following a per-cent % is ignored.
127      *
128      * @param src a String representing an IPv6 address in textual format
129      * @return a byte array representing the IPv6 numeric address
130      */
textToNumericFormatV6(String src)131     public static byte[] textToNumericFormatV6(String src)
132     {
133         // Shortest valid string is "::", hence at least 2 chars
134         if (src.length() < 2) {
135             return null;
136         }
137 
138         int colonp;
139         char ch;
140         boolean saw_xdigit;
141         int val;
142         char[] srcb = src.toCharArray();
143         byte[] dst = new byte[INADDR16SZ];
144 
145         int srcb_length = srcb.length;
146         int pc = src.indexOf ("%");
147         if (pc == srcb_length -1) {
148             return null;
149         }
150 
151         if (pc != -1) {
152             srcb_length = pc;
153         }
154 
155         colonp = -1;
156         int i = 0, j = 0;
157         /* Leading :: requires some special handling. */
158         if (srcb[i] == ':')
159             if (srcb[++i] != ':')
160                 return null;
161         int curtok = i;
162         saw_xdigit = false;
163         val = 0;
164         while (i < srcb_length) {
165             ch = srcb[i++];
166             int chval = Character.digit(ch, 16);
167             if (chval != -1) {
168                 val <<= 4;
169                 val |= chval;
170                 if (val > 0xffff)
171                     return null;
172                 saw_xdigit = true;
173                 continue;
174             }
175             if (ch == ':') {
176                 curtok = i;
177                 if (!saw_xdigit) {
178                     if (colonp != -1)
179                         return null;
180                     colonp = j;
181                     continue;
182                 } else if (i == srcb_length) {
183                     return null;
184                 }
185                 if (j + INT16SZ > INADDR16SZ)
186                     return null;
187                 dst[j++] = (byte) ((val >> 8) & 0xff);
188                 dst[j++] = (byte) (val & 0xff);
189                 saw_xdigit = false;
190                 val = 0;
191                 continue;
192             }
193             if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
194                 String ia4 = src.substring(curtok, srcb_length);
195                 /* check this IPv4 address has 3 dots, ie. A.B.C.D */
196                 int dot_count = 0, index=0;
197                 while ((index = ia4.indexOf ('.', index)) != -1) {
198                     dot_count ++;
199                     index ++;
200                 }
201                 if (dot_count != 3) {
202                     return null;
203                 }
204                 byte[] v4addr = textToNumericFormatV4(ia4);
205                 if (v4addr == null) {
206                     return null;
207                 }
208                 for (int k = 0; k < INADDR4SZ; k++) {
209                     dst[j++] = v4addr[k];
210                 }
211                 saw_xdigit = false;
212                 break;  /* '\0' was seen by inet_pton4(). */
213             }
214             return null;
215         }
216         if (saw_xdigit) {
217             if (j + INT16SZ > INADDR16SZ)
218                 return null;
219             dst[j++] = (byte) ((val >> 8) & 0xff);
220             dst[j++] = (byte) (val & 0xff);
221         }
222 
223         if (colonp != -1) {
224             int n = j - colonp;
225 
226             if (j == INADDR16SZ)
227                 return null;
228             for (i = 1; i <= n; i++) {
229                 dst[INADDR16SZ - i] = dst[colonp + n - i];
230                 dst[colonp + n - i] = 0;
231             }
232             j = INADDR16SZ;
233         }
234         if (j != INADDR16SZ)
235             return null;
236         byte[] newdst = convertFromIPv4MappedAddress(dst);
237         if (newdst != null) {
238             return newdst;
239         } else {
240             return dst;
241         }
242     }
243 
244     /**
245      * @param src a String representing an IPv4 address in textual format
246      * @return a boolean indicating whether src is an IPv4 literal address
247      */
isIPv4LiteralAddress(String src)248     public static boolean isIPv4LiteralAddress(String src) {
249         return textToNumericFormatV4(src) != null;
250     }
251 
252     /**
253      * @param src a String representing an IPv6 address in textual format
254      * @return a boolean indicating whether src is an IPv6 literal address
255      */
isIPv6LiteralAddress(String src)256     public static boolean isIPv6LiteralAddress(String src) {
257         return textToNumericFormatV6(src) != null;
258     }
259 
260     /*
261      * Convert IPv4-Mapped address to IPv4 address. Both input and
262      * returned value are in network order binary form.
263      *
264      * @param src a String representing an IPv4-Mapped address in textual format
265      * @return a byte array representing the IPv4 numeric address
266      */
convertFromIPv4MappedAddress(byte[] addr)267     public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
268         if (isIPv4MappedAddress(addr)) {
269             byte[] newAddr = new byte[INADDR4SZ];
270             System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
271             return newAddr;
272         }
273         return null;
274     }
275 
276     /**
277      * Utility routine to check if the InetAddress is an
278      * IPv4 mapped IPv6 address.
279      *
280      * @return a <code>boolean</code> indicating if the InetAddress is
281      * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
282      */
isIPv4MappedAddress(byte[] addr)283     private static boolean isIPv4MappedAddress(byte[] addr) {
284         if (addr.length < INADDR16SZ) {
285             return false;
286         }
287         if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
288             (addr[2] == 0x00) && (addr[3] == 0x00) &&
289             (addr[4] == 0x00) && (addr[5] == 0x00) &&
290             (addr[6] == 0x00) && (addr[7] == 0x00) &&
291             (addr[8] == 0x00) && (addr[9] == 0x00) &&
292             (addr[10] == (byte)0xff) &&
293             (addr[11] == (byte)0xff))  {
294             return true;
295         }
296         return false;
297     }
298 }
299