View Javadoc

1   /*
2    * Copyright 2009 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 edu.internet2.middleware.shibboleth.idp.util;
18  
19  import java.net.InetAddress;
20  import java.net.UnknownHostException;
21  import java.util.BitSet;
22  
23  import org.opensaml.xml.util.DatatypeHelper;
24  
25  /** Represents a range of IP addresses. */
26  public class IPRange {
27  
28      /** Number of bits within */
29      private int addressLength;
30  
31      /** The IP network address for the range. */
32      private BitSet network;
33  
34      /** The netmask for the range. */
35      private BitSet mask;
36      
37      /**
38       * Constructor
39       * 
40       * @param networkAddress the network address for the range
41       * @param maskSize the number of bits in the netmask
42       */
43      public IPRange(InetAddress networkAddress, int maskSize) {
44          this(networkAddress.getAddress(), maskSize);
45      }
46  
47      /**
48       * Constructor
49       * 
50       * @param networkAddress the network address for the range
51       * @param maskSize the number of bits in the netmask
52       */
53      public IPRange(byte[] networkAddress, int maskSize) {
54          addressLength = networkAddress.length * 8;
55          if (addressLength != 32 && addressLength != 128) {
56              throw new IllegalArgumentException("Network address was neither an IPv4 or IPv6 address");
57          }
58  
59          network = toBitSet(networkAddress);
60          mask = new BitSet(addressLength);
61          mask.set(addressLength - maskSize, addressLength, true);
62      }
63  
64      /**
65       * Parses a CIDR block definition in to an IP range.
66       * 
67       * @param cidrBlock the CIDR block definition
68       * 
69       * @return the resultant IP range
70       */
71      public static IPRange parseCIDRBlock(String cidrBlock){
72          String block = DatatypeHelper.safeTrimOrNullString(cidrBlock);
73          if(block == null){
74              throw new IllegalArgumentException("CIDR block definition may not be null");
75          }
76          
77          String[] blockParts = block.split("/");
78          try{
79              InetAddress networkAddress = InetAddress.getByName(blockParts[0]);
80              int maskSize = Integer.parseInt(blockParts[1]);
81              return new IPRange(networkAddress, maskSize);
82          }catch(UnknownHostException e){
83              throw new IllegalArgumentException("Invalid IP address");
84          }catch(NumberFormatException e){
85              throw new IllegalArgumentException("Invalid netmask size");
86          }
87      }
88      
89      /**
90       * Determines whether the given address is contained in the IP range.
91       * 
92       * @param address the address to check
93       * 
94       * @return true if the address is in the range, false it not
95       */
96      public boolean contains(InetAddress address) {
97          return contains(address.getAddress());
98      }
99  
100     /**
101      * Determines whether the given address is contained in the IP range.
102      * 
103      * @param address the address to check
104      * 
105      * @return true if the address is in the range, false it not
106      */
107     public boolean contains(byte[] address) {
108         if (address.length * 8 != addressLength) {
109             return false;
110         }
111 
112         BitSet addrNetwork = toBitSet(address);
113         addrNetwork.and(mask);
114 
115         return addrNetwork.equals(network);
116     }
117 
118     /**
119      * Converts a byte array to a BitSet.
120      * 
121      * The supplied byte array is assumed to have the most significant bit in element 0.
122      * 
123      * @param bytes the byte array with most significant bit in element 0.
124      * 
125      * @return the BitSet
126      */
127     protected BitSet toBitSet(byte[] bytes) {
128         BitSet bits = new BitSet(bytes.length * 8);
129 
130         for (int i = 0; i < bytes.length * 8; i++) {
131             if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
132                 bits.set(i);
133             }
134         }
135 
136         return bits;
137     }
138 }