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