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