/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.ipfilter; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.StringTokenizer; /** */ public abstract class CIDR implements Comparable<CIDR> { /** The base address of the CIDR notation */ protected InetAddress baseAddress; /** The mask used in the CIDR notation */ protected int cidrMask; /** * Create CIDR using the CIDR Notation * * @return the generated CIDR */ public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException { if (cidrMask < 0) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } if (baseAddress instanceof Inet4Address) { if (cidrMask > 32) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR4((Inet4Address) baseAddress, cidrMask); } // IPv6. if (cidrMask > 128) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR6((Inet6Address) baseAddress, cidrMask); } /** * Create CIDR using the normal Notation * * @return the generated CIDR */ public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException { int cidrMask = getNetMask(scidrMask); if (cidrMask < 0) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } if (baseAddress instanceof Inet4Address) { if (cidrMask > 32) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR4((Inet4Address) baseAddress, cidrMask); } cidrMask += 96; // IPv6. if (cidrMask > 128) { throw new UnknownHostException("Invalid mask length used: " + cidrMask); } return new CIDR6((Inet6Address) baseAddress, cidrMask); } /** * Create CIDR using the CIDR or normal Notation<BR> * i.e.: * CIDR subnet = newCIDR ("10.10.10.0/24"); or * CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or * CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0"); * * @return the generated CIDR */ public static CIDR newCIDR(String cidr) throws UnknownHostException { int p = cidr.indexOf('/'); if (p < 0) { throw new UnknownHostException("Invalid CIDR notation used: " + cidr); } String addrString = cidr.substring(0, p); String maskString = cidr.substring(p + 1); InetAddress addr = addressStringToInet(addrString); int mask; if (maskString.indexOf('.') < 0) { mask = parseInt(maskString, -1); } else { mask = getNetMask(maskString); if (addr instanceof Inet6Address) { mask += 96; } } if (mask < 0) { throw new UnknownHostException("Invalid mask length used: " + maskString); } return newCIDR(addr, mask); } /** @return the baseAddress of the CIDR block. */ public InetAddress getBaseAddress() { return baseAddress; } /** @return the Mask length. */ public int getMask() { return cidrMask; } /** @return the textual CIDR notation. */ @Override public String toString() { return baseAddress.getHostAddress() + '/' + cidrMask; } /** @return the end address of this block. */ public abstract InetAddress getEndAddress(); /** * Compares the given InetAddress against the CIDR and returns true if * the ip is in the subnet-ip-range and false if not. * * @return returns true if the given IP address is inside the currently * set network. */ public abstract boolean contains(InetAddress inetAddress); @Override public boolean equals(Object o) { if (!(o instanceof CIDR)) { return false; } return compareTo((CIDR) o) == 0; } @Override public int hashCode() { return baseAddress.hashCode(); } /** * Convert an IPv4 or IPv6 textual representation into an * InetAddress. * * @return the created InetAddress */ private static InetAddress addressStringToInet(String addr) throws UnknownHostException { return InetAddress.getByName(addr); } /** * Get the Subnet's Netmask in Decimal format.<BR> * i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask * * @param netMask a network mask * @return the integer CIDR mask */ private static int getNetMask(String netMask) { StringTokenizer nm = new StringTokenizer(netMask, "."); int i = 0; int[] netmask = new int[4]; while (nm.hasMoreTokens()) { netmask[i] = Integer.parseInt(nm.nextToken()); i++; } int mask1 = 0; for (i = 0; i < 4; i++) { mask1 += Integer.bitCount(netmask[i]); } return mask1; } /** * @param intstr a string containing an integer. * @param def the default if the string does not contain a valid * integer. * @return the inetAddress from the integer */ private static int parseInt(String intstr, int def) { Integer res; if (intstr == null) { return def; } try { res = Integer.decode(intstr); } catch (Exception e) { res = def; } return res.intValue(); } /** * Compute a byte representation of IpV4 from a IpV6 * * @return the byte representation * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 */ public static byte[] getIpV4FromIpV6(Inet6Address address) { byte[] baddr = address.getAddress(); for (int i = 0; i < 9; i++) { if (baddr[i] != 0) { throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); } } if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF) { throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); } return new byte[] {baddr[12], baddr[13], baddr[14], baddr[15]}; } /** * Compute a byte representation of IpV6 from a IpV4 * * @return the byte representation * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 */ public static byte[] getIpV6FromIpV4(Inet4Address address) { byte[] baddr = address.getAddress(); return new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]}; } }