diff --git a/modules/curl/curl.c b/modules/curl/curl.c index 2b152d6a5f5..79da671d480 100644 --- a/modules/curl/curl.c +++ b/modules/curl/curl.c @@ -74,15 +74,16 @@ MODULE_VERSION /* Module parameter variables */ unsigned int default_connection_timeout = 4; char *default_tls_cacert = NULL; /*!< File name: Default CA cert to use for curl TLS connection */ -char *default_tls_clientcert = NULL; /*!< File name: Default client certificate to use for curl TLS connection */ -char *default_tls_clientkey = NULL; /*!< File name: Key in PEM format that belongs to client cert */ -char *default_cipher_suite_list = NULL; /*!< List of allowed cipher suites */ +str default_tls_clientcert = STR_NULL; /*!< File name: Default client certificate to use for curl TLS connection */ +str default_tls_clientkey = STR_NULL; /*!< File name: Key in PEM format that belongs to client cert */ +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 */ 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 */ -char *default_useragent = CURL_USER_AGENT; /*!< Default CURL useragent. Default "Kamailio Curl " */ +str default_useragent = { CURL_USER_AGENT, CURL_USER_AGENT_LEN }; /*!< Default CURL useragent. Default "Kamailio Curl " */ unsigned int default_maxdatasize = 0; /*!< Default download size. 0=disabled */ static curl_version_info_data *curl_info; @@ -142,6 +143,7 @@ static param_export_t params[] = { {"tlsclientcert", PARAM_STRING, &default_tls_clientcert }, {"tlsclientkey", PARAM_STRING, &default_tls_clientkey }, {"tlscipherlist", PARAM_STRING, &default_cipher_suite_list }, + {"tlsversion", PARAM_INT, &default_tls_version }, {"tlsverifypeer", PARAM_INT, &default_tls_verify_peer }, {"tlsverifyhost", PARAM_INT, &default_tls_verify_host }, {"httpproxyport", PARAM_INT, &default_http_proxy_port }, @@ -246,10 +248,13 @@ static int mod_init(void) LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version); LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count()); - LM_DBG("**** init curl: User Agent: %s \n", default_useragent); + LM_DBG("**** init curl: User Agent: %.*s \n", default_useragent.len, default_useragent.s); LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect); - LM_DBG("**** init curl: Client Cert: %s Key %s\n", default_tls_clientcert, default_tls_clientkey); + LM_DBG("**** init curl: Client Cert: %.*s Key %.*s\n", default_tls_clientcert.len, default_tls_clientcert.s, default_tls_clientkey.len, default_tls_clientkey.s); LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert); + 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("Extra: Curl supports %s %s %s \n", diff --git a/modules/curl/curl.h b/modules/curl/curl.h index ab563e2204c..f167e63a3de 100644 --- a/modules/curl/curl.h +++ b/modules/curl/curl.h @@ -37,15 +37,16 @@ extern unsigned int default_connection_timeout; extern char *default_tls_cacert; /*!< File name: Default CA cert to use for curl TLS connection */ -extern char *default_tls_clientcert; /*!< File name: Default client certificate to use for curl TLS connection */ -extern char *default_tls_clientkey; /*!< File name: Key in PEM format that belongs to client cert */ -extern char *default_cipher_suite_list; /*!< List of allowed cipher suites */ +extern str default_tls_clientcert; /*!< File name: Default client certificate to use for curl TLS connection */ +extern str default_tls_clientkey; /*!< File name: Key in PEM format that belongs to client cert */ +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 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 char *default_useragent; /*!< Default CURL useragent. Default "Kamailio Curl " */ +extern str default_useragent; /*!< Default CURL useragent. Default "Kamailio Curl " */ extern unsigned int default_maxdatasize; /*!< Default Maximum download size */ extern counter_handle_t connections; /* Number of connection definitions */ @@ -68,15 +69,17 @@ typedef struct _curl_con unsigned int conid; /*!< Connection ID */ str url; /*!< The URL without schema (host + base URL)*/ str schema; /*!< The URL schema */ - str username; /*!< The username to use for auth */ - str password; /*!< The password to use for auth */ + char *username; /*!< The username to use for auth */ + char *password; /*!< The password to use for auth */ str failover; /*!< Another connection to use if this one fails */ - str useragent; /*!< Useragent to use for this connection */ - str cacert; /*!< File name of CA cert to use */ - str clientcert; /*!< File name of CA client cert */ - str clientkey; /*!< File name of CA client key */ - int verify_peer; /*!< TRUE if server cert to be verified */ - int verify_host; /*!< TRUE if server CN/SAN to be verified */ + char *useragent; /*!< Useragent to use for this connection */ + char *cacert; /*!< File name of CA cert to use */ + char *clientcert; /*!< File name of CA client cert */ + char *clientkey; /*!< File name of CA client key */ + char *ciphersuites; /*!< List of allowed cipher suites */ + unsigned int sslversion; /*!< SSL/TLS version to use */ + unsigned int verify_peer; /*!< TRUE if server cert to be verified */ + unsigned int verify_host; /*!< TRUE if server CN/SAN to be verified */ int http_follow_redirect; /*!< TRUE if we should follow HTTP 302 redirects */ unsigned int port; /*!< The port to connect to */ int timeout; /*!< Timeout for this connection */ diff --git a/modules/curl/curlcon.c b/modules/curl/curlcon.c index f0a4a53ce6d..85a0142e241 100644 --- a/modules/curl/curlcon.c +++ b/modules/curl/curlcon.c @@ -26,6 +26,8 @@ * \ingroup curl */ +#include + #include "../../hashes.h" #include "../../dprint.h" #include "../../parser/parse_param.h" @@ -110,15 +112,17 @@ int curl_parse_param(char *val) str params = STR_NULL; str failover = STR_NULL; - str client_cert = { default_tls_clientcert, default_tls_clientcert ? strlen(default_tls_clientcert) : 0 }; - str client_key = { default_tls_clientkey, default_tls_clientkey ? strlen(default_tls_clientkey) : 0 }; + str client_cert = default_tls_clientcert; + str client_key = default_tls_clientkey; + str ciphersuites = default_cipher_suite_list; + str useragent = default_useragent; unsigned int maxdatasize = default_maxdatasize; unsigned int timeout = default_connection_timeout; - str useragent = { default_useragent, strlen(default_useragent) }; unsigned int http_follow_redirect = default_http_follow_redirect; unsigned int verify_peer = default_tls_verify_peer; unsigned int verify_host = default_tls_verify_host; + unsigned int sslversion = default_tls_version; str in; char *p; @@ -126,8 +130,6 @@ int curl_parse_param(char *val) param_t *conparams = NULL; curl_con_t *cc; - username.len = 0; - password.len = 0; LM_INFO("curl modparam parsing starting\n"); LM_DBG("modparam curlcon: %s\n", val); @@ -307,7 +309,7 @@ int curl_parse_param(char *val) maxdatasize = default_maxdatasize; } LM_DBG("curl [%.*s] - timeout [%d]\n", pit->name.len, pit->name.s, maxdatasize); - } else if(pit->name.len==12 && strncmp(pit->name.s, "verifypeer", 7)==0) { + } else if(pit->name.len==10 && strncmp(pit->name.s, "verifypeer", 10)==0) { if(str2int(&tok, &verify_peer)!=0) { /* Bad integer */ LM_DBG("curl connection [%.*s]: verifypeer bad value. Using default\n", name.len, name.s); @@ -318,7 +320,7 @@ int curl_parse_param(char *val) verify_peer = default_tls_verify_peer; } LM_DBG("curl [%.*s] - verifypeer [%d]\n", pit->name.len, pit->name.s, verify_peer); - } else if(pit->name.len==12 && strncmp(pit->name.s, "verifyhost", 7)==0) { + } else if(pit->name.len==10 && strncmp(pit->name.s, "verifyhost", 10)==0) { if(str2int(&tok, &verify_host)!=0) { /* Bad integer */ LM_DBG("curl connection [%.*s]: verifyhost bad value. Using default\n", name.len, name.s); @@ -329,6 +331,29 @@ int curl_parse_param(char *val) verify_host = default_tls_verify_host; } LM_DBG("curl [%.*s] - verifyhost [%d]\n", pit->name.len, pit->name.s, verify_host); + } else if(pit->name.len==10 && strncmp(pit->name.s, "sslversion", 10)==0) { + if(str2int(&tok, &sslversion)!=0) { + /* Bad integer */ + LM_DBG("curl connection [%.*s]: sslversion bad value. Using default\n", name.len, name.s); + sslversion = default_tls_version; + } + if (sslversion >= CURL_SSLVERSION_LAST) { + LM_DBG("curl connection [%.*s]: sslversion bad value. Using default\n", name.len, name.s); + sslversion = default_tls_version; + } + LM_DBG("curl [%.*s] - sslversion [%d]\n", pit->name.len, pit->name.s, sslversion); + } else if(pit->name.len==10 && strncmp(pit->name.s, "clientcert", 10)==0) { + client_cert = tok; + LM_DBG("curl [%.*s] - clientcert [%.*s]\n", pit->name.len, pit->name.s, + client_cert.len, client_cert.s); + } else if(pit->name.len==9 && strncmp(pit->name.s, "clientkey", 9)==0) { + client_key = tok; + LM_DBG("curl [%.*s] - clientkey [%.*s]\n", pit->name.len, pit->name.s, + client_key.len, client_key.s); + } else if(pit->name.len==12 && strncmp(pit->name.s, "ciphersuites", 12)==0) { + ciphersuites = tok; + LM_DBG("curl [%.*s] - ciphersuites [%.*s]\n", pit->name.len, pit->name.s, + ciphersuites.len, ciphersuites.s); } else { LM_ERR("curl Unknown parameter [%.*s] \n", pit->name.len, pit->name.s); } @@ -337,14 +362,6 @@ int curl_parse_param(char *val) /* The URL ends either with nothing or parameters. Parameters start with ; */ - LM_DBG("cname: [%.*s] url: [%.*s] username [%.*s] password [%.*s] failover [%.*s] timeout [%d] useragent [%.*s] maxdatasize [%d]\n", - name.len, name.s, url.len, url.s, username.len, username.s, - password.len, password.s, failover.len, failover.s, timeout, - useragent.len, useragent.s, maxdatasize); - LM_DBG("cname: [%.*s] client_cert [%.*s] client_key [%.*s] verify_peer [%d] verify_host [%d]\n", - name.len, name.s, client_cert.len, client_cert.s, client_key.len, client_key.s, - verify_peer, verify_host); - if(conparams != NULL) { free_params(conparams); } @@ -353,19 +370,29 @@ int curl_parse_param(char *val) if (cc == NULL) { return -1; } - cc->username = username; - cc->password = password; + + cc->username = username.s ? as_asciiz(&username) : NULL; + cc->password = password.s ? as_asciiz(&password) : NULL; cc->schema = schema; cc->failover = failover; - cc->useragent = useragent; + cc->useragent = as_asciiz(&useragent); cc->url = url; - cc->clientcert = client_cert; - cc->clientkey = client_key; + cc->clientcert = client_cert.s ? as_asciiz(&client_cert) : NULL; + cc->clientkey = client_key.s ? as_asciiz(&client_key) : NULL; + cc->ciphersuites = ciphersuites.s ? as_asciiz(&ciphersuites) : NULL; + cc->sslversion = sslversion; cc->verify_peer = verify_peer; cc->verify_host = verify_host; cc->timeout = timeout; cc->maxdatasize = maxdatasize; 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", + name.len, name.s, cc->url.len, cc->url.s, cc->username ? cc->username : "", cc->password ? cc->password : "", + cc->failover.len, cc->failover.s, cc->timeout, cc->useragent, cc->maxdatasize); + LM_DBG("cname: [%.*s] client_cert [%s] client_key [%s] ciphersuites [%s] sslversion [%d] verify_peer [%d] verify_host [%d]\n", + name.len, name.s, cc->clientcert, cc->clientkey, cc->ciphersuites, cc->sslversion, cc->verify_peer, cc->verify_host); + return 0; error: diff --git a/modules/curl/functions.c b/modules/curl/functions.c index eb909635453..1b530d63a1e 100644 --- a/modules/curl/functions.c +++ b/modules/curl/functions.c @@ -55,6 +55,7 @@ typedef struct { char *clientkey; char *cacert; char *ciphersuites; + unsigned int sslversion; unsigned int verify_peer; unsigned int verify_host; unsigned int timeout; @@ -160,7 +161,6 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const /* Client certificate */ if (params->clientcert != NULL && params->clientkey != NULL) { - LM_ERR("Setting curl cert %s key %s \n", params->clientcert, params->clientkey); res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert); @@ -169,12 +169,14 @@ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const } if (params->cacert != NULL) { - LM_ERR("Setting ca cert %s\n", params->cacert); res |= curl_easy_setopt(curl, CURLOPT_CAINFO, params->cacert); } + if (params->sslversion != CURL_SSLVERSION_DEFAULT) { + res |= curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long) params->sslversion); + } + if (params->ciphersuites != NULL) { - LM_ERR("Setting ciphersuites %s\n", params->ciphersuites); res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites); } @@ -288,8 +290,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url { curl_con_t *conn = NULL; char *urlbuf = NULL; - char *username_str = NULL; - char *password_str = NULL; char *postdata = NULL; curl_query_t query_params; @@ -308,14 +308,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url return -1; } LM_DBG("******** CURL Connection found %.*s\n", connection->len, connection->s); - if (conn->username.s != NULL && conn->username.len > 0) - { - username_str = as_asciiz(&conn->username); - } - if (conn->password.s != NULL && conn->password.len > 0) - { - password_str = as_asciiz(&conn->password); - } maxdatasize = conn->maxdatasize; @@ -359,14 +351,15 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url } memset(&query_params, 0, sizeof(curl_query_t)); - query_params.username = username_str; - query_params.secret = password_str; + query_params.username = conn->username; + query_params.secret = conn->password; query_params.contenttype = contenttype ? (char*)contenttype : "text/plain"; query_params.post = postdata; - query_params.clientcert = conn->clientcert.s; - query_params.clientkey = conn->clientkey.s; + query_params.clientcert = conn->clientcert; + query_params.clientkey = conn->clientkey; query_params.cacert = default_tls_cacert; - query_params.ciphersuites = default_cipher_suite_list; + query_params.ciphersuites = conn->ciphersuites; + query_params.sslversion = conn->sslversion; query_params.verify_peer = conn->verify_peer; query_params.verify_host = conn->verify_host; query_params.timeout = conn->timeout; @@ -381,12 +374,6 @@ int curl_con_query_url(struct sip_msg* _m, const str *connection, const str* url if (urlbuf != NULL) { pkg_free(urlbuf); } - if (username_str != NULL) { - pkg_free(username_str); - } - if (password_str != NULL) { - pkg_free(password_str); - } if (postdata != NULL) { pkg_free(postdata); } @@ -413,6 +400,7 @@ int http_query(struct sip_msg* _m, char* _url, str* _dst, char* _post) query_params.clientkey = NULL; query_params.cacert = NULL; query_params.ciphersuites = NULL; + query_params.sslversion = default_tls_version; query_params.verify_peer = default_tls_verify_peer; query_params.verify_host = default_tls_verify_host; query_params.timeout = default_connection_timeout;