1 /* 2 * Copyright 2005 University Corporation for Advanced Internet Development, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.opensaml.xml.util; 18 19 import java.net.InetAddress; 20 import java.net.UnknownHostException; 21 22 import org.slf4j.Logger; 23 import org.slf4j.LoggerFactory; 24 25 /** Helper class for working with IP address data. */ 26 public final class IPAddressHelper { 27 28 /** Constructor. */ 29 private IPAddressHelper() { 30 31 } 32 33 /** 34 * Convert the byte array representation of an IP address into a string. Supports IPv4 and IPv6 addresses. 35 * Supports optional subnet mask stored within the same byte array. If the latter is present, 36 * output will be: "ipAddr/mask". 37 * 38 * @param address IP address in byte array form (in network byte order) 39 * @return IP address as a string, or null if can not be processed 40 */ 41 public static String addressToString(byte[] address) { 42 Logger log = getLogger(); 43 if (isIPv4(address)) { 44 return ipv4ToString(address); 45 } else if (isIPv6(address)) { 46 return ipv6ToString(address); 47 } else { 48 log.error("IP address byte array was an invalid length: {}", address.length); 49 return null; 50 } 51 } 52 53 /** 54 * Convert the byte array representation of an IPv4 address into a string. 55 * Supports optional subnet mask stored within the same byte array. If the latter is present, 56 * output will be: "ipAddr/mask". 57 * 58 * @param address IP address in byte array form (in network byte order) 59 * @return IP address as a string, or null if can not be processed 60 */ 61 private static String ipv4ToString(byte[] address) { 62 Logger log = getLogger(); 63 // This code was modeled after similar code in Sun's sun.security.x509.IPAddressName, 64 // used by sun.security.x509.X509CertImpl. 65 StringBuilder builder = new StringBuilder(); 66 byte[] ip = new byte[4]; 67 System.arraycopy(address, 0, ip, 0, 4); 68 try { 69 builder.append(InetAddress.getByAddress(ip).getHostAddress()); 70 } catch (UnknownHostException e) { 71 // Thrown if address is illegal length. 72 // Can't happen, we know that address is the right length. 73 log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); 74 return null; 75 } 76 77 if(hasMask(address)) { 78 byte[] mask = new byte[4]; 79 System.arraycopy(address, 4, mask, 0, 4); 80 builder.append("/"); 81 try { 82 builder.append(InetAddress.getByAddress(mask).getHostAddress()); 83 } catch (UnknownHostException e) { 84 // Thrown if address is illegal length. 85 // Can't happen, we know that address is the right length. 86 log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); 87 return null; 88 } 89 } 90 return builder.toString(); 91 } 92 93 /** 94 * Convert the byte array representation of an IPv6 address into a string. 95 * Supports optional subnet mask stored within the same byte array. If the latter is present, 96 * output will be: "ipAddr/mask". 97 * 98 * @param address IP address in byte array form (in network byte order) 99 * @return IP address as a string, or null if can not be processed 100 */ 101 private static String ipv6ToString(byte[] address) { 102 Logger log = getLogger(); 103 // This code was modeled after similar code in Sun's sun.security.x509.IPAddressName, 104 // used by sun.security.x509.X509CertImpl. 105 StringBuilder builder = new StringBuilder(); 106 byte[] ip = new byte[16]; 107 System.arraycopy(address, 0, ip, 0, 16); 108 try { 109 builder.append(InetAddress.getByAddress(ip).getHostAddress()); 110 } catch (UnknownHostException e) { 111 // Thrown if address is illegal length. 112 // Can't happen, we know that address is the right length. 113 log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); 114 return null; 115 } 116 117 if(hasMask(address)) { 118 log.error("IPv6 subnet masks are currently unsupported"); 119 return null; 120 /* 121 byte[] mask = new byte[16]; 122 for(int i = 16; i < 32; i++) { 123 mask[i - 16] = address[i]; 124 } 125 126 // TODO need to process bitmask array 127 // to determine and validate subnet mask 128 BitArray bitarray = new BitArray(128, mask); 129 int j; 130 for (j = 0; j < 128 && bitarray.get(j); j++); 131 builder.append("/"); 132 builder.append(j).toString(); 133 for (; j < 128; j++) { 134 if (bitarray.get(j)) { 135 log.error("Invalid IPv6 subdomain: set bit " + j + " not contiguous"); 136 return null; 137 } 138 } 139 */ 140 } 141 return builder.toString(); 142 } 143 144 145 /** 146 * Check whether IP address array is IPv4. 147 * 148 * @param address IP address byte array 149 * @return true if IPv4, false otherwise 150 */ 151 public static boolean isIPv4(byte[] address) { 152 return address.length == 4 || address.length == 8; 153 } 154 155 /** 156 * Check whether IP address array is IPv6. 157 * 158 * @param address IP address byte array 159 * @return true if IPv6, false otherwise 160 */ 161 public static boolean isIPv6(byte[] address) { 162 return address.length == 16 || address.length == 32; 163 } 164 165 /** 166 * Check whether IP address array has a subnet mask or not. 167 * 168 * @param address IP address byte array 169 * @return true if has subnet mask, false otherwise 170 */ 171 public static boolean hasMask(byte[] address) { 172 return address.length == 8 || address.length == 32; 173 } 174 175 /** 176 * Get an SLF4J Logger. 177 * 178 * @return a Logger instance 179 */ 180 private static Logger getLogger() { 181 return LoggerFactory.getLogger(IPAddressHelper.class); 182 } 183 184 }