@@ -7,6 +7,8 @@ import lombok.experimental.Accessors; | |||
import lombok.extern.slf4j.Slf4j; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; | |||
import static org.cobbzilla.util.http.HttpSchemes.SCHEME_HTTP; | |||
import static org.cobbzilla.util.http.HttpSchemes.SCHEME_HTTPS; | |||
@NoArgsConstructor @Accessors(chain=true) @Slf4j | |||
public class BubbleBlockCondition { | |||
@@ -44,13 +46,25 @@ public class BubbleBlockCondition { | |||
public boolean matches(String fqdn, String path, String contentType, String referer) { | |||
switch (field) { | |||
case fqdn: return operation.matches(fqdn, value); | |||
case path: return operation.matches(path, value); | |||
case url: return operation.matches(fqdn + path, value); | |||
case host: return operation.matches(fqdn, value); | |||
case path: return operation.matches(path, value); | |||
case url: return operation.matches(fqdn + path, value); | |||
case content_type: return operation.matches(contentType, value); | |||
case referer: return operation.matches(referer, value); | |||
case referer_host: return operation.matches(toFqdn(referer), value); | |||
case referer_url: return operation.matches(referer, value); | |||
default: log.warn("matches: invalid field: "+field); | |||
} | |||
return false; | |||
} | |||
private String toFqdn(String referer) { | |||
if (referer.startsWith(SCHEME_HTTPS)) { | |||
referer = referer.substring(SCHEME_HTTPS.length()); | |||
} else if (referer.startsWith(SCHEME_HTTP)) { | |||
referer = referer.substring(SCHEME_HTTP.length()); | |||
} | |||
final int slashPos = referer.indexOf("/"); | |||
return slashPos == -1 ? referer : referer.substring(0, slashPos); | |||
} | |||
} |
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; | |||
public enum BubbleBlockConditionField { | |||
fqdn, path, url, referer, content_type; | |||
host, path, url, referer_host, referer_url, content_type; | |||
@JsonCreator public static BubbleBlockConditionField fromString (String v) { return valueOf(v.toLowerCase()); | |||
} | |||
@@ -2,6 +2,7 @@ package bubble.abp; | |||
import com.fasterxml.jackson.annotation.JsonCreator; | |||
import lombok.AllArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.collection.ExpirationEvictionPolicy; | |||
import org.cobbzilla.util.collection.ExpirationMap; | |||
@@ -9,7 +10,7 @@ import java.util.regex.Pattern; | |||
import static java.util.regex.Pattern.CASE_INSENSITIVE; | |||
@AllArgsConstructor | |||
@AllArgsConstructor @Slf4j | |||
public enum BubbleBlockConditionOperation { | |||
eq (String::equalsIgnoreCase), | |||
@@ -29,6 +30,10 @@ public enum BubbleBlockConditionOperation { | |||
@JsonCreator public static BubbleBlockConditionOperation fromString (String v) { return valueOf(v.toLowerCase()); } | |||
public boolean matches(String input, String value) { return comparison.matches(input, value); } | |||
public boolean matches(String input, String value) { | |||
final boolean matches = comparison.matches(input, value); | |||
if (log.isDebugEnabled()) log.debug("matches: "+input+" "+this+" "+value+" -> "+matches); | |||
return matches; | |||
} | |||
} |
@@ -160,22 +160,28 @@ public class BlockListTest { | |||
} | |||
public static final String[][] CONDITIONAL_SPECS = { | |||
{"~foo.bar.com~[\"referer ne bar.com\"]", "foo.com", "foo.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer ne bar.com\"]", "bar.com", "bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer ne bar.com\"]", "foo.bar.com", "bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer ne bar.com\"]", "foo.bar.com", "foo.com", BLOCK}, | |||
{"~foo.bar.com~[\"referer ne bar.com\"]", "bar.com", "foo.com", ALLOW} | |||
// todo: add more tests for other operators, regex_find vs regex_exact, multiple conditions, etc | |||
// rule // fqdn // referer // expect | |||
{"~foo.bar.com~[\"referer_host ne bar.com\"]", "foo.com", "foo.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\"]", "bar.com", "bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\"]", "foo.bar.com", "bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\"]", "foo.bar.com", "foo.com", BLOCK}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\"]", "bar.com", "foo.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\", \"referer_host ne www.bar.com\"]", "foo.bar.com", "bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\", \"referer_host ne www.bar.com\"]", "foo.bar.com", "www.bar.com", ALLOW}, | |||
{"~foo.bar.com~[\"referer_host ne bar.com\", \"referer_host ne www.bar.com\"]", "foo.bar.com", "baz.com", BLOCK} | |||
// todo: add more tests for other operators, regex_find vs regex_exact, more conditions, etc | |||
}; | |||
@Test public void testConditionalMatches () throws Exception { | |||
final BlockList blockList = new BlockList(); | |||
for (String[] test : CONDITIONAL_SPECS) { | |||
blockList.addToBlacklist(BlockSpec.parse(test[0])); | |||
final BlockList blockList = new BlockList(); | |||
final String line = test[0]; | |||
blockList.addToBlacklist(BlockSpec.parse(line)); | |||
final BlockDecisionType expected = BlockDecisionType.fromString(test[3]); | |||
final String fqdn = test[1]; | |||
final String referer = test[2]; | |||
assertEquals("expected "+expected+" for test: fqdn="+fqdn+", referer="+referer, | |||
assertEquals("expected "+expected+" for test: fqdn="+fqdn+", referer="+referer+" for line: "+line, | |||
expected, | |||
blockList.getDecision(fqdn, "/", null, referer, true).getDecisionType()); | |||
} | |||