@@ -, +, @@ --- java/org/apache/catalina/util/NetMask.java | 103 ++++++++++++++++++++++++++++ 1 files changed, 103 insertions(+), 0 deletions(-) create mode 100644 java/org/apache/catalina/util/NetMask.java --- a/java/org/apache/catalina/util/NetMask.java +++ a/java/org/apache/catalina/util/NetMask.java @@ -0,0 +1,103 @@ +package org.apache.catalina.util; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A class representing a netmask, which is at the core of this valve. + * + *

The constructor takes a {@link java.lang.String} representing a + * CIDR netmask as an argument and extracts two informations from it: the + * network address and the CIDR. It then turns the address into a {@link + * java.math.BigInteger}, calculates the right shift and shifts that + * BigInteger by it.

+ *

The process to verify whether an IP address falls within the mask + * is to also convert it to a BigInteger, shifting it right and comparing + * it to the stored BigInteger. + *

+ */ + +public final class NetMask { + /** + * The argument to the constructor, used for .toString() + */ + private final String expression; + + /** + * The number of bits a matching candidate needs to be shifted right + * in order to see if it matches + */ + private final int shift; + + /** + * The network address, already shifted right + */ + private final BigInteger mask; + + /** + * Constructor. + * + * @param expression the CIDR netmask + * @throws IllegalArgumentException if the netmask is not correct + * (invalid address specification, malformed CIDR prefix, etc) + */ + public NetMask(final String expression) { + final int idx = expression.indexOf("/"); + final int cidr, addrlen; + final String addressPart; + final InetAddress addr; + final byte[] bytes; + + if (idx == -1) { + cidr = -1; + addressPart = expression; + } else { + final String substring = expression.substring(idx + 1); + try { + cidr = Integer.parseInt(substring); + if (cidr < 0) + throw new NumberFormatException("CIDR is negative"); + } catch (NumberFormatException ignored) { + throw new IllegalArgumentException("provided CIDR mask (" + + substring + ") is invalid"); + } + addressPart = expression.substring(0, idx); + } + + try { + addr = InetAddress.getByName(addressPart); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("provided address (" + + addressPart + ") is invalid"); + } + + bytes = addr.getAddress(); + addrlen = bytes.length * 8; + shift = cidr == -1 ? 0 : addrlen - cidr; + + if (shift < 0) + throw new IllegalArgumentException("CIDR prefix (" + cidr + + ") is greater than address length (" + addrlen + ")"); + mask = new BigInteger(bytes).shiftRight(shift); + this.expression = expression; + } + + /** + * Test if a given address matches this netmask + * + * @param addr The {@link java.net.InetAddress} to test + * @return true on match, false otherwise + */ + public boolean matches (final InetAddress addr) { + final BigInteger provided = new BigInteger(addr.getAddress()) + .shiftRight(shift); + + return mask.equals(provided); + } + + @Override + public String toString() { + return expression; + } +} --