Merge remote branch 'tags/2.3.4'
[java-idp.git] / src / main / java / edu / internet2 / middleware / shibboleth / idp / util / IPRange.java
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 }