Create IP range helper class
[java-idp.git] / src / main / java / edu / internet2 / middleware / shibboleth / idp / util / IPRange.java
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 }