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      /** 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 }