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          BigInteger search = ipv6AddressToBigInteger(inetAddress);
97          return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0;
98      }
99  
100     /**
101      * Given an IPv6 baseAddress length, return the block length.  I.e., a
102      * baseAddress length of 96 will return 2**32.
103      */
104     private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask) {
105         return BigInteger.ONE.shiftLeft(128 - cidrMask);
106     }
107 
108     private static BigInteger ipv6CidrMaskToMask(int cidrMask) {
109         return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not();
110     }
111 
112     /**
113      * Given an IPv6 address, convert it into a BigInteger.
114      *
115      * @return the integer representation of the InetAddress
116      * @throws IllegalArgumentException if the address is not an IPv6
117      *                                  address.
118      */
119     private static BigInteger ipv6AddressToBigInteger(InetAddress addr) {
120         byte[] ipv6;
121         if (addr instanceof Inet4Address) {
122             ipv6 = getIpV6FromIpV4((Inet4Address) addr);
123         } else {
124             ipv6 = addr.getAddress();
125         }
126         if (ipv6[0] == -1) {
127             return new BigInteger(1, ipv6);
128         }
129         return new BigInteger(ipv6);
130     }
131 
132     /**
133      * Convert a big integer into an IPv6 address.
134      *
135      * @return the inetAddress from the integer
136      * @throws UnknownHostException if the big integer is too large,
137      *                              and thus an invalid IPv6 address.
138      */
139     private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException {
140         byte[] a = new byte[16];
141         byte[] b = addr.toByteArray();
142         if (b.length > 16 && !(b.length == 17 && b[0] == 0)) {
143             throw new UnknownHostException("invalid IPv6 address (too big)");
144         }
145         if (b.length == 16) {
146             return InetAddress.getByAddress(b);
147         }
148         // handle the case where the IPv6 address starts with "FF".
149         if (b.length == 17) {
150             System.arraycopy(b, 1, a, 0, 16);
151         } else {
152             // copy the address into a 16 byte array, zero-filled.
153             int p = 16 - b.length;
154             System.arraycopy(b, 0, a, p, b.length);
155         }
156         return InetAddress.getByAddress(a);
157     }
158 }