1 /*
2  * Copyright (c) 2004, 2005, 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      */
textToNumericFormatV4(String src)40     public static byte[] textToNumericFormatV4(String src)
41     {
42         if (src.length() == 0) {
43             return null;
44         }
45 
46         byte[] res = new byte[INADDR4SZ];
47         String[] s = src.split("\\.", -1);
48         long val;
49         try {
50             switch(s.length) {
51             // BEGIN Android-removed
52             /*
53             case 1:
54                 // When only one part is given, the value is stored directly in
55                 // the network address without any byte rearrangement.
56 
57                 val = Long.parseLong(s[0]);
58                 if (val < 0 || val > 0xffffffffL)
59                     return null;
60                 res[0] = (byte) ((val >> 24) & 0xff);
61                 res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);
62                 res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
63                 res[3] = (byte) (val & 0xff);
64                 break;
65             case 2:
66                 // When a two part address is supplied, the last part is
67                 // interpreted as a 24-bit quantity and placed in the right
68                 // most three bytes of the network address. This makes the
69                 // two part address format convenient for specifying Class A
70                 // network addresses as net.host.
71 
72                 val = Integer.parseInt(s[0]);
73                 if (val < 0 || val > 0xff)
74                     return null;
75                 res[0] = (byte) (val & 0xff);
76                 val = Integer.parseInt(s[1]);
77                 if (val < 0 || val > 0xffffff)
78                     return null;
79                 res[1] = (byte) ((val >> 16) & 0xff);
80                 res[2] = (byte) (((val & 0xffff) >> 8) &0xff);
81                 res[3] = (byte) (val & 0xff);
82                 break;
83             case 3:
84                 //
85                 // When a three part address is specified, the last part is
86                 // interpreted as a 16-bit quantity and placed in the right
87                 // most two bytes of the network address. This makes the
88                 // three part address format convenient for specifying
89                 // Class B net- work addresses as 128.net.host.
90                 for (int i = 0; i < 2; i++) {
91                     val = Integer.parseInt(s[i]);
92                     if (val < 0 || val > 0xff)
93                         return null;
94                     res[i] = (byte) (val & 0xff);
95                 }
96                 val = Integer.parseInt(s[2]);
97                 if (val < 0 || val > 0xffff)
98                     return null;
99                 res[2] = (byte) ((val >> 8) & 0xff);
100                 res[3] = (byte) (val & 0xff);
101                 break;
102             */
103             // END Android-removed
104             case 4:
105                 /*
106                  * When four parts are specified, each is interpreted as a
107                  * byte of data and assigned, from left to right, to the
108                  * four bytes of an IPv4 address.
109                  */
110                 for (int i = 0; i < 4; i++) {
111                     val = Integer.parseInt(s[i]);
112                     if (val < 0 || val > 0xff)
113                         return null;
114                     res[i] = (byte) (val & 0xff);
115                 }
116                 break;
117             default:
118                 return null;
119             }
120         } catch(NumberFormatException e) {
121             return null;
122         }
123         return res;
124     }
125 
126     /*
127      * Convert IPv6 presentation level address to network order binary form.
128      * credit:
129      *  Converted from C code from Solaris 8 (inet_pton)
130      *
131      * Any component of the string following a per-cent % is ignored.
132      *
133      * @param src a String representing an IPv6 address in textual format
134      * @return a byte array representing the IPv6 numeric address
135      */
textToNumericFormatV6(String src)136     public static byte[] textToNumericFormatV6(String src)
137     {
138         // Shortest valid string is "::", hence at least 2 chars
139         if (src.length() < 2) {
140             return null;
141         }
142 
143         int colonp;
144         char ch;
145         boolean saw_xdigit;
146         int val;
147         char[] srcb = src.toCharArray();
148         byte[] dst = new byte[INADDR16SZ];
149 
150         int srcb_length = srcb.length;
151         int pc = src.indexOf ("%");
152         if (pc == srcb_length -1) {
153             return null;
154         }
155 
156         if (pc != -1) {
157             srcb_length = pc;
158         }
159 
160         colonp = -1;
161         int i = 0, j = 0;
162         /* Leading :: requires some special handling. */
163         if (srcb[i] == ':')
164             if (srcb[++i] != ':')
165                 return null;
166         int curtok = i;
167         saw_xdigit = false;
168         val = 0;
169         while (i < srcb_length) {
170             ch = srcb[i++];
171             int chval = Character.digit(ch, 16);
172             if (chval != -1) {
173                 val <<= 4;
174                 val |= chval;
175                 if (val > 0xffff)
176                     return null;
177                 saw_xdigit = true;
178                 continue;
179             }
180             if (ch == ':') {
181                 curtok = i;
182                 if (!saw_xdigit) {
183                     if (colonp != -1)
184                         return null;
185                     colonp = j;
186                     continue;
187                 } else if (i == srcb_length) {
188                     return null;
189                 }
190                 if (j + INT16SZ > INADDR16SZ)
191                     return null;
192                 dst[j++] = (byte) ((val >> 8) & 0xff);
193                 dst[j++] = (byte) (val & 0xff);
194                 saw_xdigit = false;
195                 val = 0;
196                 continue;
197             }
198             if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
199                 String ia4 = src.substring(curtok, srcb_length);
200                 /* check this IPv4 address has 3 dots, ie. A.B.C.D */
201                 int dot_count = 0, index=0;
202                 while ((index = ia4.indexOf ('.', index)) != -1) {
203                     dot_count ++;
204                     index ++;
205                 }
206                 if (dot_count != 3) {
207                     return null;
208                 }
209                 byte[] v4addr = textToNumericFormatV4(ia4);
210                 if (v4addr == null) {
211                     return null;
212                 }
213                 for (int k = 0; k < INADDR4SZ; k++) {
214                     dst[j++] = v4addr[k];
215                 }
216                 saw_xdigit = false;
217                 break;  /* '\0' was seen by inet_pton4(). */
218             }
219             return null;
220         }
221         if (saw_xdigit) {
222             if (j + INT16SZ > INADDR16SZ)
223                 return null;
224             dst[j++] = (byte) ((val >> 8) & 0xff);
225             dst[j++] = (byte) (val & 0xff);
226         }
227 
228         if (colonp != -1) {
229             int n = j - colonp;
230 
231             if (j == INADDR16SZ)
232                 return null;
233             for (i = 1; i <= n; i++) {
234                 dst[INADDR16SZ - i] = dst[colonp + n - i];
235                 dst[colonp + n - i] = 0;
236             }
237             j = INADDR16SZ;
238         }
239         if (j != INADDR16SZ)
240             return null;
241         byte[] newdst = convertFromIPv4MappedAddress(dst);
242         if (newdst != null) {
243             return newdst;
244         } else {
245             return dst;
246         }
247     }
248 
249     /**
250      * @param src a String representing an IPv4 address in textual format
251      * @return a boolean indicating whether src is an IPv4 literal address
252      */
isIPv4LiteralAddress(String src)253     public static boolean isIPv4LiteralAddress(String src) {
254         return textToNumericFormatV4(src) != null;
255     }
256 
257     /**
258      * @param src a String representing an IPv6 address in textual format
259      * @return a boolean indicating whether src is an IPv6 literal address
260      */
isIPv6LiteralAddress(String src)261     public static boolean isIPv6LiteralAddress(String src) {
262         return textToNumericFormatV6(src) != null;
263     }
264 
265     /*
266      * Convert IPv4-Mapped address to IPv4 address. Both input and
267      * returned value are in network order binary form.
268      *
269      * @param src a String representing an IPv4-Mapped address in textual format
270      * @return a byte array representing the IPv4 numeric address
271      */
convertFromIPv4MappedAddress(byte[] addr)272     public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
273         if (isIPv4MappedAddress(addr)) {
274             byte[] newAddr = new byte[INADDR4SZ];
275             System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
276             return newAddr;
277         }
278         return null;
279     }
280 
281     /**
282      * Utility routine to check if the InetAddress is an
283      * IPv4 mapped IPv6 address.
284      *
285      * @return a <code>boolean</code> indicating if the InetAddress is
286      * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
287      */
isIPv4MappedAddress(byte[] addr)288     private static boolean isIPv4MappedAddress(byte[] addr) {
289         if (addr.length < INADDR16SZ) {
290             return false;
291         }
292         if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
293             (addr[2] == 0x00) && (addr[3] == 0x00) &&
294             (addr[4] == 0x00) && (addr[5] == 0x00) &&
295             (addr[6] == 0x00) && (addr[7] == 0x00) &&
296             (addr[8] == 0x00) && (addr[9] == 0x00) &&
297             (addr[10] == (byte)0xff) &&
298             (addr[11] == (byte)0xff))  {
299             return true;
300         }
301         return false;
302     }
303 }
304