View Javadoc

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         } else if (o.subnet > subnet) {
247             return -1;
248         } else if (o.cidrMask < cidrMask) {
249             // greater Mask means less IpAddresses so -1
250             return -1;
251         }
252         return 1;
253     }
254 }