Currently the only way to use a proxy is via XferCommand; however, when doing so there is no support for parallel downloads. This change introduces a new directive Proxy which supports whatever proxy protocols are supported by libcurl. Signed-off-by: Brian Geffon <briang@apache.org> --- doc/pacman.conf.5.asciidoc | 7 +++++++ etc/pacman.conf.in | 5 +++++ lib/libalpm/alpm.h | 24 ++++++++++++++++++++++++ lib/libalpm/dload.c | 3 +++ lib/libalpm/handle.c | 22 ++++++++++++++++++++++ lib/libalpm/handle.h | 1 + scripts/completion/zsh_completion.in | 1 + src/pacman/conf.c | 10 ++++++++++ src/pacman/conf.h | 2 ++ src/pacman/pacman-conf.c | 4 +++- 10 files changed, 78 insertions(+), 1 deletion(-) diff --git a/doc/pacman.conf.5.asciidoc b/doc/pacman.conf.5.asciidoc index 41f3ea03..657264e1 100644 --- a/doc/pacman.conf.5.asciidoc +++ b/doc/pacman.conf.5.asciidoc @@ -132,6 +132,13 @@ Options HTTP/FTP support, or need the more advanced proxy support that comes with utilities like wget. +*Proxy =* https://host:port:: + If set, use this endpoint as the proxy for downloads. The currently + supported set of protocols are http, https, socks4, socks4a, socks5, + and socks5h. If no port is specified it defaults to 1080. This option + only applies when using the built in downloader. When using XferCommand + any proxy settings must be passed as command line arguments to the command. + *NoUpgrade =* file ...:: All files listed with a `NoUpgrade` directive will never be touched during a package install/upgrade, and the new files will be installed with a diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 1799efc7..6b2ef8b9 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -21,6 +21,11 @@ HoldPkg = pacman glibc #CleanMethod = KeepInstalled Architecture = auto +# The Proxy directive only applies when not using an XferCommand. When using +# an XferCommand any proxy strings must be passed as arguments to the command. +#Proxy = socks5h://127.0.0.1:1080 +#Proxy = https://127.0.0.1:8080 + # Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup #IgnorePkg = #IgnoreGroup = diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 07e16b9f..37dd414f 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -2166,6 +2166,30 @@ int alpm_option_set_dbext(alpm_handle_t *handle, const char *dbext); /* End of dbext accessors */ /** @} */ +/** @name Accessors for proxy server configuration + * + * This controls the proxy server that will be used for downloads. + * This may be necessary for computers that only have internet access + * via HTTP or Socks proxies. + * + * @{ + */ + +/** Gets the configured proxy. + * @param handle the context handle + * @return the configured proxy + */ +const char *alpm_option_get_proxy(alpm_handle_t *handle); + +/** Sets the proxy server. + * @param handle the context handle + * @param proxy the full proxy string to use. + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int alpm_option_set_proxy(alpm_handle_t *handle, const char *proxy); + +/* End of proxy accessors */ +/** @} */ /** @name Accessors for the signature levels * @{ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 4fa17b35..171a802c 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -340,6 +340,9 @@ static void curl_set_handle_opts(CURL *curl, struct dload_payload *payload) curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(curl, CURLOPT_PRIVATE, (void *)payload); + if (handle->proxy) { + curl_easy_setopt(curl, CURLOPT_PROXY, handle->proxy); + } _alpm_log(handle, ALPM_LOG_DEBUG, "%s: url is %s\n", payload->remote_name, payload->fileurl); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index d1eafeda..e72627ea 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -73,6 +73,7 @@ void _alpm_handle_free(alpm_handle_t *handle) FREE(handle->root); FREE(handle->dbpath); FREE(handle->dbext); + FREE(handle->proxy); FREELIST(handle->cachedirs); FREELIST(handle->hookdirs); FREE(handle->logfile); @@ -330,6 +331,12 @@ const char SYMEXPORT *alpm_option_get_dbext(alpm_handle_t *handle) return handle->dbext; } +const char SYMEXPORT *alpm_option_get_proxy(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->proxy; +} + int SYMEXPORT alpm_option_get_parallel_downloads(alpm_handle_t *handle) { CHECK_HANDLE(handle, return -1); @@ -822,6 +829,21 @@ int SYMEXPORT alpm_option_set_dbext(alpm_handle_t *handle, const char *dbext) return 0; } +int SYMEXPORT alpm_option_set_proxy(alpm_handle_t *handle, const char *proxy) +{ + CHECK_HANDLE(handle, return -1); + ASSERT(proxy, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); + + if(handle->proxy) { + FREE(handle->proxy); + } + + STRDUP(handle->proxy, proxy, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + + _alpm_log(handle, ALPM_LOG_DEBUG, "option 'proxy' = %s\n", handle->proxy); + return 0; +} + int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle, int level) { diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 3a464689..32063ef9 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -107,6 +107,7 @@ struct _alpm_handle_t { int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ int checkspace; /* Check disk space before installing */ char *dbext; /* Sync DB extension */ + char *proxy; /* Proxy server to use */ int siglevel; /* Default signature verification level */ int localfilesiglevel; /* Signature verification level for local file upgrade operations */ diff --git a/scripts/completion/zsh_completion.in b/scripts/completion/zsh_completion.in index f65edeb2..69b19a18 100644 --- a/scripts/completion/zsh_completion.in +++ b/scripts/completion/zsh_completion.in @@ -516,6 +516,7 @@ _pacman_conf_general_directives=( 'DisableDownloadTimeout' 'NoProgressBar' 'ParallelDownloads' + 'Proxy' 'CleanMethod' 'SigLevel' 'LocalFileSigLevel' diff --git a/src/pacman/conf.c b/src/pacman/conf.c index f9edf75b..37691519 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -154,6 +154,7 @@ int config_free(config_t *oldconfig) free(oldconfig->rootdir); free(oldconfig->dbpath); free(oldconfig->logfile); + free(oldconfig->proxy); free(oldconfig->gpgdir); FREELIST(oldconfig->hookdirs); FREELIST(oldconfig->cachedirs); @@ -668,6 +669,11 @@ static int _parse_options(const char *key, char *value, config->logfile = strdup(value); pm_printf(ALPM_LOG_DEBUG, "config: logfile: %s\n", value); } + } else if(strcmp(key, "Proxy") == 0) { + if(!config->proxy) { + config->proxy = strdup(value); + pm_printf(ALPM_LOG_DEBUG, "config: proxy: %s\n", value); + } } else if(strcmp(key, "XferCommand") == 0) { char **c; if((config->xfercommand_argv = wordsplit(value)) == NULL) { @@ -901,6 +907,10 @@ static int setup_libalpm(void) pm_printf(ALPM_LOG_WARNING, _("no '%s' configured\n"), "XferCommand"); } + if (config->proxy) { + alpm_option_set_proxy(handle, config->proxy); + } + alpm_option_set_architectures(handle, config->architectures); alpm_option_set_checkspace(handle, config->checkspace); alpm_option_set_usesyslog(handle, config->usesyslog); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index f7916ca9..c441cd80 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -115,6 +115,8 @@ typedef struct __config_t { unsigned short verbosepkglists; /* number of parallel download streams */ unsigned int parallel_downloads; + /* the proxy server to use */ + char *proxy; /* select -Sc behavior */ unsigned short cleanmethod; alpm_list_t *holdpkg; diff --git a/src/pacman/pacman-conf.c b/src/pacman/pacman-conf.c index a9d1f52b..baf3cebd 100644 --- a/src/pacman/pacman-conf.c +++ b/src/pacman/pacman-conf.c @@ -269,6 +269,7 @@ static void dump_config(void) show_bool("ILoveCandy", config->chomp); show_bool("NoProgressBar", config->noprogressbar); + show_str("Proxy", config->proxy); show_int("ParallelDownloads", config->parallel_downloads); show_cleanmethod("CleanMethod", config->cleanmethod); @@ -384,7 +385,8 @@ static int list_directives(void) } else if(strcasecmp(i->data, "ParallelDownloads") == 0) { show_int("ParallelDownloads", config->parallel_downloads); - + } else if(strcasecmp(i->data, "Proxy") == 0) { + show_str("Proxy", config->proxy); } else if(strcasecmp(i->data, "CleanMethod") == 0) { show_cleanmethod("CleanMethod", config->cleanmethod); -- 2.38.0