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 /** Class logger. */ 29 private static Logger log = LoggerFactory.getLogger(IPAddressHelper.class); 30 31 /** Constructor. */ 32 private IPAddressHelper() { 33 34 } 35 36 /** 37 * Convert the byte array representation of an IP address into a string. Supports IPv4 and IPv6 addresses. 38 * Supports optional subnet mask stored within the same byte array. If the latter is present, 39 * output will be: "ipAddr/mask". 40 * 41 * @param address IP address in byte array form (in network byte order) 42 * @return IP address as a string, or null if can not be processed 43 */ 44 public static String addressToString(byte[] address) { 45 if (isIPv4(address)) { 46 return ipv4ToString(address); 47 } else if (isIPv6(address)) { 48 return ipv6ToString(address); 49 } else { 50 log.error("IP address byte array was an invalid length: {}", address.length); 51 return null; 52 } 53 } 54 55 /** 56 * Convert the byte array representation of an IPv4 address into a string. 57 * Supports optional subnet mask stored within the same byte array. If the latter is present, 58 * output will be: "ipAddr/mask". 59 * 60 * @param address IP address in byte array form (in network byte order) 61 * @return IP address as a string, or null if can not be processed 62 */ 63 private static String ipv4ToString(byte[] address) { 64 // This code was modeled after similar code in Sun's sun.security.x509.IPAddressName, 65 // used by sun.security.x509.X509CertImpl. 66 StringBuilder builder = new StringBuilder(); 67 byte[] ip = new byte[4]; 68 System.arraycopy(address, 0, ip, 0, 4); 69 try { 70 builder.append(InetAddress.getByAddress(ip).getHostAddress()); 71 } catch (UnknownHostException e) { 72 // Thrown if address is illegal length. 73 // Can't happen, we know that address is the right length. 74 log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); 75 return null; 76 } 77 78 if(hasMask(address)) { 79 byte[] mask = new byte[4]; 80 System.arraycopy(address, 4, mask, 0, 4); 81 builder.append("/"); 82 try { 83 builder.append(InetAddress.getByAddress(mask).getHostAddress()); 84 } catch (UnknownHostException e) { 85 // Thrown if address is illegal length. 86 // Can't happen, we know that address is the right length. 87 log.error("Unknown host exception processing IP address byte array: {}", e.getMessage()); 88 return null; 89 } 90 } 91 return builder.toString(); 92 } 93 94 /** 95 * Convert the byte array representation of an IPv6 address into a string. 96 * Supports optional subnet mask stored within the same byte array. If the latter is present, 97 * output will be: "ipAddr/mask". 98 * 99 * @param address IP address in byte array form (in network byte order) 100 * @return IP address as a string, or null if can not be processed 101 */ 102 private static String ipv6ToString(byte[] address) { 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 }