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 }