View Javadoc

1   /*
2    * Licensed to the University Corporation for Advanced Internet Development, 
3    * Inc. (UCAID) under one or more contributor license agreements.  See the 
4    * NOTICE file distributed with this work for additional information regarding
5    * copyright ownership. The UCAID licenses this file to You under the Apache 
6    * License, Version 2.0 (the "License"); you may not use this file except in 
7    * compliance with the License.  You may obtain a copy of the License at
8    *
9    *    http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package edu.internet2.middleware.shibboleth.idp.util;
19  
20  import java.net.InetAddress;
21  import java.net.UnknownHostException;
22  import java.util.BitSet;
23  
24  import org.opensaml.xml.util.DatatypeHelper;
25  
26  /** Represents a range of IP addresses. */
27  public class IPRange {
28  
29      /** Number of bits within */
30      private int addressLength;
31  
32      /** The IP network address for the range. */
33      private BitSet network;
34  
35      /** The netmask for the range. */
36      private BitSet mask;
37      
38      /**
39       * Constructor
40       * 
41       * @param networkAddress the network address for the range
42       * @param maskSize the number of bits in the netmask
43       */
44      public IPRange(InetAddress networkAddress, int maskSize) {
45          this(networkAddress.getAddress(), maskSize);
46      }
47  
48      /**
49       * Constructor
50       * 
51       * @param networkAddress the network address for the range
52       * @param maskSize the number of bits in the netmask
53       */
54      public IPRange(byte[] networkAddress, int maskSize) {
55          addressLength = networkAddress.length * 8;
56          if (addressLength != 32 && addressLength != 128) {
57              throw new IllegalArgumentException("Network address was neither an IPv4 or IPv6 address");
58          }
59  
60          network = toBitSet(networkAddress);
61          mask = new BitSet(addressLength);
62          mask.set(addressLength - maskSize, addressLength, true);
63      }
64  
65      /**
66       * Parses a CIDR block definition in to an IP range.
67       * 
68       * @param cidrBlock the CIDR block definition
69       * 
70       * @return the resultant IP range
71       */
72      public static IPRange parseCIDRBlock(String cidrBlock){
73          String block = DatatypeHelper.safeTrimOrNullString(cidrBlock);
74          if(block == null){
75              throw new IllegalArgumentException("CIDR block definition may not be null");
76          }
77          
78          String[] blockParts = block.split("/");
79          try{
80              InetAddress networkAddress = InetAddress.getByName(blockParts[0]);
81              int maskSize = Integer.parseInt(blockParts[1]);
82              return new IPRange(networkAddress, maskSize);
83          }catch(UnknownHostException e){
84              throw new IllegalArgumentException("Invalid IP address");
85          }catch(NumberFormatException e){
86              throw new IllegalArgumentException("Invalid netmask size");
87          }
88      }
89      
90      /**
91       * Determines whether the given address is contained in the IP range.
92       * 
93       * @param address the address to check
94       * 
95       * @return true if the address is in the range, false it not
96       */
97      public boolean contains(InetAddress address) {
98          return contains(address.getAddress());
99      }
100 
101     /**
102      * Determines whether the given address is contained in the IP range.
103      * 
104      * @param address the address to check
105      * 
106      * @return true if the address is in the range, false it not
107      */
108     public boolean contains(byte[] address) {
109         if (address.length * 8 != addressLength) {
110             return false;
111         }
112 
113         BitSet addrNetwork = toBitSet(address);
114         addrNetwork.and(mask);
115 
116         return addrNetwork.equals(network);
117     }
118 
119     /**
120      * Converts a byte array to a BitSet.
121      * 
122      * The supplied byte array is assumed to have the most significant bit in element 0.
123      * 
124      * @param bytes the byte array with most significant bit in element 0.
125      * 
126      * @return the BitSet
127      */
128     protected BitSet toBitSet(byte[] bytes) {
129         BitSet bits = new BitSet(bytes.length * 8);
130 
131         for (int i = 0; i < bytes.length * 8; i++) {
132             if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
133                 bits.set(i);
134             }
135         }
136 
137         return bits;
138     }
139 }