View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  
21  package org.apache.mina.filter.firewall;
22  
23  import java.net.Inet4Address;
24  import java.net.Inet6Address;
25  import java.net.InetAddress;
26  
27  /**
28   * A IP subnet using the CIDR notation. Currently, only IP version 4
29   * address are supported.
30   *
31   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
32   */
33  public class Subnet {
34  
35      private static final int IP_MASK_V4 = 0x80000000;
36  
37      private static final long IP_MASK_V6 = 0x8000000000000000L;
38  
39      private static final int BYTE_MASK = 0xFF;
40  
41      private InetAddress subnet;
42  
43      /** An int representation of a subnet for IPV4 addresses */
44      private int subnetInt;
45  
46      /** An long representation of a subnet for IPV6 addresses */
47      private long subnetLong;
48  
49      private long subnetMask;
50  
51      private int suffix;
52  
53      /**
54       * Creates a subnet from CIDR notation. For example, the subnet
55       * 192.168.0.0/24 would be created using the {@link InetAddress}
56       * 192.168.0.0 and the mask 24.
57       * @param subnet The {@link InetAddress} of the subnet
58       * @param mask The mask
59       */
60      public Subnet(InetAddress subnet, int mask) {
61          if (subnet == null) {
62              throw new IllegalArgumentException("Subnet address can not be null");
63          }
64  
65          if (!(subnet instanceof Inet4Address) && !(subnet instanceof Inet6Address)) {
66              throw new IllegalArgumentException("Only IPv4 and IPV6 supported");
67          }
68  
69          if (subnet instanceof Inet4Address) {
70              // IPV4 address
71              if ((mask < 0) || (mask > 32)) {
72                  throw new IllegalArgumentException("Mask has to be an integer between 0 and 32 for an IPV4 address");
73              } else {
74                  this.subnet = subnet;
75                  subnetInt = toInt(subnet);
76                  this.suffix = mask;
77  
78                  // binary mask for this subnet
79                  this.subnetMask = IP_MASK_V4 >> (mask - 1);
80              }
81          } else {
82              // IPV6 address
83              if ((mask < 0) || (mask > 128)) {
84                  throw new IllegalArgumentException("Mask has to be an integer between 0 and 128 for an IPV6 address");
85              } else {
86                  this.subnet = subnet;
87                  subnetLong = toLong(subnet);
88                  this.suffix = mask;
89  
90                  // binary mask for this subnet
91                  this.subnetMask = IP_MASK_V6 >> (mask - 1);
92              }
93          }
94      }
95  
96      /**
97       * Converts an IP address into an integer
98       */
99      private int toInt(InetAddress inetAddress) {
100         byte[] address = inetAddress.getAddress();
101         int result = 0;
102 
103         for (int i = 0; i < address.length; i++) {
104             result <<= 8;
105             result |= address[i] & BYTE_MASK;
106         }
107 
108         return result;
109     }
110 
111     /**
112      * Converts an IP address into a long
113      */
114     private long toLong(InetAddress inetAddress) {
115         byte[] address = inetAddress.getAddress();
116         long result = 0;
117 
118         for (int i = 0; i < address.length; i++) {
119             result <<= 8;
120             result |= address[i] & BYTE_MASK;
121         }
122 
123         return result;
124     }
125 
126     /**
127      * Converts an IP address to a subnet using the provided mask
128      * 
129      * @param address
130      *            The address to convert into a subnet
131      * @return The subnet as an integer
132      */
133     private long toSubnet(InetAddress address) {
134         if (address instanceof Inet4Address) {
135             return toInt(address) & (int) subnetMask;
136         } else {
137             return toLong(address) & subnetMask;
138         }
139     }
140 
141     /**
142      * Checks if the {@link InetAddress} is within this subnet
143      * @param address The {@link InetAddress} to check
144      * @return True if the address is within this subnet, false otherwise
145      */
146     public boolean inSubnet(InetAddress address) {
147         if (address.isAnyLocalAddress()) {
148             return true;
149         }
150 
151         if (address instanceof Inet4Address) {
152             return (int) toSubnet(address) == subnetInt;
153         } else {
154             return toSubnet(address) == subnetLong;
155         }
156     }
157 
158     /**
159      * @see Object#toString()
160      */
161     @Override
162     public String toString() {
163         return subnet.getHostAddress() + "/" + suffix;
164     }
165 
166     @Override
167     public boolean equals(Object obj) {
168         if (!(obj instanceof Subnet)) {
169             return false;
170         }
171 
172         Subnet other = (Subnet) obj;
173 
174         return other.subnetInt == subnetInt && other.suffix == suffix;
175     }
176 
177 }