From 330cc3258c72d96266fdc5a67b9571c841601bdc Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 21 Jul 2016 10:15:06 +0100 Subject: [PATCH] proxy: add libproxy support --- configure.ac | 88 ++++++++++++++++++++++++++++++++++++ docs/libcurl/curl_easy_setopt.3 | 3 ++ docs/libcurl/opts/CURLOPT_LIBPROXY.3 | 46 +++++++++++++++++++ docs/libcurl/opts/Makefile.am | 3 ++ docs/libcurl/symbols-in-versions | 1 + include/curl/curl.h | 3 ++ lib/Makefile.inc | 5 +- lib/curl_libproxy.c | 72 +++++++++++++++++++++++++++++ lib/curl_libproxy.h | 37 +++++++++++++++ lib/easy.c | 8 ++++ lib/url.c | 11 +++++ lib/urldata.h | 5 ++ 12 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 docs/libcurl/opts/CURLOPT_LIBPROXY.3 create mode 100644 lib/curl_libproxy.c create mode 100644 lib/curl_libproxy.h diff --git a/configure.ac b/configure.ac index 1040a07..49ed5f8 100644 --- a/configure.ac +++ b/configure.ac @@ -166,10 +166,11 @@ curl_verbose_msg="enabled (--disable-verbose)" curl_ldaps_msg="no (--enable-ldaps)" curl_rtsp_msg="no (--enable-rtsp)" curl_rtmp_msg="no (--with-librtmp)" curl_mtlnk_msg="no (--with-libmetalink)" curl_psl_msg="no (--with-libpsl)" +curl_libproxy_msg="no (--with-libproxy)" init_ssl_msg=${curl_ssl_msg} dnl dnl Save some initial values the user might have provided @@ -2619,10 +2620,96 @@ if test X"$OPT_LIBSSH2" != Xno; then LIBS=$CLEANLIBS fi fi dnl ********************************************************************** +dnl Check for the presence of LIBPROXY libraries and headers +dnl ********************************************************************** + +dnl Default to compiler & linker defaults for LIBPROXY files & libraries. +OPT_LIBPROXY=off +AC_ARG_WITH(libproxy,dnl +AC_HELP_STRING([--with-libproxy=PATH],[Where to look for libproxy, PATH points to the LIBPROXY installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option]) +AC_HELP_STRING([--without-libproxy], [disable LIBPROXY]), + OPT_LIBPROXY=$withval) + +if test X"$OPT_LIBPROXY" != Xno; then + dnl backup the pre-libproxy variables + CLEANLDFLAGS="$LDFLAGS" + CLEANCPPFLAGS="$CPPFLAGS" + CLEANLIBS="$LIBS" + + case "$OPT_LIBPROXY" in + yes) + dnl --with-libproxy (without path) used + CURL_CHECK_PKGCONFIG(libproxy) + + if test "$PKGCONFIG" != "no" ; then + LIB_PROXY=`$PKGCONFIG --libs-only-l libproxy` + LD_PROXY=`$PKGCONFIG --libs-only-L libproxy` + CPP_PROXY=`$PKGCONFIG --cflags-only-I libproxy` + version=`$PKGCONFIG --modversion libproxy` + DIR_PROXY=`echo $LD_PROXY | $SED -e 's/-L//'` + fi + + ;; + off) + dnl no --with-libproxy option given, just check default places + ;; + *) + dnl use the given --with-libproxy spot + PREFIX_PROXY=$OPT_LIBPROXY + ;; + esac + + dnl if given with a prefix, we set -L and -I based on that + if test -n "$PREFIX_PROXY"; then + LIB_PROXY="-lproxy" + LD_PROXY=-L${PREFIX_PROXY}/lib$libsuff + CPP_PROXY=-I${PREFIX_PROXY}/include + DIR_PROXY=${PREFIX_PROXY}/lib$libsuff + fi + + LDFLAGS="$LDFLAGS $LD_PROXY" + CPPFLAGS="$CPPFLAGS $CPP_PROXY" + LIBS="$LIB_PROXY $LIBS" + + AC_CHECK_LIB(proxy, px_proxy_factory_new) + + AC_CHECK_HEADERS(proxy.h, + curl_libproxy_msg="enabled" + LIBPROXY_ENABLED=1 + AC_DEFINE(USE_LIBPROXY, 1, [if libproxy is in use]) + AC_SUBST(USE_LIBPROXY, [1]) + ) + + if test X"$OPT_LIBPROXY" != Xoff && + test "$LIBPROXY_ENABLED" != "1"; then + AC_MSG_ERROR([libproxy libs and/or directories were not found where specified!]) + fi + + if test "$LIBPROXY_ENABLED" = "1"; then + if test -n "$DIR_LIBPROXY"; then + dnl when the libproxy shared libs were found in a path that the run-time + dnl linker doesn't search through, we need to add it to LD_LIBRARY_PATH + dnl to prevent further configure tests to fail due to this + + if test "x$cross_compiling" != "xyes"; then + LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$DIR_LIBPROXY" + export LD_LIBRARY_PATH + AC_MSG_NOTICE([Added $DIR_LIBPROXY to LD_LIBRARY_PATH]) + fi + fi + else + dnl no libproxy; revert back to clean variables + LDFLAGS=$CLEANLDFLAGS + CPPFLAGS=$CLEANCPPFLAGS + LIBS=$CLEANLIBS + fi +fi + +dnl ********************************************************************** dnl Check for the presence of LIBRTMP libraries and headers dnl ********************************************************************** dnl Default to compiler & linker defaults for LIBRTMP files & libraries. OPT_LIBRTMP=off @@ -3905,10 +3992,11 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: RTSP support: ${curl_rtsp_msg} RTMP support: ${curl_rtmp_msg} metalink support: ${curl_mtlnk_msg} PSL support: ${curl_psl_msg} HTTP2 support: ${curl_h2_msg} + libproxy support: ${curl_libproxy_msg} Protocols: ${SUPPORT_PROTOCOLS} ]) if test "x$soname_bump" = "xyes"; then diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 75f1ce4..7c92390 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -161,10 +161,13 @@ Proxy to use. See \fICURLOPT_PROXY(3)\fP Proxy port to use. See \fICURLOPT_PROXYPORT(3)\fP .IP CURLOPT_PROXYTYPE Proxy type. See \fICURLOPT_PROXYTYPE(3)\fP .IP CURLOPT_NOPROXY Filter out hosts from proxy use. \fICURLOPT_NOPROXY(3)\fP +.IP CURLOPT_LIBPROXY +Use the libproxy API to determine which proxy, if any, to +use. \fICURLOPT_LIBPROXY(3)\fP .IP CURLOPT_HTTPPROXYTUNNEL Tunnel through the HTTP proxy. \fICURLOPT_HTTPPROXYTUNNEL(3)\fP .IP CURLOPT_CONNECT_TO Connect to a specific host and port. See \fICURLOPT_CONNECT_TO(3)\fP .IP CURLOPT_SOCKS5_GSSAPI_SERVICE diff --git a/docs/libcurl/opts/CURLOPT_LIBPROXY.3 b/docs/libcurl/opts/CURLOPT_LIBPROXY.3 new file mode 100644 index 0000000..90328d0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_LIBPROXY.3 @@ -0,0 +1,46 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at http://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_LIBPROXY 3 "26 Jul 2016" "libcurl 7.51.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_LIBPROXY \- enable automatic proxy detection via libproxy +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_LIBPROXY, long enable); +.SH DESCRIPTION +Set \fIenable\fP to 1L to tell libcurl to use the libproxy API to determine +which proxy, if any, to use for each request according to the system +configuration. +.SH DEFAULT +0 (off) +.SH PROTOCOLS +All except file://. Note that some protocols don't do very well over proxy. +.SH EXAMPLE +TODO +.SH AVAILABILITY +Added in 7.51.0 +.SH RETURN VALUE +Returns CURLE_OK if libproxy is supported, CURLE_NOT_BUILT_IN if not. +.SH "SEE ALSO" +.BR CURLOPT_PROXYPORT "(3), " CURLOPT_HTTPPROXYTUNNEL "(3), " +.BR CURLOPT_PROXYTYPE "(3), " CURLOPT_PROXY "(3)" " diff --git a/docs/libcurl/opts/Makefile.am b/docs/libcurl/opts/Makefile.am index a3fc064..3c453b5 100644 --- a/docs/libcurl/opts/Makefile.am +++ b/docs/libcurl/opts/Makefile.am @@ -170,10 +170,11 @@ man_MANS = \ CURLOPT_IOCTLFUNCTION.3 \ CURLOPT_IPRESOLVE.3 \ CURLOPT_ISSUERCERT.3 \ CURLOPT_KEYPASSWD.3 \ CURLOPT_KRBLEVEL.3 \ + CURLOPT_LIBPROXY.3 \ CURLOPT_LOCALPORT.3 \ CURLOPT_LOCALPORTRANGE.3 \ CURLOPT_LOGIN_OPTIONS.3 \ CURLOPT_LOW_SPEED_LIMIT.3 \ CURLOPT_LOW_SPEED_TIME.3 \ @@ -457,10 +458,11 @@ HTMLPAGES = \ CURLOPT_IOCTLFUNCTION.html \ CURLOPT_IPRESOLVE.html \ CURLOPT_ISSUERCERT.html \ CURLOPT_KEYPASSWD.html \ CURLOPT_KRBLEVEL.html \ + CURLOPT_LIBPROXY.html \ CURLOPT_LOCALPORT.html \ CURLOPT_LOCALPORTRANGE.html \ CURLOPT_LOGIN_OPTIONS.html \ CURLOPT_LOW_SPEED_LIMIT.html \ CURLOPT_LOW_SPEED_TIME.html \ @@ -744,10 +746,11 @@ PDFPAGES = \ CURLOPT_IOCTLFUNCTION.pdf \ CURLOPT_IPRESOLVE.pdf \ CURLOPT_ISSUERCERT.pdf \ CURLOPT_KEYPASSWD.pdf \ CURLOPT_KRBLEVEL.pdf \ + CURLOPT_LIBPROXY.pdf \ CURLOPT_LOCALPORT.pdf \ CURLOPT_LOCALPORTRANGE.pdf \ CURLOPT_LOGIN_OPTIONS.pdf \ CURLOPT_LOW_SPEED_LIMIT.pdf \ CURLOPT_LOW_SPEED_TIME.pdf \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index e613195..a735ca4 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -411,10 +411,11 @@ CURLOPT_IOCTLFUNCTION 7.12.3 CURLOPT_IPRESOLVE 7.10.8 CURLOPT_ISSUERCERT 7.19.0 CURLOPT_KEYPASSWD 7.17.0 CURLOPT_KRB4LEVEL 7.3 7.17.0 CURLOPT_KRBLEVEL 7.16.4 +CURLOPT_LIBPROXY 7.51.0 CURLOPT_LOCALPORT 7.15.2 CURLOPT_LOCALPORTRANGE 7.15.2 CURLOPT_LOGIN_OPTIONS 7.34.0 CURLOPT_LOW_SPEED_LIMIT 7.1 CURLOPT_LOW_SPEED_TIME 7.1 diff --git a/include/curl/curl.h b/include/curl/curl.h index 0ac238c..e14675d 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1698,10 +1698,13 @@ typedef enum { CINIT(CONNECT_TO, OBJECTPOINT, 243), /* Set TCP Fast Open */ CINIT(TCP_FASTOPEN, LONG, 244), + /* Use libproxy to determine which proxy to use */ + CINIT(LIBPROXY, LONG, 245), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 0ed998c..d34f23d 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -51,11 +51,12 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c + x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \ + curl_libproxy.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ @@ -70,11 +71,11 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h + curl_printf.h system_win32.h curl_libproxy.h LIB_RCFILES = libcurl.rc CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) diff --git a/lib/curl_libproxy.c b/lib/curl_libproxy.c new file mode 100644 index 0000000..b5b35ee --- /dev/null +++ b/lib/curl_libproxy.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef USE_LIBPROXY + +#include "urldata.h" + +#include +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static pxProxyFactory *factory; + +CURLcode Curl_libproxy_global_init(void) +{ + factory = px_proxy_factory_new(); + if(!factory) + return CURLE_OUT_OF_MEMORY; + return CURLE_OK; +} + +void Curl_libproxy_global_cleanup(void) +{ + if(factory) + px_proxy_factory_free(factory); + factory = NULL; +} + +char *Curl_libproxy_detect_proxy(const char *url) +{ + char *result = NULL; + + if(factory) { + char **libproxy_results = px_proxy_factory_get_proxies(factory, url); + if(libproxy_results) { + int i; + + /* We only cope with one; can't fall back on failure */ + result = libproxy_results[0]; + for(i=1; libproxy_results[i]; i++) + free(libproxy_results[i]); + free(libproxy_results); + } + } + + return result; +} + +#endif /* USE_LIBPROXY */ diff --git a/lib/curl_libproxy.h b/lib/curl_libproxy.h new file mode 100644 index 0000000..8541c1e --- /dev/null +++ b/lib/curl_libproxy.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_LIBPROXY_H +#define HEADER_CURL_LIBPROXY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" +#include "urldata.h" + +#ifdef USE_LIBPROXY + +CURLcode Curl_libproxy_global_init(void); +void Curl_libproxy_global_cleanup(void); + +char *Curl_libproxy_detect_proxy(const char *url); + +#endif /* USE_LIBPROXY */ + +#endif /* HEADER_CURL_LIBPROXY_H */ diff --git a/lib/easy.c b/lib/easy.c index 583de15..3fa2590 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -139,10 +139,14 @@ static CURLcode win32_init(void) if(result) return result; } #endif +#ifdef USE_LIBPROXY + Curl_libproxy_global_init(); +#endif + return CURLE_OK; } #ifdef USE_LIBIDN /* @@ -358,10 +362,14 @@ void curl_global_cleanup(void) #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT) (void)libssh2_exit(); #endif +#ifdef USE_LIBPROXY + Curl_libproxy_global_cleanup(); +#endif + init_flags = 0; } /* * curl_easy_init() is the external interface to alloc, setup and init an diff --git a/lib/url.c b/lib/url.c index f355c7a..2061bcb 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2694,10 +2694,17 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, #endif } case CURLOPT_CONNECT_TO: data->set.connect_to = va_arg(param, struct curl_slist *); break; + case CURLOPT_LIBPROXY: +#ifdef USE_LIBPROXY + data->set.libproxy = (0 != va_arg(param, long))?TRUE:FALSE; +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; break; } @@ -5941,10 +5948,14 @@ static CURLcode create_conn(struct Curl_easy *data, if(data->set.str[STRING_NOPROXY] && check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { free(proxy); /* proxy is in exception list */ proxy = NULL; } +#ifdef USE_LIBPROXY + else if(data->set.libproxy) + proxy = Curl_libproxy_detect_proxy(data->change.url); +#endif else if(!proxy) proxy = detect_proxy(conn); #ifdef USE_UNIX_SOCKETS if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { diff --git a/lib/urldata.h b/lib/urldata.h index 3ac050b..9032f3a 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -196,10 +196,14 @@ #ifdef HAVE_LIBSSH2_H #include #include #endif /* HAVE_LIBSSH2_H */ +#ifdef USE_LIBPROXY +#include "curl_libproxy.h" +#endif + /* Download buffer size, keep it fairly big for speed reasons */ #undef BUFSIZE #define BUFSIZE CURL_MAX_WRITE_SIZE /* Initial size of the buffer to store headers in, it'll be enlarged in case @@ -1685,10 +1689,11 @@ struct UserDefined { bool ssl_enable_npn; /* TLS NPN extension? */ bool ssl_enable_alpn; /* TLS ALPN extension? */ bool path_as_is; /* allow dotdots? */ bool pipewait; /* wait for pipe/multiplex status before starting a new connection */ + bool libproxy; /* use libproxy to discover proxies */ long expect_100_timeout; /* in milliseconds */ struct Curl_easy *stream_depends_on; bool stream_depends_e; /* set or don't set the Exclusive bit */ int stream_weight; -- 2.9.3