package com.netifera.platform.util.addresses.inet;
import java.util.NoSuchElementException;
import com.netifera.platform.util.addresses.AddressFormatException;
public class IPv4Netblock extends InternetNetblock {
private static final long serialVersionUID = -1490064632240429900L;
private static final int MAX_MASKBIT = IPv4Address.BYTESLENGTH * 8;;
private static long[] subnetMaskIpSize;
static {
subnetMaskIpSize = new long[MAX_MASKBIT + 1];
int ipNumber = 1;
for (int i = MAX_MASKBIT; i != 0; i--) {
subnetMaskIpSize[i] = ipNumber;
ipNumber <<= 1;
}
}
public IPv4Netblock(final IPv4Address network, final int maskBitCount) {
super(network, maskBitCount);
}
public IPv4Netblock(final byte[] bytes, final int maskBitCount) {
super(IPv4Address.BYTESLENGTH, bytes, maskBitCount);
}
//public IPv4Netblock(final String fromIP, final String toIP) {
// super(fromIP, toIP);
//}
@Override
protected IPv4Address netblockStartAddress(InternetAddress network,
int maskBitCount) {
return new IPv4Address(((IPv4Address)network).addressData
& makeMask(maskBitCount));
}
@Override
public IPv4Address getNetworkAddress() {
return (IPv4Address) network;
}
@Override
public IPv4Address getNetmaskAddress() {
return new IPv4Address(makeMask(maskBitCount));
}
@Override
public IPv4Address getBroadcastAddress() {
return new IPv4Address(getNetworkAddress().addressData
| ~makeMask(maskBitCount));
}
/**
* @return the smaller network Mask (in bits) required to fit ipNumber
* InternetAddress.
*/
public static int getMaskBits(final int ipNumber) {
if (ipNumber < 0) {
throw new
IllegalArgumentException("Invalid IPv4 number: " + ipNumber);
}
int maskBit = MAX_MASKBIT;
while(maskBit != 0 && subnetMaskIpSize[maskBit] < ipNumber) {
maskBit--;
}
return maskBit;
}
public static long getIpNumber(int maskBit) {
if (maskBit < 0 || maskBit > MAX_MASKBIT) {
throw new
IllegalArgumentException("Invalid IPv4 bitmask: " + maskBit);
}
return subnetMaskIpSize[maskBit];
}
public boolean contains(final InternetAddress address) {
if(!(address instanceof IPv4Address)) { // FIXME about encapsulable?
return false;
}
IPv4Address ipv4 = (IPv4Address) address;
int mask = makeMask();
return ((ipv4.addressData & mask)
== (getNetworkAddress().addressData & mask));
}
private int makeMask() {
return makeMask(maskBitCount);
}
public static int makeMask(final int maskBitCount) {
return maskBitCount == 0 ? 0 : (1 << 31) >> (maskBitCount - 1);
}
public boolean isIndexedIterable() {
return maskBitCount >= 2; /* to fit java signed integer */
}
public IPv4Address itemAt(final int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("index:" + index
+ " for itemcount:" + itemCount());
}
if (!isIndexedIterable()) {
throw new NoSuchElementException("index:" + index);
}
return new IPv4Address(getNetworkAddress().addressData & makeMask()
| index);
}
/**
* @return how many InternetAddress this Netblock contains.
* @see com.netifera.platform.util.addresses.INetworkblock#itemCount()
*/
public int itemCount() {
if (!isIndexedIterable()) {
return 0;
}
return (int) subnetMaskIpSize[maskBitCount];
// return (1 << (MAX_MASKBIT - maskBitCount));
}
/**
* Hosts available for this network block.
*
* @return the number of hosts available
*/
public int availableHosts() {
int r = itemCount() - 2;
if (r <= 0) {
/* RFC 3021 for PPP links */
r += 2;
}
return r;
}
/*
* see RCF 3330: Special-Use IPv4 Addresses
* see IANA Internet Protocol v4 Address Space
*/
public boolean isBogus() {
byte[] bytes = network.toBytes();
int b0 = bytes[0] & 0xFF;
int b1 = bytes[1] & 0xFF;
int b2 = bytes[2] & 0xFF;
return (b0 == 192 && b1 == 0 && b2 == 2 && maskBitCount >= 24); // 192.0.2/24
}
/* TODO:
* - 0/7 2/8 5/8
* - 27/8 31/8 36/7 39/8
* - 42/8 46/8 49/8 50/8 100/5 108/6 112/7
* - 173/8 174/7 176/6
* - 193/8 223/8 241->255/8
*/
public boolean isReserved() {
return (network.toBytes()[0] & 0xFF) == 240 && maskBitCount >= 4; // 240/4
}
@Override
public boolean isLoopback() {
return (network.toBytes()[0] & 0xFF) == 127 && maskBitCount >= 8; // 127/8
}
public boolean isLocal() {
byte[] bytes = network.toBytes();
int b0 = bytes[0] & 0xFF;
int b1 = bytes[1] & 0xFF;
return (b0 == 169 && b1 == 254 && maskBitCount >= 16) // 169.254/16
|| isLoopback();
}
public boolean isPrivate() {
/*
* see RFC 1918: Address Allocation for Private Internets
*/
byte[] bytes = network.toBytes();
int b0 = bytes[0] & 0xFF;
if (b0 == 10) return maskBitCount >= 8; // 10/8
int b1 = bytes[1] & 0xFF;
if (b0 == 172) {
return b1 >= 16 && b1 <= 32 && maskBitCount >= 12; // 172.16/12
}
if (b0 == 192 && b1 == 168) return maskBitCount >= 16; // 192.168/16
return false;
}
public int compareTo(final IPv4Netblock other) {
int r;
r = network.compareTo(other.network);
if (r > 0) {
return 1;
} else if (r < 0) {
return -1;
}
return maskBitCount < other.maskBitCount ? 1
: (maskBitCount == other.maskBitCount ? 0 : -1);
}
public int compareTo(InternetNetblock other) {
if (other instanceof IPv4Netblock) {
return compareTo((IPv4Netblock)other);
}
return -1; // XXX
}
/*
* see RFC 1112: Host Extensions for IP Multicasting
* see IANA Internet Multicast Addresses
*/
// TODO isMulticast()
/**
* @param addr IP address in network byte order
* @param maskBitCount bit mask
*
* @exception IllegalArgumentException if the prefix is invalid.
* @exception AddressFormatException if the array length is not valid
*/
public static IPv4Netblock fromData(byte[] addr, int maskBitCount) {
verifyIPv4Buffer(addr);
return (IPv4Netblock) IPv4Address.fromBytes(addr).createNetblock(
maskBitCount);
}
private static void verifyIPv4Buffer(byte[] addr) {
if (addr.length != IPv4Address.BYTESLENGTH) {
throw new AddressFormatException("Invalid IPv4 array size: "
+ addr.length);
}
}
}