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 }