diff options
author | nicolas.dufresne@gmail.com <nicolas.dufresne@gmail.com@c587cffe-e639-0410-9787-d7902ae8ed56> | 2012-07-05 16:01:12 +0000 |
---|---|---|
committer | nicolas.dufresne@gmail.com <nicolas.dufresne@gmail.com@c587cffe-e639-0410-9787-d7902ae8ed56> | 2012-07-05 16:01:12 +0000 |
commit | 3288de18200b82fc1a76e0c557a4d8df513e1082 (patch) | |
tree | b1c3384447f88766ab15579f536bfabc9201007f | |
parent | ef735cb817f3e83dd8c903313298d88296c2d93a (diff) | |
download | libproxy-git-3288de18200b82fc1a76e0c557a4d8df513e1082.tar.gz |
Allow multiple result to be returned from static config
-rw-r--r-- | libproxy/extension_config.cpp | 4 | ||||
-rw-r--r-- | libproxy/extension_config.hpp | 6 | ||||
-rw-r--r-- | libproxy/extension_ignore.hpp | 2 | ||||
-rw-r--r-- | libproxy/modules/config_envvar.cpp | 15 | ||||
-rw-r--r-- | libproxy/modules/config_gnome.cpp | 107 | ||||
-rw-r--r-- | libproxy/modules/config_gnome3.cpp | 105 | ||||
-rw-r--r-- | libproxy/modules/config_kde4.cpp | 23 | ||||
-rw-r--r-- | libproxy/modules/config_macosx.cpp | 25 | ||||
-rw-r--r-- | libproxy/modules/config_sysconfig.cpp | 21 | ||||
-rw-r--r-- | libproxy/modules/config_w32reg.cpp | 23 | ||||
-rw-r--r-- | libproxy/modules/ignore_domain.cpp | 2 | ||||
-rw-r--r-- | libproxy/modules/ignore_hostname.cpp | 2 | ||||
-rw-r--r-- | libproxy/modules/ignore_ip.cpp | 2 | ||||
-rw-r--r-- | libproxy/modules/wpad_dns_alias.cpp | 16 | ||||
-rw-r--r-- | libproxy/proxy.cpp | 169 |
15 files changed, 292 insertions, 230 deletions
diff --git a/libproxy/extension_config.cpp b/libproxy/extension_config.cpp index 6cefd30..075b91a 100644 --- a/libproxy/extension_config.cpp +++ b/libproxy/extension_config.cpp @@ -20,11 +20,11 @@ #include "extension_config.hpp" using namespace libproxy; -string config_extension::get_ignore(url) { +string config_extension::get_ignore(const url&) { return ""; } -bool config_extension::set_creds(url, string, string) { +bool config_extension::set_creds(const url&, const string&, const string&) { return false; } diff --git a/libproxy/extension_config.hpp b/libproxy/extension_config.hpp index a24add8..79f1624 100644 --- a/libproxy/extension_config.hpp +++ b/libproxy/extension_config.hpp @@ -31,11 +31,11 @@ using namespace libmodman; class DLL_PUBLIC config_extension : public extension<config_extension> { public: // Abstract methods - virtual url get_config(url dst) throw (runtime_error)=0; + virtual vector<url> get_config(const url &dst) throw (runtime_error)=0; // Virtual methods - virtual string get_ignore(url dst); - virtual bool set_creds(url proxy, string username, string password); + virtual string get_ignore(const url &dst); + virtual bool set_creds(const url &proxy, const string &username, const string &password); // Final methods bool get_valid(); diff --git a/libproxy/extension_ignore.hpp b/libproxy/extension_ignore.hpp index 7659bf3..63845fe 100644 --- a/libproxy/extension_ignore.hpp +++ b/libproxy/extension_ignore.hpp @@ -30,7 +30,7 @@ using namespace libmodman; class DLL_PUBLIC ignore_extension : public extension<ignore_extension> { public: - virtual bool ignore(url& dst, string ignorestr)=0; + virtual bool ignore(url& dst, const string &ignorestr)=0; }; } diff --git a/libproxy/modules/config_envvar.cpp b/libproxy/modules/config_envvar.cpp index f1c4e46..37713c7 100644 --- a/libproxy/modules/config_envvar.cpp +++ b/libproxy/modules/config_envvar.cpp @@ -24,17 +24,18 @@ using namespace libproxy; class envvar_config_extension : public config_extension { public: - url get_config(url url) throw (runtime_error) { - char *proxy = NULL; + vector<url> get_config(const url &dst) throw (runtime_error) { + const char *proxy = NULL; + vector<url> response; // If the URL is an ftp url, try to read the ftp proxy - if (url.get_scheme() == "ftp") { + if (dst.get_scheme() == "ftp") { if (!(proxy = getenv("ftp_proxy"))) proxy = getenv("FTP_PROXY"); } // If the URL is an https url, try to read the https proxy - if (url.get_scheme() == "https") { + if (dst.get_scheme() == "https") { if (!(proxy = getenv("https_proxy"))) proxy = getenv("HTTPS_PROXY"); } @@ -47,10 +48,12 @@ public: if (!proxy) throw runtime_error("Unable to read configuration"); - return libproxy::url(proxy); + + response.push_back(url(proxy)); + return response; } - string get_ignore(url) { + string get_ignore(const url&) { char *ignore = getenv("no_proxy"); ignore = ignore ? ignore : getenv("NO_PROXY"); return string(ignore ? ignore : ""); diff --git a/libproxy/modules/config_gnome.cpp b/libproxy/modules/config_gnome.cpp index 1599e62..027e5e7 100644 --- a/libproxy/modules/config_gnome.cpp +++ b/libproxy/modules/config_gnome.cpp @@ -123,7 +123,7 @@ static int popen2(const char *program, FILE** read, FILE** write, pid_t* pid) { } } -static inline uint16_t get_port(string &port) +static inline uint16_t get_port(const string &port) { uint16_t retval; @@ -133,6 +133,22 @@ static inline uint16_t get_port(string &port) return retval; } +void store_response(const string &type, + const string &host, + const string &port, + bool auth, + const string &username, + const string &password, + vector<url> &response) { + if (host != "" && get_port(port) != 0) { + string tmp = type + "://"; + if (auth) + tmp += username + ":" + password + "@"; + tmp += host + ":" + port; + response.push_back(url(tmp)); + } +} + class gnome_config_extension : public config_extension { public: gnome_config_extension() { @@ -173,10 +189,12 @@ public: kill(this->pid, SIGTERM); } - url get_config(url dest) throw (runtime_error) { + vector<url> get_config(const url &dest) throw (runtime_error) { // Check for changes in the config fd_set rfds; struct timeval timeout = { 0, 0 }; + vector<url> response; + FD_ZERO(&rfds); FD_SET(fileno(this->read), &rfds); if (select(fileno(this->read)+1, &rfds, NULL, NULL, &timeout) > 0) @@ -185,76 +203,53 @@ public: // Mode is wpad:// or pac+http://... if (this->data[PROXY_MODE] == "auto") { string pac = this->data[PROXY_AUTOCONFIG_URL]; - return url::is_valid(pac) ? url(string("pac+") + pac) : url("wpad://"); + response.push_back(url::is_valid(pac) ? url(string("pac+") + pac) : url("wpad://")); + return response; } // Mode is http://... or socks://... else if (this->data[PROXY_MODE] == "manual") { - string type, host, port; bool auth = this->data[PROXY_USE_AUTHENTICATION] == "true"; string username = url::encode(this->data[PROXY_AUTH_USER], URL_ALLOWED_IN_USERINFO_ELEMENT); string password = url::encode(this->data[PROXY_AUTH_PASSWORD], URL_ALLOWED_IN_USERINFO_ELEMENT); - bool same_proxy = this->data[PROXY_SAME_FOR_ALL] == "true"; - - // If socks is set use it (except when same_proxy is set) - if (!same_proxy) { - type = "socks"; - host = this->data[PROXY_SOCKS_HOST]; - port = this->data[PROXY_SOCKS_PORT]; - } - if (host == "" || get_port(port) == 0) { - // Get the per-scheme proxy settings - if (dest.get_scheme() == "http") { - type = "http"; - host = this->data[PROXY_HTTP_HOST]; - port = this->data[PROXY_HTTP_PORT]; - } - else if (dest.get_scheme() == "https") { - // It is expected that the configured server is an - // HTTP server that support CONNECT method. - type = "http"; - host = this->data[PROXY_SECURE_HOST]; - port = this->data[PROXY_SECURE_PORT]; - } - else if (dest.get_scheme() == "ftp") { - // It is expected that the configured server is an - // HTTP server that handles proxying FTP URLs - // (e.g. request with header "Host: ftp://ftp.host.org") - type = "http"; - host = this->data[PROXY_FTP_HOST]; - port = this->data[PROXY_FTP_PORT]; - } - - // If no proxy is set and we have the same_proxy option - // enabled try socks at the end only. - if (same_proxy && (host == "" || get_port(port) == 0)) { - type = "socks"; - host = this->data[PROXY_SOCKS_HOST]; - port = this->data[PROXY_SOCKS_PORT]; - } - } - - - // If host and port were found, build config url - if (host != "" && get_port(port) != 0) { - string tmp = type + "://"; - if (auth) - tmp += username + ":" + password + "@"; - tmp += host + ":" + port; - return url(tmp); + // Get the per-scheme proxy settings + if (dest.get_scheme() == "http") + store_response("http", this->data[PROXY_HTTP_HOST], + this->data[PROXY_HTTP_PORT], auth, username, password, response); + else if (dest.get_scheme() == "https") + // It is expected that the configured server is an + // HTTP server that support CONNECT method. + store_response("http", this->data[PROXY_SECURE_HOST], + this->data[PROXY_SECURE_PORT], auth, username, password, response); + else if (dest.get_scheme() == "ftp") + // It is expected that the configured server is an + // HTTP server that handles proxying FTP URLs + // (e.g. request with header "Host: ftp://ftp.host.org") + store_response("http", this->data[PROXY_FTP_HOST], + this->data[PROXY_FTP_PORT], auth, username, password, response); + + store_response("socks", this->data[PROXY_SOCKS_HOST], + this->data[PROXY_SOCKS_PORT], auth, username, password, response); + + // In case nothing matched, try HTTP Connect and fallback to direct. + // If there is not secure HTTP proxy, this will only add direct:// to + // the response + if (response.size() == 0) { + store_response("http", this->data[PROXY_SECURE_HOST], + this->data[PROXY_SECURE_PORT], auth, username, password, response); + response.push_back(url("direct://")); } } - // Mode is direct:// - return url("direct://"); + return response; } - string get_ignore(url) { + string get_ignore(const url&) { return this->data[PROXY_IGNORE_HOSTS]; } - bool set_creds(url /*proxy*/, string username, string password) { + virtual bool set_creds(url /*proxy*/, string username, string password) { string auth = PROXY_USE_AUTHENTICATION "\ttrue\n"; string user = string(PROXY_AUTH_USER "\t") + username + "\n"; string pass = string(PROXY_AUTH_PASSWORD "\t") + password + "\n"; diff --git a/libproxy/modules/config_gnome3.cpp b/libproxy/modules/config_gnome3.cpp index 07f9f14..00c0146 100644 --- a/libproxy/modules/config_gnome3.cpp +++ b/libproxy/modules/config_gnome3.cpp @@ -113,7 +113,7 @@ static int popen2(const char *program, FILE** read, FILE** write, pid_t* pid) { } } -static inline uint16_t get_port(string &port) +static inline uint16_t get_port(const string &port) { uint16_t retval; @@ -163,10 +163,28 @@ public: kill(this->pid, SIGTERM); } - url get_config(url dest) throw (runtime_error) { + void store_response(const string &type, + const string &host, + const string &port, + bool auth, + const string &username, + const string &password, + vector<url> &response) { + if (host != "" && get_port(port) != 0) { + string tmp = type + "://"; + if (auth) + tmp += username + ":" + password + "@"; + tmp += host + ":" + port; + response.push_back(url(tmp)); + } + } + + vector<url> get_config(const url &dest) throw (runtime_error) { // Check for changes in the config fd_set rfds; struct timeval timeout = { 0, 0 }; + vector<url> response; + FD_ZERO(&rfds); FD_SET(fileno(this->read), &rfds); if (select(fileno(this->read)+1, &rfds, NULL, NULL, &timeout) > 0) @@ -175,72 +193,49 @@ public: // Mode is wpad:// or pac+http://... if (this->data[PROXY_MODE] == "auto") { string pac = this->data[PROXY_AUTOCONFIG_URL]; - return url::is_valid(pac) ? url(string("pac+") + pac) : url("wpad://"); + response.push_back(url::is_valid(pac) ? url(string("pac+") + pac) : url("wpad://")); + return response; } // Mode is http://... or socks://... else if (this->data[PROXY_MODE] == "manual") { - string type, host, port; bool auth = this->data[PROXY_USE_AUTHENTICATION] == "true"; string username = url::encode(this->data[PROXY_AUTH_USER], URL_ALLOWED_IN_USERINFO_ELEMENT); string password = url::encode(this->data[PROXY_AUTH_PASSWORD], URL_ALLOWED_IN_USERINFO_ELEMENT); - bool same_proxy = this->data[PROXY_SAME_FOR_ALL] == "true"; - - // If socks is set use it (except when same_proxy is set) - if (!same_proxy) { - type = "socks"; - host = this->data[PROXY_SOCKS_HOST]; - port = this->data[PROXY_SOCKS_PORT]; - } - if (host == "" || get_port(port) == 0) { - // Get the per-scheme proxy settings - if (dest.get_scheme() == "http") { - type = "http"; - host = this->data[PROXY_HTTP_HOST]; - port = this->data[PROXY_HTTP_PORT]; - } - else if (dest.get_scheme() == "https") { - // It is expected that the configured server is an - // HTTP server that support CONNECT method. - type = "http"; - host = this->data[PROXY_SECURE_HOST]; - port = this->data[PROXY_SECURE_PORT]; - } - else if (dest.get_scheme() == "ftp") { - // It is expected that the configured server is an - // HTTP server that handles proxying FTP URLs - // (e.g. request with header "Host: ftp://ftp.host.org") - type = "http"; - host = this->data[PROXY_FTP_HOST]; - port = this->data[PROXY_FTP_PORT]; - } - - // If no proxy is set and we have the same_proxy option - // enabled try socks at the end only. - if (same_proxy && (host == "" || get_port(port) == 0)) { - type = "socks"; - host = this->data[PROXY_SOCKS_HOST]; - port = this->data[PROXY_SOCKS_PORT]; - } - } - - - // If host and port were found, build config url - if (host != "" && get_port(port) != 0) { - string tmp = type + "://"; - if (auth) - tmp += username + ":" + password + "@"; - tmp += host + ":" + port; - return url(tmp); + // Get the per-scheme proxy settings + if (dest.get_scheme() == "http") + store_response("http", this->data[PROXY_HTTP_HOST], + this->data[PROXY_HTTP_PORT], auth, username, password, response); + else if (dest.get_scheme() == "https") + // It is expected that the configured server is an + // HTTP server that support CONNECT method. + store_response("http", this->data[PROXY_SECURE_HOST], + this->data[PROXY_SECURE_PORT], auth, username, password, response); + else if (dest.get_scheme() == "ftp") + // It is expected that the configured server is an + // HTTP server that handles proxying FTP URLs + // (e.g. request with header "Host: ftp://ftp.host.org") + store_response("http", this->data[PROXY_FTP_HOST], + this->data[PROXY_FTP_PORT], auth, username, password, response); + + store_response("socks", this->data[PROXY_SOCKS_HOST], + this->data[PROXY_SOCKS_PORT], auth, username, password, response); + + // In case nothing matched, try HTTP Connect and fallback to direct. + // If there is not secure HTTP proxy, this will only add direct:// to + // the response + if (response.size() == 0) { + store_response("http", this->data[PROXY_SECURE_HOST], + this->data[PROXY_SECURE_PORT], auth, username, password, response); + response.push_back(url("direct://")); } } - // Mode is direct:// - return url("direct://"); + return response; } - string get_ignore(url) { + string get_ignore(const url&) { return this->data[PROXY_IGNORE_HOSTS]; } diff --git a/libproxy/modules/config_kde4.cpp b/libproxy/modules/config_kde4.cpp index bbf1910..f23320d 100644 --- a/libproxy/modules/config_kde4.cpp +++ b/libproxy/modules/config_kde4.cpp @@ -46,9 +46,11 @@ public: delete this->cfg; } - url get_config(url dst) throw (runtime_error) { + vector<url> get_config(const url &dst) throw (runtime_error) { string tmp; QString prxy; + vector<url> response; + switch (this->grp->readEntry("ProxyType", 0)) { case 1: // Use a manual proxy prxy = this->grp->readEntry(QString(dst.get_scheme().c_str()) + "Proxy", ""); @@ -62,26 +64,31 @@ public: }; // The result of toLatin1() is undefined for non-Latin1 strings. // However, KDE saves this entry using IDN and percent-encoding, so no problem... - return string(prxy.toLatin1().data()); + response.push_back(string(prxy.toLatin1().data())); + break; case 2: // Use a manual PAC // The result of toLatin1() is undefined for non-Latin1 strings. // However, KDE saves this entry using IDN and percent-encoding, so no problem... tmp = string(this->grp->readEntry("Proxy Config Script", "").toLatin1().data()); if (url::is_valid("pac+" + tmp)) - return url("pac+" + tmp); - return url("wpad://"); + response.push_back(url("pac+" + tmp)); + else + response.push_back(string("wpad://")); + break; case 3: // Use WPAD - return url("wpad://"); + response.push_back(string("wpad://")); + break; case 4: // Use envvar throw runtime_error("User config_envvar"); // We'll bypass this config plugin and let the envvar plugin work default: - return url("direct://"); + response.push_back(url("direct://")); + break; }; - // Never get here! + return response; } - string get_ignore(url /*dst*/) { + string get_ignore(const url& /*dst*/) { // Apply ignore list only for manual proxy configuration if (this->grp->readEntry("ProxyType", 0) == 1) { string prefix = this->grp->readEntry("ReversedException", false) ? "-" : ""; diff --git a/libproxy/modules/config_macosx.cpp b/libproxy/modules/config_macosx.cpp index c675662..1c43000 100644 --- a/libproxy/modules/config_macosx.cpp +++ b/libproxy/modules/config_macosx.cpp @@ -114,40 +114,45 @@ static string capitalize(string str) { class macosx_config_extension : public config_extension { public: - url get_config(url url) throw (runtime_error) { + vector<url> get_config(const url &url) throw (runtime_error) { string tmp; CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + vector<url> response; + if (!proxies) throw runtime_error("Unable to fetch proxy configuration"); // wpad:// if (getbool(proxies, "ProxyAutoDiscoveryEnable")) { CFRelease(proxies); - return libproxy::url(string("wpad://")); + response.push_back(url("wpad://")); } // pac+http://... - if (getbool(proxies, "ProxyAutoConfigEnable") && + else if (getbool(proxies, "ProxyAutoConfigEnable") && (tmp = str(getobj<CFStringRef>(proxies, "ProxyAutoConfigURLString"))) != "" && url::is_valid(tmp)) { CFRelease(proxies); - return libproxy::url(string("pac+") + tmp); + response.push_back(url(string("pac+") + tmp)); } // http:// or socks:// (TODO: gopher:// and rtsp:// ???) - if ((protocol_url(proxies, toupper(url.get_scheme()), tmp) && url::is_valid(tmp)) || + else if ((protocol_url(proxies, toupper(url.get_scheme()), tmp) && url::is_valid(tmp)) || (protocol_url(proxies, capitalize(url.get_scheme()), tmp) && url::is_valid(tmp)) || (protocol_url(proxies, toupper("http"), tmp) && url::is_valid(tmp)) || (protocol_url(proxies, toupper("socks"), tmp) && url::is_valid(tmp))) { CFRelease(proxies); - return libproxy::url(tmp); + response.push_back(url(tmp)); + } + else { + // direct:// + CFRelease(proxies); + response.push_back(url("direct://")); } - // direct:// - CFRelease(proxies); - return libproxy::url(string("direct://")); + return response; } - string get_ignore(url) { + string get_ignore(const url&) { // Get config dict CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); if (!proxies) return ""; diff --git a/libproxy/modules/config_sysconfig.cpp b/libproxy/modules/config_sysconfig.cpp index 6e97ae8..b7985ae 100644 --- a/libproxy/modules/config_sysconfig.cpp +++ b/libproxy/modules/config_sysconfig.cpp @@ -124,20 +124,24 @@ public: ~sysconfig_config_extension() { } - url get_config(url url) throw (runtime_error) { + vector<url> get_config(const url &dst) throw (runtime_error) { map<string,string>::const_iterator it = _data.find("PROXY_ENABLED"); - if (it != _data.end() && it->second == "no") - return libproxy::url("direct://"); + vector<url> response; + + if (it != _data.end() && it->second == "no") { + response.push_back(url("direct://")); + return response; + } string key; string proxy; // If the URL is an ftp url, try to read the ftp proxy - if (url.get_scheme() == "ftp") + if (dst.get_scheme() == "ftp") key = "FTP_PROXY"; - else if (url.get_scheme() == "http") + else if (dst.get_scheme() == "http") key = "HTTP_PROXY"; - else if (url.get_scheme() == "https") + else if (dst.get_scheme() == "https") key = "HTTPS_PROXY"; it = _data.find(key); @@ -147,10 +151,11 @@ public: if (proxy.empty()) throw runtime_error("Unable to read configuration"); - return libproxy::url(proxy); + response.push_back(url(proxy)); + return response; } - string get_ignore(url) { + string get_ignore(const url&) { map<string,string>::const_iterator it = _data.find("NO_PROXY"); if (it != _data.end()) return it->second; diff --git a/libproxy/modules/config_w32reg.cpp b/libproxy/modules/config_w32reg.cpp index 0111c33..fc49e41 100644 --- a/libproxy/modules/config_w32reg.cpp +++ b/libproxy/modules/config_w32reg.cpp @@ -108,22 +108,24 @@ static map<string, string> parse_manual(string data) { class w32reg_config_extension : public config_extension { public: - url get_config(url dst) throw (runtime_error) { + vector<url> get_config(const url &dst) throw (runtime_error) { char *tmp = NULL; uint32_t enabled = 0; + vector<url> response; // WPAD if (is_enabled(W32REG_OFFSET_WPAD)) { - return url("wpad://"); + response.push_back(url("wpad://")); + return response; } // PAC if (is_enabled(W32REG_OFFSET_PAC) && get_registry(W32REG_BASEKEY, "AutoConfigURL", &tmp, NULL, NULL) && url::is_valid(string("pac+") + tmp)) { - url cfg(string("pac+") + tmp); + response.push_back(url(string("pac+") + tmp)); delete tmp; - return cfg; + return response; } // Manual proxy @@ -135,22 +137,25 @@ public: // First we look for an exact match if (manual.find(dst.get_scheme()) != manual.end()) - return manual[dst.get_scheme()]; + response.push_back(manual[dst.get_scheme()]); // Next we look for http else if (manual.find("http") != manual.end()) - return manual["http"]; + response.push_back(manual["http"]); // Last we look for socks else if (manual.find("socks") != manual.end()) - return manual["socks"]; + response.push_back(manual["socks"]); + + return response; } // Direct - return url("direct://"); + response.push_back(url("direct://")); + return response; } - string get_ignore(url dst) { + string get_ignore(const url &dst) { char *tmp; if (get_registry(W32REG_BASEKEY, "ProxyOverride", &tmp, NULL, NULL)) { string po = tmp; diff --git a/libproxy/modules/ignore_domain.cpp b/libproxy/modules/ignore_domain.cpp index 9ec28ce..f39e545 100644 --- a/libproxy/modules/ignore_domain.cpp +++ b/libproxy/modules/ignore_domain.cpp @@ -24,7 +24,7 @@ using namespace libproxy; class domain_ignore_extension : public ignore_extension { public: - virtual bool ignore(url& url, string ignorestr) { + virtual bool ignore(url& url, const string &ignorestr) { /* Get our URL's hostname and port */ string host = url.get_host(); int port = url.get_port(); diff --git a/libproxy/modules/ignore_hostname.cpp b/libproxy/modules/ignore_hostname.cpp index c9a7621..6caa291 100644 --- a/libproxy/modules/ignore_hostname.cpp +++ b/libproxy/modules/ignore_hostname.cpp @@ -24,7 +24,7 @@ using namespace libproxy; class hostname_ignore_extension : public ignore_extension { public: - virtual bool ignore(url& url, string ignorestr) { + virtual bool ignore(url& url, const string &ignorestr) { if (ignorestr == "<local>" && url.get_host().find(':') == string::npos && // Make sure it's not IPv6 url.get_host().find('.') == string::npos) diff --git a/libproxy/modules/ignore_ip.cpp b/libproxy/modules/ignore_ip.cpp index c019fec..e1b99bd 100644 --- a/libproxy/modules/ignore_ip.cpp +++ b/libproxy/modules/ignore_ip.cpp @@ -113,7 +113,7 @@ sockaddr_from_cidr(sa_family_t af, uint8_t cidr) class ip_ignore_extension : public ignore_extension { public: - virtual bool ignore(url& url, string ignore) { + virtual bool ignore(url& url, const string &ignore) { bool result = false; uint16_t port = 0; const struct sockaddr *dst_ip = url.get_ips(false) ? url.get_ips(false)[0] : NULL; diff --git a/libproxy/modules/wpad_dns_alias.cpp b/libproxy/modules/wpad_dns_alias.cpp index ca89c36..449d8ee 100644 --- a/libproxy/modules/wpad_dns_alias.cpp +++ b/libproxy/modules/wpad_dns_alias.cpp @@ -22,9 +22,15 @@ using namespace libproxy; class dns_alias_wpad_extension : public wpad_extension { public: - dns_alias_wpad_extension() { rewind(); } - bool found() { return lastpac != NULL; } - void rewind() { lasturl = NULL; lastpac = NULL; } + dns_alias_wpad_extension() : lasturl(NULL), lastpac(NULL) { } + bool found() { return lastpac != NULL; } + + void rewind() { + if (lasturl) delete lasturl; + if (lastpac) delete lastpac; + lasturl = NULL; + lastpac = NULL; + } url* next(char** pac) { if (lasturl) return false; @@ -32,8 +38,8 @@ public: lasturl = new url("http://wpad/wpad.dat"); lastpac = *pac = lasturl->get_pac(); if (!lastpac) { - delete lasturl; - return NULL; + delete lasturl; + return NULL; } return lasturl; diff --git a/libproxy/proxy.cpp b/libproxy/proxy.cpp index e9e5026..6d048db 100644 --- a/libproxy/proxy.cpp +++ b/libproxy/proxy.cpp @@ -59,7 +59,13 @@ private: void lock(); void unlock(); - void _get_proxies(url *realurl, vector<string> &response); + void check_network_topology(); + void get_config(url &realurl, vector<url> &configs, string &ignore); + bool is_ignored(url &realurl, const string &ignore); + bool expand_wpad(const url &confurl); + bool expand_pac(url &configurl); + void run_pac(url &realurl, const url &confurl, vector<string> &response); + void clear_cache(); #ifdef WIN32 HANDLE mutex; @@ -70,6 +76,7 @@ private: char* pac; url* pacurl; bool wpad; + bool debug; }; static bool istringcmp(string a, string b) { @@ -79,18 +86,17 @@ static bool istringcmp(string a, string b) { } // Convert the PAC formatted response into our proxy URL array response -static vector<string> -format_pac_response(string response) +static void format_pac_response(string response, vector<string> &retval) { - vector<string> retval; - // Skip ahead one character if we start with ';' - if (response[0] == ';') - return format_pac_response(response.substr(1)); + if (response[0] == ';') { + format_pac_response(response.substr(1), retval); + return; + } // If the string contains a delimiter (';') if (response.find(';') != string::npos) { - retval = format_pac_response(response.substr(response.find(';')+1)); + format_pac_response(response.substr(response.find(';') + 1), retval); response = response.substr(0, response.find(';')); } @@ -115,12 +121,12 @@ format_pac_response(string response) retval.insert(retval.begin(), string("socks://") + server); else if (istringcmp(method, "socks4") && url::is_valid("http://" + server)) retval.insert(retval.begin(), string("socks4://") + server); + else if (istringcmp(method, "socks4a") && url::is_valid("http://" + server)) + retval.insert(retval.begin(), string("socks4a://") + server); else if (istringcmp(method, "socks5") && url::is_valid("http://" + server)) retval.insert(retval.begin(), string("socks5://") + server); else if (istringcmp(method, "direct")) retval.insert(retval.begin(), string("direct://")); - - return retval; } proxy_factory::proxy_factory() { @@ -159,6 +165,8 @@ proxy_factory::proxy_factory() { this->mm.load_dir(module_dir); this->mm.load_dir(module_dir, false); + this->debug = (getenv("_PX_DEBUG") != NULL); + unlock(); } @@ -179,25 +187,42 @@ proxy_factory::~proxy_factory() { } -vector<string> proxy_factory::get_proxies(string url_) { - url* realurl = NULL; +vector<string> proxy_factory::get_proxies(string realurl) { vector<string> response; // Check to make sure our url is valid - if (!url::is_valid(url_)) + if (!url::is_valid(realurl)) goto do_return; - realurl = new url(url_); lock(); // Let trap and forward exceptions so we don't deadlock try { - _get_proxies(realurl, response); + vector<url> configs; + string ignore; + url dst(realurl); + + check_network_topology(); + get_config(dst, configs, ignore); + + if (debug) cerr << "Config is: " << endl; + + for (vector<url>::iterator i=configs.begin() ; i != configs.end() ; i++) { + url confurl(*i); + + if (debug) cerr << "\t" << confurl.to_string() << endl; + + if (expand_wpad(confurl) || expand_pac(confurl)) { + run_pac(dst, confurl, response); + } else { + clear_cache(); + response.push_back(confurl.to_string()); + } + } + unlock(); - if (realurl) delete realurl; } catch (exception &e) { unlock(); - if (realurl) delete realurl; throw e; } @@ -207,16 +232,8 @@ do_return: return response; } -void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { - url confurl("direct://"); - bool ignored = false, invign = false; - string confign; - config_extension* config = NULL; +void proxy_factory::check_network_topology() { vector<network_extension*> networks; - vector<config_extension*> configs; - vector<ignore_extension*> ignores; - const char* debug = getenv("_PX_DEBUG"); - // Check to see if our network topology has changed... networks = this->mm.get_extensions<network_extension>(); @@ -232,32 +249,40 @@ void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { break; } } +} + +void proxy_factory::get_config(url &realurl, vector<url> &config, string &ignore) { + vector<config_extension*> configs; configs = this->mm.get_extensions<config_extension>(); for (vector<config_extension*>::iterator i=configs.begin() ; i != configs.end() ; i++) { - config = *i; + config_extension *configurator = *i; - // Try to get the confurl + // Try to get the configuration try { - confurl = config->get_config(*realurl); - confign = config->get_ignore(*realurl); - config->set_valid(true); + ignore = configurator->get_ignore(realurl); + if (!is_ignored(realurl, ignore)) + config = configurator->get_config(realurl); + if (debug) { + if (configurator) { + cerr << "Configuration extension is: " << typeid(*configurator).name() << endl; + cerr << "Ingored list is: " << ignore << endl; + } else { + cerr << "No configuration extension found." << endl; + } + } break; } catch (runtime_error e) { - confurl = "direct://"; - confign = ""; - config->set_valid(false); - config = NULL; + ignore = ""; } } - if (debug) { - if (config) - cerr << "Using config: " << typeid(*config).name() << endl; - else - cerr << "Using config: NULL" << endl; - cerr << "Using ignore: " << confign << endl; - } +} + +bool proxy_factory::is_ignored(url &realurl, const string &ignore) { + vector<ignore_extension*> ignores; + bool ignored = false, invign = false; + string confign = ignore; /* Check our ignore patterns */ ignores = this->mm.get_extensions<ignore_extension>(); @@ -270,16 +295,22 @@ void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { string ignorestr = confign.substr (i, next - i); ignorestr = ignorestr.substr(ignorestr.find_first_not_of(" \t\n"), ignorestr.find_last_not_of(" \t\n")+1); for (vector<ignore_extension*>::iterator it=ignores.begin() ; it != ignores.end() && !ignored ; it++) - ignored = ((*it)->ignore(*realurl, ignorestr)); + ignored = ((*it)->ignore(realurl, ignorestr)); } i = next+1; } - if (!ignored && invign) return; - if (ignored && !invign) return; - /* If we have a wpad config */ - if (debug) cerr << "Config is: " << confurl.to_string() << endl; + if (invign) + return !ignored; + else + return ignored; +} + +bool proxy_factory::expand_wpad(const url &confurl) +{ + bool rtv = false; if (confurl.get_scheme() == "wpad") { + rtv = true; /* If the config has just changed from PAC to WPAD, clear the PAC */ if (!this->wpad) { if (this->pac) delete this->pac; @@ -331,8 +362,17 @@ void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { } } + return rtv; +} + +bool proxy_factory::expand_pac(url &confurl) +{ + bool rtv = false; + // If we have a PAC config - else if (confurl.get_scheme().substr(0, 4) == "pac+") { + if (confurl.get_scheme().substr(0, 4) == "pac+") { + rtv = true; + /* Save the PAC config */ if (this->wpad) this->wpad = false; @@ -350,15 +390,20 @@ void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { /* Try to load the PAC if it is not already loaded */ if (!this->pac) { this->pacurl = new url(confurl); - this->pac = confurl.get_pac(); - if (!this->pac) { - if (debug) cerr << "Unable to download PAC!" << endl; - return; + this->pac = confurl.get_pac(); + if (debug) { + if (!this->pac) + cerr << "Unable to download PAC!" << endl; + else + cerr << "PAC received!" << endl; } - if (debug) cerr << "PAC received!" << endl; } } + return rtv; +} + +void proxy_factory::run_pac(url &realurl, const url &confurl, vector<string> &response) { /* In case of either PAC or WPAD, we'll run the PAC */ if (this->pac && (confurl.get_scheme() == "wpad" || confurl.get_scheme().substr(0, 4) == "pac+") ) { vector<pacrunner_extension*> pacrunners = this->mm.get_extensions<pacrunner_extension>(); @@ -371,20 +416,16 @@ void proxy_factory::_get_proxies(url *realurl, vector<string> &response) { /* Run the PAC, but only try one PACRunner */ if (debug) cerr << "Using pacrunner: " << typeid(*pacrunners[0]).name() << endl; - string pacresp = pacrunners[0]->get(this->pac, this->pacurl->to_string())->run(*realurl); + string pacresp = pacrunners[0]->get(this->pac, this->pacurl->to_string())->run(realurl); if (debug) cerr << "Pacrunner returned: " << pacresp << endl; - response = format_pac_response(pacresp); + format_pac_response(pacresp, response); } +} - /* If we have a manual config (http://..., socks://..., etc.) */ - else - { - this->wpad = false; - if (this->pac) { delete this->pac; this->pac = NULL; } - if (this->pacurl) { delete this->pacurl; this->pacurl = NULL; } - response.clear(); - response.push_back(confurl.to_string()); - } +void proxy_factory::clear_cache() { + this->wpad = false; + if (this->pac) { delete this->pac; this->pac = NULL; } + if (this->pacurl) { delete this->pacurl; this->pacurl = NULL; } } void proxy_factory::lock() { |