summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/btr/proxy/selector/whitelist
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/btr/proxy/selector/whitelist')
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/DefaultWhiteListParser.java78
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/HostnameFilter.java93
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/IPv4WithSubnetChecker.java29
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/IpRangeFilter.java83
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/ProxyBypassListSelector.java84
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/UseProxyWhiteListSelector.java74
-rw-r--r--src/main/java/com/btr/proxy/selector/whitelist/WhiteListParser.java24
7 files changed, 465 insertions, 0 deletions
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/DefaultWhiteListParser.java b/src/main/java/com/btr/proxy/selector/whitelist/DefaultWhiteListParser.java
new file mode 100644
index 0000000..0f949e1
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/DefaultWhiteListParser.java
@@ -0,0 +1,78 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.btr.proxy.selector.whitelist.HostnameFilter.Mode;
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Default implementation for an white list parser. This will support the most
+ * common forms of filters found in white lists.
+ * The white list is a comma (or space) separated list of domain names or IP addresses.
+ * The following section shows some examples.
+ *
+ * .mynet.com - Filters all host names ending with .mynet.com
+ * *.mynet.com - Filters all host names ending with .mynet.com
+ * www.mynet.* - Filters all host names starting with www.mynet.
+ * 123.12.32.1 - Filters the IP 123.12.32.1
+ * 123.12.32.1/255 - Filters the IP range
+ * http://www.mynet.com - Filters only HTTP protocol not FTP and no HTTPS
+ *
+ * Example of a list:
+ *
+ * .mynet.com, *.my-other-net.org, 123.55.23.222, 123.55.23.0/24
+ *
+ * Some info about this topic can be found here:
+ * http://kb.mozillazine.org/No_proxy_for
+ * http://technet.microsoft.com/en-us/library/dd361953.aspx
+ *
+ * Note that this implementation does not cover all variations of all browsers
+ * but should cover the most used formats.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class DefaultWhiteListParser implements WhiteListParser {
+
+ /*************************************************************************
+ * parseWhiteList
+ * @see com.btr.proxy.selector.whitelist.WhiteListParser#parseWhiteList(java.lang.String)
+ ************************************************************************/
+
+ public List<UriFilter> parseWhiteList(String whiteList) {
+ List<UriFilter> result = new ArrayList<UriFilter>();
+
+ String[] token = whiteList.split("[, ]+");
+ for (int i = 0; i < token.length; i++) {
+ String tkn = token[i].trim();
+ if (isIP4SubnetFilter(tkn)) {
+ result.add(new IpRangeFilter(tkn));
+ continue;
+ } else
+ if (tkn.endsWith("*")) {
+ tkn = tkn.substring(0, tkn.length()-1);
+ result.add(new HostnameFilter(Mode.BEGINS_WITH, tkn));
+ continue;
+ } else
+ if (tkn.trim().startsWith("*")) {
+ tkn = tkn.substring(1);
+ result.add(new HostnameFilter(Mode.ENDS_WITH, tkn));
+ } else {
+ result.add(new HostnameFilter(Mode.ENDS_WITH, tkn));
+ }
+ }
+
+ return result;
+ }
+
+ /*************************************************************************
+ * @param token
+ * @return
+ ************************************************************************/
+
+ private boolean isIP4SubnetFilter(String token) {
+ return IPv4WithSubnetChecker.isValid(token);
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/HostnameFilter.java b/src/main/java/com/btr/proxy/selector/whitelist/HostnameFilter.java
new file mode 100644
index 0000000..176eaeb
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/HostnameFilter.java
@@ -0,0 +1,93 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.net.URI;
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Tests if a host name of a given URI matches some criteria.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class HostnameFilter implements UriFilter {
+
+ private static final String PROTOCOL_ENDING = "://";
+
+ public enum Mode {BEGINS_WITH, ENDS_WITH, REGEX}
+
+ private String matchTo;
+ private String protocolFilter;
+ private Mode mode;
+
+ /*************************************************************************
+ * Constructor
+ * @param mode the filter mode.
+ * @param matchTo the match criteria.
+ ************************************************************************/
+
+ public HostnameFilter(Mode mode, String matchTo) {
+ super();
+ this.mode = mode;
+ this.matchTo = matchTo.toLowerCase();
+
+ extractProtocolFilter();
+ }
+
+ /*************************************************************************
+ * Extracts the protocol if one is given to initialize the protocol matcher.
+ ************************************************************************/
+
+ private void extractProtocolFilter() {
+ int protocolIndex = this.matchTo.indexOf(PROTOCOL_ENDING);
+ if (protocolIndex != -1) {
+ this.protocolFilter = this.matchTo.substring(0, protocolIndex);
+ this.matchTo = this.matchTo.substring(protocolIndex+PROTOCOL_ENDING.length());
+ }
+ }
+
+ /*************************************************************************
+ * accept
+ * @see com.btr.proxy.util.UriFilter#accept(java.net.URI)
+ ************************************************************************/
+
+ public boolean accept(URI uri) {
+ if (uri == null || uri.getAuthority() == null) {
+ return false;
+ }
+
+ if (!isProtocolMatching(uri)) {
+ return false;
+ }
+
+ String host = uri.getAuthority();
+
+ // Strip away port.
+ int index = host.indexOf(':');
+ if (index != -1) {
+ host = host.substring(0, index);
+ }
+
+ switch (this.mode) {
+ case BEGINS_WITH :
+ return host.toLowerCase().startsWith(this.matchTo);
+ case ENDS_WITH :
+ return host.toLowerCase().endsWith(this.matchTo);
+ case REGEX :
+ return host.toLowerCase().matches(this.matchTo);
+ }
+ return false;
+ }
+
+ /*************************************************************************
+ * Applies the protocol filter if available to see if we have a match.
+ * @param uri to test for a correct protocol.
+ * @return true if passed else false.
+ ************************************************************************/
+
+ private boolean isProtocolMatching(URI uri) {
+ return this.protocolFilter == null
+ || uri.getScheme() == null
+ || uri.getScheme().equalsIgnoreCase(this.protocolFilter);
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/IPv4WithSubnetChecker.java b/src/main/java/com/btr/proxy/selector/whitelist/IPv4WithSubnetChecker.java
new file mode 100644
index 0000000..b8e713e
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/IPv4WithSubnetChecker.java
@@ -0,0 +1,29 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.util.regex.Pattern;
+
+/*****************************************************************************
+ * Checks if the given string is a IP4 range subnet definition
+ * of the format 192.168.0/24
+ * Based on a contribution by Jan Engler
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class IPv4WithSubnetChecker {
+
+ private static Pattern IP_SUB_PATTERN = Pattern.compile(
+ "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])/(\\d|([12]\\d|3[0-2]))$");
+
+ /*************************************************************************
+ * Tests if a given string is of in the correct format for an IP4 subnet mask.
+ * @param possibleIPAddress to test for valid format.
+ * @return true if valid else false.
+ ************************************************************************/
+
+ public static boolean isValid(String possibleIPAddress) {
+ return IP_SUB_PATTERN.matcher(possibleIPAddress).matches();
+ }
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/IpRangeFilter.java b/src/main/java/com/btr/proxy/selector/whitelist/IpRangeFilter.java
new file mode 100644
index 0000000..293f520
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/IpRangeFilter.java
@@ -0,0 +1,83 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Filters an URI by inspecting it's IP address is in a given range.
+ * The range as must be defined in CIDR notation.
+ * e.g. 192.0.2.1/24,
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class IpRangeFilter implements UriFilter {
+
+ private byte[] matchTo;
+ int numOfBits;
+
+ /*************************************************************************
+ * Constructor
+ * @param matchTo the match subnet in CIDR notation.
+ ************************************************************************/
+
+ public IpRangeFilter(String matchTo) {
+ super();
+
+ String[] parts = matchTo.split("/");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("IP range is not valid:"+matchTo);
+ }
+
+ try {
+ InetAddress address = InetAddress.getByName(parts[0].trim());
+ this.matchTo = address.getAddress();
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("IP range is not valid:"+matchTo);
+ }
+
+ this.numOfBits = Integer.parseInt(parts[1].trim());
+ }
+
+ /*************************************************************************
+ * accept
+ * @see com.btr.proxy.util.UriFilter#accept(java.net.URI)
+ ************************************************************************/
+
+ public boolean accept(URI uri) {
+ if (uri == null || uri.getHost() == null) {
+ return false;
+ }
+ try {
+ InetAddress address = InetAddress.getByName(uri.getHost());
+ byte[] addr = address.getAddress();
+
+ // Comparing IP6 against IP4?
+ if (addr.length != this.matchTo.length) {
+ return false;
+ }
+
+ int bit = 0;
+ for (int nibble = 0; nibble < addr.length; nibble++) {
+ for (int nibblePos = 7; nibblePos >= 0; nibblePos--) {
+ int mask = 1 << nibblePos;
+ if ((this.matchTo[nibble] & mask) != (addr[nibble] & mask)) {
+ return false;
+ }
+ bit++;
+ if (bit >= this.numOfBits) {
+ return true;
+ }
+ }
+ }
+
+ } catch (UnknownHostException e) {
+ // In this case we can not get the IP do not match.
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/ProxyBypassListSelector.java b/src/main/java/com/btr/proxy/selector/whitelist/ProxyBypassListSelector.java
new file mode 100644
index 0000000..81e2a7d
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/ProxyBypassListSelector.java
@@ -0,0 +1,84 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.List;
+
+import com.btr.proxy.util.ProxyUtil;
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Special purpose ProxySelector used as Facade on top of a normal ProxySelector.
+ * A wrapper that will first check the URI against a white list and if it matches
+ * it will return DIRECT else it will pass the URI to an delegate for inspection.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class ProxyBypassListSelector extends ProxySelector {
+
+ private ProxySelector delegate;
+ private List<UriFilter> whiteListFilter;
+
+
+ /*************************************************************************
+ * Constructor
+ * @param whiteListFilter a list of filters for whitelist URLs.
+ * @param proxySelector the proxy selector to use.
+ ************************************************************************/
+
+ public ProxyBypassListSelector(List<UriFilter> whiteListFilter, ProxySelector proxySelector) {
+ super();
+ if (whiteListFilter == null) {
+ throw new NullPointerException("Whitelist must not be null.");
+ }
+ if (proxySelector == null) {
+ throw new NullPointerException("ProxySelector must not be null.");
+ }
+
+ this.delegate = proxySelector;
+ this.whiteListFilter = whiteListFilter;
+ }
+
+
+ /*************************************************************************
+ * Constructor
+ * @param whiteList a list of filters for whitelist URLs as comma/space separated string.
+ * @param proxySelector the proxy selector to use.
+ ************************************************************************/
+
+ public ProxyBypassListSelector(String whiteList, ProxySelector proxySelector) {
+ this(new DefaultWhiteListParser().parseWhiteList(whiteList), proxySelector);
+ }
+
+ /*************************************************************************
+ * connectFailed
+ * @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
+ ************************************************************************/
+ @Override
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+ this.delegate.connectFailed(uri, sa, ioe);
+ }
+
+ /*************************************************************************
+ * select
+ * @see java.net.ProxySelector#select(java.net.URI)
+ ************************************************************************/
+
+ @Override
+ public List<Proxy> select(URI uri) {
+
+ // If in white list, use DIRECT connection.
+ for (UriFilter filter : this.whiteListFilter) {
+ if (filter.accept(uri)) {
+ return ProxyUtil.noProxyList();
+ }
+ }
+
+ return this.delegate.select(uri);
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/UseProxyWhiteListSelector.java b/src/main/java/com/btr/proxy/selector/whitelist/UseProxyWhiteListSelector.java
new file mode 100644
index 0000000..1aface9
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/UseProxyWhiteListSelector.java
@@ -0,0 +1,74 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.List;
+
+import com.btr.proxy.util.ProxyUtil;
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Special purpose ProxySelector used as Facade on top of a normal ProxySelector.
+ * A wrapper that will first check the URI against a white list and if it matches
+ * it will use a proxy as provided by the delegate ProxySelector else it will
+ * return DIRECT.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class UseProxyWhiteListSelector extends ProxySelector {
+
+ private ProxySelector delegate;
+ private List<UriFilter> whiteListFilter;
+
+ /*************************************************************************
+ * Constructor
+ * @param proxySelector the proxy selector to use.
+ ************************************************************************/
+
+ public UseProxyWhiteListSelector(String whiteList, ProxySelector proxySelector) {
+ super();
+ if (whiteList == null) {
+ throw new NullPointerException("Whitelist must not be null.");
+ }
+ if (proxySelector == null) {
+ throw new NullPointerException("ProxySelector must not be null.");
+ }
+
+ this.delegate = proxySelector;
+
+ WhiteListParser parser = new DefaultWhiteListParser();
+ this.whiteListFilter = parser.parseWhiteList(whiteList);
+ }
+
+ /*************************************************************************
+ * connectFailed
+ * @see java.net.ProxySelector#connectFailed(java.net.URI, java.net.SocketAddress, java.io.IOException)
+ ************************************************************************/
+ @Override
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+ this.delegate.connectFailed(uri, sa, ioe);
+ }
+
+ /*************************************************************************
+ * select
+ * @see java.net.ProxySelector#select(java.net.URI)
+ ************************************************************************/
+
+ @Override
+ public List<Proxy> select(URI uri) {
+
+ // If in white list, use proxy selector.
+ for (UriFilter filter : this.whiteListFilter) {
+ if (filter.accept(uri)) {
+ return this.delegate.select(uri);
+ }
+ }
+
+ return ProxyUtil.noProxyList();
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/whitelist/WhiteListParser.java b/src/main/java/com/btr/proxy/selector/whitelist/WhiteListParser.java
new file mode 100644
index 0000000..7cd5fd5
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/whitelist/WhiteListParser.java
@@ -0,0 +1,24 @@
+package com.btr.proxy.selector.whitelist;
+
+import java.util.List;
+
+import com.btr.proxy.util.UriFilter;
+
+/*****************************************************************************
+ * Interface for an white list parser. This will take an white list string and
+ * parse it into a list of UriFilter rules.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public interface WhiteListParser {
+
+ /*************************************************************************
+ * Parses a list of host name and IP filters into UriFilter objects.
+ * @param whiteList the string to parse.
+ * @return a list of UriFilters
+ ************************************************************************/
+
+ public List<UriFilter> parseWhiteList(String whiteList);
+
+}