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.math.BigInteger;
    19  import java.net.Inet4Address;
    20  import java.net.Inet6Address;
    21  import java.net.InetAddress;
    22  import java.net.UnknownHostException;
    23
    24  import org.jboss.netty.logging.InternalLogger;
    25  import org.jboss.netty.logging.InternalLoggerFactory;
    26
    27  /**
    28   */
    29  public class CIDR6 extends CIDR {
    30
    31      private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class);
    32
    33      /** The big integer for the base address */
    34      private BigInteger addressBigInt;
    35
    36      /** The big integer for the end address */
    37      private final BigInteger addressEndBigInt;
    38
    39      /**
    40       * @param newaddress
    41       * @param newmask
    42       */
    43      protected CIDR6(Inet6Address newaddress, int newmask) {
    44          cidrMask = newmask;
    45          addressBigInt = ipv6AddressToBigInteger(newaddress);
    46          BigInteger mask = ipv6CidrMaskToMask(newmask);
    47          try {
    48              addressBigInt = addressBigInt.and(mask);
    49              baseAddress = bigIntToIPv6Address(addressBigInt);
    50          } catch (UnknownHostException e) {
    51              // this should never happen.
    52          }
    53          addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE);
    54      }
    55
    56      @Override
    57      public InetAddress getEndAddress() {
    58          try {
    59              return bigIntToIPv6Address(addressEndBigInt);
    60          } catch (UnknownHostException e) {
    61              if (logger.isErrorEnabled()) {
    62                  logger.error("invalid ip address calculated as an end address");
    63              }
    64              return null;
    65          }
    66      }
    67
    68
    69      public int compareTo(CIDR arg) {
    70          if (arg instanceof CIDR4) {
    71              BigInteger net = ipv6AddressToBigInteger(arg.baseAddress);
    72              int res = net.compareTo(addressBigInt);
    73              if (res == 0) {
    74                  if (arg.cidrMask == cidrMask) {
    75                      return 0;
    76                  } else if (arg.cidrMask < cidrMask) {
    77                      return -1;
    78                  }
    79                  return 1;
    80              }
    81              return res;
    82          }
    83          CIDR6 o = (CIDR6) arg;
    84          if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask) {
    85              return 0;
    86          }
    87          int res = o.addressBigInt.compareTo(addressBigInt);
    88          if (res == 0) {
    89              if (o.cidrMask < cidrMask) {
    90                  // greater Mask means less IpAddresses so -1
    91                  return -1;
    92              }
    93              return 1;
    94          }
    95          return res;
    96      }
    97
    98      @Override
    99      public boolean contains(InetAddress inetAddress) {
    100         BigInteger search = ipv6AddressToBigInteger(inetAddress);
    101         return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0;
    102     }
    103
    104     /**
    105      * Given an IPv6 baseAddress length, return the block length.  I.e., a
    106      * baseAddress length of 96 will return 2**32.
    107      */
    108     private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask) {
    109         return BigInteger.ONE.shiftLeft(128 - cidrMask);
    110     }
    111
    112     private static BigInteger ipv6CidrMaskToMask(int cidrMask) {
    113         return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not();
    114     }
    115
    116     /**
    117      * Given an IPv6 address, convert it into a BigInteger.
    118      *
    119      * @return the integer representation of the InetAddress
    120      * @throws IllegalArgumentException if the address is not an IPv6
    121      *                                  address.
    122      */
    123     private static BigInteger ipv6AddressToBigInteger(InetAddress addr) {
    124         byte[] ipv6;
    125         if (addr instanceof Inet4Address) {
    126             ipv6 = getIpV6FromIpV4((Inet4Address) addr);
    127         } else {
    128             ipv6 = addr.getAddress();
    129         }
    130         if (ipv6[0] == -1) {
    131             return new BigInteger(1, ipv6);
    132         }
    133         return new BigInteger(ipv6);
    134     }
    135
    136     /**
    137      * Convert a big integer into an IPv6 address.
    138      *
    139      * @return the inetAddress from the integer
    140      * @throws UnknownHostException if the big integer is too large,
    141      *                              and thus an invalid IPv6 address.
    142      */
    143     private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException {
    144         byte[] a = new byte[16];
    145         byte[] b = addr.toByteArray();
    146         if (b.length > 16 && !(b.length == 17 && b[0] == 0)) {
    147             throw new UnknownHostException("invalid IPv6 address (too big)");
    148         }
    149         if (b.length == 16) {
    150             return InetAddress.getByAddress(b);
    151         }
    152         // handle the case where the IPv6 address starts with "FF".
    153         if (b.length == 17) {
    154             System.arraycopy(b, 1, a, 0, 16);
    155         } else {
    156             // copy the address into a 16 byte array, zero-filled.
    157             int p = 16 - b.length;
    158             System.arraycopy(b, 0, a, p + 0, b.length);
    159         }
    160         return InetAddress.getByAddress(a);
    161     }
    162 }