1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package org.jboss.netty.handler.ipfilter;
17
18 import org.jboss.netty.logging.InternalLogger;
19 import org.jboss.netty.logging.InternalLoggerFactory;
20 import org.jboss.netty.util.internal.StringUtil;
21
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.util.StringTokenizer;
25
26 /**
27 * This class allows to check if an IP-V4-Address is contained in a subnet.<BR>
28 * Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation)
29 * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.<BR>
30 * <BR><BR>Example1:<BR>
31 * <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");</tt><BR>
32 * <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
33 * <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
34 * <BR>Example1 bis:<BR>
35 * <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);</tt><BR>
36 * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
37 * <BR><BR>Example2:<BR>
38 * <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");</tt><BR>
39 * <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR>
40 * <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR>
41 * <BR>Example2 bis:<BR>
42 * <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");</tt><BR>
43 * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR>
44 */
45 public class IpV4Subnet implements IpSet, Comparable<IpV4Subnet> {
46
47 private static final InternalLogger logger =
48 InternalLoggerFactory.getInstance(IpV4Subnet.class);
49
50 private static final int SUBNET_MASK = 0x80000000;
51
52 private static final int BYTE_ADDRESS_MASK = 0xFF;
53
54 private InetAddress inetAddress;
55
56 private int subnet;
57
58 private int mask;
59
60 private int cidrMask;
61
62 /** Create IpV4Subnet for ALL (used for ALLOW or DENY ALL) */
63 public IpV4Subnet() {
64 // ALLOW or DENY ALL
65 mask = -1;
66 // other will be ignored
67 inetAddress = null;
68 subnet = 0;
69 cidrMask = 0;
70 }
71
72 /**
73 * Create IpV4Subnet using the CIDR or normal Notation<BR>
74 * i.e.:
75 * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or
76 * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0");
77 *
78 * @param netAddress a network address as string.
79 */
80 public IpV4Subnet(String netAddress) throws UnknownHostException {
81 setNetAddress(netAddress);
82 }
83
84 /** Create IpV4Subnet using the CIDR Notation */
85 public IpV4Subnet(InetAddress inetAddress, int cidrNetMask) {
86 setNetAddress(inetAddress, cidrNetMask);
87 }
88
89 /** Create IpV4Subnet using the normal Notation */
90 public IpV4Subnet(InetAddress inetAddress, String netMask) {
91 setNetAddress(inetAddress, netMask);
92 }
93
94 /**
95 * Sets the Network Address in either CIDR or Decimal Notation.<BR>
96 * i.e.: setNetAddress("1.1.1.1/24"); or<BR>
97 * setNetAddress("1.1.1.1/255.255.255.0");<BR>
98 *
99 * @param netAddress a network address as string.
100 */
101 private void setNetAddress(String netAddress) throws UnknownHostException {
102 String[] tokens = StringUtil.split(netAddress, '/');
103 if (tokens.length != 2) {
104 throw new IllegalArgumentException("netAddress: " + netAddress + " (expected: CIDR or Decimal Notation)");
105 }
106
107 if (tokens[1].length() < 3) {
108 setNetId(tokens[0]);
109 setCidrNetMask(Integer.parseInt(tokens[1]));
110 } else {
111 setNetId(tokens[0]);
112 setNetMask(tokens[1]);
113 }
114 }
115
116 /** Sets the Network Address in CIDR Notation. */
117 private void setNetAddress(InetAddress inetAddress, int cidrNetMask) {
118 setNetId(inetAddress);
119 setCidrNetMask(cidrNetMask);
120 }
121
122 /** Sets the Network Address in Decimal Notation. */
123 private void setNetAddress(InetAddress inetAddress, String netMask) {
124 setNetId(inetAddress);
125 setNetMask(netMask);
126 }
127
128 /**
129 * Sets the BaseAdress of the Subnet.<BR>
130 * i.e.: setNetId("192.168.1.0");
131 *
132 * @param netId a network ID
133 */
134 private void setNetId(String netId) throws UnknownHostException {
135 InetAddress inetAddress1 = InetAddress.getByName(netId);
136 setNetId(inetAddress1);
137 }
138
139 /**
140 * Compute integer representation of InetAddress
141 *
142 * @return the integer representation
143 */
144 private static int toInt(InetAddress inetAddress1) {
145 byte[] address = inetAddress1.getAddress();
146 int net = 0;
147 for (byte addres : address) {
148 net <<= 8;
149 net |= addres & BYTE_ADDRESS_MASK;
150 }
151 return net;
152 }
153
154 /** Sets the BaseAdress of the Subnet. */
155 private void setNetId(InetAddress inetAddress) {
156 this.inetAddress = inetAddress;
157 subnet = toInt(inetAddress);
158 }
159
160 /**
161 * Sets the Subnet's Netmask in Decimal format.<BR>
162 * i.e.: setNetMask("255.255.255.0");
163 *
164 * @param netMask a network mask
165 */
166 private void setNetMask(String netMask) {
167 StringTokenizer nm = new StringTokenizer(netMask, ".");
168 int i = 0;
169 int[] netmask = new int[4];
170 while (nm.hasMoreTokens()) {
171 netmask[i] = Integer.parseInt(nm.nextToken());
172 i++;
173 }
174 int mask1 = 0;
175 for (i = 0; i < 4; i++) {
176 mask1 += Integer.bitCount(netmask[i]);
177 }
178 setCidrNetMask(mask1);
179 }
180
181 /**
182 * Sets the CIDR Netmask<BR>
183 * i.e.: setCidrNetMask(24);
184 *
185 * @param cidrNetMask a netmask in CIDR notation
186 */
187 private void setCidrNetMask(int cidrNetMask) {
188 cidrMask = cidrNetMask;
189 mask = SUBNET_MASK >> cidrMask - 1;
190 }
191
192 /**
193 * Compares the given IP-Address against the Subnet and returns true if
194 * the ip is in the subnet-ip-range and false if not.
195 *
196 * @param ipAddr an ipaddress
197 * @return returns true if the given IP address is inside the currently
198 * set network.
199 */
200 public boolean contains(String ipAddr) throws UnknownHostException {
201 InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
202 return contains(inetAddress1);
203 }
204
205 /**
206 * Compares the given InetAddress against the Subnet and returns true if
207 * the ip is in the subnet-ip-range and false if not.
208 *
209 * @return returns true if the given IP address is inside the currently
210 * set network.
211 */
212 public boolean contains(InetAddress inetAddress1) {
213 if (mask == -1) {
214 // ANY
215 return true;
216 }
217 return (toInt(inetAddress1) & mask) == subnet;
218 }
219
220 @Override
221 public String toString() {
222 return inetAddress.getHostAddress() + '/' + cidrMask;
223 }
224
225 @Override
226 public boolean equals(Object o) {
227 if (!(o instanceof IpV4Subnet)) {
228 return false;
229 }
230 IpV4Subnet ipV4Subnet = (IpV4Subnet) o;
231 return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask;
232 }
233
234 @Override
235 public int hashCode() {
236 return subnet;
237 }
238
239 /** Compare two IpV4Subnet */
240 public int compareTo(IpV4Subnet o) {
241 if (o.subnet == subnet && o.cidrMask == cidrMask) {
242 return 0;
243 }
244 if (o.subnet < subnet) {
245 return 1;
246 }
247 if (o.subnet > subnet) {
248 return -1;
249 }
250 if (o.cidrMask < cidrMask) {
251 // greater Mask means less IpAddresses so -1
252 return -1;
253 }
254 return 1;
255 }
256 }