/*
* This file is part of ReadonlyREST.
*
* ReadonlyREST is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ReadonlyREST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ReadonlyREST. If not, see http://www.gnu.org/licenses/
*/
package org.elasticsearch.plugin.readonlyrest.acl.domain;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Represents an IP range based on an address/mask.
*
* @author Scott Plante, using code snippets by John Kugelman.
*/
public class IPMask {
private Inet4Address i4addr;
private byte maskCtr;
private int addrInt;
private int maskInt;
public IPMask(Inet4Address i4addr, byte mask) {
this.i4addr = i4addr;
this.maskCtr = mask;
this.addrInt = addrToInt(i4addr);
this.maskInt = ~((1 << (32 - maskCtr)) - 1);
}
/**
* IPMask factory method.
*
* @param addrSlashMask IP/Mask String in format "nnn.nnn.nnn.nnn/mask". If
* the "/mask" is omitted, "/32" (just the single address) is assumed.
* @return a new IPMask
* @throws UnknownHostException if address part cannot be parsed by
* InetAddress
*/
public static IPMask getIPMask(String addrSlashMask)
throws UnknownHostException {
int pos = addrSlashMask.indexOf('/');
String addr;
byte maskCtr;
if (pos == -1) {
addr = addrSlashMask;
maskCtr = 32;
}
else {
addr = addrSlashMask.substring(0, pos);
maskCtr = Byte.parseByte(addrSlashMask.substring(pos + 1));
}
return new IPMask((Inet4Address) InetAddress.getByName(addr), maskCtr);
}
/**
* Converts IPv4 address to integer representation.
*/
private static int addrToInt(Inet4Address i4addr) {
byte[] ba = i4addr.getAddress();
return (ba[0] << 24)
| ((ba[1] & 0xFF) << 16)
| ((ba[2] & 0xFF) << 8)
| (ba[3] & 0xFF);
}
/**
* Test given IPv4 address against this IPMask object.
*
* @param testAddr address to check.
* @return true if address is in the IP Mask range, false if not.
*/
public boolean matches(Inet4Address testAddr) {
int testAddrInt = addrToInt(testAddr);
// Always allow 0.0.0.0/0 as a wild card
if (maskInt == -1 && addrInt == 0) {
return true;
}
return (addrInt & maskInt) == (testAddrInt & maskInt);
}
/**
* Convenience method that converts String host to IPv4 address.
*
* @param addr IP address to match in nnn.nnn.nnn.nnn format or hostname.
* @return true if address is in the IP Mask range, false if not.
* @throws UnknownHostException if the string cannot be decoded.
*/
public boolean matches(String addr)
throws UnknownHostException {
return matches((Inet4Address) InetAddress.getByName(addr));
}
@Override
public String toString() {
return "IPMask(" + i4addr.getHostAddress() + "/" + maskCtr + ")";
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final IPMask that = (IPMask) obj;
return this.addrInt == that.addrInt && this.maskInt == that.maskInt;
}
@Override
public int hashCode() {
return this.maskInt + this.addrInt;
}
}