From e70ee5b59306ea37dd0c72603c61b33b1555def9 Mon Sep 17 00:00:00 2001
From: Björn Hagemeister
Date: Tue, 11 Nov 2014 14:40:18 +0100
Subject: Added proxy java classes.
---
.../java/com/btr/proxy/search/ProxySearch.java | 258 ++++++
.../com/btr/proxy/search/ProxySearchStrategy.java | 22 +
.../browser/firefox/FirefoxProfileSource.java | 23 +
.../firefox/FirefoxProxySearchStrategy.java | 267 +++++++
.../browser/firefox/FirefoxSettingParser.java | 79 ++
.../browser/firefox/LinuxFirefoxProfileSource.java | 46 ++
.../browser/firefox/WinFirefoxProfileSource.java | 71 ++
.../search/browser/ie/IELocalByPassFilter.java | 28 +
.../search/browser/ie/IEProxySearchStrategy.java | 213 +++++
.../search/desktop/DesktopProxySearchStrategy.java | 69 ++
.../desktop/gnome/GnomeProxySearchStrategy.java | 353 +++++++++
.../desktop/gnome/ProxySchemasGSettingsAccess.java | 60 ++
.../search/desktop/kde/KdeProxySearchStrategy.java | 198 +++++
.../search/desktop/kde/KdeSettingsParser.java | 132 ++++
.../search/desktop/osx/OsxProxySearchStrategy.java | 325 ++++++++
.../btr/proxy/search/desktop/win/DLLManager.java | 171 ++++
.../proxy/search/desktop/win/Win32IESettings.java | 68 ++
.../proxy/search/desktop/win/Win32ProxyUtils.java | 88 +++
.../search/desktop/win/WinProxySearchStrategy.java | 52 ++
.../proxy/search/env/EnvProxySearchStrategy.java | 130 +++
.../proxy/search/java/JavaProxySearchStrategy.java | 133 ++++
.../proxy/search/wpad/WpadProxySearchStrategy.java | 234 ++++++
.../wpad/WpadProxySearchStrategyWithDHPC.java | 315 ++++++++
.../btr/proxy/search/wpad/dhcp/DHCPMessage.java | 880 +++++++++++++++++++++
.../btr/proxy/search/wpad/dhcp/DHCPOptions.java | 235 ++++++
.../com/btr/proxy/search/wpad/dhcp/DHCPSocket.java | 107 +++
.../btr/proxy/selector/direct/NoProxySelector.java | 70 ++
.../proxy/selector/fixed/FixedProxySelector.java | 69 ++
.../proxy/selector/fixed/FixedSocksSelector.java | 27 +
.../proxy/selector/misc/BufferedProxySelector.java | 126 +++
.../selector/misc/ProtocolDispatchSelector.java | 115 +++
.../selector/misc/ProxyListFallbackSelector.java | 150 ++++
.../proxy/selector/pac/JavaxPacScriptParser.java | 147 ++++
.../btr/proxy/selector/pac/PacProxySelector.java | 184 +++++
.../btr/proxy/selector/pac/PacScriptMethods.java | 656 +++++++++++++++
.../btr/proxy/selector/pac/PacScriptParser.java | 29 +
.../btr/proxy/selector/pac/PacScriptSource.java | 31 +
.../selector/pac/ProxyEvaluationException.java | 51 ++
.../proxy/selector/pac/RhinoPacScriptParser.java | 318 ++++++++
.../btr/proxy/selector/pac/ScriptAvailability.java | 46 ++
.../com/btr/proxy/selector/pac/ScriptMethods.java | 256 ++++++
.../btr/proxy/selector/pac/UrlPacScriptSource.java | 270 +++++++
.../selector/whitelist/DefaultWhiteListParser.java | 78 ++
.../proxy/selector/whitelist/HostnameFilter.java | 93 +++
.../selector/whitelist/IPv4WithSubnetChecker.java | 29 +
.../proxy/selector/whitelist/IpRangeFilter.java | 83 ++
.../whitelist/ProxyBypassListSelector.java | 84 ++
.../whitelist/UseProxyWhiteListSelector.java | 74 ++
.../proxy/selector/whitelist/WhiteListParser.java | 24 +
src/main/java/com/btr/proxy/test/ProxyTester.java | 176 +++++
.../java/com/btr/proxy/util/EmptyXMLResolver.java | 26 +
src/main/java/com/btr/proxy/util/Logger.java | 87 ++
src/main/java/com/btr/proxy/util/PListParser.java | 544 +++++++++++++
src/main/java/com/btr/proxy/util/PlatformUtil.java | 114 +++
.../java/com/btr/proxy/util/ProxyException.java | 50 ++
src/main/java/com/btr/proxy/util/ProxyUtil.java | 84 ++
src/main/java/com/btr/proxy/util/UriFilter.java | 21 +
src/main/resources/lib/gsettings-amd64.so | Bin 0 -> 11979 bytes
src/main/resources/lib/gsettings-x86.so | Bin 0 -> 11822 bytes
src/main/resources/lib/proxy_util_amd64.dll | Bin 0 -> 40448 bytes
src/main/resources/lib/proxy_util_ia64.dll | Bin 0 -> 91136 bytes
src/main/resources/lib/proxy_util_w32.dll | Bin 0 -> 43520 bytes
src/test/java/com/btr/proxy/Examples.java | 47 ++
src/test/java/com/btr/proxy/TestUtil.java | 61 ++
.../com/btr/proxy/search/browser/FirefoxTest.java | 144 ++++
.../java/com/btr/proxy/search/browser/IeTest.java | 59 ++
.../search/desktop/DesktopProxySearchTest.java | 45 ++
.../proxy/search/desktop/win/DLLManagerTest.java | 78 ++
.../proxy/search/gnome/GnomeProxySearchTest.java | 117 +++
.../btr/proxy/search/java/JavaProxySearchTest.java | 137 ++++
.../btr/proxy/search/kde/KdeProxySearchTest.java | 177 +++++
.../btr/proxy/selector/fixed/FixedProxyTest.java | 56 ++
.../proxy/selector/java/JavaProxySelectorTest.java | 28 +
.../proxy/selector/misc/ProtocolDispatchTest.java | 87 ++
.../misc/ProxyListFallbackSelectorTest.java | 94 +++
.../selector/pac/JavaxPacScriptParserTest.java | 119 +++
.../btr/proxy/selector/pac/PacPerProtocolTest.java | 47 ++
.../btr/proxy/selector/pac/PacProxyDebugging.java | 103 +++
.../proxy/selector/pac/PacProxySelectorTest.java | 133 ++++
.../proxy/selector/pac/PacScriptMethodsTest.java | 165 ++++
.../selector/pac/RhinoPacScriptParserTest.java | 114 +++
.../proxy/selector/pac/UrlPacScriptSourceTest.java | 34 +
.../btr/proxy/selector/whitelist/NoProxyTest.java | 108 +++
.../java/com/btr/proxy/util/PListParserTest.java | 101 +++
.../java/com/btr/proxy/util/ProxyUtilTest.java | 78 ++
.../java/com/btr/proxy/util/UriFilterTest.java | 122 +++
.../.mozilla/firefox/9f1uyzzu.default/prefs.js | 76 ++
.../.mozilla/firefox/9f1uyzzu.default/prefs.js | 77 ++
.../.mozilla/firefox/9f1uyzzu.default/prefs.js | 76 ++
.../.mozilla/firefox/9f1uyzzu.default/prefs.js | 77 ++
.../.gconf/system/http_proxy/%gconf.xml | 23 +
.../gnome_manual/.gconf/system/proxy/%gconf.xml | 36 +
.../gnome_none/.gconf/system/http_proxy/%gconf.xml | 21 +
.../.gconf/system/http_proxy/%gconf.xml | 26 +
.../.gconf/system/proxy/%gconf.xml | 39 +
.../.gconf/system/http_proxy/%gconf.xml | 26 +
.../.gconf/system/proxy/%gconf.xml | 36 +
.../data/kde_env/.kde/share/config/kioslaverc | 17 +
.../data/kde_manual/.kde/share/config/kioslaverc | 17 +
.../data/kde_none/.kde/share/config/kioslaverc | 17 +
.../kde_pac_script/.kde/share/config/kioslaverc | 17 +
.../kde_white_list/.kde/share/config/kioslaverc | 17 +
src/test/resources/data/osx/osx_all.plist | 144 ++++
src/test/resources/data/osx/osx_manual.plist | 144 ++++
src/test/resources/data/osx/osx_pac.plist | 144 ++++
src/test/resources/data/pac/test1.pac | 4 +
src/test/resources/data/pac/test2.pac | 10 +
src/test/resources/data/pac/testDateRange.pac | 11 +
src/test/resources/data/pac/testLocalIP.pac | 4 +
src/test/resources/data/pac/testMultiProxy.pac | 4 +
src/test/resources/data/pac/testTimeRange.pac | 11 +
src/test/resources/data/pac/testWeekDay.pac | 10 +
src/test/resources/data/win/proxy_util_amd64.dll | 0
src/test/resources/data/win/proxy_util_ia64.dll | 0
src/test/resources/data/win/proxy_util_w32.dll | 0
src/test/resources/data/wpad/wpad.pac | 4 +
116 files changed, 12011 insertions(+)
create mode 100644 src/main/java/com/btr/proxy/search/ProxySearch.java
create mode 100644 src/main/java/com/btr/proxy/search/ProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProfileSource.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/ie/IELocalByPassFilter.java
create mode 100644 src/main/java/com/btr/proxy/search/browser/ie/IEProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/DesktopProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/gnome/GnomeProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/gnome/ProxySchemasGSettingsAccess.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/kde/KdeProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/kde/KdeSettingsParser.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/osx/OsxProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/win/DLLManager.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/win/Win32IESettings.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/win/Win32ProxyUtils.java
create mode 100644 src/main/java/com/btr/proxy/search/desktop/win/WinProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/env/EnvProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/java/JavaProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategy.java
create mode 100644 src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java
create mode 100644 src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java
create mode 100644 src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPOptions.java
create mode 100644 src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPSocket.java
create mode 100644 src/main/java/com/btr/proxy/selector/direct/NoProxySelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/fixed/FixedProxySelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/fixed/FixedSocksSelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/misc/BufferedProxySelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/misc/ProtocolDispatchSelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/misc/ProxyListFallbackSelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/JavaxPacScriptParser.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/PacProxySelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/PacScriptMethods.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/PacScriptParser.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/PacScriptSource.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/ProxyEvaluationException.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/RhinoPacScriptParser.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/ScriptAvailability.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/ScriptMethods.java
create mode 100644 src/main/java/com/btr/proxy/selector/pac/UrlPacScriptSource.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/DefaultWhiteListParser.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/HostnameFilter.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/IPv4WithSubnetChecker.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/IpRangeFilter.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/ProxyBypassListSelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/UseProxyWhiteListSelector.java
create mode 100644 src/main/java/com/btr/proxy/selector/whitelist/WhiteListParser.java
create mode 100644 src/main/java/com/btr/proxy/test/ProxyTester.java
create mode 100644 src/main/java/com/btr/proxy/util/EmptyXMLResolver.java
create mode 100644 src/main/java/com/btr/proxy/util/Logger.java
create mode 100644 src/main/java/com/btr/proxy/util/PListParser.java
create mode 100644 src/main/java/com/btr/proxy/util/PlatformUtil.java
create mode 100644 src/main/java/com/btr/proxy/util/ProxyException.java
create mode 100644 src/main/java/com/btr/proxy/util/ProxyUtil.java
create mode 100644 src/main/java/com/btr/proxy/util/UriFilter.java
create mode 100644 src/main/resources/lib/gsettings-amd64.so
create mode 100644 src/main/resources/lib/gsettings-x86.so
create mode 100644 src/main/resources/lib/proxy_util_amd64.dll
create mode 100644 src/main/resources/lib/proxy_util_ia64.dll
create mode 100644 src/main/resources/lib/proxy_util_w32.dll
create mode 100644 src/test/java/com/btr/proxy/Examples.java
create mode 100644 src/test/java/com/btr/proxy/TestUtil.java
create mode 100644 src/test/java/com/btr/proxy/search/browser/FirefoxTest.java
create mode 100644 src/test/java/com/btr/proxy/search/browser/IeTest.java
create mode 100644 src/test/java/com/btr/proxy/search/desktop/DesktopProxySearchTest.java
create mode 100644 src/test/java/com/btr/proxy/search/desktop/win/DLLManagerTest.java
create mode 100644 src/test/java/com/btr/proxy/search/gnome/GnomeProxySearchTest.java
create mode 100644 src/test/java/com/btr/proxy/search/java/JavaProxySearchTest.java
create mode 100644 src/test/java/com/btr/proxy/search/kde/KdeProxySearchTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/fixed/FixedProxyTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/java/JavaProxySelectorTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/misc/ProtocolDispatchTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/misc/ProxyListFallbackSelectorTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/JavaxPacScriptParserTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/PacPerProtocolTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/PacProxyDebugging.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/PacProxySelectorTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/PacScriptMethodsTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/RhinoPacScriptParserTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/pac/UrlPacScriptSourceTest.java
create mode 100644 src/test/java/com/btr/proxy/selector/whitelist/NoProxyTest.java
create mode 100644 src/test/java/com/btr/proxy/util/PListParserTest.java
create mode 100644 src/test/java/com/btr/proxy/util/ProxyUtilTest.java
create mode 100644 src/test/java/com/btr/proxy/util/UriFilterTest.java
create mode 100644 src/test/resources/data/ff3_manual/.mozilla/firefox/9f1uyzzu.default/prefs.js
create mode 100644 src/test/resources/data/ff3_none/.mozilla/firefox/9f1uyzzu.default/prefs.js
create mode 100644 src/test/resources/data/ff3_pac_script/.mozilla/firefox/9f1uyzzu.default/prefs.js
create mode 100644 src/test/resources/data/ff3_white_list/.mozilla/firefox/9f1uyzzu.default/prefs.js
create mode 100755 src/test/resources/data/gnome_manual/.gconf/system/http_proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_manual/.gconf/system/proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_none/.gconf/system/http_proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_pac_script/.gconf/system/http_proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_pac_script/.gconf/system/proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_white_list/.gconf/system/http_proxy/%gconf.xml
create mode 100755 src/test/resources/data/gnome_white_list/.gconf/system/proxy/%gconf.xml
create mode 100644 src/test/resources/data/kde_env/.kde/share/config/kioslaverc
create mode 100644 src/test/resources/data/kde_manual/.kde/share/config/kioslaverc
create mode 100644 src/test/resources/data/kde_none/.kde/share/config/kioslaverc
create mode 100644 src/test/resources/data/kde_pac_script/.kde/share/config/kioslaverc
create mode 100644 src/test/resources/data/kde_white_list/.kde/share/config/kioslaverc
create mode 100644 src/test/resources/data/osx/osx_all.plist
create mode 100644 src/test/resources/data/osx/osx_manual.plist
create mode 100644 src/test/resources/data/osx/osx_pac.plist
create mode 100644 src/test/resources/data/pac/test1.pac
create mode 100644 src/test/resources/data/pac/test2.pac
create mode 100644 src/test/resources/data/pac/testDateRange.pac
create mode 100644 src/test/resources/data/pac/testLocalIP.pac
create mode 100644 src/test/resources/data/pac/testMultiProxy.pac
create mode 100644 src/test/resources/data/pac/testTimeRange.pac
create mode 100644 src/test/resources/data/pac/testWeekDay.pac
create mode 100644 src/test/resources/data/win/proxy_util_amd64.dll
create mode 100644 src/test/resources/data/win/proxy_util_ia64.dll
create mode 100644 src/test/resources/data/win/proxy_util_w32.dll
create mode 100644 src/test/resources/data/wpad/wpad.pac
(limited to 'src')
diff --git a/src/main/java/com/btr/proxy/search/ProxySearch.java b/src/main/java/com/btr/proxy/search/ProxySearch.java
new file mode 100644
index 0000000..19db95f
--- /dev/null
+++ b/src/main/java/com/btr/proxy/search/ProxySearch.java
@@ -0,0 +1,258 @@
+package com.btr.proxy.search;
+
+import java.awt.GraphicsEnvironment;
+import java.net.ProxySelector;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.btr.proxy.search.browser.firefox.FirefoxProxySearchStrategy;
+import com.btr.proxy.search.browser.ie.IEProxySearchStrategy;
+import com.btr.proxy.search.desktop.DesktopProxySearchStrategy;
+import com.btr.proxy.search.desktop.gnome.GnomeProxySearchStrategy;
+import com.btr.proxy.search.desktop.kde.KdeProxySearchStrategy;
+import com.btr.proxy.search.desktop.win.WinProxySearchStrategy;
+import com.btr.proxy.search.env.EnvProxySearchStrategy;
+import com.btr.proxy.search.java.JavaProxySearchStrategy;
+import com.btr.proxy.selector.misc.BufferedProxySelector;
+import com.btr.proxy.selector.misc.ProxyListFallbackSelector;
+import com.btr.proxy.selector.pac.PacProxySelector;
+import com.btr.proxy.util.Logger;
+import com.btr.proxy.util.PlatformUtil;
+import com.btr.proxy.util.ProxyException;
+import com.btr.proxy.util.Logger.LogBackEnd;
+import com.btr.proxy.util.Logger.LogLevel;
+
+/*****************************************************************************
+ * Main class to setup and initialize the proxy detection system.
+ * This class can be used to select a proxy discovery strategy.
+ * Implements the "Builder" pattern.
+ * Use addStrategy
to add one or more search strategies.
+ * If you are done call the getProxySelector
method.
+ * Then the strategies are asked one after the other for a ProxySelector until
+ * an valid selector is found.
+ *
+ * Invoke the static getDefaultProxySearch
method to use a default search strategy.
+ *
+ * .mozilla/firefox/(profile)/ folder. + *
+ * + * See Mozilla_Networking_Preferences + * for an explanation of the proxy settings. + *+ * The following settings are extracted from + * this file: + *
+ * Some generic settings:+ * Note that if there are more than one profile the first profile found will be used. + *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class FirefoxProxySearchStrategy implements ProxySearchStrategy { + + private FirefoxProfileSource profileScanner; + private FirefoxSettingParser settingsParser; + + /************************************************************************* + * ProxySelector + * @see java.net.ProxySelector#ProxySelector() + ************************************************************************/ + + public FirefoxProxySearchStrategy() { + super(); + if (PlatformUtil.getCurrentPlattform() == Platform.WIN) { + this.profileScanner = new WinFirefoxProfileSource(); + } else { + this.profileScanner = new LinuxFirefoxProfileSource(); + } + this.settingsParser = new FirefoxSettingParser(); + } + + /************************************************************************* + * Loads the proxy settings and initializes a proxy selector for the firefox + * proxy settings. + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException on file reading error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + Logger.log(getClass(), LogLevel.TRACE, "Detecting Firefox settings."); + + Properties settings = readSettings(); + + ProxySelector result = null; + int type = Integer.parseInt(settings.getProperty("network.proxy.type", "-1")); + switch (type) { + case -1: // Use system settings + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses system settings"); + result = new DesktopProxySearchStrategy().getProxySelector(); + break; + case 0: // Use no proxy + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses no proxy"); + result = NoProxySelector.getInstance(); + break; + case 1: // Fixed settings + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses manual settings"); + result = setupFixedProxySelector(settings); + break; + case 2: // PAC Script + String pacScriptUrl = settings.getProperty("network.proxy.autoconfig_url", ""); + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses script (PAC) {0}", pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + break; + case 3: // Backward compatibility to netscape. + Logger.log(getClass(), LogLevel.TRACE, "Netscape compability mode -> uses no proxy"); + result = NoProxySelector.getInstance(); + break; + case 4: // WPAD auto config + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses automatic detection (WPAD)"); + result = new WpadProxySearchStrategy().getProxySelector(); + break; + default: + break; + } + + // Wrap in white list filter. + String noProxyList = settings.getProperty("network.proxy.no_proxies_on", null); + if (result != null && noProxyList != null && noProxyList.trim().length() > 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox uses proxy bypass list for: {0}", noProxyList); + result = new ProxyBypassListSelector(noProxyList, result); + } + + return result; + } + + /************************************************************************* + * Reads the settings file and stores all settings in a Properties map. + * @return the parsed settings. + * @throws ProxyException on read error. + ************************************************************************/ + + public Properties readSettings() throws ProxyException { + try { + Properties settings = this.settingsParser.parseSettings(this.profileScanner); + return settings; + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Error parsing settings", e); + throw new ProxyException(e); + } + } + + /************************************************************************* + * Parse the fixed proxy settings and build an ProxySelector for this a + * chained configuration. + * @param settings the proxy settings to evaluate. + ************************************************************************/ + + private ProxySelector setupFixedProxySelector(Properties settings) { + ProtocolDispatchSelector ps = new ProtocolDispatchSelector(); + installHttpProxy(ps, settings); + if (isProxyShared(settings)) { + installSharedProxy(ps); + } else { + installFtpProxy(ps, settings); + installSecureProxy(ps, settings); + installSocksProxy(ps, settings); + } + return ps; + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installFtpProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + installSelectorForProtocol(ps, settings, "ftp"); + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installHttpProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + installSelectorForProtocol(ps, settings, "http"); + } + + /************************************************************************* + * @param settings + * @return + ************************************************************************/ + + private boolean isProxyShared(Properties settings) { + return Boolean.TRUE.toString().equals(settings.getProperty("network.proxy.share_proxy_settings", "false").toLowerCase()); + } + + /************************************************************************* + * @param ps + ************************************************************************/ + + private void installSharedProxy(ProtocolDispatchSelector ps) { + ProxySelector httpProxy = ps.getSelector("http"); + if (httpProxy != null) { + ps.setFallbackSelector(httpProxy); + } + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installSocksProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + String proxyHost = settings.getProperty("network.proxy.socks", null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy.socks_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox socks proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector("socks", new FixedSocksSelector(proxyHost, proxyPort)); + } + } + + /************************************************************************* + * @param ps + * @param settings + * @throws NumberFormatException + ************************************************************************/ + + private void installSecureProxy(ProtocolDispatchSelector ps, + Properties settings) throws NumberFormatException { + String proxyHost = settings.getProperty("network.proxy.ssl", null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy.ssl_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox secure proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector("https", new FixedProxySelector(proxyHost, proxyPort)); + ps.setSelector("sftp", new FixedProxySelector(proxyHost, proxyPort)); + } + } + + /************************************************************************* + * Installs a proxy selector for the given protocol when settings are + * available. + * @param ps a ProtocolDispatchSelector to configure. + * @param settings to read the config from. + * @param protocol to configure. + * @throws NumberFormatException + ************************************************************************/ + + private void installSelectorForProtocol(ProtocolDispatchSelector ps, + Properties settings, String protocol) throws NumberFormatException { + + String proxyHost = settings.getProperty("network.proxy."+protocol, null); + int proxyPort = Integer.parseInt(settings.getProperty("network.proxy."+protocol+"_port", "0")); + if (proxyHost != null && proxyPort != 0) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox "+protocol+" proxy is {0}:{1}", proxyHost, proxyPort); + ps.setSelector(protocol, new FixedProxySelector(proxyHost, proxyPort)); + } + } + + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java new file mode 100644 index 0000000..b793299 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/FirefoxSettingParser.java @@ -0,0 +1,79 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Properties; + +/***************************************************************************** + * Parser for the Firefox settings file. + * Will extract all relevant proxy settings form the configuration file. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class FirefoxSettingParser { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public FirefoxSettingParser() { + super(); + } + + /************************************************************************* + * Parse the settings file and extract all network.proxy.* settings from it. + * @param source of the Firefox profiles. + * @return the parsed properties. + * @throws IOException on read error. + ************************************************************************/ + + public Properties parseSettings(FirefoxProfileSource source) throws IOException { + // Search settings folder + File profileFolder = source.getProfileFolder(); + + // Read settings from file + File settingsFile = new File(profileFolder, "prefs.js"); + + BufferedReader fin = new BufferedReader( + new InputStreamReader( + new FileInputStream(settingsFile))); + + Properties result = new Properties(); + try { + String line = fin.readLine(); + while (line != null) { + line = line.trim(); + if (line.startsWith("user_pref(\"network.proxy")) { + line = line.substring(10, line.length()-2); + int index = line.indexOf(","); + String key = line.substring(0, index).trim(); + if (key.startsWith("\"")) { + key = key.substring(1); + } + if (key.endsWith("\"")) { + key = key.substring(0, key.length()-1); + } + String value = line.substring(index+1).trim(); + if (value.startsWith("\"")) { + value = value.substring(1); + } + if (value.endsWith("\"")) { + value = value.substring(0, value.length()-1); + } + result.put(key, value); + } + line = fin.readLine(); + } + } finally { + fin.close(); + } + + return result; + } + + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java b/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java new file mode 100644 index 0000000..38b1553 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/LinuxFirefoxProfileSource.java @@ -0,0 +1,46 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.File; + +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Searches for Firefox profile on an Linux / Unix base system. + * This will scan the .mozilla folder in the users home directory to find the + * profiles. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class LinuxFirefoxProfileSource implements FirefoxProfileSource { + + /************************************************************************* + * Get profile folder for the Linux Firefox profile + ************************************************************************/ + + public File getProfileFolder() { + File userDir = new File(System.getProperty("user.home")); + File cfgDir = new File(userDir, ".mozilla"+File.separator+"firefox"+File.separator); + if (!cfgDir.exists()) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox settings folder not found!"); + return null; + } + File[] profiles = cfgDir.listFiles(); + if (profiles == null || profiles.length == 0) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox settings folder not found!"); + return null; + } + for (File p : profiles) { + if (p.getName().endsWith(".default")) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox settings folder is {0}", p); + return p; + } + } + + // Fall back -> take the first one found. + Logger.log(getClass(), LogLevel.TRACE, "Firefox settings folder is {0}", profiles[0]); + return profiles[0]; + } + +} diff --git a/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java b/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java new file mode 100644 index 0000000..9189585 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/firefox/WinFirefoxProfileSource.java @@ -0,0 +1,71 @@ +package com.btr.proxy.search.browser.firefox; + +import java.io.File; +import java.io.IOException; + +import com.btr.proxy.search.desktop.win.Win32ProxyUtils; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Finds the Firefox profile on Windows platforms. + * On Windows the profiles are located in the users appdata directory under: + *+ * Mozilla\Firefox\Profiles\ + *
+ * The location of the appdata folder is read from the windows registry. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +class WinFirefoxProfileSource implements FirefoxProfileSource { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public WinFirefoxProfileSource() { + super(); + } + + /************************************************************************* + * Reads the current location of the app data folder from the registry. + * @return a path to the folder. + ************************************************************************/ + + private String getAppFolder() { + return new Win32ProxyUtils().readUserHomedir(); + } + + /************************************************************************* + * Get profile folder for the Windows Firefox profile + * @throws IOException on error. + ************************************************************************/ + + public File getProfileFolder() throws IOException { + + File appDataDir = new File(getAppFolder()); + File cfgDir = new File(appDataDir, "Mozilla"+File.separator+"Firefox"+File.separator+"Profiles"); + + if (!cfgDir.exists()) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox windows settings folder not found."); + return null; + } + File[] profiles = cfgDir.listFiles(); + if (profiles == null || profiles.length == 0) { + Logger.log(getClass(), LogLevel.DEBUG, "Firefox windows settings folder not found."); + return null; + } + for (File p : profiles) { + if (p.getName().endsWith(".default")) { + Logger.log(getClass(), LogLevel.TRACE, "Firefox windows settings folder is {0}.", p); + return p; + } + } + + // Fall back -> take the first one found. + Logger.log(getClass(), LogLevel.TRACE, "Firefox windows settings folder is {0}.", profiles[0]); + return profiles[0]; + } + +} diff --git a/src/main/java/com/btr/proxy/search/browser/ie/IELocalByPassFilter.java b/src/main/java/com/btr/proxy/search/browser/ie/IELocalByPassFilter.java new file mode 100644 index 0000000..fb81d6f --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/ie/IELocalByPassFilter.java @@ -0,0 +1,28 @@ +package com.btr.proxy.search.browser.ie; + +import java.net.URI; + +import com.btr.proxy.util.UriFilter; + +/***************************************************************************** + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class IELocalByPassFilter implements UriFilter { + + /************************************************************************* + * accept + * @see com.btr.proxy.util.UriFilter#accept(java.net.URI) + ************************************************************************/ + + public boolean accept(URI uri) { + if (uri == null) { + return false; + } + String host = uri.getAuthority(); + return host != null && !host.contains("."); + } + +} + diff --git a/src/main/java/com/btr/proxy/search/browser/ie/IEProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/browser/ie/IEProxySearchStrategy.java new file mode 100644 index 0000000..2a9b078 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/browser/ie/IEProxySearchStrategy.java @@ -0,0 +1,213 @@ +package com.btr.proxy.search.browser.ie; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.ProxySelector; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import com.btr.proxy.search.ProxySearchStrategy; +import com.btr.proxy.search.desktop.win.Win32IESettings; +import com.btr.proxy.search.desktop.win.Win32ProxyUtils; +import com.btr.proxy.selector.fixed.FixedProxySelector; +import com.btr.proxy.selector.misc.ProtocolDispatchSelector; +import com.btr.proxy.selector.pac.PacProxySelector; +import com.btr.proxy.selector.pac.UrlPacScriptSource; +import com.btr.proxy.selector.whitelist.ProxyBypassListSelector; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.ProxyException; +import com.btr.proxy.util.ProxyUtil; +import com.btr.proxy.util.Logger.LogLevel; +import com.btr.proxy.util.UriFilter; + +/***************************************************************************** + * Extracts the proxy settings for Microsoft Internet Explorer. + * The settings are read by invoking native Windows API methods. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class IEProxySearchStrategy implements ProxySearchStrategy { + + /************************************************************************* + * getProxySelector + * @see com.btr.proxy.search.ProxySearchStrategy#getProxySelector() + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + + Logger.log(getClass(), LogLevel.TRACE, "Detecting IE proxy settings"); + + Win32IESettings ieSettings = readSettings(); + + ProxySelector result = createPacSelector(ieSettings); + if (result == null) { + result = createFixedProxySelector(ieSettings); + } + return result; + } + + /************************************************************************* + * Loads the settings from the windows registry. + * @return WinIESettings containing all proxy settings. + ************************************************************************/ + + public Win32IESettings readSettings() { + Win32IESettings ieSettings = new Win32ProxyUtils().winHttpGetIEProxyConfigForCurrentUser(); + return ieSettings; + } + + /************************************************************************* + * Parses the settings and creates an PAC ProxySelector for it. + * @param ieSettings the IE settings to use. + * @return a PacProxySelector the selector or null. + ************************************************************************/ + + private PacProxySelector createPacSelector(Win32IESettings ieSettings) { + String pacUrl = null; + + if (ieSettings.isAutoDetect()) { + Logger.log(getClass(), LogLevel.TRACE, "Autodetecting script URL."); + // This will take some time. + pacUrl = new Win32ProxyUtils().winHttpDetectAutoProxyConfigUrl( + Win32ProxyUtils.WINHTTP_AUTO_DETECT_TYPE_DHCP+ + Win32ProxyUtils.WINHTTP_AUTO_DETECT_TYPE_DNS_A); + } + if (pacUrl == null) { + pacUrl = ieSettings.getAutoConfigUrl(); + } + if (pacUrl != null && pacUrl.trim().length() > 0) { + Logger.log(getClass(), LogLevel.TRACE, "IE uses script: "+pacUrl); + + // Fix for issue 9 + // If the IE has a file URL and it only starts has 2 slashes, + // add a third so it can be properly converted to the URL class + if (pacUrl.startsWith("file://") && !pacUrl.startsWith("file:///")) { + pacUrl = "file:///" + pacUrl.substring(7); + } + return ProxyUtil.buildPacSelectorForUrl(pacUrl); + } + + return null; + } + + /************************************************************************* + * Parses the proxy settings into an ProxySelector. + * @param ieSettings the settings to use. + * @return a ProxySelector, null if no settings are set. + * @throws ProxyException on error. + ************************************************************************/ + + private ProxySelector createFixedProxySelector(Win32IESettings ieSettings) throws ProxyException { + String proxyString = ieSettings.getProxy(); + String bypassList = ieSettings.getProxyBypass(); + if (proxyString == null) { + return null; + } + Logger.log(getClass(), LogLevel.TRACE, + "IE uses manual settings: {0} with bypass list: {1}", proxyString, bypassList); + + Properties p = parseProxyList(proxyString); + + ProtocolDispatchSelector ps = new ProtocolDispatchSelector(); + addSelectorForProtocol(p, "http", ps); + addSelectorForProtocol(p, "https", ps); + addSelectorForProtocol(p, "ftp", ps); + addSelectorForProtocol(p, "gopher", ps); + addSelectorForProtocol(p, "socks", ps); + addFallbackSelector(p, ps); + + ProxySelector result = setByPassListOnSelector(bypassList, ps); + return result; + } + + /************************************************************************* + * @param bypassList + * @param ps + * @return + ************************************************************************/ + + private ProxySelector setByPassListOnSelector(String bypassList, + ProtocolDispatchSelector ps) { + if (bypassList != null && bypassList.trim().length() > 0) { + ProxyBypassListSelector result; + if ("+ * The following settings are extracted from the configuration that is stored + * in .gconf folder found in the user's home directory: + *
+ *+ * GNOME Proxy_configuration settings are explained + * here in detail + *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class GnomeProxySearchStrategy implements ProxySearchStrategy { + + /************************************************************************* + * ProxySelector + * @see java.net.ProxySelector#ProxySelector() + ************************************************************************/ + + public GnomeProxySearchStrategy() { + super(); + } + + /************************************************************************* + * Loads the proxy settings and initializes a proxy selector for the Gnome + * proxy settings. + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException on file reading error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + + Logger.log(getClass(), LogLevel.TRACE, "Detecting Gnome proxy settings"); + + Properties settings = readSettings(); + + String type = settings.getProperty("/system/proxy/mode"); + ProxySelector result = null; + if (type == null) { + String useProxy = settings.getProperty("/system/http_proxy/use_http_proxy"); + if (useProxy == null) { + return null; + } + type = Boolean.parseBoolean(useProxy)?"manual":"none"; + } + + if ("none".equals(type)) { + Logger.log(getClass(), LogLevel.TRACE, "Gnome uses no proxy"); + result = NoProxySelector.getInstance(); + } + if ("manual".equals(type)) { + Logger.log(getClass(), LogLevel.TRACE, "Gnome uses manual proxy settings"); + result = setupFixedProxySelector(settings); + } + if ("auto".equals(type)) { + String pacScriptUrl = settings.getProperty("/system/proxy/autoconfig_url", ""); + Logger.log(getClass(), LogLevel.TRACE, "Gnome uses autodetect script {0}", pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + } + + // Wrap into white-list filter? + String noProxyList = settings.getProperty("/system/http_proxy/ignore_hosts", null); + if (result != null && noProxyList != null && noProxyList.trim().length() > 0) { + Logger.log(getClass(), LogLevel.TRACE, "Gnome uses proxy bypass list: {0}", noProxyList); + result = new ProxyBypassListSelector(noProxyList, result); + } + + return result; + } + + /************************************************************************* + * Load the proxy settings from the gconf settings XML file. + * @return the loaded settings stored in a properties object. + * @throws ProxyException on processing error. + ************************************************************************/ + + public Properties readSettings() throws ProxyException { + Properties settings = new Properties(); + try { + parseSettings("/system/proxy/", settings); + parseSettings("/system/http_proxy/", settings); + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Gnome settings file error.", e); + throw new ProxyException(e); + } + return settings; + } + + /************************************************************************* + * Finds the Gnome GConf settings file. + * @param context the gconf context to parse. + * @return a file or null if does not exist. + ************************************************************************/ + + private File findSettingsFile(String context) { + // Normally we should inspect /etc/gconf/+ * .kde/share/config/kioslaverc + *
+ * starting from the current users home directory. + *+ * The following settings are extracted from the section "[Proxy Settings]": + *
+ *+ * .kde/share/config/kioslaverc + *
+ * in the users home directory. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class KdeSettingsParser { + + private File settingsFile; + + /************************************************************************* + * Constructor + ************************************************************************/ + + public KdeSettingsParser() { + this(null); + } + + /************************************************************************* + * Constructor + ************************************************************************/ + + public KdeSettingsParser(File settingsFile) { + super(); + this.settingsFile = settingsFile; + } + + /************************************************************************* + * Parse the settings file and extract all network.proxy.* settings from it. + * @return the parsed properties. + * @throws IOException on read error. + ************************************************************************/ + + public Properties parseSettings() throws IOException { + // Search for existing settings. + if (this.settingsFile == null) { + this.settingsFile = findSettingsFile(); + } + if (this.settingsFile == null) { + return null; + } + + // Read settings from file. + BufferedReader fin = new BufferedReader( + new InputStreamReader( + new FileInputStream(this.settingsFile))); + + Properties result = new Properties(); + try { + String line = fin.readLine(); + + // Find section start. + while (line != null && !"[Proxy Settings]".equals(line.trim())) { + line = fin.readLine(); + } + if (line == null) { + return result; + } + + // Read full section + line = ""; + while (line != null && !line.trim().startsWith("[")) { + line = line.trim(); + int index = line.indexOf('='); + if (index > 0) { + String key = line.substring(0, index).trim(); + String value = line.substring(index+1).trim(); + result.setProperty(key, value); + } + + line = fin.readLine(); + } + } finally { + fin.close(); + } + + return result; + } + + /************************************************************************* + * Finds all the KDE network settings file. + * @return a file or null if does not exist. + ************************************************************************/ + + private File findSettingsFile() { + File userDir = new File(System.getProperty("user.home")); + if ("4".equals(System.getenv("KDE_SESSION_VERSION"))) { + this.settingsFile = findSettingsFile( + new File(userDir, ".kde4"+File.separator+"share"+File.separator+"config"+File.separator+"kioslaverc")); + } + if (this.settingsFile == null) { + return findSettingsFile( + new File(userDir, ".kde"+File.separator+"share"+File.separator+"config"+File.separator+"kioslaverc")); + } else { + return this.settingsFile; + } + } + + /************************************************************************* + * Internal method to test if the settings file is at the given place. + * @param settingsFile the path to test. + * @return the file or null if it does not exist. + ************************************************************************/ + + private File findSettingsFile(File settingsFile) { + Logger.log(getClass(), LogLevel.TRACE, "Searching Kde settings in {0}", settingsFile); + if (!settingsFile.exists()) { + Logger.log(getClass(), LogLevel.DEBUG, "Settings not found"); + return null; + } + Logger.log(getClass(), LogLevel.TRACE, "Settings found"); + return settingsFile; + } + +} diff --git a/src/main/java/com/btr/proxy/search/desktop/osx/OsxProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/desktop/osx/OsxProxySearchStrategy.java new file mode 100644 index 0000000..3d67ae7 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/desktop/osx/OsxProxySearchStrategy.java @@ -0,0 +1,325 @@ +package com.btr.proxy.search.desktop.osx; + +import java.io.File; +import java.io.IOException; +import java.net.NetworkInterface; +import java.net.ProxySelector; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; + +import com.btr.proxy.search.ProxySearchStrategy; +import com.btr.proxy.search.browser.ie.IELocalByPassFilter; +import com.btr.proxy.search.wpad.WpadProxySearchStrategy; +import com.btr.proxy.selector.direct.NoProxySelector; +import com.btr.proxy.selector.fixed.FixedProxySelector; +import com.btr.proxy.selector.fixed.FixedSocksSelector; +import com.btr.proxy.selector.misc.ProtocolDispatchSelector; +import com.btr.proxy.selector.whitelist.ProxyBypassListSelector; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; +import com.btr.proxy.util.PListParser; +import com.btr.proxy.util.PListParser.Dict; +import com.btr.proxy.util.PListParser.XmlParseException; +import com.btr.proxy.util.ProxyException; +import com.btr.proxy.util.ProxyUtil; +import com.btr.proxy.util.UriFilter; + +/***************************************************************************** + * Loads the OSX system proxy settings from the settings file. + *+ * All settings are stored in OSX in a special XML file format. + * These settings file are named plist files and contain nested dictionaries, arrays and values. + *
+ * To parse this file we use a parser that is derived from a plist parser that + * comes with the xmlwise XML parser package: + *
+ * http://code.google.com/p/xmlwise/ + *
+ * I modified that parser to work with the default Java XML parsing library. + *
+ * The plist file is located on OSX at: + *
+ * /Library/Preferences/SystemConfiguration/preferences.plist + *
+ * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2011 + ****************************************************************************/ + +public class OsxProxySearchStrategy implements ProxySearchStrategy { + + public static final String OVERRIDE_SETTINGS_FILE = "com.btr.proxy.osx.settingsFile"; + public static final String OVERRIDE_ACCEPTED_DEVICES = "com.btr.proxy.osx.acceptedDevices"; + + private static final String SETTINGS_FILE = "/Library/Preferences/SystemConfiguration/preferences.plist"; + + /************************************************************************* + * ProxySelector + * @see java.net.ProxySelector#ProxySelector() + ************************************************************************/ + + public OsxProxySearchStrategy() { + super(); + } + + /************************************************************************* + * Loads the proxy settings and initializes a proxy selector for the OSX + * proxy settings. + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException on file reading error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + + Logger.log(getClass(), LogLevel.TRACE, "Detecting OSX proxy settings"); + + try { + List+ * This class will need some native code from the library proxy_util_"arch".dll. + * To load this library we use a three step algorithm as following: + *
+ * First check the System property "proxy_vole_lib_dir" if it is set and + * it points to a folder where the dll is found than the dll from this + * folder is loaded as e.g. "proxy_vole_lib_dir"/proxy_util_w32.dll + *
+ * Second we try to load the dll from the subfolder lib if that one exists.
+ * Finally if we are inside of a jar file we need to extract the dll file
+ * to a temp-file because windows can not load dlls from a jar
+ * directly. This is a hack but it may work.
+ *
+ * Please note that the file is named Win32ProxyUtils but has now also support + * for x64 architecture. + *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class Win32ProxyUtils { + + public static final int WINHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001; + public static final int WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002; + + + // Code for loading the windows native dll + static { + try { + File libFile = DLLManager.findLibFile(); + System.load(libFile.getAbsolutePath()); + DLLManager.cleanupTempFiles(); + } catch (IOException e) { + throw new RuntimeException("Error loading dll"+e.getMessage(), e); + } + } + + /************************************************************************* + * Constructor + ************************************************************************/ + + public Win32ProxyUtils() { + super(); + } + + /************************************************************************* + * WinHTTP method to detect an PAC URL. + * @param mode the mode to use. + * @return the PAC URL, null if none was found. + ************************************************************************/ + + public native String winHttpDetectAutoProxyConfigUrl(int mode); + + /************************************************************************* + * Gets the default windows proxy settings. + * The returned string will have the following format. + * TYPE PROXY | BYPASSLIST + *+ * e.g. DIRECT myproxy.mycompany.com:8080 | *.mycompany.com, localhost + *
+ * @return a string containing all info, null if not found. + ************************************************************************/ + // TODO Not implemented correctly in DLL yet. + native String winHttpGetDefaultProxyConfiguration(); + + /************************************************************************* + * Extracts the Internet Explorer proxy settings from the Windows system. + * @return a data structure containing all details, null on fail. + ************************************************************************/ + + public native Win32IESettings winHttpGetIEProxyConfigForCurrentUser(); + + /************************************************************************* + * Extracts the Internet Explorer proxy settings from the Windows system. + * @return a data structure containing all details, null on fail. + ************************************************************************/ + + public native String readUserHomedir(); + + +} + diff --git a/src/main/java/com/btr/proxy/search/desktop/win/WinProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/desktop/win/WinProxySearchStrategy.java new file mode 100644 index 0000000..1f26505 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/desktop/win/WinProxySearchStrategy.java @@ -0,0 +1,52 @@ +package com.btr.proxy.search.desktop.win; + +import java.net.ProxySelector; + +import com.btr.proxy.search.ProxySearchStrategy; +import com.btr.proxy.search.browser.ie.IEProxySearchStrategy; +import com.btr.proxy.util.ProxyException; + +/***************************************************************************** + * Extracts the proxy settings from the windows registry. + * This will read the windows system proxy settings. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class WinProxySearchStrategy implements ProxySearchStrategy { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public WinProxySearchStrategy() { + super(); + } + + /************************************************************************* + * getProxySelector + * @see com.btr.proxy.search.ProxySearchStrategy#getProxySelector() + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + // TODO Rossi 08.05.2009 Implement this by using Win API calls. + // new Win32ProxyUtils().winHttpGetDefaultProxyConfiguration() + // Current fallback is to use the IE settings. This is better + // because the registry settings are most of the time not set. + // Some Windows server installations may use it though. + return new IEProxySearchStrategy().getProxySelector(); + } + + /************************************************************************* + * Loads the settings. + * @return a WinIESettings object containing all proxy settings. + ************************************************************************/ + + public Win32IESettings readSettings() { + return new IEProxySearchStrategy().readSettings(); + } + + + + +} diff --git a/src/main/java/com/btr/proxy/search/env/EnvProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/env/EnvProxySearchStrategy.java new file mode 100644 index 0000000..37bd0a1 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/env/EnvProxySearchStrategy.java @@ -0,0 +1,130 @@ +package com.btr.proxy.search.env; + +import java.net.ProxySelector; +import java.util.Properties; + +import com.btr.proxy.search.ProxySearchStrategy; +import com.btr.proxy.selector.misc.ProtocolDispatchSelector; +import com.btr.proxy.selector.whitelist.ProxyBypassListSelector; +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.ProxyUtil; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Reads some environment variables and extracts the proxy settings from them. + * These variables are mainly set on linux / unix environments. + * The following variables are read per default: + *
+ * This is based on information found here:
+ * http://download.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
+ *
+ * Note: at the moment only the DNS name guessing schema is implemented. + * All others are missing. + *
+ * For more information about WPAD: + * Web_Proxy_Autodiscovery_Protocol + *
+ * Outdated RFC draft: + * draft-ietf-wrec-wpad-01.txt + *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class WpadProxySearchStrategy implements ProxySearchStrategy { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public WpadProxySearchStrategy() { + super(); + } + + /************************************************************************* + * Loads the proxy settings from a PAC file. + * The location of the PAC file is determined automatically. + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException on error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + try { + Logger.log(getClass(), LogLevel.TRACE, "Using WPAD to find a proxy"); + + String pacScriptUrl = detectScriptUrlPerDHCP(); + if (pacScriptUrl == null) { + pacScriptUrl = detectScriptUrlPerDNS(); + } + if (pacScriptUrl == null) { + return null; + } + Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", pacScriptUrl); + return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Error during WPAD search.", e); + throw new ProxyException(e); + } + } + + /************************************************************************* + * Loads the settings and stores them in a properties map. + * @return the settings. + ************************************************************************/ + + public Properties readSettings() { + try { + String pacScriptUrl = detectScriptUrlPerDHCP(); + if (pacScriptUrl == null) { + pacScriptUrl = detectScriptUrlPerDNS(); + } + if (pacScriptUrl == null) { + return null; + } + Properties result = new Properties(); + result.setProperty("url", pacScriptUrl); + return result; + } catch (IOException e) { + // Ignore and return empty properties. + return new Properties(); + } + } + + /************************************************************************* + * Uses DNS to find the script URL. + * Attention: this detection method is known to have some severe security issues. + * @return the URL, null if not found. + ************************************************************************/ + + private String detectScriptUrlPerDNS() throws IOException { + String result = null; + // String fqdn = InetAddress.getLocalHost().getCanonicalHostName(); + + Logger.log(getClass(), LogLevel.TRACE, "Searching per DNS guessing."); + // Logger.log(getClass(), LogLevel.INFO, "fqdn: ", fqdn); + + /** Reading address from "/etc/resolv.conf"; file looks like: + * + # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) + # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN + nameserver 127.0.1.1 + search ruf.uni-freiburg.de lp.ruf.uni-freiburg.de + */ + + FileReader fr = new FileReader("/etc/resolv.conf"); + BufferedReader br = new BufferedReader(fr); + + String input; + String[] addresses = null; + // using the 4th line of the file. + while ((input = br.readLine()) != null) { + if (input.startsWith("search")) { + // the first one is "search" and afterwards addresses are following. + addresses = input.substring(6).split(" "); + break; + } + } + + if (addresses == null) { + addresses = new String[]{""}; + } + + + for (int i = 0; i < addresses.length; ++i) { + String address = addresses[i]; + int index = -1; + do { + if (index != -1) { + address = address.substring(index); + } else { + address = ""; + } + + // Try to connect to URL + try { + address = ".uni-freiburg.de"; + URL lookupURL = new URL("http://wpad"+ address +"/wpad.dat"); + Logger.log(getClass(), LogLevel.TRACE, "Trying url: {0}", lookupURL); + + HttpURLConnection con = (HttpURLConnection) lookupURL.openConnection(Proxy.NO_PROXY); + con.setInstanceFollowRedirects(true); + con.setRequestProperty("accept", "application/x-ns-proxy-autoconfig"); + if (con.getResponseCode() == 200) { + result = lookupURL.toString(); + return result; + } + con.disconnect(); + } catch (UnknownHostException e) { + Logger.log(getClass(), LogLevel.DEBUG, "Not available!"); + // Not a real error, try next address + } + if (address.length() == 0) { + break; + } + index = address.indexOf('.', 1); + } while (true); + } + + return null; + } + + /************************************************************************* + * Uses DHCP to find the script URL. + * @return the URL, null if not found. + ************************************************************************/ + + private String detectScriptUrlPerDHCP() { + Logger.log(getClass(), LogLevel.DEBUG, "Searching per DHCP not supported yet."); + // TODO Rossi 28.04.2009 Not implemented yet. + return null; + } + + // Main method for testing. + public static void main( String[] args ) throws IOException { + WpadProxySearchStrategy wPSS = new WpadProxySearchStrategy(); +// System.setProperty("com.btr.proxy.pac.overrideLocalIP", "10.0.0.1"); + try { + ProxySelector pS = wPSS.getProxySelector(); + ProxySelector.setDefault(pS); + List+ * Note: at the moment only the DNS name guessing schema is implemented. All + * others are missing. + *
+ *+ * For more information about WPAD: Web_Proxy_Autodiscovery_Protocol + *
+ *+ * Outdated RFC draft: draft-ietf-wrec-wpad-01.txt + *
+ * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class WpadProxySearchStrategyWithDHPC implements ProxySearchStrategy { + DHCPSocket bindSocket = null; + byte hwaddr[] = new byte[16]; + InetAddress serverIP; + int portNum; + boolean gSentinel; + + /************************************************************************* + * Constructor + ************************************************************************/ + + public WpadProxySearchStrategyWithDHPC() { + super(); + } + + /************************************************************************* + * Loads the proxy settings from a PAC file. The location of the PAC file is + * determined automatically. + * + * @return a configured ProxySelector, null if none is found. + * @throws ProxyException + * on error. + ************************************************************************/ + + public ProxySelector getProxySelector() throws ProxyException { + try { + Logger.log(getClass(), LogLevel.TRACE, "Using WPAD to find a proxy"); + + String pacScriptUrl = detectScriptUrlPerDHCP(); + if (pacScriptUrl == null) { + pacScriptUrl = detectScriptUrlPerDNS(); + } + if (pacScriptUrl == null) { + return null; + } + Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", + pacScriptUrl); + return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Error during WPAD search.", + e); + throw new ProxyException(e); + } + } + + /************************************************************************* + * Loads the settings and stores them in a properties map. + * + * @return the settings. + ************************************************************************/ + + public Properties readSettings() { + try { + String pacScriptUrl = detectScriptUrlPerDHCP(); + if (pacScriptUrl == null) { + pacScriptUrl = detectScriptUrlPerDNS(); + } + if (pacScriptUrl == null) { + return null; + } + Properties result = new Properties(); + result.setProperty("url", pacScriptUrl); + return result; + } catch (IOException e) { + // Ignore and return empty properties. + return new Properties(); + } + } + + /************************************************************************* + * Uses DNS to find the script URL. Attention: this detection method is + * known to have some severe security issues. + * + * @return the URL, null if not found. + ************************************************************************/ + + private String detectScriptUrlPerDNS() throws IOException { + String result = null; + // String fqdn = InetAddress.getLocalHost().getCanonicalHostName(); + + Logger.log(getClass(), LogLevel.TRACE, "Searching per DNS guessing."); + // Logger.log(getClass(), LogLevel.INFO, "fqdn: ", fqdn); + + /** + * Reading address from "/etc/resolv.conf"; file looks like: + * + * # Dynamic resolv.conf(5) file for glibc resolver(3) generated by + * resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE + * OVERWRITTEN nameserver 127.0.1.1 search ruf.uni-freiburg.de + * lp.ruf.uni-freiburg.de + */ + + FileReader fr = new FileReader("/etc/resolv.conf"); + BufferedReader br = new BufferedReader(fr); + + String input; + // using the 4th line of the file. + br.readLine(); + br.readLine(); + br.readLine(); + input = br.readLine(); + + String[] addresses = input.split(" "); + // the first one is "search" and afterwards addresses are following. + + for (int i = 0; i < addresses.length; ++i) { + String address = addresses[i]; + int index = -1; + do { + address = address.substring(index + 1); + + // if we are already on TLD level then escape + if (address.indexOf('.') == -1) { + break; + } + + // Try to connect to URL + try { + URL lookupURL = new URL("http://wpad." + address + + "/wpad.dat"); + Logger.log(getClass(), LogLevel.TRACE, "Trying url: {0}", + lookupURL); + + HttpURLConnection con = (HttpURLConnection) lookupURL + .openConnection(Proxy.NO_PROXY); + con.setInstanceFollowRedirects(true); + con.setRequestProperty("accept", + "application/x-ns-proxy-autoconfig"); + if (con.getResponseCode() == 200) { + result = lookupURL.toString(); + return result; + } + con.disconnect(); + } catch (UnknownHostException e) { + Logger.log(getClass(), LogLevel.DEBUG, "Not available!"); + // Not a real error, try next address + } + index = address.indexOf('.'); + } while (index != -1); + } + + return null; + } + + /************************************************************************* + * Uses DHCP to find the script URL. + * + * @return the URL, null if not found. + ************************************************************************/ + + private String detectScriptUrlPerDHCP() { + Logger.log(getClass(), LogLevel.DEBUG, + "Searching per DHCP not supported yet."); + + // create socket. + try { + // bindSocket = new DHCPSocket(DHCPMessage.CLIENT_PORT); + // --> Not able to use ports under 1024 without being root. + this.bindSocket = new DHCPSocket(1068); + } catch (SocketException e) { + System.err.println(e); + return null; + } + + + + return null; + } + + // Sends DHCPDISCOVER Message and returns server message + private DHCPMessage SendDiscover() { + DHCPSocket bindSocket = null; + try { + bindSocket = new DHCPSocket(1068); + } catch (SocketException e1) { + // TODO bjoern 29.10.2014 Auto-generated catch block + e1.printStackTrace(); + return null; + } + + Random ranXid = new Random(); + DHCPMessage messageOut = new DHCPMessage(DHCPMessage.BROADCAST_ADDR, + DHCPMessage.SERVER_PORT); + DHCPMessage messageIn = new DHCPMessage(DHCPMessage.BROADCAST_ADDR, + DHCPMessage.SERVER_PORT); + try { + // Specify type of message: 1 = request - message, 2 = reply - message + messageOut.setOp((byte) 1); + // set Hardware type: 1 = Ethernet, 6 = IEEE 802 Networks, ... + messageOut.setHtype((byte) 1); // 1 = ethernet + // set hardware address length: 6 for MAC address + messageOut.setHlen((byte) 6); + messageOut.setHops((byte) 0); + // set session ID for later comparing with incoming message. + messageOut.setXid(ranXid.nextInt()); + messageOut.setSecs((short) 0); + messageOut.setFlags((short) 0x8000); + // set client hardware address, in this case my own hardware address of eth0. + messageOut.setChaddr(ChaddrToByte("D8:D3:85:80:8F:C9")); + + byte[] opt = new byte[1]; + byte[] wpadOpt = new byte[1]; + opt[0] = DHCPMessage.DHCPDISCOVER; + + // change message type + messageOut.setOption(DHCPOptions.OPTION_DHCP_MESSAGE_TYPE, opt); + wpadOpt[0] = DHCPMessage.OPTION_DHCP_WPAD; + messageOut.setOption(DHCPOptions.OPTION_DHCP_PARAMETER_REQUEST_LIST, wpadOpt); +// messageOut.setOption(DHCPOptions.OPTION_DHCP_IP_ADRESS_REQUESTED, +// offerMessageIn.getYiaddr()); + + bindSocket.send(messageOut); // send DHCPREQUEST + System.out.println("Sending DHCPDISCOVER ..."); + boolean sentinal = true; + int counter = 0; + while (sentinal) { + if (counter == 2) { return null; } + if (bindSocket.receive(messageIn)) { + if (messageOut.getXid() == messageIn.getXid()) { + sentinal = false; + } else { + bindSocket.send(messageOut); + counter++; + } + } else { + bindSocket.send(messageOut); + counter++; + } + } + } catch (SocketException e) { + System.err.println(e); + return null; + } catch (IOException e) { + System.err.println(e); + return null; + } finally { + try { + bindSocket.close(); + } catch (Exception e) { + // do nothing. + } + } // end catch + return messageIn; + } + + // Main method for testing. + public static void main(String[] args) throws UnsupportedEncodingException { + WpadProxySearchStrategyWithDHPC wPSSDHCP = new WpadProxySearchStrategyWithDHPC(); + DHCPMessage serverAnswer = wPSSDHCP.SendDiscover(); + + Logger.log(WpadProxySearchStrategyWithDHPC.class, LogLevel.INFO, + "DHCP serverAnswer: {0}", new String(serverAnswer.getOption(DHCPMessage.OPTION_DHCP_WPAD), "UTF-8")); + } + + private byte[] ChaddrToByte(String inChaddr) { + StringTokenizer token = new StringTokenizer(inChaddr, ":"); + Integer tempInt = new Integer(0); + byte outHwaddr[] = new byte[16]; + int temp; + int i = 0; + while (i < 6) { + temp = tempInt.parseInt(token.nextToken(), 16); + outHwaddr[i] = (byte) temp; + i++; + } + return outHwaddr; + } + +} diff --git a/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java new file mode 100644 index 0000000..86323d5 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java @@ -0,0 +1,880 @@ +package com.btr.proxy.search.wpad.dhcp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * This class represents a DHCP Message. + * + * @author Jason Goldschmidt, Nick Stone and Simon Frankenberger + */ +public class DHCPMessage { + // ----------------------------------------------------------- + // Constants + // ----------------------------------------------------------- + /** + * Operation for a request + */ + public static final byte OP_REQUEST = 1; + + /** + * Operation for a reply + */ + public static final byte OP_REPLY = 2; + + /** + * Message Code representing a DHCPDISCOVER message + */ + public static final byte DHCPDISCOVER = 1; + + /** + * Message Code representing a DHCPOFFER message + */ + public static final byte DHCPOFFER = 2; + + /** + * Message Code representing a DHCPREQUEST message + */ + public static final byte DHCPREQUEST = 3; + + /** + * Message Code representing a DHCPDECLINE message + */ + public static final byte DHCPDECLINE = 4; + + /** + * Message Code representing a DHCPACK message + */ + public static final byte DHCPACK = 5; + + /** + * Message Code representing a DHCPNAK message + */ + public static final byte DHCPNAK = 6; + + /** + * Message Code representing a DHCPRELEASE message + */ + public static final byte DHCPRELEASE = 7; + + /** + * Message Code representing a DHCPINFORM message + */ + public static final byte DHCPINFORM = 8; + + /** + * Default DHCP client port + */ + public static final int CLIENT_PORT = 68; // client port (by default) + + /** + * Default DHCP server port + */ + public static final int SERVER_PORT = 67; // server port (by default) + + /** + * Broadcast Adress to send packets to + */ + public static InetAddress BROADCAST_ADDR = null; + + public static final byte OPTION_DHCP_WPAD = (byte) 252; + + + + // ----------------------------------------------------------- + // Fields defining a dhcp message + // ----------------------------------------------------------- + /** + * Operation Code.true
if message is received,
+ * false
if timeout occurs.
+ * @param outMessage DHCPMessage object to receive new message into
+ */
+ public synchronized boolean receive(DHCPMessage outMessage) {
+ try {
+ DatagramPacket incoming = new DatagramPacket(new byte[this.mtu],
+ this.mtu);
+ //gSocket.
+ receive(incoming); // block on receive for SOCKET_TIMEOUT
+
+ outMessage.internalize(incoming.getData());
+ }
+ catch (java.io.IOException e) {
+ e.printStackTrace();
+ return false;
+ } // end catch
+ return true;
+ }
+}
diff --git a/src/main/java/com/btr/proxy/selector/direct/NoProxySelector.java b/src/main/java/com/btr/proxy/selector/direct/NoProxySelector.java
new file mode 100644
index 0000000..cf9e150
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/direct/NoProxySelector.java
@@ -0,0 +1,70 @@
+package com.btr.proxy.selector.direct;
+
+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;
+
+/*****************************************************************************
+ * This proxy selector will always return a "DIRECT" proxy.
+ * Implemented as singleton.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+public class NoProxySelector extends ProxySelector {
+
+ private static NoProxySelector instance;
+
+ /*************************************************************************
+ * Constructor
+ ************************************************************************/
+
+ private NoProxySelector() {
+ super();
+ }
+
+ /*************************************************************************
+ * Gets the one and only instance of this selector.
+ * @return a DirectSelector.
+ ************************************************************************/
+
+ public static synchronized NoProxySelector getInstance() {
+ if (NoProxySelector.instance == null) {
+ NoProxySelector.instance = new NoProxySelector();
+ }
+ return instance;
+ }
+
+ /*************************************************************************
+ * 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) {
+ // Not used.
+ }
+
+ /*************************************************************************
+ * select
+ * @see java.net.ProxySelector#select(java.net.URI)
+ ************************************************************************/
+
+ @Override
+ public ListURI
to be evaluated.
+ * @return Proxy
-object list as result of the evaluation.
+ ************************************************************************/
+
+ private ListProxy
for it.
+ * @param pacResult the result from the PAC parser.
+ * @return a Proxy
+ ************************************************************************/
+
+ private Proxy buildProxyFromPacResult(String pacResult) {
+ if (pacResult == null || pacResult.trim().length() < 6) {
+ return Proxy.NO_PROXY;
+ }
+ String proxyDef = pacResult.trim();
+ if (proxyDef.toUpperCase().startsWith(PAC_DIRECT)) {
+ return Proxy.NO_PROXY;
+ }
+
+ // Check proxy type.
+ Proxy.Type type = Proxy.Type.HTTP;
+ if (proxyDef.toUpperCase().startsWith(PAC_SOCKS)) {
+ type = Proxy.Type.SOCKS;
+ }
+
+ String host = proxyDef.substring(6);
+ Integer port = ProxyUtil.DEFAULT_PROXY_PORT;
+
+ // Split port from host
+ int indexOfPort = host.indexOf(':');
+ if (indexOfPort != -1) {
+ port = Integer.parseInt(host.substring(indexOfPort+1).trim());
+ host = host.substring(0, indexOfPort).trim();
+ }
+
+ SocketAddress adr = InetSocketAddress.createUnresolved(host, port);
+ return new Proxy(type, adr);
+ }
+
+}
diff --git a/src/main/java/com/btr/proxy/selector/pac/PacScriptMethods.java b/src/main/java/com/btr/proxy/selector/pac/PacScriptMethods.java
new file mode 100644
index 0000000..101c267
--- /dev/null
+++ b/src/main/java/com/btr/proxy/selector/pac/PacScriptMethods.java
@@ -0,0 +1,656 @@
+package com.btr.proxy.selector.pac;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+
+import com.btr.proxy.util.Logger;
+import com.btr.proxy.util.Logger.LogLevel;
+
+/***************************************************************************
+ * Implementation of PAC JavaScript functions.
+ *
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ***************************************************************************
+ */
+public class PacScriptMethods implements ScriptMethods {
+
+ public static final String OVERRIDE_LOCAL_IP = "com.btr.proxy.pac.overrideLocalIP";
+
+ private final static String GMT = "GMT";
+
+ private final static List+ * timeRange(hour) + * timeRange(hour1, hour2) + * timeRange(hour1, min1, hour2, min2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt) + *+ * + * @param hour1 + * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min1 + * minutes from 0 to 59. + * @param sec1 + * seconds from 0 to 59. + * @param hour2 + * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min2 + * minutes from 0 to 59. + * @param sec2 + * seconds from 0 to 59. + * @param gmt + * "GMT" for gmt time format else "undefined" + * @return true if the current time matches the given range. + ************************************************************************/ + + public boolean timeRange(Object hour1, Object min1, Object sec1, + Object hour2, Object min2, Object sec2, Object gmt) { + boolean useGmt = GMT.equalsIgnoreCase(String.valueOf(min1)) + || GMT.equalsIgnoreCase(String.valueOf(sec1)) + || GMT.equalsIgnoreCase(String.valueOf(min2)) + || GMT.equalsIgnoreCase(String.valueOf(gmt)); + + Calendar cal = getCurrentTime(useGmt); + cal.set(Calendar.MILLISECOND, 0); + Date current = cal.getTime(); + Date from; + Date to; + if (sec2 instanceof Number) { + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour1).intValue()); + cal.set(Calendar.MINUTE, ((Number) min1).intValue()); + cal.set(Calendar.SECOND, ((Number) sec1).intValue()); + from = cal.getTime(); + + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour2).intValue()); + cal.set(Calendar.MINUTE, ((Number) min2).intValue()); + cal.set(Calendar.SECOND, ((Number) sec2).intValue()); + to = cal.getTime(); + } else if (hour2 instanceof Number) { + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour1).intValue()); + cal.set(Calendar.MINUTE, ((Number) min1).intValue()); + cal.set(Calendar.SECOND, 0); + from = cal.getTime(); + + cal.set(Calendar.HOUR_OF_DAY, ((Number) sec1).intValue()); + cal.set(Calendar.MINUTE, ((Number) hour2).intValue()); + cal.set(Calendar.SECOND, 59); + to = cal.getTime(); + } else if (min1 instanceof Number) { + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour1).intValue()); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + from = cal.getTime(); + + cal.set(Calendar.HOUR_OF_DAY, ((Number) min1).intValue()); + cal.set(Calendar.MINUTE, 59); + cal.set(Calendar.SECOND, 59); + to = cal.getTime(); + } else { + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour1).intValue()); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + from = cal.getTime(); + + cal.set(Calendar.HOUR_OF_DAY, ((Number) hour1).intValue()); + cal.set(Calendar.MINUTE, 59); + cal.set(Calendar.SECOND, 59); + to = cal.getTime(); + } + + if (to.before(from)) { + cal.setTime(to); + cal.add(Calendar.DATE, +1); + to = cal.getTime(); + } + + return current.compareTo(from) >= 0 && current.compareTo(to) <= 0; + } + + // Microsoft PAC extensions for IPv6 support. + + /************************************************************************* + * isResolvableEx + * @see com.btr.proxy.selector.pac.ScriptMethods#isResolvableEx(java.lang.String) + ************************************************************************/ + + public boolean isResolvableEx(String host) { + return isResolvable(host); + } + + /************************************************************************* + * isInNetEx + * @see com.btr.proxy.selector.pac.ScriptMethods#isInNetEx(java.lang.String, java.lang.String) + ************************************************************************/ + + public boolean isInNetEx(String ipAddress, String ipPrefix) { + // TODO rossi 27.06.2011 Auto-generated method stub + return false; + } + + /************************************************************************* + * dnsResolveEx + * @see com.btr.proxy.selector.pac.ScriptMethods#dnsResolveEx(java.lang.String) + ************************************************************************/ + + public String dnsResolveEx(String host) { + StringBuilder result = new StringBuilder(); + try { + InetAddress[] list = InetAddress.getAllByName(host); + for (InetAddress inetAddress : list) { + result.append(inetAddress.getHostAddress()); + result.append("; "); + } + } catch (UnknownHostException e) { + Logger.log(JavaxPacScriptParser.class, LogLevel.DEBUG, + "DNS name not resolvable {0}.", host); + } + return result.toString(); + } + + /************************************************************************* + * myIpAddressEx + * @see com.btr.proxy.selector.pac.ScriptMethods#myIpAddressEx() + ************************************************************************/ + + public String myIpAddressEx() { + return getLocalAddressOfType(Inet6Address.class); + } + + /************************************************************************* + * sortIpAddressList + * @see com.btr.proxy.selector.pac.ScriptMethods#sortIpAddressList(java.lang.String) + ************************************************************************/ + + public String sortIpAddressList(String ipAddressList) { + if (ipAddressList == null || ipAddressList.trim().length() == 0) { + return ""; + } + String[] ipAddressToken = ipAddressList.split(";"); + List
+ * More information about PAC can be found there:
+ * Proxy_auto-config
+ * web-browser-auto-proxy-configuration
+ *
+ * timeRange(hour) + * timeRange(hour1, hour2) + * timeRange(hour1, min1, hour2, min2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt) + *+ * + * @param hour1 is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min1 minutes from 0 to 59. + * @param sec1 seconds from 0 to 59. + * @param hour2 is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min2 minutes from 0 to 59. + * @param sec2 seconds from 0 to 59. + * @param gmt "GMT" for gmt time format else "undefined" + * @return true if the current time matches the given range. + ************************************************************************/ + + public static boolean timeRange(Object hour1, Object min1, Object sec1, Object hour2, Object min2, Object sec2, Object gmt) { + return SCRIPT_METHODS.timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt); + } + +} diff --git a/src/main/java/com/btr/proxy/selector/pac/ScriptAvailability.java b/src/main/java/com/btr/proxy/selector/pac/ScriptAvailability.java new file mode 100644 index 0000000..d7f6e04 --- /dev/null +++ b/src/main/java/com/btr/proxy/selector/pac/ScriptAvailability.java @@ -0,0 +1,46 @@ +package com.btr.proxy.selector.pac; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/**************************************************************************** + * Utility to check availablility of javax.script + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ***************************************************************************/ +abstract class ScriptAvailability { + + /************************************************************************* + * Checks whether javax.script is available or not. + * Completely done per Reflection to allow compilation under Java 1.5 + * @return true if javax.script is available; false otherwise + ************************************************************************/ + public static boolean isJavaxScriptingAvailable() { + Object engine = null; + try { + Class> managerClass = Class.forName("javax.script.ScriptEngineManager"); + Method m = managerClass.getMethod("getEngineByMimeType", String.class); + engine = m.invoke(managerClass.newInstance(), "text/javascript"); + } catch (ClassNotFoundException e) { + // javax.script not available + } catch (NoSuchMethodException e) { + // javax.script not available + } catch (IllegalAccessException e) { + // javax.script not available + } catch (InvocationTargetException e) { + // javax.script not available + } catch (InstantiationException e) { + // javax.script not available + } + + return engine != null; + } + + /************************************************************************* + * Constructor + ************************************************************************/ + + ScriptAvailability() { + super(); + } +} diff --git a/src/main/java/com/btr/proxy/selector/pac/ScriptMethods.java b/src/main/java/com/btr/proxy/selector/pac/ScriptMethods.java new file mode 100644 index 0000000..9f559c5 --- /dev/null +++ b/src/main/java/com/btr/proxy/selector/pac/ScriptMethods.java @@ -0,0 +1,256 @@ +package com.btr.proxy.selector.pac; + +/*************************************************************************** + * Defines the public interface for PAC scripts. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ***************************************************************************/ +public interface ScriptMethods { + + public boolean isPlainHostName(String host); + + /************************************************************************* + * Tests if an URL is in a given domain. + * + * @param host + * is the host name from the URL. + * @param domain + * is the domain name to test the host name against. + * @return true if the domain of host name matches. + ************************************************************************/ + + public boolean dnsDomainIs(String host, String domain); + + /************************************************************************* + * Is true if the host name matches exactly the specified host name, or if + * there is no domain name part in the host name, but the unqualified host + * name matches. + * + * @param host + * the host name from the URL. + * @param domain + * fully qualified host name with domain to match against. + * @return true if matches else false. + ************************************************************************/ + + public boolean localHostOrDomainIs(String host, String domain); + + /************************************************************************* + * Tries to resolve the host name. Returns true if succeeds. + * + * @param host + * is the host name from the URL. + * @return true if resolvable else false. + ************************************************************************/ + + public boolean isResolvable(String host); + + /************************************************************************* + * Tries to resolve the host name. Returns true if succeeds to resolve + * the host to an IPv4 or IPv6 address. + * + * @param host + * is the host name from the URL. + * @return true if resolvable else false. + ************************************************************************/ + + public boolean isResolvableEx(String host); + + /************************************************************************* + * Returns true if the IP address of the host matches the specified IP + * address pattern. Pattern and mask specification is done the same way as + * for SOCKS configuration. + * + * Example: isInNet(host, "198.95.0.0", "255.255.0.0") is true if the IP + * address of the host matches 198.95.*.*. + * + * @param host + * a DNS host name, or IP address. If a host name is passed, it + * will be resolved into an IP address by this function. + * @param pattern + * an IP address pattern in the dot-separated format. + * @param mask + * mask for the IP address pattern informing which parts of the + * IP address should be matched against. 0 means ignore, 255 + * means match. + * @return true if it matches else false. + ************************************************************************/ + + public boolean isInNet(String host, String pattern, String mask); + + /************************************************************************* + * Extension of the isInNet method to support IPv6. + * @param ipAddress an IP4 or IP6 address + * @param ipPrefix A string containing colon delimited IP prefix + * with top n bits specified in the bit field + * (i.e. 3ffe:8311:ffff::/48 or 123.112.0.0/16). + * @return true if the host is in the given subnet, else false. + ************************************************************************/ + + public boolean isInNetEx(String ipAddress, String ipPrefix); + + /************************************************************************* + * Resolves the given DNS host name into an IP address, and returns it in + * the dot separated format as a string. + * + * @param host + * the host to resolve. + * @return the resolved IP, empty string if not resolvable. + ************************************************************************/ + + public String dnsResolve(String host); + + /************************************************************************* + * @param host the host to resolve + * @return a semicolon separated list of IP6 and IP4 addresses the host + * name resolves to, empty string if not resolvable. + ************************************************************************/ + + public String dnsResolveEx(String host); + + /************************************************************************* + * Returns the IP address of the host that the process is running on, as a + * string in the dot-separated integer format. + * + * @return an IP as string. + ************************************************************************/ + + public String myIpAddress(); + + /************************************************************************* + * Returns a list of IP4 and IP6 addresses of the host that the process + * is running on. The list is separated with semicolons. + * @return the list, empty string if not available. + ************************************************************************/ + + public String myIpAddressEx(); + + /************************************************************************* + * Returns the number of DNS domain levels (number of dots) in the host + * name. + * + * @param host + * is the host name from the URL. + * @return number of DNS domain levels. + ************************************************************************/ + + public int dnsDomainLevels(String host); + + /************************************************************************* + * Returns true if the string matches the specified shell expression. + * Actually, currently the patterns are shell expressions, not regular + * expressions. + * + * @param str + * is any string to compare (e.g. the URL, or the host name). + * @param shexp + * is a shell expression to compare against. + * @return true if the string matches, else false. + ************************************************************************/ + + public boolean shExpMatch(String str, String shexp); + + /************************************************************************* + * Only the first parameter is mandatory. Either the second, the third, or + * both may be left out. If only one parameter is present, the function + * yields a true value on the weekday that the parameter represents. If the + * string "GMT" is specified as a second parameter, times are taken to be in + * GMT, otherwise in local time zone. If both wd1 and wd2 are defined, the + * condition is true if the current weekday is in between those two + * weekdays. Bounds are inclusive. If the "GMT" parameter is specified, + * times are taken to be in GMT, otherwise the local time zone is used. + * + * @param wd1 + * weekday 1 is one of SUN MON TUE WED THU FRI SAT + * @param wd2 + * weekday 2 is one of SUN MON TUE WED THU FRI SAT + * @param gmt + * "GMT" for gmt time format else "undefined" + * @return true if current day matches the criteria. + ************************************************************************/ + + public boolean weekdayRange(String wd1, String wd2, String gmt); + + /************************************************************************* + * Only the first parameter is mandatory. All other parameters can be left + * out therefore the meaning of the parameters changes. The method + * definition shows the version with the most possible parameters filled. + * The real meaning of the parameters is guessed from it's value. If "from" + * and "to" are specified then the bounds are inclusive. If the "GMT" + * parameter is specified, times are taken to be in GMT, otherwise the local + * time zone is used. + * + * @param day1 + * is the day of month between 1 and 31 (as an integer). + * @param month1 + * one of JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC + * @param year1 + * is the full year number, for example 1995 (but not 95). + * Integer. + * @param day2 + * is the day of month between 1 and 31 (as an integer). + * @param month2 + * one of JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC + * @param year2 + * is the full year number, for example 1995 (but not 95). + * Integer. + * @param gmt + * "GMT" for gmt time format else "undefined" + * @return true if the current date matches the given range. + ************************************************************************/ + + public boolean dateRange(Object day1, Object month1, Object year1, Object day2, Object month2, Object year2, + Object gmt); + + /************************************************************************* + * Some parameters can be left out therefore the meaning of the parameters + * changes. The method definition shows the version with the most possible + * parameters filled. The real meaning of the parameters is guessed from + * it's value. If "from" and "to" are specified then the bounds are + * inclusive. If the "GMT" parameter is specified, times are taken to be in + * GMT, otherwise the local time zone is used.
+ * timeRange(hour) + * timeRange(hour1, hour2) + * timeRange(hour1, min1, hour2, min2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2) + * timeRange(hour1, min1, sec1, hour2, min2, sec2, gmt) + *+ * + * @param hour1 + * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min1 + * minutes from 0 to 59. + * @param sec1 + * seconds from 0 to 59. + * @param hour2 + * is the hour from 0 to 23. (0 is midnight, 23 is 11 pm.) + * @param min2 + * minutes from 0 to 59. + * @param sec2 + * seconds from 0 to 59. + * @param gmt + * "GMT" for gmt time format else "undefined" + * @return true if the current time matches the given range. + ************************************************************************/ + + public boolean timeRange(Object hour1, Object min1, Object sec1, Object hour2, Object min2, Object sec2, Object gmt); + + /************************************************************************* + * Sorts a list of IP4 and IP6 addresses. Separated by semicolon. + * Dual addresses first, then IPv6 and last IPv4. + * @param ipAddressList the address list. + * @return the sorted list, empty string if sort is not possible + ************************************************************************/ + + public String sortIpAddressList(String ipAddressList); + + /************************************************************************* + * Gets the version of the PAC extension that is available. + * @return the extension version, currently 1.0 + ************************************************************************/ + + public String getClientVersion(); + +} diff --git a/src/main/java/com/btr/proxy/selector/pac/UrlPacScriptSource.java b/src/main/java/com/btr/proxy/selector/pac/UrlPacScriptSource.java new file mode 100644 index 0000000..6ac8faa --- /dev/null +++ b/src/main/java/com/btr/proxy/selector/pac/UrlPacScriptSource.java @@ -0,0 +1,270 @@ +package com.btr.proxy.selector.pac; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.URISyntaxException; +import java.net.URL; + +import com.btr.proxy.util.Logger; +import com.btr.proxy.util.Logger.LogLevel; + +/***************************************************************************** + * Script source that will load the content of a PAC file from an webserver. + * The script content is cached once it was downloaded. + * + * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009 + ****************************************************************************/ + +public class UrlPacScriptSource implements PacScriptSource { + + private static final int DEFAULT_CONNECT_TIMEOUT = 15 * 1000; // seconds + private static final int DEFAULT_READ_TIMEOUT = 20 * 1000; // seconds + public static final String OVERRIDE_CONNECT_TIMEOUT = "com.btr.proxy.url.connectTimeout"; + public static final String OVERRIDE_READ_TIMEOUT = "com.btr.proxy.url.readTimeout"; + + private final String scriptUrl; + private String scriptContent; + private long expireAtMillis; + + /************************************************************************* + * Constructor + * @param url the URL to download the script from. + ************************************************************************/ + + public UrlPacScriptSource(String url) { + super(); + this.expireAtMillis = 0; + this.scriptUrl = url; + } + + /************************************************************************* + * getScriptContent + * @see com.btr.proxy.selector.pac.PacScriptSource#getScriptContent() + ************************************************************************/ + + public synchronized String getScriptContent() throws IOException { + if (this.scriptContent == null || + (this.expireAtMillis > 0 + && this.expireAtMillis > System.currentTimeMillis())) { + try { + if (this.scriptUrl.startsWith("file:/") || this.scriptUrl.indexOf(":/") == -1) { + this.scriptContent = readPacFileContent(this.scriptUrl); + } else { + this.scriptContent = downloadPacContent(this.scriptUrl); + } + } catch (IOException e) { + Logger.log(getClass(), LogLevel.ERROR, "Loading script failed from: {0} with error {1}", this.scriptUrl, e); + this.scriptContent = ""; + throw e; + } + } + return this.scriptContent; + } + + /************************************************************************* + * Reads a PAC script from a local file. + * @param scriptUrl + * @return the content of the script file. + * @throws IOException + * @throws URISyntaxException + ************************************************************************/ + + private String readPacFileContent(String scriptUrl) throws IOException { + try { + File file = null; + if (scriptUrl.indexOf(":/") == -1) { + file = new File(scriptUrl); + } else { + file = new File(new URL(scriptUrl).toURI()); + } + BufferedReader r = new BufferedReader(new FileReader(file)); + StringBuilder result = new StringBuilder(); + try { + String line; + while ((line = r.readLine()) != null) { + result.append(line).append("\n"); + } + } finally { + r.close(); + } + return result.toString(); + } catch (Exception e) { + Logger.log(getClass(), LogLevel.ERROR, "File reading error.", e); + throw new IOException(e.getMessage()); + } + } + + /************************************************************************* + * Downloads the script from a webserver. + * @param url the URL to the script file. + * @return the script content. + * @throws IOException on read error. + ************************************************************************/ + + private String downloadPacContent(String url) throws IOException { + if (url == null) { + throw new IOException("Invalid PAC script URL: null"); + } + + setPacProxySelectorEnabled(false); + + HttpURLConnection con = null; + try { + con = setupHTTPConnection(url); + if (con.getResponseCode() != 200) { + throw new IOException("Server returned: "+con.getResponseCode()+" "+con.getResponseMessage()); + } + // Read expire date. + this.expireAtMillis = con.getExpiration(); + + BufferedReader r = getReader(con); + String result = readAllContent(r); + r.close(); + return result; + } finally { + setPacProxySelectorEnabled(true); + if (con != null) { + con.disconnect(); + } + } + } + + /************************************************************************* + * Enables/disables the PAC proxy selector while we download to prevent recursion. + * See issue: 26 in the change tracker. + ************************************************************************/ + + private void setPacProxySelectorEnabled(boolean enable) { + PacProxySelector.setEnabled(enable); + } + + /************************************************************************* + * Reads the whole content available into a String. + * @param r to read from. + * @return the complete PAC file content. + * @throws IOException + ************************************************************************/ + + private String readAllContent(BufferedReader r) throws IOException { + StringBuilder result = new StringBuilder(); + String line; + while ((line = r.readLine()) != null) { + result.append(line).append("\n"); + } + return result.toString(); + } + + /************************************************************************* + * Build a BufferedReader around the open HTTP connection. + * @param con to read from + * @return the BufferedReader. + * @throws UnsupportedEncodingException + * @throws IOException + ************************************************************************/ + + private BufferedReader getReader(HttpURLConnection con) + throws UnsupportedEncodingException, IOException { + String charsetName = parseCharsetFromHeader(con.getContentType()); + BufferedReader r = new BufferedReader(new InputStreamReader(con.getInputStream(), charsetName)); + return r; + } + + /************************************************************************* + * Configure the connection to download from. + * @param url to get the pac file content from + * @return a HTTPUrlConnecion to this url. + * @throws IOException + * @throws MalformedURLException + ************************************************************************/ + + private HttpURLConnection setupHTTPConnection(String url) + throws IOException, MalformedURLException { + HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(Proxy.NO_PROXY); + con.setConnectTimeout(getTimeOut(OVERRIDE_CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT)); + con.setReadTimeout(getTimeOut(OVERRIDE_READ_TIMEOUT, DEFAULT_READ_TIMEOUT)); + con.setInstanceFollowRedirects(true); + con.setRequestProperty("accept", "application/x-ns-proxy-autoconfig, */*;q=0.8"); + return con; + } + + /************************************************************************* + * Gets the timeout value from a property or uses the given default value if + * the property cannot be parsed. + * @param overrideProperty the property to define the timeout value in milliseconds + * @param defaultValue the default timeout value in milliseconds. + * @return the value to use. + ************************************************************************/ + + protected int getTimeOut(String overrideProperty, int defaultValue) { + int timeout = defaultValue; + String prop = System.getProperty(overrideProperty); + if (prop != null && prop.trim().length() > 0) { + try { + timeout = Integer.parseInt(prop.trim()); + } catch (NumberFormatException e) { + Logger.log(getClass(), LogLevel.DEBUG, "Invalid override property : {0}={1}", overrideProperty, prop); + // In this case use the default value. + } + } + return timeout; + } + + /************************************************************************* + * Response Content-Type could be something like this: + * application/x-ns-proxy-autoconfig; charset=UTF-8 + * @param contentType header field. + * @return the extracted charset if set else a default charset. + ************************************************************************/ + + String parseCharsetFromHeader(String contentType) { + String result = "ISO-8859-1"; + if (contentType != null) { + String[] paramList = contentType.split(";"); + for (String param : paramList) { + if (param.toLowerCase().trim().startsWith("charset") && param.indexOf("=") != -1) { + result = param.substring(param.indexOf("=")+1).trim(); + } + } + } + return result; + } + + /*************************************************************************** + * @see java.lang.Object#toString() + **************************************************************************/ + @Override + public String toString() { + return this.scriptUrl; + } + + /************************************************************************* + * isScriptValid + * @see com.btr.proxy.selector.pac.PacScriptSource#isScriptValid() + ************************************************************************/ + + public boolean isScriptValid() { + try { + String script = getScriptContent(); + if (script == null || script.trim().length() == 0) { + Logger.log(getClass(), LogLevel.DEBUG, "PAC script is empty. Skipping script!"); + return false; + } + if (script.indexOf("FindProxyForURL") == -1) { + Logger.log(getClass(), LogLevel.DEBUG, "PAC script entry point FindProxyForURL not found. Skipping script!"); + return false; + } + return true; + } catch (IOException e) { + Logger.log(getClass(), LogLevel.DEBUG, "File reading error: {0}", e); + return false; + } + } + +} 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
+ * The xml plist dtd can be found at http://www.apple.com/DTDs/PropertyList-1.0.dtd + *
+ * The plist spec handles 8 types of objects: booleans, real, integers, dates, binary data, + * strings, arrays (lists) and dictionaries (maps). + *
+ * The java Plist lib handles converting xml plists to a nested {@code Map
+ * The following mapping will be done when converting from plist to Map:
+ *
+ * When converting from Map -> plist the conversion is as follows:
+ *
+ * true/false -> Boolean
+ * real -> Double
+ * integer -> Integer/Long (depends on size, values exceeding an int will be rendered as longs)
+ * data -> byte[]
+ * string -> String
+ * array -> List
+ * dict -> Map
+ *
+ *
+ * Boolean -> true/false
+ * Float/Double -> real
+ * Byte/Short/Integer/Long -> integer
+ * byte[] -> data
+ * List -> array
+ * Map -> dict
+ *
+ *
+ * @author Christoffer Lerno / Modified by Bernd Rosstauscher
+ */
+public final class PListParser
+{
+ /*****************************************************************************
+ * Exception is used for XML parse problems.
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+ public static class XmlParseException extends Exception {
+
+ /** Comment for serialVersionUID
*/
+ private static final long serialVersionUID = 1L;
+
+ /*************************************************************************
+ * Constructor
+ ************************************************************************/
+
+ public XmlParseException() {
+ super();
+ }
+
+ /*************************************************************************
+ * Constructor
+ * @param msg the error message
+ ************************************************************************/
+
+ public XmlParseException(String msg) {
+ super(msg);
+ }
+
+ /*************************************************************************
+ * Constructor
+ * @param msg error message
+ * @param e the cause.
+ ************************************************************************/
+
+ public XmlParseException(String msg, Exception e) {
+ super(msg, e);
+ }
+
+ }
+
+ /*****************************************************************************
+ * Small helper class representing a tree node.
+ * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
+ ****************************************************************************/
+
+ public static class Dict implements Iterable