package com.netifera.platform.util.patternmatching;
// TODO Cisco style
// TODO cache result
public final class NetblockMatcher {
public enum Mode {
Any,
IPv4Only,
IPv6Only
}
private final boolean matched;
private String network;
private int cidr;
/**
* matches any IPv4 or IPv6 network block.
*
* @param text The string to match.
* @return <code>true</code> if the string matches.
*/
public NetblockMatcher(final String text) {
this(text, Mode.Any);
}
public NetblockMatcher(final String text, final Mode mode) {
if (text == null) {
matched = false;
} else if (text.contains("/")) {
matched = matchesCIDR(text, mode);
} else if (text.contains("-")) {
matched = matchesRange(text, mode);
} else {
matched = false;
}
}
@Override
public String toString() {
return matched ? network + "/" + cidr : "No match";
}
public boolean matches() {
return matched;
}
public String getNetwork() {
return network;
}
public int getCIDR() {
return cidr;
}
private boolean matchesCIDR(final String text, final Mode mode) {
String parts[] = text.split("\\/");
if (parts.length != 2) {
return false;
}
try {
cidr = Integer.parseInt(parts[1]);
} catch (NumberFormatException e) {
return false;
}
if (cidr < 0) {
return false;
}
if ((mode != Mode.IPv6Only
&& matchesIPv4CIDR(parts[0], cidr))
|| (mode != Mode.IPv4Only
&& matchesIPv6CIDR(parts[0], cidr))) {
network = parts[0];
return true;
}
return false;
}
private boolean matchesRange(final String text, final Mode mode) {
String parts[] = text.split("-");
if (parts.length != 2) {
return false;
}
if (mode != Mode.IPv6Only
&& InternetAddressMatcher.matchesIPv4(parts[0])
&& InternetAddressMatcher.matchesIPv4(parts[1])) {
network = parts[0];
cidr = 32; // XXX
return true;
}
if (mode != Mode.IPv4Only
&& InternetAddressMatcher.matchesIPv6(parts[0])
&& InternetAddressMatcher.matchesIPv6(parts[1])) {
network = parts[0];
cidr = 128; // XXX
return true;
}
return false;
}
private boolean matchesIPv4CIDR(final String addr, final int cidr) {
return cidr <= 32 && InternetAddressMatcher.matchesIPv4(addr);
}
private boolean matchesIPv6CIDR(final String addr, final int cidr) {
return cidr <= 128 && InternetAddressMatcher.matchesIPv6(addr);
}
/**
* matches any IPv4 or IPv6 network block.
*
* @param text The string to match.
* @return <code>true</code> if the string matches.
*/
public static boolean matches(final String text) {
return new NetblockMatcher(text, Mode.Any).matches();
}
/**
* matches an IPv4 network block.
*
* @param text The string to match.
* @return <code>true</code> if the string matches.
*/
public static boolean matchesIPv4(final String text) {
return new NetblockMatcher(text, Mode.IPv4Only).matches();
}
/**
* matches an IPv6 network block.
*
* @param text The string to match.
* @return <code>true</code> if the string matches.
*/
public static boolean matchesIPv6(final String text) {
return new NetblockMatcher(text, Mode.IPv6Only).matches();
}
}