Home | History | Annotate | Download | only in util
      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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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