Mega Code Archive

 
Categories / Java / Network Protocol
 

Convert IPv6 presentation level address to network order binary form

/*  * Copyright 2004-2005 Sun Microsystems, Inc.  All Rights Reserved.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.  *  * This code is free software; you can redistribute it and/or modify it  * under the terms of the GNU General Public License version 2 only, as  * published by the Free Software Foundation.  Sun designates this  * particular file as subject to the "Classpath" exception as provided  * by Sun in the LICENSE file that accompanied this code.  *  * This code is distributed in the hope that it will be useful, but WITHOUT  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License  * version 2 for more details (a copy is included in the LICENSE file that  * accompanied this code).  *  * You should have received a copy of the GNU General Public License version  * 2 along with this work; if not, write to the Free Software Foundation,  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  *  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,  * CA 95054 USA or visit www.sun.com if you need additional information or  * have any questions.  */ //package sun.net.util; public class IPAddressUtil {     private final static int INADDR4SZ = 4;     private final static int INADDR16SZ = 16;     private final static int INT16SZ = 2;     /*      * Converts IPv4 address in its textual presentation form      * into its numeric binary form.      *      * @param src a String representing an IPv4 address in standard format      * @return a byte array representing the IPv4 numeric address      */     public static byte[] textToNumericFormatV4(String src)     {         if (src.length() == 0) {             return null;         }         byte[] res = new byte[INADDR4SZ];         String[] s = src.split("\\.", -1);         long val;         try {             switch(s.length) {             case 1:                 /*                  * When only one part is given, the value is stored directly in                  * the network address without any byte rearrangement.                  */                 val = Long.parseLong(s[0]);                 if (val < 0 || val > 0xffffffffL)                     return null;                 res[0] = (byte) ((val >> 24) & 0xff);                 res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);                 res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);                 res[3] = (byte) (val & 0xff);                 break;             case 2:                 /*                  * When a two part address is supplied, the last part is                  * interpreted as a 24-bit quantity and placed in the right                  * most three bytes of the network address. This makes the                  * two part address format convenient for specifying Class A                  * network addresses as net.host.                  */                 val = Integer.parseInt(s[0]);                 if (val < 0 || val > 0xff)                     return null;                 res[0] = (byte) (val & 0xff);                 val = Integer.parseInt(s[1]);                 if (val < 0 || val > 0xffffff)                     return null;                 res[1] = (byte) ((val >> 16) & 0xff);                 res[2] = (byte) (((val & 0xffff) >> 8) &0xff);                 res[3] = (byte) (val & 0xff);                 break;             case 3:                 /*                  * When a three part address is specified, the last part is                  * interpreted as a 16-bit quantity and placed in the right                  * most two bytes of the network address. This makes the                  * three part address format convenient for specifying                  * Class B net- work addresses as 128.net.host.                  */                 for (int i = 0; i < 2; i++) {                     val = Integer.parseInt(s[i]);                     if (val < 0 || val > 0xff)                         return null;                     res[i] = (byte) (val & 0xff);                 }                 val = Integer.parseInt(s[2]);                 if (val < 0 || val > 0xffff)                     return null;                 res[2] = (byte) ((val >> 8) & 0xff);                 res[3] = (byte) (val & 0xff);                 break;             case 4:                 /*                  * When four parts are specified, each is interpreted as a                  * byte of data and assigned, from left to right, to the                  * four bytes of an IPv4 address.                  */                 for (int i = 0; i < 4; i++) {                     val = Integer.parseInt(s[i]);                     if (val < 0 || val > 0xff)                         return null;                     res[i] = (byte) (val & 0xff);                 }                 break;             default:                 return null;             }         } catch(NumberFormatException e) {             return null;         }         return res;     }     /*      * Convert IPv6 presentation level address to network order binary form.      * credit:      *  Converted from C code from Solaris 8 (inet_pton)      *      * Any component of the string following a per-cent % is ignored.      *      * @param src a String representing an IPv6 address in textual format      * @return a byte array representing the IPv6 numeric address      */     public static byte[] textToNumericFormatV6(String src)     {         // Shortest valid string is "::", hence at least 2 chars         if (src.length() < 2) {             return null;         }         int colonp;         char ch;         boolean saw_xdigit;         int val;         char[] srcb = src.toCharArray();         byte[] dst = new byte[INADDR16SZ];         int srcb_length = srcb.length;         int pc = src.indexOf ("%");         if (pc == srcb_length -1) {             return null;         }         if (pc != -1) {             srcb_length = pc;         }         colonp = -1;         int i = 0, j = 0;         /* Leading :: requires some special handling. */         if (srcb[i] == ':')             if (srcb[++i] != ':')                 return null;         int curtok = i;         saw_xdigit = false;         val = 0;         while (i < srcb_length) {             ch = srcb[i++];             int chval = Character.digit(ch, 16);             if (chval != -1) {                 val <<= 4;                 val |= chval;                 if (val > 0xffff)                     return null;                 saw_xdigit = true;                 continue;             }             if (ch == ':') {                 curtok = i;                 if (!saw_xdigit) {                     if (colonp != -1)                         return null;                     colonp = j;                     continue;                 } else if (i == srcb_length) {                     return null;                 }                 if (j + INT16SZ > INADDR16SZ)                     return null;                 dst[j++] = (byte) ((val >> 8) & 0xff);                 dst[j++] = (byte) (val & 0xff);                 saw_xdigit = false;                 val = 0;                 continue;             }             if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {                 String ia4 = src.substring(curtok, srcb_length);                 /* check this IPv4 address has 3 dots, ie. A.B.C.D */                 int dot_count = 0, index=0;                 while ((index = ia4.indexOf ('.', index)) != -1) {                     dot_count ++;                     index ++;                 }                 if (dot_count != 3) {                     return null;                 }                 byte[] v4addr = textToNumericFormatV4(ia4);                 if (v4addr == null) {                     return null;                 }                 for (int k = 0; k < INADDR4SZ; k++) {                     dst[j++] = v4addr[k];                 }                 saw_xdigit = false;                 break;  /* '\0' was seen by inet_pton4(). */             }             return null;         }         if (saw_xdigit) {             if (j + INT16SZ > INADDR16SZ)                 return null;             dst[j++] = (byte) ((val >> 8) & 0xff);             dst[j++] = (byte) (val & 0xff);         }         if (colonp != -1) {             int n = j - colonp;             if (j == INADDR16SZ)                 return null;             for (i = 1; i <= n; i++) {                 dst[INADDR16SZ - i] = dst[colonp + n - i];                 dst[colonp + n - i] = 0;             }             j = INADDR16SZ;         }         if (j != INADDR16SZ)             return null;         byte[] newdst = convertFromIPv4MappedAddress(dst);         if (newdst != null) {             return newdst;         } else {             return dst;         }     }     /*      * Convert IPv4-Mapped address to IPv4 address. Both input and      * returned value are in network order binary form.      *      * @param src a String representing an IPv4-Mapped address in textual format      * @return a byte array representing the IPv4 numeric address      */     public static byte[] convertFromIPv4MappedAddress(byte[] addr) {         if (isIPv4MappedAddress(addr)) {             byte[] newAddr = new byte[INADDR4SZ];             System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);             return newAddr;         }         return null;     }     /**      * Utility routine to check if the InetAddress is an      * IPv4 mapped IPv6 address.      *      * @return a <code>boolean</code> indicating if the InetAddress is      * an IPv4 mapped IPv6 address; or false if address is IPv4 address.      */     private static boolean isIPv4MappedAddress(byte[] addr) {         if (addr.length < INADDR16SZ) {             return false;         }         if ((addr[0] == 0x00) && (addr[1] == 0x00) &&             (addr[2] == 0x00) && (addr[3] == 0x00) &&             (addr[4] == 0x00) && (addr[5] == 0x00) &&             (addr[6] == 0x00) && (addr[7] == 0x00) &&             (addr[8] == 0x00) && (addr[9] == 0x00) &&             (addr[10] == (byte)0xff) &&             (addr[11] == (byte)0xff))  {             return true;         }         return false;     } }