/* * Copyright 2009 Red Hat, Inc. * * Red Hat 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.InetAddress; import java.net.UnknownHostException; import java.util.StringTokenizer; import java.util.Vector; /** * This class allows to check if an IP-V4-Address is contained in a subnet.<BR> * Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.<BR> * <BR><BR>Example1:<BR> * <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");</tt><BR> * <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR> * <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR> * <BR>Example1 bis:<BR> * <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);</tt><BR> * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR> * <BR><BR>Example2:<BR> * <tt>IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");</tt><BR> * <tt>System.out.println("Result: "+ ips.contains("192.168.1.123"));</tt><BR> * <tt>System.out.println("Result: "+ ips.contains(inetAddress2));</tt><BR> * <BR>Example2 bis:<BR> * <tt>IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");</tt><BR> * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123<BR> * @author frederic bregier * */ public class IpV4Subnet implements IpSet, Comparable<IpV4Subnet> { private static final int SUBNET_MASK = 0x80000000; private static final int BYTE_ADDRESS_MASK = 0xFF; private InetAddress inetAddress; private int subnet; private int mask; private int cidrMask; /** * Create IpV4Subnet for ALL (used for ALLOW or DENY ALL) */ public IpV4Subnet() { // ALLOW or DENY ALL mask = -1; // other will be ignored inetAddress = null; subnet = 0; cidrMask = 0; } /** * Create IpV4Subnet using the CIDR or normal Notation<BR> * i.e.: * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0"); * @param netAddress a network address as string. * @throws UnknownHostException * */ public IpV4Subnet(String netAddress) throws UnknownHostException { setNetAddress(netAddress); } /** * Create IpV4Subnet using the CIDR Notation * @param inetAddress * @param cidrNetMask */ public IpV4Subnet(InetAddress inetAddress, int cidrNetMask) { setNetAddress(inetAddress, cidrNetMask); } /** * Create IpV4Subnet using the normal Notation * @param inetAddress * @param netMask */ public IpV4Subnet(InetAddress inetAddress, String netMask) { setNetAddress(inetAddress, netMask); } /** * Sets the Network Address in either CIDR or Decimal Notation.<BR> * i.e.: setNetAddress("1.1.1.1/24"); or<BR> * setNetAddress("1.1.1.1/255.255.255.0");<BR> * @param netAddress a network address as string. * @throws UnknownHostException * */ private void setNetAddress(String netAddress) throws UnknownHostException { Vector<Object> vec = new Vector<Object>(); StringTokenizer st = new StringTokenizer(netAddress, "/"); while (st.hasMoreTokens()) { vec.add(st.nextElement()); } if (vec.get(1).toString().length() < 3) { setNetId(vec.get(0).toString()); setCidrNetMask(Integer.parseInt(vec.get(1).toString())); } else { setNetId(vec.get(0).toString()); setNetMask(vec.get(1).toString()); } } /** * Sets the Network Address in CIDR Notation. * @param inetAddress * @param cidrNetMask * */ private void setNetAddress(InetAddress inetAddress, int cidrNetMask) { setNetId(inetAddress); setCidrNetMask(cidrNetMask); } /** * Sets the Network Address in Decimal Notation. * @param inetAddress * @param netMask * */ private void setNetAddress(InetAddress inetAddress, String netMask) { setNetId(inetAddress); setNetMask(netMask); } /** * Sets the BaseAdress of the Subnet.<BR> * i.e.: setNetId("192.168.1.0"); * @param netId a network ID * @throws UnknownHostException * */ private void setNetId(String netId) throws UnknownHostException { InetAddress inetAddress1 = InetAddress.getByName(netId); this.setNetId(inetAddress1); } /** * Compute integer representation of InetAddress * @param inetAddress1 * @return the integer representation */ private int toInt(InetAddress inetAddress1) { byte[] address = inetAddress1.getAddress(); int net = 0; for (byte addres : address) { net <<= 8; net |= addres & BYTE_ADDRESS_MASK; } return net; } /** * Sets the BaseAdress of the Subnet. * @param inetAddress * */ private void setNetId(InetAddress inetAddress) { this.inetAddress = inetAddress; subnet = toInt(inetAddress); } /** * Sets the Subnet's Netmask in Decimal format.<BR> * i.e.: setNetMask("255.255.255.0"); * @param netMask a network mask * */ private void setNetMask(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]); } setCidrNetMask(mask1); } /** * Sets the CIDR Netmask<BR> * i.e.: setCidrNetMask(24); * @param cidrNetMask a netmask in CIDR notation * */ private void setCidrNetMask(int cidrNetMask) { cidrMask = cidrNetMask; mask = SUBNET_MASK >> cidrMask - 1; } /** * Compares the given IP-Address against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * @param ipAddr an ipaddress * @return returns true if the given IP address is inside the currently * set network. * @throws UnknownHostException * */ public boolean contains(String ipAddr) throws UnknownHostException { InetAddress inetAddress1 = InetAddress.getByName(ipAddr); return this.contains(inetAddress1); } /** * Compares the given InetAddress against the Subnet and returns true if * the ip is in the subnet-ip-range and false if not. * @param inetAddress1 * @return returns true if the given IP address is inside the currently * set network. * */ public boolean contains(InetAddress inetAddress1) { if (mask == -1) { // ANY return true; } return (toInt(inetAddress1) & mask) == subnet; } @Override public String toString() { return inetAddress.getHostAddress() + "/" + cidrMask; } @Override public boolean equals(Object o) { if (!(o instanceof IpV4Subnet)) { return false; } IpV4Subnet ipV4Subnet = (IpV4Subnet) o; return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask; } /** * Compare two IpV4Subnet */ public int compareTo(IpV4Subnet o) { if (o.subnet == subnet && o.cidrMask == cidrMask) { return 0; } if (o.subnet < subnet) { return 1; } else if (o.subnet > subnet) { return -1; } else if (o.cidrMask < cidrMask) { // greater Mask means less IpAddresses so -1 return -1; } return 1; } /** * Simple test functions * @param args * where args[0] is the netmask (standard or CIDR notation) and optional args[1] is * the inetAddress to test with this IpV4Subnet */ public static void main(String[] args) { if (args.length != 0) { IpV4Subnet ipV4Subnet = null; try { ipV4Subnet = new IpV4Subnet(args[0]); } catch (UnknownHostException e) { return; } if (args.length > 1) { try { System.out.println("Is IN: " + args[1] + " " + ipV4Subnet.contains(args[1])); } catch (UnknownHostException e) { } } } } }