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.Inet4Address;
    19  import java.net.Inet6Address;
    20  import java.net.InetAddress;
    21  import java.net.UnknownHostException;
    22  import java.util.StringTokenizer;
    23
    24  /**
    25   */
    26  public abstract class CIDR implements Comparable<CIDR> {
    27      /** The base address of the CIDR notation */
    28      protected InetAddress baseAddress;
    29
    30      /** The mask used in the CIDR notation */
    31      protected int cidrMask;
    32
    33      /**
    34       * Create CIDR using the CIDR Notation
    35       *
    36       * @return the generated CIDR
    37       */
    38      public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException {
    39          if (cidrMask < 0) {
    40              throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    41          }
    42          if (baseAddress instanceof Inet4Address) {
    43              if (cidrMask > 32) {
    44                  throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    45              }
    46              return new CIDR4((Inet4Address) baseAddress, cidrMask);
    47          }
    48          // IPv6.
    49          if (cidrMask > 128) {
    50              throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    51          }
    52          return new CIDR6((Inet6Address) baseAddress, cidrMask);
    53      }
    54
    55      /**
    56       * Create CIDR using the normal Notation
    57       *
    58       * @return the generated CIDR
    59       */
    60      public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException {
    61          int cidrMask = getNetMask(scidrMask);
    62          if (cidrMask < 0) {
    63              throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    64          }
    65          if (baseAddress instanceof Inet4Address) {
    66              if (cidrMask > 32) {
    67                  throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    68              }
    69              return new CIDR4((Inet4Address) baseAddress, cidrMask);
    70          }
    71          cidrMask += 96;
    72          // IPv6.
    73          if (cidrMask > 128) {
    74              throw new UnknownHostException("Invalid mask length used: " + cidrMask);
    75          }
    76          return new CIDR6((Inet6Address) baseAddress, cidrMask);
    77      }
    78
    79      /**
    80       * Create CIDR using the CIDR or normal Notation<BR>
    81       * i.e.:
    82       * CIDR  subnet = newCIDR ("10.10.10.0/24"); or
    83       * CIDR  subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or
    84       * CIDR  subnet = newCIDR ("10.10.10.0/255.255.255.0");
    85       *
    86       * @return the generated CIDR
    87       */
    88      public static CIDR newCIDR(String cidr) throws UnknownHostException {
    89          int p = cidr.indexOf("/");
    90          if (p < 0) {
    91              throw new UnknownHostException("Invalid CIDR notation used: " + cidr);
    92          }
    93          String addrString = cidr.substring(0, p);
    94          String maskString = cidr.substring(p + 1);
    95          InetAddress addr = addressStringToInet(addrString);
    96          int mask = 0;
    97          if (maskString.indexOf(".") < 0) {
    98              mask = parseInt(maskString, -1);
    99          } else {
    100             mask = getNetMask(maskString);
    101             if (addr instanceof Inet6Address) {
    102                 mask += 96;
    103             }
    104         }
    105         if (mask < 0) {
    106             throw new UnknownHostException("Invalid mask length used: " + maskString);
    107         }
    108         return newCIDR(addr, mask);
    109     }
    110
    111     /** @return the baseAddress of the CIDR block. */
    112     public InetAddress getBaseAddress() {
    113         return baseAddress;
    114     }
    115
    116     /** @return the Mask length. */
    117     public int getMask() {
    118         return cidrMask;
    119     }
    120
    121     /** @return the textual CIDR notation. */
    122     @Override
    123     public String toString() {
    124         return baseAddress.getHostAddress() + "/" + cidrMask;
    125     }
    126
    127     /** @return the end address of this block. */
    128     public abstract InetAddress getEndAddress();
    129
    130     /**
    131      * Compares the given InetAddress against the CIDR and returns true if
    132      * the ip is in the subnet-ip-range and false if not.
    133      *
    134      * @return returns true if the given IP address is inside the currently
    135      *         set network.
    136      */
    137     public abstract boolean contains(InetAddress inetAddress);
    138
    139     @Override
    140     public boolean equals(Object arg0) {
    141         if (!(arg0 instanceof CIDR)) {
    142             return false;
    143         }
    144         return compareTo((CIDR) arg0) == 0;
    145     }
    146
    147     @Override
    148     public int hashCode() {
    149         return baseAddress.hashCode();
    150     }
    151
    152     /**
    153      * Convert an IPv4 or IPv6 textual representation into an
    154      * InetAddress.
    155      *
    156      * @return the created InetAddress
    157      */
    158     private static InetAddress addressStringToInet(String addr) throws UnknownHostException {
    159         return InetAddress.getByName(addr);
    160     }
    161
    162     /**
    163      * Get the Subnet's Netmask in Decimal format.<BR>
    164      * i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask
    165      *
    166      * @param netMask a network mask
    167      * @return the integer CIDR mask
    168      */
    169     private static int getNetMask(String netMask) {
    170         StringTokenizer nm = new StringTokenizer(netMask, ".");
    171         int i = 0;
    172         int[] netmask = new int[4];
    173         while (nm.hasMoreTokens()) {
    174             netmask[i] = Integer.parseInt(nm.nextToken());
    175             i++;
    176         }
    177         int mask1 = 0;
    178         for (i = 0; i < 4; i++) {
    179             mask1 += Integer.bitCount(netmask[i]);
    180         }
    181         return mask1;
    182     }
    183
    184     /**
    185      * @param intstr a string containing an integer.
    186      * @param def    the default if the string does not contain a valid
    187      *               integer.
    188      * @return the inetAddress from the integer
    189      */
    190     private static int parseInt(String intstr, int def) {
    191         Integer res;
    192         if (intstr == null) {
    193             return def;
    194         }
    195         try {
    196             res = Integer.decode(intstr);
    197         } catch (Exception e) {
    198             res = def;
    199         }
    200         return res.intValue();
    201     }
    202
    203     /**
    204      * Compute a byte representation of IpV4 from a IpV6
    205      *
    206      * @return the byte representation
    207      * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
    208      */
    209     public static byte[] getIpV4FromIpV6(Inet6Address address) {
    210         byte[] baddr = address.getAddress();
    211         for (int i = 0; i < 9; i++) {
    212             if (baddr[i] != 0) {
    213                 throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
    214             }
    215         }
    216         if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF) {
    217             throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context");
    218         }
    219         return new byte[]
    220                 {baddr[12], baddr[13], baddr[14], baddr[15]};
    221     }
    222
    223     /**
    224      * Compute a byte representation of IpV6 from a IpV4
    225      *
    226      * @return the byte representation
    227      * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4
    228      */
    229     public static byte[] getIpV6FromIpV4(Inet4Address address) {
    230         byte[] baddr = address.getAddress();
    231         return new byte[]
    232                 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]};
    233     }
    234 }