View Javadoc

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 }