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 }