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 java.net.InetAddress;
    19  import java.net.UnknownHostException;
    20  import java.util.StringTokenizer;
    21  import java.util.Vector;
    22
    23  import org.jboss.netty.logging.InternalLogger;
    24  import org.jboss.netty.logging.InternalLoggerFactory;
    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         Vector<Object> vec = new Vector<Object>();
    103         StringTokenizer st = new StringTokenizer(netAddress, "/");
    104         while (st.hasMoreTokens()) {
    105             vec.add(st.nextElement());
    106         }
    107
    108         if (vec.get(1).toString().length() < 3) {
    109             setNetId(vec.get(0).toString());
    110             setCidrNetMask(Integer.parseInt(vec.get(1).toString()));
    111         } else {
    112             setNetId(vec.get(0).toString());
    113             setNetMask(vec.get(1).toString());
    114         }
    115     }
    116
    117     /** Sets the Network Address in CIDR Notation. */
    118     private void setNetAddress(InetAddress inetAddress, int cidrNetMask) {
    119         setNetId(inetAddress);
    120         setCidrNetMask(cidrNetMask);
    121     }
    122
    123     /** Sets the Network Address in Decimal Notation. */
    124     private void setNetAddress(InetAddress inetAddress, String netMask) {
    125         setNetId(inetAddress);
    126         setNetMask(netMask);
    127     }
    128
    129     /**
    130      * Sets the BaseAdress of the Subnet.<BR>
    131      * i.e.: setNetId("192.168.1.0");
    132      *
    133      * @param netId a network ID
    134      */
    135     private void setNetId(String netId) throws UnknownHostException {
    136         InetAddress inetAddress1 = InetAddress.getByName(netId);
    137         this.setNetId(inetAddress1);
    138     }
    139
    140     /**
    141      * Compute integer representation of InetAddress
    142      *
    143      * @return the integer representation
    144      */
    145     private static int toInt(InetAddress inetAddress1) {
    146         byte[] address = inetAddress1.getAddress();
    147         int net = 0;
    148         for (byte addres : address) {
    149             net <<= 8;
    150             net |= addres & BYTE_ADDRESS_MASK;
    151         }
    152         return net;
    153     }
    154
    155     /** Sets the BaseAdress of the Subnet. */
    156     private void setNetId(InetAddress inetAddress) {
    157         this.inetAddress = inetAddress;
    158         subnet = toInt(inetAddress);
    159     }
    160
    161     /**
    162      * Sets the Subnet's Netmask in Decimal format.<BR>
    163      * i.e.: setNetMask("255.255.255.0");
    164      *
    165      * @param netMask a network mask
    166      */
    167     private void setNetMask(String netMask) {
    168         StringTokenizer nm = new StringTokenizer(netMask, ".");
    169         int i = 0;
    170         int[] netmask = new int[4];
    171         while (nm.hasMoreTokens()) {
    172             netmask[i] = Integer.parseInt(nm.nextToken());
    173             i++;
    174         }
    175         int mask1 = 0;
    176         for (i = 0; i < 4; i++) {
    177             mask1 += Integer.bitCount(netmask[i]);
    178         }
    179         setCidrNetMask(mask1);
    180     }
    181
    182     /**
    183      * Sets the CIDR Netmask<BR>
    184      * i.e.: setCidrNetMask(24);
    185      *
    186      * @param cidrNetMask a netmask in CIDR notation
    187      */
    188     private void setCidrNetMask(int cidrNetMask) {
    189         cidrMask = cidrNetMask;
    190         mask = SUBNET_MASK >> cidrMask - 1;
    191     }
    192
    193     /**
    194      * Compares the given IP-Address against the Subnet and returns true if
    195      * the ip is in the subnet-ip-range and false if not.
    196      *
    197      * @param ipAddr an ipaddress
    198      * @return returns true if the given IP address is inside the currently
    199      *         set network.
    200      */
    201     public boolean contains(String ipAddr) throws UnknownHostException {
    202         InetAddress inetAddress1 = InetAddress.getByName(ipAddr);
    203         return this.contains(inetAddress1);
    204     }
    205
    206     /**
    207      * Compares the given InetAddress against the Subnet and returns true if
    208      * the ip is in the subnet-ip-range and false if not.
    209      *
    210      * @return returns true if the given IP address is inside the currently
    211      *         set network.
    212      */
    213     public boolean contains(InetAddress inetAddress1) {
    214         if (mask == -1) {
    215             // ANY
    216             return true;
    217         }
    218         return (toInt(inetAddress1) & mask) == subnet;
    219     }
    220
    221     @Override
    222     public String toString() {
    223         return inetAddress.getHostAddress() + "/" + cidrMask;
    224     }
    225
    226     @Override
    227     public boolean equals(Object o) {
    228         if (!(o instanceof IpV4Subnet)) {
    229             return false;
    230         }
    231         IpV4Subnet ipV4Subnet = (IpV4Subnet) o;
    232         return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask;
    233     }
    234
    235     @Override
    236     public int hashCode() {
    237         return subnet;
    238     }
    239
    240     /** Compare two IpV4Subnet */
    241     public int compareTo(IpV4Subnet o) {
    242         if (o.subnet == subnet && o.cidrMask == cidrMask) {
    243             return 0;
    244         }
    245         if (o.subnet < subnet) {
    246             return 1;
    247         } else if (o.subnet > subnet) {
    248             return -1;
    249         } else if (o.cidrMask < cidrMask) {
    250             // greater Mask means less IpAddresses so -1
    251             return -1;
    252         }
    253         return 1;
    254     }
    255 }