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.InetAddress;
25  
26  /**
27   * A IP subnet using the CIDR notation. Currently, only IP version 4
28   * address are supported.
29   *
30   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
31   */
32  public class Subnet {
33  
34      private static final int IP_MASK_V4 = 0x80000000;
35  
36      private static final long IP_MASK_V6 = 0x8000000000000000L;
37  
38      private static final int BYTE_MASK = 0xFF;
39  
40      private InetAddress subnet;
41  
42      /** An int representation of a subnet for IPV4 addresses */
43      private int subnetInt;
44  
45      /** An long representation of a subnet for IPV6 addresses */
46      private long subnetLong;
47  
48      private long subnetMask;
49  
50      private int suffix;
51  
52      /**
53       * Creates a subnet from CIDR notation. For example, the subnet
54       * 192.168.0.0/24 would be created using the {@link InetAddress}
55       * 192.168.0.0 and the mask 24.
56       * @param subnet The {@link InetAddress} of the subnet
57       * @param mask The mask
58       */
59      public Subnet(InetAddress subnet, int mask) {
60          if (subnet == null) {
61              throw new IllegalArgumentException("Subnet address can not be null");
62          }
63  
64          if (!(subnet instanceof Inet4Address)) {
65              throw new IllegalArgumentException("Only IPv4 supported");
66          }
67  
68          if (subnet instanceof Inet4Address) {
69              // IPV4 address
70              if ((mask < 0) || (mask > 32)) {
71                  throw new IllegalArgumentException("Mask has to be an integer between 0 and 32 for an IPV4 address");
72              } else {
73                  this.subnet = subnet;
74                  subnetInt = toInt(subnet);
75                  this.suffix = mask;
76  
77                  // binary mask for this subnet
78                  this.subnetMask = IP_MASK_V4 >> (mask - 1);
79              }
80          } else {
81              // IPV6 address
82              if ((mask < 0) || (mask > 128)) {
83                  throw new IllegalArgumentException("Mask has to be an integer between 0 and 128 for an IPV6 address");
84              } else {
85                  this.subnet = subnet;
86                  subnetLong = toLong(subnet);
87                  this.suffix = mask;
88  
89                  // binary mask for this subnet
90                  this.subnetMask = IP_MASK_V6 >> (mask - 1);
91              }
92          }
93      }
94  
95      /**
96       * Converts an IP address into an integer
97       */
98      private int toInt(InetAddress inetAddress) {
99          byte[] address = inetAddress.getAddress();
100         int result = 0;
101 
102         for (int i = 0; i < address.length; i++) {
103             result <<= 8;
104             result |= address[i] & BYTE_MASK;
105         }
106 
107         return result;
108     }
109 
110     /**
111      * Converts an IP address into a long
112      */
113     private long toLong(InetAddress inetAddress) {
114         byte[] address = inetAddress.getAddress();
115         long result = 0;
116 
117         for (int i = 0; i < address.length; i++) {
118             result <<= 8;
119             result |= address[i] & BYTE_MASK;
120         }
121 
122         return result;
123     }
124 
125     /**
126      * Converts an IP address to a subnet using the provided mask
127      * 
128      * @param address
129      *            The address to convert into a subnet
130      * @return The subnet as an integer
131      */
132     private long toSubnet(InetAddress address) {
133         if (address instanceof Inet4Address) {
134             return toInt(address) & (int) subnetMask;
135         } else {
136             return toLong(address) & subnetMask;
137         }
138     }
139 
140     /**
141      * Checks if the {@link InetAddress} is within this subnet
142      * @param address The {@link InetAddress} to check
143      * @return True if the address is within this subnet, false otherwise
144      */
145     public boolean inSubnet(InetAddress address) {
146         if (address.isAnyLocalAddress()) {
147             return true;
148         }
149 
150         if (address instanceof Inet4Address) {
151             return (int) toSubnet(address) == subnetInt;
152         } else {
153             return toSubnet(address) == subnetLong;
154         }
155     }
156 
157     /**
158      * @see Object#toString()
159      */
160     @Override
161     public String toString() {
162         return subnet.getHostAddress() + "/" + suffix;
163     }
164 
165     @Override
166     public boolean equals(Object obj) {
167         if (!(obj instanceof Subnet)) {
168             return false;
169         }
170 
171         Subnet other = (Subnet) obj;
172 
173         return other.subnetInt == subnetInt && other.suffix == suffix;
174     }
175 
176 }