IPUtils.java

package com.ziesemer.utils.web.addressFilter.conditions;

/**
 * @author Mark A. Ziesemer
 * 	<a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a>
 */
public abstract class IPUtils{
	
	/**
	 * <p>
	 * 	Checks if a given address falls into the specified subnet (defined by network address and subnet length).
	 * </p>
	 * <p>
	 * 	Both addresses must be of the same length (same number of bytes), or <code>false</code> will be returned.
	 * 	(Addresses must be padded to match.)
	 * </p>
	 * <p>
	 * 	This is essentially a convenience method for {@link #createSubnetMask(int, int)} and
	 * 		{@link #isInSubnet(byte[], byte[], byte[])}.
	 * </p>
	 */
	public static boolean isInSubnet(final byte[] network, final int subnetLength, final byte[] address){
		final byte[] netmask = createSubnetMask(network.length, subnetLength);
		return isInSubnet(network, netmask, address);
	}
	
	/**
	 * <p>
	 * 	Generates a subnet mask (netmask).  The returned byte array will be of length
	 * 		<code>addressLength</code>, with the first <code>subnetLength</code> bits set to <code>1</code>.
	 * </p>
	 * @throws IllegalArgumentException If <code>subnetLength &gt; addressLength * 8</code>.
	 */
	public static byte[] createSubnetMask(final int addressLength, final int subnetLength){
		if(subnetLength > addressLength * 8){
			throw new IllegalArgumentException("subnetLength must be <= addressLength * 8.");
		}
		final byte[] netmask = new byte[addressLength];
		int maskPos;
		for(maskPos=0; maskPos < subnetLength / 8; maskPos++){
			netmask[maskPos] = (byte)0xFF;
		}
		if(maskPos < netmask.length){
			netmask[maskPos] = (byte)(0xFF << (8 - subnetLength % 8));
		}
		return netmask;
	}
	
	/**
	 * <p>
	 * 	Checks if a given address falls into the specified subnet (defined by network address and subnet mask).
	 * </p>
	 * <p>
	 * 	All addresses must be of the same length (same number of bytes), or <code>false</code> will be returned.
	 * 	(All addresses must be padded to match.)
	 * </p>
	 */
	public static boolean isInSubnet(final byte[] network, final byte[] netmask, final byte[] address){
		if(network.length != netmask.length || address.length != netmask.length){
			return false;
		}
		
		for(int i=0; i < address.length; i++){
			if((network[i] & netmask[i]) != (address[i] & netmask[i])){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * <p>
	 * 	Checks if a given address falls into the range specified b the start and end addresses, inclusive.
	 * </p>
	 * <p>
	 * 	All addresses must be of the same length (same number of bytes), or <code>false</code> will be returned.
	 * 	(All addresses must be padded to match.)
	 * </p>
	 */
	public static boolean isInRange(final byte[] begin, final byte[] end, final byte[] address){
		return lte(begin, address) && lte(address, end);
	}
	
	protected static boolean lte(final byte[] a, final byte[] b){
		if(a.length != b.length){
			return false;
		}
		for(int i=0; i < a.length; i++){
			final byte c = a[i];
			final byte d = b[i];
			if(c == d){
				continue;
			}
			if((c & 0xFF) < (d & 0xFF)){
				return true;
			}
			return false;
		}
		return true;
	}
	
}