From eee6382b683349395004627e7ebc5a7ae9216024 Mon Sep 17 00:00:00 2001 From: "Olle E. Johansson" Date: Wed, 16 Mar 2016 15:01:08 +0100 Subject: [PATCH] http_client Adding support for HTTP proxy on a connection and default level Addresses issue #541 Documentation coming in separate commit --- modules/http_client/curlcon.c | 66 +++++++++++++++++++++++-------- modules/http_client/functions.c | 14 +++++++ modules/http_client/http_client.c | 8 ++-- modules/http_client/http_client.h | 4 +- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/modules/http_client/curlcon.c b/modules/http_client/curlcon.c index d5dca0af92d..aa618602d38 100644 --- a/modules/http_client/curlcon.c +++ b/modules/http_client/curlcon.c @@ -58,6 +58,8 @@ typedef struct raw_http_client_conn str clientcert; str clientkey; str ciphersuites; + str http_proxy; + int http_proxy_port; int verify_peer; int verify_host; int tlsversion; @@ -82,20 +84,22 @@ static cfg_option_t tls_versions[] = { }; static cfg_option_t http_client_options[] = { - {"url", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"username", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"password", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"failover", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"useragent", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"verify_peer", .f = cfg_parse_bool_opt}, - {"verify_host", .f = cfg_parse_bool_opt}, - {"client_cert", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"client_key", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"cipher_suites", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, - {"tlsversion", .f = cfg_parse_enum_opt, .param = tls_versions}, - {"timeout", .f = cfg_parse_int_opt}, - {"maxdatasize", .f = cfg_parse_int_opt}, - {"httpredirect", .f = cfg_parse_bool_opt}, + {"url", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 0 */ + {"username", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 1 */ + {"password", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 2 */ + {"failover", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 3 */ + {"useragent", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 4 */ + {"verify_peer", .f = cfg_parse_bool_opt}, /* 5 */ + {"verify_host", .f = cfg_parse_bool_opt}, /* 6 */ + {"client_cert", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 7 */ + {"client_key", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 8 */ + {"cipher_suites", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 9 */ + {"tlsversion", .f = cfg_parse_enum_opt, .param = tls_versions}, /* 10 */ + {"timeout", .f = cfg_parse_int_opt}, /* 11 */ + {"maxdatasize", .f = cfg_parse_int_opt}, /* 12 */ + {"httpredirect", .f = cfg_parse_bool_opt}, /* 13 */ + {"httpproxy", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM}, /* 14 */ + {"httpproxyport", .f = cfg_parse_int_opt}, /* 15 */ {0} }; @@ -171,7 +175,9 @@ int curl_parse_param(char *val) str client_key = default_tls_clientkey; str ciphersuites = default_cipher_suite_list; str useragent = default_useragent; + str http_proxy = default_http_proxy; + unsigned int http_proxy_port = default_http_proxy_port; unsigned int maxdatasize = default_maxdatasize; unsigned int timeout = default_connection_timeout; unsigned int http_follow_redirect = default_http_follow_redirect; @@ -185,8 +191,9 @@ int curl_parse_param(char *val) param_t *conparams = NULL; curl_con_t *cc = NULL; - LM_INFO("curl modparam parsing starting\n"); + LM_INFO("http_client modparam parsing starting\n"); LM_DBG("modparam httpcon: %s\n", val); + LM_DBG(" *** Default httproxy: %s\n", http_proxy.s); /* parse: name=>http_url*/ in.s = val; @@ -436,6 +443,11 @@ int curl_parse_param(char *val) cc->verify_host = verify_host; cc->timeout = timeout; cc->maxdatasize = maxdatasize; + if (http_proxy_port > 0) { + cc->http_proxy_port = http_proxy_port; + cc->http_proxy = http_proxy.s ? as_asciiz(&http_proxy) : NULL; + LM_DBG("*** Setting HTTP proxy for connection to %s \n", cc->http_proxy); + } cc->http_follow_redirect = http_follow_redirect; LM_DBG("cname: [%.*s] url: [%.*s] username [%s] password [%s] failover [%.*s] timeout [%d] useragent [%s] maxdatasize [%d]\n", @@ -443,6 +455,10 @@ int curl_parse_param(char *val) cc->failover.len, cc->failover.s, cc->timeout, cc->useragent, cc->maxdatasize); LM_DBG("cname: [%.*s] client_cert [%s] client_key [%s] ciphersuites [%s] tlsversion [%d] verify_peer [%d] verify_host [%d]\n", cc->name.len, cc->name.s, cc->clientcert, cc->clientkey, cc->ciphersuites, cc->tlsversion, cc->verify_peer, cc->verify_host); + if (cc->http_proxy_port > 0) { + LM_DBG("cname: [%.*s] http_proxy [%s] http_proxy_port [%d]\n", + cc->name.len, cc->name.s, cc->http_proxy, cc->http_proxy_port); + } return 0; @@ -501,6 +517,12 @@ int curl_parse_conn(void *param, cfg_parser_t *parser, unsigned int flags) if (default_cipher_suite_list.s != NULL) pkg_str_dup(&raw_cc->ciphersuites, &default_cipher_suite_list); pkg_str_dup(&raw_cc->useragent, &default_useragent); + if (default_http_proxy_port > 0) { + raw_cc->http_proxy_port = default_http_proxy_port; + if (default_http_proxy.s != NULL) { + pkg_str_dup(&raw_cc->http_proxy, &default_http_proxy); + } + } raw_cc->verify_peer = default_tls_verify_peer; raw_cc->verify_host = default_tls_verify_host; raw_cc->maxdatasize = default_maxdatasize; @@ -511,6 +533,7 @@ int curl_parse_conn(void *param, cfg_parser_t *parser, unsigned int flags) for(i = 0; tls_versions[i].name; i++) { tls_versions[i].param = &raw_cc->tlsversion; } + /* Index from above structure (see top of file) */ http_client_options[0].param = &raw_cc->url; http_client_options[1].param = &raw_cc->username; http_client_options[2].param = &raw_cc->password; @@ -525,7 +548,8 @@ int curl_parse_conn(void *param, cfg_parser_t *parser, unsigned int flags) http_client_options[11].param = &raw_cc->timeout; http_client_options[12].param = &raw_cc->maxdatasize; http_client_options[13].param = &raw_cc->http_follow_redirect; - + http_client_options[14].param = &raw_cc->http_proxy; + http_client_options[15].param = &raw_cc->http_proxy_port; cfg_set_options(parser, http_client_options); @@ -583,6 +607,11 @@ int fixup_raw_http_client_conn_list(void) LM_WARN("curl connection [%.*s]: tlsversion %d unsupported value. Using default\n", cc->name.len, cc->name.s, cc->tlsversion); cc->tlsversion = default_tls_version; } + cc->http_proxy_port = raw_cc->http_proxy_port; + if (cc->http_proxy_port > 0 && raw_cc->http_proxy.s != NULL) { + cc->http_proxy = raw_cc->http_proxy.s ? as_asciiz(&raw_cc->http_proxy) : NULL; + } + cc->verify_peer = raw_cc->verify_peer; cc->verify_host = raw_cc->verify_host; cc->timeout = raw_cc->timeout; @@ -594,6 +623,10 @@ int fixup_raw_http_client_conn_list(void) cc->failover.len, cc->failover.s, cc->timeout, cc->useragent, cc->maxdatasize); LM_DBG("cname: [%.*s] client_cert [%s] client_key [%s] ciphersuites [%s] tlsversion [%d] verify_peer [%d] verify_host [%d]\n", cc->name.len, cc->name.s, cc->clientcert, cc->clientkey, cc->ciphersuites, cc->tlsversion, cc->verify_peer, cc->verify_host); + if (cc->http_proxy_port > 0) { + LM_DBG("cname: [%.*s] http_proxy [%s] http_proxy_port [%d]\n", + cc->name.len, cc->name.s, cc->http_proxy, cc->http_proxy_port); + } } done: @@ -609,6 +642,7 @@ int fixup_raw_http_client_conn_list(void) if (raw_cc->clientcert.s) pkg_free(raw_cc->clientcert.s); if (raw_cc->clientkey.s) pkg_free(raw_cc->clientkey.s); if (raw_cc->ciphersuites.s) pkg_free(raw_cc->ciphersuites.s); + if (raw_cc->http_proxy.s) pkg_free(raw_cc->http_proxy.s); pkg_free(raw_cc); raw_conn_list = raw_conn_list->next; } diff --git a/modules/http_client/functions.c b/modules/http_client/functions.c index e5fe6bda559..30681762449 100644 --- a/modules/http_client/functions.c +++ b/modules/http_client/functions.c @@ -55,6 +55,8 @@ typedef struct { char *clientkey; char *cacert; char *ciphersuites; + char *http_proxy; + unsigned int http_proxy_port; unsigned int tlsversion; unsigned int verify_peer; unsigned int verify_host; @@ -180,6 +182,15 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites); } + if (params->http_proxy != NULL) { + res |= curl_easy_setopt(curl, CURLOPT_PROXY, params->http_proxy); + } + + if (params->http_proxy_port > 0) { + res |= curl_easy_setopt(curl, CURLOPT_PROXYPORT, params->http_proxy_port); + } + + res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) params->verify_peer); res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long) params->verify_host?2:0); @@ -191,6 +202,7 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); res |= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); + if (res != CURLE_OK) { /* PANIC */ LM_ERR("Could not set CURL options. Library error \n"); @@ -366,6 +378,8 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url query_params.http_follow_redirect = conn->http_follow_redirect; query_params.oneline = 0; query_params.maxdatasize = maxdatasize; + query_params.http_proxy_port = conn->http_proxy_port; + query_params.http_proxy = conn->http_proxy; res = curL_query_url(_m, urlbuf, result, &query_params); diff --git a/modules/http_client/http_client.c b/modules/http_client/http_client.c index 4dd2b66b7f5..c49c2407daf 100644 --- a/modules/http_client/http_client.c +++ b/modules/http_client/http_client.c @@ -80,7 +80,7 @@ str default_cipher_suite_list = STR_NULL; /*!< List of allowed cipher suites * unsigned int default_tls_version = 0; /*!< 0 = Use libcurl default */ unsigned int default_tls_verify_peer = 1; /*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */ unsigned int default_tls_verify_host = 2; /*!< 0 = Do not verify TLS server CN/SAN 2 = Verify TLS server CN/SAN (default) */ -char *default_http_proxy = NULL; /*!< Default HTTP proxy to use */ +str default_http_proxy = STR_NULL; /*!< Default HTTP proxy to use */ unsigned int default_http_proxy_port = 0; /*!< Default HTTP proxy port to use */ unsigned int default_http_follow_redirect = 0; /*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */ str default_useragent = { CURL_USER_AGENT, CURL_USER_AGENT_LEN }; /*!< Default CURL useragent. Default "Kamailio Curl " */ @@ -140,7 +140,6 @@ static cmd_export_t cmds[] = { /* Exported parameters */ static param_export_t params[] = { {"connection_timeout", PARAM_INT, &default_connection_timeout}, - {"httpcon", PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param}, {"cacert", PARAM_STRING, &default_tls_cacert }, {"client_cert", PARAM_STR, &default_tls_clientcert }, {"client_key", PARAM_STR, &default_tls_clientkey }, @@ -149,11 +148,12 @@ static param_export_t params[] = { {"verify_peer", PARAM_INT, &default_tls_verify_peer }, {"verify_host", PARAM_INT, &default_tls_verify_host }, {"httpproxyport", PARAM_INT, &default_http_proxy_port }, - {"httpproxy", PARAM_STRING, &default_http_proxy}, + {"httpproxy", PARAM_STR, &default_http_proxy}, {"httpredirect", PARAM_INT, &default_http_follow_redirect }, {"useragent", PARAM_STR, &default_useragent }, {"maxdatasize", PARAM_INT, &default_maxdatasize }, {"config_file", PARAM_STR, &http_client_config_file }, + {"httpcon", PARAM_STRING|USE_FUNC_PARAM, (void*)curl_con_param}, {0, 0, 0} }; @@ -271,7 +271,7 @@ static int mod_init(void) LM_DBG("**** init curl: Cipher Suites: %.*s \n", default_cipher_suite_list.len, default_cipher_suite_list.s); LM_DBG("**** init curl: SSL Version: %d \n", default_tls_version); LM_DBG("**** init curl: verifypeer: %d verifyhost: %d\n", default_tls_verify_peer, default_tls_verify_host); - LM_DBG("**** init curl: HTTP Proxy: %s Port %d\n", default_http_proxy, default_http_proxy_port); + LM_DBG("**** init curl: HTTP Proxy: %.*s Port %d\n", default_http_proxy.len, default_http_proxy.s, default_http_proxy_port); LM_DBG("Extra: Curl supports %s %s %s \n", (curl_info->features & CURL_VERSION_SSL ? "SSL" : ""), diff --git a/modules/http_client/http_client.h b/modules/http_client/http_client.h index c4ebf92aa5a..a7dedb65568 100644 --- a/modules/http_client/http_client.h +++ b/modules/http_client/http_client.h @@ -43,7 +43,7 @@ extern str default_cipher_suite_list; /*!< List of allowed cipher suites */ extern unsigned int default_tls_version; /*!< 0 = Use libcurl default */ extern unsigned int default_tls_verify_peer; /*!< 0 = Do not verify TLS server cert. 1 = Verify TLS cert (default) */ extern unsigned int default_tls_verify_host; /*!< 0 = Do not verify TLS server CN/SAN. 2 = Verify TLS server CN/SAN (default) */ -extern char *default_http_proxy; /*!< Default HTTP proxy to use */ +extern str default_http_proxy; /*!< Default HTTP proxy to use */ extern unsigned int default_http_proxy_port; /*!< Default HTTP proxy port to use */ extern unsigned int default_http_follow_redirect; /*!< Follow HTTP redirects CURLOPT_FOLLOWLOCATION */ extern str default_useragent; /*!< Default CURL useragent. Default "Kamailio Curl " */ @@ -87,6 +87,8 @@ typedef struct _curl_con curl_res_stream_t *stream; /*!< Curl stream */ struct _curl_con *next; /*!< next connection */ char redirecturl[512]; /*!< Last redirect URL - to use for $curlredirect(curlcon) pv */ + char *http_proxy; /*!< HTTP proxy for this connection */ + unsigned int http_proxy_port; /*!< HTTP proxy port for this connection */ } curl_con_t;