diff options
| author | Lu <[email protected]> | 2018-05-25 10:27:28 +0800 |
|---|---|---|
| committer | Lu <[email protected]> | 2018-05-25 10:27:28 +0800 |
| commit | af3e8a16570fe1202a1e891b487742f866ee5958 (patch) | |
| tree | 7f59a4a8a8640e76a193339e381a5a496b6b5c78 | |
| parent | b73c659f33fcad83f03841a2ca63f51184f663d6 (diff) | |
HTTP解析层接口改进,增加功能。
| -rw-r--r-- | .idea/codeStyles/Project.xml | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | src/attrib.h | 13 | ||||
| -rw-r--r-- | src/cachedsess.cc | 2 | ||||
| -rw-r--r-- | src/cachemgr.cc | 2 | ||||
| -rw-r--r-- | src/cachessess.cc | 2 | ||||
| -rw-r--r-- | src/certstore.cc | 145 | ||||
| -rw-r--r-- | src/certstore.h | 9 | ||||
| -rw-r--r-- | src/cfgparser.h | 38 | ||||
| -rw-r--r-- | src/compat.cc | 57 | ||||
| -rw-r--r-- | src/compat.h | 52 | ||||
| -rw-r--r-- | src/http.cc | 5 | ||||
| -rw-r--r-- | src/http.h | 168 | ||||
| -rw-r--r-- | src/http1.cc | 503 | ||||
| -rw-r--r-- | src/httpaction.cc | 325 | ||||
| -rw-r--r-- | src/httpaction.h | 60 | ||||
| -rw-r--r-- | src/httpscan.cc | 253 | ||||
| -rw-r--r-- | src/httpscan.h | 89 | ||||
| -rw-r--r-- | src/main.cc | 38 | ||||
| -rw-r--r-- | src/opts.cc | 206 | ||||
| -rw-r--r-- | src/opts.h | 51 | ||||
| -rw-r--r-- | src/proxy.cc | 22 | ||||
| -rw-r--r-- | src/pxyconn.cc | 3580 | ||||
| -rw-r--r-- | src/pxyconn.h | 19 | ||||
| -rw-r--r-- | src/pxyhttp.cc | 182 | ||||
| -rw-r--r-- | src/pxyhttp.h | 4 | ||||
| -rw-r--r-- | src/pxysslshut.cc | 6 | ||||
| -rw-r--r-- | src/pxythrmgr.cc | 340 | ||||
| -rw-r--r-- | src/pxythrmgr.h | 13 | ||||
| -rw-r--r-- | src/ssl.cc | 3056 | ||||
| -rw-r--r-- | src/util.cc | 1 | ||||
| -rw-r--r-- | src/util.h | 148 |
33 files changed, 5502 insertions, 3905 deletions
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 910d7c2..d73cd7c 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -12,11 +12,13 @@ <option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="0" /> <option name="FUNCTION_PARAMETERS_WRAP" value="5" /> <option name="FUNCTION_PARAMETERS_NEW_LINE_AFTER_LPAR" value="true" /> + <option name="FUNCTION_CALL_ARGUMENTS_ALIGN_MULTILINE" value="false" /> <option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" /> <option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" /> <option name="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="5" /> <option name="SUPERCLASS_LIST_BEFORE_COLON" value="0" /> <option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" /> + <option name="INSERT_OVERRIDE" value="false" /> <option name="ADD_BRIEF_TAG" value="true" /> </Objective-C> <Objective-C-extensions> diff --git a/CMakeLists.txt b/CMakeLists.txt index ec9885d..35d1c9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(tfe) set(CMAKE_CXX_STANDARD 11) set(CMAKE_C_STANDARD 11) +include_directories(/opt/MESA/include/MESA) + add_definitions(-DPKGLABEL="tfe") add_definitions(-DBUILD_PKGNAME="tfe") add_definitions(-DBUILD_VERSION="") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7772e1c..30e3fa6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,15 +1,17 @@ find_package(OpenSSL REQUIRED) -add_library(tfe-library base64.cc build.cc cache.cc cachemgr.cc cachessess.cc - cachedsess.cc cachetgcrt.cc cachefkcrt.cc cert.cc +add_library(tfe-library base64.cc build.cc cache.cc cachemgr.cc cachessess.cc compat.cc + cachedsess.cc cachetgcrt.cc cachefkcrt.cc cert.cc certstore.cc dynbuf.cc logbuf.cc log.cc logger.cc nat.cc opts.cc - privsep.cc proxy.cc pxyconn.cc pxythrmgr.cc pxysslshut.cc - pxyhttp.cc ssl.cc sys.cc thrqueue.cc url.cc util.cc) + privsep.cc proxy.cc pxythrmgr.cc pxysslshut.cc + ssl.cc sys.cc thrqueue.cc url.cc util.cc httpscan.cc httpaction.cc http1.cc http.cc) + +#pxyconn.cc target_include_directories(tfe-library PRIVATE ${OPENSSL_INCLUDE_DIR}) target_link_libraries(tfe-library ${OPENSSL_LIBRARIES}) -target_link_libraries(tfe-library pthread libevent-static libevent-static-openssl - libevent-static-pthreads http-parser-static MESA_prof_load-static) +target_link_libraries(tfe-library pthread libevent-static libevent-static-openssl libevent-static-pthreads http-parser-static MESA_prof_load-static) +target_link_libraries(tfe-library maatframe MESA_handle_logger) add_executable(tfe main.cc) target_link_libraries(tfe tfe-library)
\ No newline at end of file diff --git a/src/attrib.h b/src/attrib.h index 9b502bf..046f732 100644 --- a/src/attrib.h +++ b/src/attrib.h @@ -55,19 +55,6 @@ #define NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #define PURE __attribute__((pure)) -/* - * Branch prediction macros. - * These serve to tell the compiler which of the branches is more likely. - */ - -#if !defined(__GNUC__) && !defined(__clang__) -#define likely(expr) (expr) -#define unlikely(expr) (expr) -#else -#define likely(expr) __builtin_expect((expr), 1) -#define unlikely(expr) __builtin_expect((expr), 0) -#endif - #endif /* !ATTRIB_H */ /* vim: set noet ft=c: */ diff --git a/src/cachedsess.cc b/src/cachedsess.cc index 5bd70d8..0572c93 100644 --- a/src/cachedsess.cc +++ b/src/cachedsess.cc @@ -35,7 +35,7 @@ #include <netinet/in.h> /* - * Cache for outgoing dst connection SSL sessions. + * Cache for outgoing dst connection SSL http_sessions_. * * key: dynbuf_t * original destination IP address, port and SNI string * val: dynbuf_t * ASN.1 serialized SSL_SESSION diff --git a/src/cachemgr.cc b/src/cachemgr.cc index bdd3c00..58b4dc5 100644 --- a/src/cachemgr.cc +++ b/src/cachemgr.cc @@ -118,7 +118,7 @@ cachemgr_fini(void) /* * Garbage collect all the cache contents; free's up resources occupied by - * certificates and sessions which are no longer valid. + * certificates and http_sessions_ which are no longer valid. * This function returns after the cleanup completed and all threads are * joined. */ diff --git a/src/cachessess.cc b/src/cachessess.cc index 9bff1c9..9cb5338 100644 --- a/src/cachessess.cc +++ b/src/cachessess.cc @@ -33,7 +33,7 @@ #include "khash.h" /* - * Cache for incoming src connection SSL sessions. + * Cache for incoming src connection SSL http_sessions_. * * key: dynbuf_t * SSL session ID * val: dynbuf_t * ASN.1 serialized SSL_SESSION diff --git a/src/certstore.cc b/src/certstore.cc new file mode 100644 index 0000000..1c384db --- /dev/null +++ b/src/certstore.cc @@ -0,0 +1,145 @@ +/* \brief CertStore Client Module + * + * \author Lu Qiuwen<[email protected]> + * \date 2018-5-10 * + */ + +extern "C" +{ +#include <event2/util.h> +#include <event2/http.h> +} + +#include <thread> +#include <mutex> +#include <vector> +#include <map> +#include <cassert> + +#include "certstore.h" +#include "ssl.h" + +class CertCache +{ +public: + X509 * x509_cert_query_by_fingerpoint(X509 *crt); + X509 * x509_cert_query_by_sni(std::string sni); +}; + +class CertStoreRpc +{ +public: + /* RPC调用异步回调处理函数 */ + using certstore_rpc_done_cb_t = std::function<void(X509 *)>; + + CertStoreRpc(struct event_base * ev_base); + void backend_server_register(std::string str_backend_addr, uint16_t port); + void backend_server_unregister(std::string str_backend_addr, uint16_t port); + + X509 * x509_cert_query_by_fingerpoint(X509 *crt, certstore_rpc_done_cb_t cb); + X509 * x509_cert_query_by_sni(std::string sni, certstore_rpc_done_cb_t cb); + + void x09_cert_sign(); + +private: + struct rpc_server_ctx + { + std::string str_backend_addr; + uint16_t backend_port; + struct evhttp_connection * ev_http_conn; + }; + + struct rpc_request_ctx + { + CertStoreRpc * pthis; + std::string str_query_uri; + certstore_rpc_done_cb_t user_cb; + }; + + struct evhttp_connection * ev_http_conn_default; + struct event_base *ev_base; + + /* HTTP Connection管理 */ + std::mutex rpc_server_ctxs_lock; + using rpc_server_ctx_key_t = std::pair<std::string, uint16_t>; + std::map<rpc_server_ctx_key_t, rpc_server_ctx *> rpc_server_ctxs; + + /* HTTP应答处理函数 */ + static void rpc_request_done_cb(struct evhttp_request *req, void *ctx); +}; + +void CertStoreRpc::backend_server_register(std::string str_backend_addr, uint16_t port) +{ + /* 加锁,防止rpc_server_ctxs并发写,离开作用域时自行释放 */ + std::lock_guard<decltype(rpc_server_ctxs_lock)> __lock_guard(rpc_server_ctxs_lock); + + auto *server_ctx = new rpc_server_ctx; + server_ctx->str_backend_addr = str_backend_addr; + server_ctx->backend_port = port; + server_ctx->ev_http_conn = evhttp_connection_base_new(ev_base, nullptr, str_backend_addr.c_str(), port); + + /* evhttp_connection为空 */ + if(server_ctx->ev_http_conn == nullptr) + { + throw std::runtime_error("Failed at create evhttp_connection, backend server is " + str_backend_addr); + } + + rpc_server_ctxs[{str_backend_addr, port}] = server_ctx; + ev_http_conn_default = server_ctx->ev_http_conn; +} + +void CertStoreRpc::backend_server_unregister(std::string str_backend_addr, uint16_t port) +{ + /* 加锁,防止rpc_server_ctxs并发写,离开作用域时自行释放 */ + std::lock_guard<decltype(rpc_server_ctxs_lock)> __lock_guard(rpc_server_ctxs_lock); + + /* 查找,是否存在了目的服务器地址 */ + rpc_server_ctx * server_ctx = rpc_server_ctxs[{str_backend_addr, port}]; + evhttp_connection_free(server_ctx->ev_http_conn); + delete server_ctx; + + /* 删除map中的ctx */ + rpc_server_ctxs.erase({str_backend_addr, port}); +} + +X509 * CertStoreRpc::x509_cert_query_by_fingerpoint(X509 *crt, certstore_rpc_done_cb_t cb) +{ + /* 计算x509证书的SHA1指纹 */ + char * x509_sha1 = ssl_x509_fingerprint(crt, 0); + if(x509_sha1 == nullptr) + { + throw std::runtime_error("Failed at calling ssl_x509_fingerprint of crt"); + } + + /* 本请求的上下文,在异步调用的回调函数中销毁 */ + auto * __request_ctx = new rpc_request_ctx; + __request_ctx->str_query_uri = "/certstore/query?fingerpoint=" + std::string(x509_sha1); + __request_ctx->user_cb = cb; + __request_ctx->pthis = this; + + /* 构造HTTP请求,发送的服务器 */ + struct evhttp_request * http_request = evhttp_request_new(rpc_request_done_cb, __request_ctx); + evhttp_make_request(ev_http_conn_default, http_request, EVHTTP_REQ_GET, __request_ctx->str_query_uri.c_str()); + + return nullptr; +} + +X509 * CertStoreRpc::x509_cert_query_by_sni(std::string sni, certstore_rpc_done_cb_t cb) +{ + /* 本请求的上下文,在异步调用的回调函数中销毁 */ + auto * __request_ctx = new rpc_request_ctx; + __request_ctx->str_query_uri = "/certstore/query?sni=" + sni; + __request_ctx->user_cb = cb; + __request_ctx->pthis = this; + + /* 构造HTTP请求,发送的服务器 */ + struct evhttp_request * http_request = evhttp_request_new(rpc_request_done_cb, __request_ctx); + evhttp_make_request(ev_http_conn_default, http_request, EVHTTP_REQ_GET, __request_ctx->str_query_uri.c_str()); +} + +void CertStoreRpc::rpc_request_done_cb(struct evhttp_request *req, void *ctx) +{ + auto *__request_ctx = (rpc_request_ctx *) ctx; + assert(__request_ctx != nullptr && __request_ctx->pthis != nullptr); + return; +}
\ No newline at end of file diff --git a/src/certstore.h b/src/certstore.h new file mode 100644 index 0000000..d25c3ca --- /dev/null +++ b/src/certstore.h @@ -0,0 +1,9 @@ +// +// Created by luqiu on 2018-4-28. +// + +#ifndef TFE_CERTSTORE_H +#define TFE_CERTSTORE_H + + +#endif //TFE_CERTSTORE_H diff --git a/src/cfgparser.h b/src/cfgparser.h index c7f0063..10bd1cd 100644 --- a/src/cfgparser.h +++ b/src/cfgparser.h @@ -18,6 +18,8 @@ extern "C" #include <MESA_prof_load.h> } +#include "util.h" + class TfeConfigParser { public: @@ -35,34 +37,6 @@ private: std::string str_cfgfile_; }; -struct tfe_expection_cfg_invalid_format : std::runtime_error -{ - explicit tfe_expection_cfg_invalid_format( - const std::string &file, - const std::string §ion, - const std::string &item, - const std::string &what) : file(file), section(section), item(item), runtime_error(what) - {} - - std::string file; - std::string section; - std::string item; -}; - -struct tfe_expection_cfg_lost_entry : std::runtime_error -{ - explicit tfe_expection_cfg_lost_entry( - const std::string &file, - const std::string §ion, - const std::string &item, - const std::string &what) : file(file), section(section), item(item), runtime_error(what) - {} - - std::string file; - std::string section; - std::string item; -}; - template<> std::string TfeConfigParser::GetValue(const std::string &str_section, const std::string &str_entry) { @@ -70,10 +44,10 @@ std::string TfeConfigParser::GetValue(const std::string &str_section, const std: memset(__str_buffer, 0, sizeof(__str_buffer)); int ret = MESA_load_profile_string_nodef(str_cfgfile_.c_str(), str_section.c_str(), str_entry.c_str(), - __str_buffer, sizeof(__str_buffer)); + __str_buffer, sizeof(__str_buffer)); if (ret < 0) - throw tfe_expection_cfg_lost_entry(str_cfgfile_, str_section, str_entry, ""); + throw cfg_lost_entry(str_cfgfile_, str_section, str_entry, ""); return std::string(__str_buffer); } @@ -87,8 +61,8 @@ unsigned long TfeConfigParser::GetValue(const std::string &str_section, const st unsigned long __value = strtoul(__str_value.c_str(), &__ptr, 0); if (__ptr == __str_value.c_str()) { - throw tfe_expection_cfg_invalid_format(str_cfgfile_, str_section, str_entry, - __str_value + " is not valid unsigned number. "); + throw cfg_invalid_format(str_cfgfile_, str_section, str_entry, + __str_value + " is not valid unsigned number. "); } return __value; diff --git a/src/compat.cc b/src/compat.cc new file mode 100644 index 0000000..e8d5caa --- /dev/null +++ b/src/compat.cc @@ -0,0 +1,57 @@ +/* + * \brief C库接口封装 + * + * \author Qiuwen Lu<[email protected]> + * \date 2018-5-23 + */ + +#include <cassert> +#include <sys/socket.h> +#include "compat.h" + +sapp_ip_addr_ptr_t sockaddr_to_sapp_ipaddr(const struct sockaddr * sk_addr_src, + const struct sockaddr * sk_addr_dst) +{ + assert(sk_addr_src->sa_family == sk_addr_dst->sa_family); + + /* sapp_ip_addr智能指针封装,超出作用域自动析构 */ + sapp_ip_addr_ptr_t __sapp_ip_addr(new struct ipaddr); + auto sa_family = sk_addr_src->sa_family; + + /* IPv4 */ + if (sa_family == AF_INET) + { + __sapp_ip_addr->addrtype = ADDR_TYPE_IPV4; + __sapp_ip_addr->v4 = new stream_tuple4_v4; + + auto * __v4_ptr = __sapp_ip_addr->v4; + auto * __sk_in_src = (struct sockaddr_in *)(sk_addr_src); + auto * __sk_in_dst = (struct sockaddr_in *)(sk_addr_dst); + + __v4_ptr->saddr = static_cast<UINT32>(__sk_in_src->sin_addr.s_addr); + __v4_ptr->daddr = static_cast<UINT32>(__sk_in_dst->sin_addr.s_addr); + __v4_ptr->source = static_cast<UINT16>(__sk_in_src->sin_port); + __v4_ptr->dest = static_cast<UINT16>(__sk_in_dst->sin_port); + } + /* IPv6 */ + else if(sa_family == AF_INET6) + { + __sapp_ip_addr->addrtype = ADDR_TYPE_IPV6; + __sapp_ip_addr->v6 = new stream_tuple4_v6; + + auto * __v6_ptr = __sapp_ip_addr->v6; + auto * __sk_in6_src = (struct sockaddr_in6 *)(sk_addr_src); + auto * __sk_in6_dst = (struct sockaddr_in6 *)(sk_addr_dst); + + memcpy(__v6_ptr->saddr, __sk_in6_src->sin6_addr.s6_addr, IPV6_ADDR_LEN); + memcpy(__v6_ptr->daddr, __sk_in6_dst->sin6_addr.s6_addr, IPV6_ADDR_LEN); + __v6_ptr->source = static_cast<UINT16>(__sk_in6_src->sin6_port); + __v6_ptr->dest = static_cast<UINT16>(__sk_in6_dst->sin6_port); + } + else + { + assert(0); + } + + return std::move(__sapp_ip_addr); +}
\ No newline at end of file diff --git a/src/compat.h b/src/compat.h new file mode 100644 index 0000000..9615fc4 --- /dev/null +++ b/src/compat.h @@ -0,0 +1,52 @@ +#pragma once + +#include <memory> +#include <cstdio> + +extern "C" +{ +#include <event2/bufferevent.h> +#include <evdns.h> +#include <unistd.h> +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// 对关键的Libevent资源实行智能指针的封装 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +struct EventDeleter +{ + void operator()(struct evbuffer *evbuf) + { evbuffer_free(evbuf); } +}; + +struct FileDescriptorDeleter +{ + void operator()(int fd) + { close(fd); } + void operator()(FILE *fp) + { fclose(fp); } +}; + +using evbuffer_unique_ptr_t = std::unique_ptr<struct evbuffer, EventDeleter>; +using file_unique_ptr_t = std::unique_ptr<FILE, FileDescriptorDeleter>; +using fd_unique_ptr_t = std::unique_ptr<int, FileDescriptorDeleter>; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Stream.h内的数据结构转换工具 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include <stream.h> + +struct SappIpAddrDeleter +{ + void operator()(struct ipaddr * ptr_addr) + { + if (ptr_addr->addrtype == ADDR_TYPE_IPV4) delete ptr_addr->v4; + if (ptr_addr->addrtype == ADDR_TYPE_IPV6) delete ptr_addr->v6; + delete ptr_addr; + } +}; + +using sapp_ip_addr_ptr_t = std::unique_ptr<struct ipaddr, SappIpAddrDeleter>; +sapp_ip_addr_ptr_t sockaddr_to_sapp_ipaddr(const struct sockaddr * sk_addr_src, const struct sockaddr * sk_addr_dst);
\ No newline at end of file diff --git a/src/http.cc b/src/http.cc new file mode 100644 index 0000000..425c938 --- /dev/null +++ b/src/http.cc @@ -0,0 +1,5 @@ +// +// Created by luqiu on 2018-5-23. +// + +#include "http.h"
\ No newline at end of file diff --git a/src/http.h b/src/http.h new file mode 100644 index 0000000..b5bc5d4 --- /dev/null +++ b/src/http.h @@ -0,0 +1,168 @@ +#ifndef TFE_HTTP_H +#define TFE_HTTP_H + +#include <map> +#include <string> +#include <memory> + +class HttpConnection; +class HttpSession; +class HttpRequest; +class HttpResponse; + +class Http +{ +public: + /* 回调函数调用 */ + using connection_cb_t = std::function<void(Http & ht, HttpConnection & ct)>; + + /* 回调函数设置 */ + void SetHttpConnectionNewCallback(connection_cb_t cb) { connection_new_cb_ = cb; } + void SetHttpConnectionCloseCallback(connection_cb_t cb) { connection_close_cb_ = cb; } + + /* 回调函数调用 */ + void TriggerConnectionNew(HttpConnection & ct) { return connection_new_cb_(*this, ct); } + void TriggerConnectionClose(HttpConnection & ct) { return connection_close_cb_(*this, ct); } + +private: + connection_cb_t connection_new_cb_; + connection_cb_t connection_close_cb_; +}; + +class HttpConnection +{ +public: + using http_connection_cb_t = std::function<void(HttpSession &)>; + + /* 回调函数设置 */ + virtual void SetSessionNewCallback(http_connection_cb_t cb) + { session_new_cb_ = cb; } + virtual void SetSessionCloseCallback(http_connection_cb_t cb) + { session_close_cb_ = cb; } + + /* 四元组信息获取 */ + virtual const struct sockaddr * SockAddrSource() const = 0; + virtual const struct sockaddr * SockAddrDest() const = 0; + + virtual void Close() = 0; + +protected: + http_connection_cb_t session_new_cb_{nullptr}; + http_connection_cb_t session_close_cb_{nullptr}; +}; + +class HttpSession +{ +public: + explicit HttpSession(HttpConnection &connection) : http_connection_(connection) {} + ~HttpSession() = default; + + using http_session_cb_t = std::function<void(HttpSession &)>; + + HttpRequest & request() const + { return *request_; } + + void request(std::unique_ptr<HttpRequest> req) + { request_ = std::move(req); } + + HttpResponse & response() const + { return *response_; } + + void response(std::unique_ptr<HttpResponse> rsp) + { response_ = std::move(rsp); } + + HttpConnection & connection() const + { return http_connection_; } + + void context(const std::shared_ptr<void> &ctx) + { context_ = ctx; } + const std::shared_ptr<void> &context() + { return context_; } + + virtual void SetRequestHeaderCallback(http_session_cb_t cb) + { request_header_cb_ = cb; } + virtual void SetRequestBodyCallback(http_session_cb_t cb) + { request_body_cb_ = cb; } + virtual void SetResponseHeaderCallback(http_session_cb_t cb) + { response_header_cb_ = cb; } + virtual void SetResponseBodyCallback(http_session_cb_t cb) + { response_body_cb_ = cb; } + +protected: + HttpConnection &http_connection_; + std::unique_ptr<HttpRequest> request_{nullptr}; + std::unique_ptr<HttpResponse> response_{nullptr}; + std::shared_ptr<void> context_{nullptr}; + + /* Session Callbacks */ + http_session_cb_t request_header_cb_{nullptr}; + http_session_cb_t request_body_cb_{nullptr}; + http_session_cb_t response_header_cb_{nullptr}; + http_session_cb_t response_body_cb_{nullptr}; +}; + + +class HttpRequest +{ +public: + /* URL读取、设置接口 */ + virtual const std::string &Url() const = 0; + virtual void Url(const std::string &url) = 0; + + /* Header读取、设置接口 */ + virtual const std::string &HeaderValue(const std::string &field) = 0; + virtual void HeaderValue(const std::string &field, const std::string &value) = 0; + + /* Header迭代器 */ + using for_each_header_cb_t = std::function<void(const std::string & field, const std::string & value)>; + virtual void ForEachHeader(for_each_header_cb_t cb) = 0; + + /* ReadOnly,标记本请求为只读。 + * 当一个请求为只读请求时,业务不应修改它的内容,底层处理Readonly的请求时,应直接转发不缓存 */ + virtual bool ReadOnly() = 0; + virtual void ReadOnly(bool is_readonly) = 0; + + /* Forward,标记本请求应被转发到对端 + * 当请求标记为不转发时,该请求被丢弃 */ + virtual bool Forward() = 0; + virtual void Forward(bool is_forward) = 0; + + /* 完整标记,该请求是否已经完整可用 */ + virtual bool Complete() = 0; +}; + +class HttpResponse +{ +public: + /* 响应码 */ + virtual int ResponseCode() = 0; + virtual void ResponseCode(int code) = 0; + + /* Header读取、设置接口 */ + virtual const std::string &HeaderValue(const std::string &field) = 0; + virtual void HeaderValue(const std::string &field, const std::string &value) = 0; + + /* Header迭代器 */ + using for_each_header_cb_t = std::function<void(const std::string & field, const std::string & value)>; + virtual void ForEachHeader(for_each_header_cb_t cb) = 0; + + /* ReadOnly,标记本请求为只读。 + * 当一个请求为只读请求时,业务不应修改它的内容,底层处理Readonly的请求时,应直接转发不缓存 */ + virtual bool ReadOnly() = 0; + virtual void ReadOnly(bool is_readonly) = 0; + + /* Forward,标记本请求应被转发到对端 + * 当请求标记为不转发时,该请求被丢弃 */ + virtual bool Forward() = 0; + virtual void Forward(bool is_forward) = 0; + + /* 完整标记,该请求是否已经完整可用 */ + virtual bool Complete() = 0; + /* 构建指令,根据Object构建对应的Memory */ + virtual void Construct() = 0; +}; + +std::unique_ptr<HttpRequest> HttpRequestFactory(int primary_version, int second_version); +std::unique_ptr<HttpResponse> HttpResponseFactory(int primary_version, int second_version); + +#endif //TFE_HTTP_H diff --git a/src/http1.cc b/src/http1.cc new file mode 100644 index 0000000..f02c02f --- /dev/null +++ b/src/http1.cc @@ -0,0 +1,503 @@ +// +// Created by luqiu on 2018-5-22. +// + +/* HTTP/HTTP2 Protocol Handler + * + * Author: Lu Qiuwen<[email protected]> + * Date: 2018-04-08 + * + */ + +#include <vector> +#include <array> +#include <list> +#include <map> +#include <memory> +#include <cassert> + +#include <http_parser.h> +#include <event2/bufferevent.h> +#include <evdns.h> + +#include "pxyconn.h" +#include "http.h" +#include "httpscan.h" +#include "compat.h" +#include "util.h" + + +class Http1Connection : public HttpConnection +{ +public: + Http1Connection() = default; + ~Http1Connection() = default; + + int on_connection_read_request(pxy_conn_ctx_t *conn_ctx, pxy_conn_desc_t *conn_this, pxy_conn_desc_t *conn_other); + int on_connection_read_response(pxy_conn_ctx_t *conn_ctx, struct bufferevent *bev); + int on_connection_close(pxy_conn_ctx_t *conn_ctx, struct bufferevent *bev); + +private: + using http_sessions_t = std::list<std::unique_ptr<HttpSession>>; + http_sessions_t http_sessions_; + + HttpSession & create_new_session(); + HttpSession & last_uncomplete_session(); + + void drop_last_session(); + void drop_first_session(); +}; + +class Http1Request : public HttpRequest +{ +public: + Http1Request(); + virtual ~Http1Request() = default; + + virtual ssize_t ConstructFromMemory(const char *buf, size_t buflen); + virtual ssize_t ConstructFromEvBuf(struct evbuffer * evbuf_ptr); + + virtual evbuffer_unique_ptr_t StolenEvbuf() { return std::move(evbuf_content_raw_); } + + bool ReadOnly() override { return readonly_; } + void ReadOnly(bool is_readonly) override { readonly_ = is_readonly; } + + bool Forward() override { return forward_; } + void Forward(bool is_forward) override { forward_ = is_forward; } + virtual void ForEachHeader(for_each_header_cb_t cb); + bool Complete() override { return request_complete_; } + +private: + std::string str_uri{}; + std::map<std::string, std::string> str_headers{}; + std::string str_last_header_field_{}; + + bool request_header_complete_{false}; + bool request_body_complete_{false}; + bool request_complete_{false}; + + bool forward_{true}; + bool readonly_{false}; + + std::unique_ptr<struct http_parser> parser_{new struct http_parser}; + evbuffer_unique_ptr_t evbuf_content_raw_{evbuffer_unique_ptr_t(evbuffer_new())}; +}; + +Http1Request::Http1Request() +{ + http_parser_init(parser_.get(), HTTP_REQUEST); +} + +ssize_t Http1Request::ConstructFromMemory(const char *buf, size_t buflen) +{ + static http_data_cb __http_parser_cb_on_uri = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Request *>(parser->data); + __ptr_this->str_uri = std::string(at, at + length); + return 0; + }; + + static http_data_cb __http_parser_cb_on_header_field = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Request *>(parser->data); + __ptr_this->str_last_header_field_ = std::string(at, at + length); + return 0; + }; + + static http_data_cb __http_parser_cb_on_header_value = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Request *>(parser->data); + __ptr_this->str_headers[__ptr_this->str_last_header_field_] = std::string(at, at + length); + return 0; + }; + + static http_cb __http_parser_cb_on_message_complete = [](http_parser *parser) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Request *>(parser->data); + __ptr_this->request_complete_ = true; + return 0; + }; + + static struct http_parser_settings __parser_setting = + { + nullptr, /* on_message_begin */ + __http_parser_cb_on_uri, /* on_url */ + nullptr, /* on_status */ + __http_parser_cb_on_header_field, /* on_header_field */ + __http_parser_cb_on_header_value, /* on_header_value */ + __http_parser_cb_on_message_complete, /* on_headers_complete */ + nullptr, /* on_body */ + nullptr /* on_message_complete */ + }; + + parser_->data = this; + size_t sz_parsed = http_parser_execute(parser_.get(), &__parser_setting, buf, buflen); + + /* 解析错误 */ + if (sz_parsed && parser_->http_errno > 0) + { + log_err_printf("Http Parser errno: %d", parser_->http_errno); + return -1; + } + + return sz_parsed; +} + +ssize_t Http1Request::ConstructFromEvBuf(struct evbuffer * evbuf_ptr) +{ + /* 展平输入的Buffer为线性空间 */ + auto * __data_ptr = (const char *)(evbuffer_pullup(evbuf_ptr, -1)); + size_t __data_len = evbuffer_get_length(evbuf_ptr); + + /* 解析输入的Buffer */ + ssize_t forward_len = ConstructFromMemory(__data_ptr, __data_len); + if (forward_len < 0) return forward_len; + + /* 已解析的部分,从原Buffer中抽离出来 */ + struct evbuffer * reserved_buffer = evbuffer_new(); + evbuffer_remove_buffer(evbuf_ptr, reserved_buffer, static_cast<size_t>(forward_len)); + + /* 保存在上下文中 */ + evbuffer_add_buffer(evbuf_content_raw_.get(), reserved_buffer); + return forward_len; +} + +void Http1Request::ForEachHeader(HttpRequest::for_each_header_cb_t cb) +{ + for(auto & __iterate : str_headers) + { + const std::string & __key = __iterate.first; + const std::string & __value = __iterate.second; + + cb(__key, __value); + } + + return; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HTTP Response Parser Implementation for HTTP 1.0/1.1 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static const char *informational_phrases[] = { + /* 100 */ "Continue", + /* 101 */ "Switching Protocols" +}; + +static const char *success_phrases[] = { + /* 200 */ "OK", + /* 201 */ "Created", + /* 202 */ "Accepted", + /* 203 */ "Non-Authoritative Information", + /* 204 */ "No Content", + /* 205 */ "Reset Content", + /* 206 */ "Partial Content" +}; + +static const char *redirection_phrases[] = { + /* 300 */ "Multiple Choices", + /* 301 */ "Moved Permanently", + /* 302 */ "Found", + /* 303 */ "See Other", + /* 304 */ "Not Modified", + /* 305 */ "Use Proxy", + /* 307 */ "Temporary Redirect" +}; + +static const char *client_error_phrases[] = { + /* 400 */ "Bad Request", + /* 401 */ "Unauthorized", + /* 402 */ "Payment Required", + /* 403 */ "Forbidden", + /* 404 */ "Not Found", + /* 405 */ "Method Not Allowed", + /* 406 */ "Not Acceptable", + /* 407 */ "Proxy Authentication Required", + /* 408 */ "Request Time-out", + /* 409 */ "Conflict", + /* 410 */ "Gone", + /* 411 */ "Length Required", + /* 412 */ "Precondition Failed", + /* 413 */ "Request Entity Too Large", + /* 414 */ "Request-URI Too Large", + /* 415 */ "Unsupported Media Type", + /* 416 */ "Requested range not satisfiable", + /* 417 */ "Expectation Failed" +}; + +static const char *server_error_phrases[] = { + /* 500 */ "Internal Server Error", + /* 501 */ "Not Implemented", + /* 502 */ "Bad Gateway", + /* 503 */ "Service Unavailable", + /* 504 */ "Gateway Time-out", + /* 505 */ "HTTP Version not supported" +}; + +const char * __resp_code_to_str(int resp_code) +{ + if (resp_code >= 101 && resp_code <= 102) return informational_phrases[resp_code - 101]; + if (resp_code >= 200 && resp_code <= 206) return success_phrases[resp_code - 200]; + if (resp_code >= 300 && resp_code <= 307) return redirection_phrases[resp_code - 300]; + if (resp_code >= 400 && resp_code <= 417) return client_error_phrases[resp_code - 400]; + if (resp_code >= 500 && resp_code <= 505) return server_error_phrases[resp_code - 500]; + + return nullptr; +} + +class Http1Response : public HttpResponse +{ +public: + Http1Response(); + virtual ~Http1Response() = default; + + virtual ssize_t ConstructFromMemory(const char * buf, size_t buflen); + virtual ssize_t ConstructFromEvBuf(struct evbuffer * evbuf_len); + evbuffer_unique_ptr_t StolenEvBuf() { return std::move(evbuf_content_raw_); } + + virtual int ResponseCode() final { return resp_code_; } + virtual bool ReadOnly() final { return readonly_; } + virtual void ReadOnly(bool is_readonly) final { readonly_ = is_readonly; } + virtual bool Forward() final {return forward_; } + virtual void Forward(bool is_forward) final { forward_ = is_forward; } + virtual bool Complete() final { return parse_complete_; } + virtual void Construct() final; + +private: + int resp_code_; + short resp_version_major_; + short resp_version_minor_; + + std::map<std::string, std::string> str_headers{}; + std::string str_last_header_field_{}; + + bool parse_complete_{false}; + bool forward_{true}; + bool readonly_{false}; + + std::unique_ptr<struct http_parser> parser_{new struct http_parser}; + evbuffer_unique_ptr_t evbuf_content_raw_{nullptr}; +}; + +Http1Response::Http1Response() +{ + http_parser_init(parser_.get(), HTTP_RESPONSE); +} + +ssize_t Http1Response::ConstructFromMemory(const char *buf, size_t buflen) +{ + struct http_parser_settings __parser_setting{nullptr}; + + __parser_setting.on_status = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Response *>(parser->data); + __ptr_this->str_uri = std::string(at, at + length); + return 0; + }; + + __parser_setting.on_header_field = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Response *>(parser->data); + __ptr_this->str_last_header_field_ = std::string(at, at + length); + return 0; + }; + + __parser_setting.on_header_value = [](http_parser *parser, const char *at, size_t length) -> int + { + auto *__ptr_this = reinterpret_cast<Http1Response *>(parser->data); + __ptr_this->str_headers[__ptr_this->str_last_header_field_] = std::string(at, at + length); + return 0; + }; + + __parser_setting.on_message_complete = [](http_parser * parser)->int + { + auto *__ptr_this = reinterpret_cast<Http1Response *>(parser->data); + __ptr_this->parse_complete_ = true; + return 0; + }; + + parser_->data = this; + size_t sz_parsed = http_parser_execute(parser_.get(), &__parser_setting, buf, buflen); + + /* 解析错误 */ + if (sz_parsed && parser_->http_errno > 0) + { + throw invalid_input_format(string_format("Failed at http parsing: errcode=%u, %s, %s", + parser_->http_errno, http_errno_name(static_cast<http_errno>(parser_->http_errno)), + http_errno_description(static_cast<http_errno>(parser_->http_errno)))); + } + + return sz_parsed; +} + +ssize_t Http1Response::ConstructFromEvBuf(struct evbuffer *evbuf_ptr) +{ + /* 展平输入的Buffer为线性空间 */ + auto * __data_ptr = (const char *)(evbuffer_pullup(evbuf_ptr, -1)); + size_t __data_len = evbuffer_get_length(evbuf_ptr); + + /* 解析输入的Buffer */ + ssize_t forward_len = ConstructFromMemory(__data_ptr, __data_len); + if (forward_len < 0) return forward_len; + + /* 已解析的部分,从原Buffer中抽离出来 */ + struct evbuffer * reserved_buffer = evbuffer_new(); + evbuffer_remove_buffer(evbuf_ptr, reserved_buffer, static_cast<size_t>(forward_len)); + + /* 保存在上下文中 */ + evbuffer_add_buffer(evbuf_content_raw_.get(), reserved_buffer); + return forward_len; +} + +void Http1Response::Construct() +{ + /* 新申请EvBuffer */ + evbuffer_unique_ptr_t evbuf_construct = evbuffer_unique_ptr_t(evbuffer_new()); + struct evbuffer * evbuf_ptr = evbuf_construct.get(); + + /* 应答第一行 */ + evbuffer_add_printf(evbuf_ptr, "HTTP/%d.%d %d %s\r\n", + resp_version_major_, resp_version_minor_, resp_code_, __resp_code_to_str(resp_code_)); + + /* 应答头部 */ + for(const auto & __iterate : str_headers) + { + const auto & __header_field = __iterate.first; + const auto & __header_value = __iterate.second; + + evbuffer_add_printf(evbuf_ptr, "%s:%s\r\n", __header_field.c_str(), __header_value.c_str()); + } + + /* TODO: 消息体的构建 */ + evbuf_content_raw_ = std::move(evbuf_construct); +} + +int Http1Connection::on_connection_close(pxy_conn_ctx_t *conn_ctx, struct bufferevent *bev) +{ + return 0; +} + +int Http1Connection::on_connection_read_request(pxy_conn_ctx_t *conn_ctx, + pxy_conn_desc_t *conn_this, pxy_conn_desc_t *conn_other) +{ + /* Get the last session */ + auto http_session_ctx = last_uncomplete_session(); + + auto * request_ctx = reinterpret_cast<Http1Request *>(http_session_ctx.request()); + auto *downstream_evbuf = bufferevent_get_input(conn_this->bev); + auto *upstream_evbuf = bufferevent_get_output(conn_other->bev); + + ssize_t forward_len = request_ctx->ConstructFromEvBuf(downstream_evbuf); + + if (forward_len < 0) + { + conn_ctx->passthrough = 1; + return 0; + } + + if (request_ctx->request_complete) + { + httpscan_ctx->ScanRequestHeader(http_session_ctx); + httpscan_ctx->ScanRequestBody(http_session_ctx); + + if (http_session_ctx->need_to_close_connection) + { + conn_ctx->enomem = 1; + return 0; + } + + /* 转发请求 */ + if (request_ctx->forward) + { + evbuffer_add_buffer(upstream_evbuf, request_ctx->StolenRawEvbuf()); + return 0; + } + + /* 丢弃请求,检查是否构建了响应 */ + auto * response_ctx = reinterpret_cast<Http1Response *>(http_session_ctx->response()); + if (response_ctx != nullptr) + { + struct evbuffer * resp_evbuf = response_ctx->stolen_content_raw(); + bufferevent_write_buffer(conn_this->bev, resp_evbuf); + + printf("bufferevent_get_enabled, conn_this = %d\n", bufferevent_get_enabled(conn_this->bev)); + printf("bufferevent_get_enabled, conn_other = %d\n", bufferevent_get_enabled(conn_other->bev)); + } + + /* 最后一个Session已经处理完毕,丢弃上下文 */ + drop_last_session(); + return 0; + } + + if (request_ctx->transport_forward) + { + evbuffer_add_buffer(upstream_evbuf, request_ctx->StolenRawEvbuf()); + return 0; + } + + return 0; +} + +int Http1Connection::on_connection_read_response(pxy_conn_ctx_t *conn_ctx, struct bufferevent *bev) +{ + return 0; +} + +HttpSession & Http1Connection::create_new_session() +{ + /* Create new session, set a new request */ + auto __http_session = std::unique_ptr<HttpSession>(new HttpSession(*this)); + __http_session->request(HttpRequestFactory(1, 0)); + + /* Add to the last record */ + http_sessions_.push_back(__http_session); + return *__http_session; +} + +HttpSession & Http1Connection::last_uncomplete_session() +{ + if (http_sessions_.cbegin() == http_sessions_.cend()) + return create_new_session(); + + /* 最后一个Session已经处理结束了,新建一个Session */ + auto __session = http_sessions_.back(); + if (__session->request()->request_complete) + return create_new_session(); + + /* 否则,返回最后一个没有完全处理结束的Session */ + return __session; +} + +void Http1Connection::drop_last_session() +{ + assert(http_sessions_.cbegin() != http_sessions_.cend()); + http_sessions_.pop_back(); +} + +void Http1Connection::drop_first_session() +{ + assert(http_sessions_.cbegin() != http_sessions_.cend()); + http_sessions_.pop_front(); +} + +std::unique_ptr<HttpRequest> HttpRequestFactory(int primary_version, int second_version) +{ + if (primary_version == 1 && second_version == 0) + return std::move(std::make_unique<Http1Request>()); + if (primary_version == 1 && second_version == 1) + return std::move(std::make_unique<Http1Request>()); + + assert(0); + return nullptr; +} + +std::unique_ptr<HttpResponse> HttpResponseFactory(int primary_version, int second_version) +{ + if (primary_version == 1 && second_version == 0) + return std::move(std::make_unique<Http1Response>()); + if (primary_version == 1 && second_version == 1) + return std::move(std::make_unique<Http1Response>()); + + assert(0); + return nullptr; +}
\ No newline at end of file diff --git a/src/httpaction.cc b/src/httpaction.cc new file mode 100644 index 0000000..d24a652 --- /dev/null +++ b/src/httpaction.cc @@ -0,0 +1,325 @@ +// +// Created by luqiu on 2018-5-17. +// + +#include <cassert> +#include <vector> +#include <regex> + +#include "httpaction.h" +#include "log.h" +#include "http.h" +#include "util.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// HTTP白名单,不进行任何处理 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class HttpActionBypass : public HttpAction +{ +public: + void Construct(const std::string &str_service_define) override + {} + void OnRequestHeader(HttpSession *session) override + {} + void OnRequestBody(HttpSession *session) override + {} + void OnResponseHeader(HttpSession *session) override + {} + void OnResponseBody(HttpSession *session) override + {} +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// HTTP重定向 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class HttpActionRedirect : public HttpAction +{ +public: + void Construct(const std::string &str_service_define) override; + void OnRequestHeader(HttpSession *session) override + { return do_redirect_action(session); } + void OnRequestBody(HttpSession *session) override + { return do_redirect_action(session); } + void OnResponseHeader(HttpSession *session) override {}; + void OnResponseBody(HttpSession *session) override {}; + +private: + unsigned int resp_code_{500}; + std::string resp_location_{""}; + std::string resp_content_{""}; + + void do_redirect_action(HttpSession *session); +}; + +void HttpActionRedirect::Construct(const std::string &str_kv) +{ + std::vector<std::string> __split_token; + tokenize(str_kv, __split_token, ";", true); + + if (__split_token.size() != 2) + { + throw std::invalid_argument(string_format( + "Not enough tokens: %s, need two tokens.", str_kv.c_str())); + } + + for (const auto &kv_iterate : __split_token) + { + std::vector<std::string> __kv_tokens; + tokenize(kv_iterate, __kv_tokens, "=", false); + + if (__kv_tokens.size() != 2) + { + throw std::invalid_argument(string_format( + "Token %s must be conposed by key and value", kv_iterate.c_str())); + } + + const std::string &__str_key = __kv_tokens[0]; + const std::string &__str_value = __kv_tokens[1]; + + if (__str_key == "code") + { + resp_code_ = static_cast<unsigned int>(std::stoul(__str_value)); + continue; + } + + if (__str_key == "url") + { + resp_location_ = __str_value; + continue; + } + + assert(0); + } + +} + +void HttpActionRedirect::do_redirect_action(HttpSession *session) +{ + /* 创建新的HttpResponse */ + auto http_response = HttpResponseFactory(1, 1); + + /* 构建Redirect Response */ + http_response->ResponseCode(resp_code_); + http_response->HeaderValue("Location", resp_location_); + http_response->Construct(); + + /* 丢弃当前的HTTP Request,替换该请求对应的应答 */ + session->request().Forward(false); + session->response(std::move(http_response)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// HTTP连接阻断 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class HttpActionBlock : public HttpAction +{ +public: + void Construct(const std::string &str_service_define) override {} + void OnRequestHeader(HttpSession *session) override { do_block_action(session); } + void OnRequestBody(HttpSession *session) override {do_block_action(session);}; + void OnResponseHeader(HttpSession *session) override {do_block_action(session);}; + void OnResponseBody(HttpSession *session) override {do_block_action(session);}; + +private: + void do_block_action(HttpSession * session); +}; + +void HttpActionBlock::do_block_action(HttpSession *session) +{ + auto & connection = session->connection(); + connection.Close(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// HTTP内容编辑功能实现 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class HttpActionEdit : public HttpAction +{ +public: + void Construct(const std::string &str_kv) override; + void OnRequestHeader(HttpSession *session) override; + void OnRequestBody(HttpSession *session) override; + void OnResponseHeader(HttpSession *session) override; + void OnResponseBody(HttpSession *session) override; + +private: + enum edit_zone + { + kZoneRequestHeader, + kZoneRequestBody, + kZoneResponseHeader, + kZoneResponseBody, + kZoneMax + }; + + struct edit_rule + { + std::regex regex; + std::string fmt; + }; + + /* Edit Zone to string, define in maat service define */ + static std::array<std::string, kZoneMax> map_edit_zone_to_str; + std::array<std::vector<struct edit_rule>, kZoneMax> edit_rules_; +}; + +std::array<std::string, HttpActionEdit::kZoneMax> HttpActionEdit::map_edit_zone_to_str = + { + "http_req_header", + "http_req_body", + "http_resp_header", + "http_resp_body" + }; + +void HttpActionEdit::Construct(const std::string &str_kv) +{ + std::vector<std::string> __split_token; + tokenize(str_kv, __split_token, ";", true); + + if (__split_token.size() % 2 != 0) + { + throw std::invalid_argument(string_format( + "Invalid edit rule: %s, the count of tokens must be even numbers.", str_kv.c_str())); + } + + for (auto __iterate_zone = __split_token.cbegin(), __iterate_regex = __split_token.cbegin() + 1; + __iterate_zone != __split_token.cend(); __iterate_zone += 2, __iterate_regex + 2) + { + std::vector<std::string> __kv_tokens_zone; + std::vector<std::string> __kv_tokens_regex; + + tokenize(*__iterate_zone, __kv_tokens_zone, "="); + tokenize(*__iterate_regex, __kv_tokens_regex, "="); + + if (__kv_tokens_zone.size() != 2 || __kv_tokens_regex.size() != 2) + { + throw std::invalid_argument(string_format( + "Invalid edit rule: %s, the tokens must composed by key-value. ", str_kv.c_str())); + } + + if (__kv_tokens_zone[0] != "zone" || __kv_tokens_regex[0] != "regex") + { + throw std::invalid_argument(string_format( + "Invalid edit rule: %s, the tokens' key must be 'zone' or 'regex'", str_kv.c_str())); + } + + const std::string &__kv_zone = __kv_tokens_zone[1]; + const std::string &__kv_regex = __kv_tokens_regex[1]; + + /* 查找strZone对应的Zone数值 */ + auto zone_iterate = std::find(map_edit_zone_to_str.cbegin(), map_edit_zone_to_str.cend(), __kv_zone); + if (zone_iterate == map_edit_zone_to_str.cend()) + { + throw std::invalid_argument("Invalid edit rule: %s, illegal zone. "); + } + + auto zone_id = static_cast<edit_zone>(zone_iterate - map_edit_zone_to_str.cbegin()); + auto &zone_rule_ref = edit_rules_[zone_id]; + + std::vector<std::string> __token_regex; + + /* 按'/'拆分正则串,判断转义字符,若/前面是\,则不认为该字符为拆分字符 */ + tokenize(__kv_regex, __token_regex, "/", false, [](const std::string &str, std::string::size_type pos) + { + return (pos == 0 || str[pos - 1] != '\\'); + }); + + if (__token_regex.size() != 3) + { + throw std::invalid_argument(string_format( + "Invalid edit rule: %s, the regex must composed by two args.", str_kv.c_str())); + } + + const std::string &__kv_regex_base = __token_regex[1]; + const std::string &__kv_regex_fmt = __token_regex[2]; + + try + { + struct edit_rule __tmp_edit_rule = {std::regex(__kv_regex_base), __kv_regex_fmt}; + zone_rule_ref.push_back(std::move(__tmp_edit_rule)); + } + catch (std::regex_error &e) + { + throw std::invalid_argument(string_format( + "Invalid edit rule: %s, illegal regex expr, %d", str_kv.c_str(), e.code())); + } + } + + return; +} + +void HttpActionEdit::OnRequestHeader(HttpSession *session) +{ + /* 当前请求为transport时,无法替换,因为传输内容已经转发完毕了 */ + auto &request_ctx = session->request(); + + /* 扫描规则库,逐条执行 */ + const auto &edit_rule = edit_rules_[kZoneRequestHeader]; + + for (const auto &edit_rule_iter : edit_rule) + { + /* 正则表达式,确定要替换的内容 */ + const auto __edit_regex = edit_rule_iter.regex; + /* 替换表达式,替换方法 */ + const auto __edit_fmt = edit_rule_iter.fmt; + } + + return; +} + +void HttpActionEdit::OnRequestBody(HttpSession *session) +{ + const auto &edit_rule = &edit_rules_[kZoneRequestBody]; + + return; +} + +void HttpActionEdit::OnResponseHeader(HttpSession *session) +{ + +} + +void HttpActionEdit::OnResponseBody(HttpSession *session) +{ + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// 工厂函数 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +std::shared_ptr<HttpAction> HttpActionFactory(enum HttpActionType type, std::string str_service_define) +{ + std::shared_ptr<HttpAction> __http_action_object; + + switch (type) + { + case kActionBypass: + { + __http_action_object = std::make_shared<HttpActionBypass>(); + break; + } + case kActionEdit: + { + __http_action_object = std::make_shared<HttpActionEdit>(); + break; + } + case kActionBlock: + { + __http_action_object = std::make_shared<HttpActionBlock>(); + break; + } + case kActionRedirect: + { + __http_action_object = std::make_shared<HttpActionRedirect>(); + break; + } + default: assert(0); + } + + __http_action_object->Construct(str_service_define); + return std::move(__http_action_object); +}
\ No newline at end of file diff --git a/src/httpaction.h b/src/httpaction.h new file mode 100644 index 0000000..7dfb353 --- /dev/null +++ b/src/httpaction.h @@ -0,0 +1,60 @@ +// +// Created by luqiu on 2018-5-17. +// + +#ifndef TFE_HTTPACTION_H +#define TFE_HTTPACTION_H + +#include <string> +#include <memory> + +#include "http.h" + +enum HttpActionType +{ + kActionBypass = 0, + kActionMonitor = 1, + kActionBlock = 2, + kActionRedirect = 3, + kActionEdit = 4, + kActionMax +}; + +/* HttpAction接口 + * 该接口描述了命中扫描规则后的处理流程与状态 + * 根据命中处理业务的不同,分别地实现 + */ +class HttpAction +{ +public: + virtual void Construct(const std::string &str_service_define) = 0; + virtual void OnRequestHeader(HttpSession *session) = 0; + virtual void OnRequestBody(HttpSession *session) = 0; + virtual void OnResponseHeader(HttpSession *session) = 0; + virtual void OnResponseBody(HttpSession *session) = 0; + + /* Getter and Setter */ + void config_id(int cfg_id) { config_id_ = cfg_id;} + int config_id() { return config_id_; } + + void service_id(int srv_id) { service_id_ = srv_id; } + int service_id() { return service_id_; } + +protected: + int config_id_{0}; + int service_id_{0}; +}; + +class HttpActionMonitor : public HttpAction +{ +public: + virtual void Construct(const std::string &str_service_define); + virtual void OnRequestHeader(HttpSession *session); + virtual void OnRequestBody(HttpSession *session); + virtual void OnResponseHeader(); + virtual void OnResponseBody(); +}; + +std::shared_ptr<HttpAction> HttpActionFactory(enum HttpActionType type, std::string str_service_define); + +#endif //TFE_HTTPACTION_H diff --git a/src/httpscan.cc b/src/httpscan.cc new file mode 100644 index 0000000..f8683cc --- /dev/null +++ b/src/httpscan.cc @@ -0,0 +1,253 @@ +/* + * \brief HTTP扫描业务模块 + * + * \author Qiuwen Lu<[email protected]> + * \date 2018-5-15 + */ + + +#include <stdexcept> +#include <cassert> +#include <memory> + +#include <Maat_rule.h> +#include <MESA_prof_load.h> + +#include "util.h" +#include "opts.h" +#include "httpscan.h" +#include "pxyconn.h" +#include "http.h" +#include "compat.h" + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "IncompatibleTypes" +static int __maat_table_register_or_throw(Maat_feather_t feather, const char *str_table) +{ + int table_id = Maat_table_register(feather, str_table); + if (table_id < 0) throw std::runtime_error("Failed at register maat table " + std::string(str_table)); + return table_id; +} + +HttpScan::HttpScan(struct tfe_instance *instance, struct tfe_config *config) + : maat_feather_ref(instance->maat_feather) +{ + table_id_ctrl_ip = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_IP"); + table_id_ctrl_http_url = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_URL"); + table_id_ctrl_http_req_hdr = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_REQ_HDR"); + table_id_ctrl_http_req_body = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_URL"); + table_id_ctrl_http_res_hdr = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_RES_HDR"); + table_id_ctrl_http_res_body = __maat_table_register_or_throw(maat_feather_ref, "PXY_CTRL_HTTP_RES_BODY"); + + auto http_module = instance->http_module; + + http_module->SetHttpConnectionNewCallback([this](Http &ht, HttpConnection & ct)->void + { + this->handlerConnectionCreate(ct); + }); + + http_module->SetHttpConnectionCloseCallback([this](Http & ht, HttpConnection & ct)->void + { + this->handlerConnectionClose(ct); + }); + + return; +} + +void HttpScan::handlerConnectionCreate(HttpConnection &ct) +{ + /* 新Session的创建处理函数 */ + ct.SetSessionNewCallback([this](HttpSession & session)->void + { + /* 创建HttpScan的Session Ctx */ + auto __scan_ctx = std::make_shared<HttpScanSession>(*this); + + /* 设置回调函数,每个回调函数增加一次__scan_ctx的引用计数 + * 注意在栈上定义一个指针,指向__scan_ctx。 + * 这样,回调时始终保持__scan_ctx的引用计数大于等于1, + * 避免在回调过程中变更回调函数导致ctx析构。 + */ + session.SetRequestHeaderCallback([__scan_ctx](HttpSession & session) + { + auto __scan_ctx_stack = __scan_ctx; + __scan_ctx_stack->ScanRequestHeader(&session); + }); + + session.SetRequestBodyCallback([__scan_ctx](HttpSession & session) + { + auto __scan_ctx_stack = __scan_ctx; + __scan_ctx->ScanRequestBody(&session); + }); + + session.SetResponseHeaderCallback([__scan_ctx](HttpSession & session) + { + auto __scan_ctx_stack = __scan_ctx; + __scan_ctx->ScanResponseHeader(&session); + }); + + session.SetResponseBodyCallback([__scan_ctx](HttpSession & session) + { + auto __scan_ctx_stack = __scan_ctx; + __scan_ctx->ScanResponseBody(&session); + }); + }); + + /* 不设置SessionClose的回调函数,相应的逻辑在HttpScanSession的析构函数中处理 */ + ct.SetSessionCloseCallback(nullptr); +}; + +HttpScanSession::HttpScanSession(const HttpScan &httpscan_module) : + httpscan_module_ref_(httpscan_module) +{ +} + +HttpScanSession::~HttpScanSession() +{ + if (maat_scan_mid_ != nullptr) Maat_clean_status(&maat_scan_mid_); +} + +void HttpScanSession::ScanRequestHeader(HttpSession *http_session_ctx) +{ + auto & http_request = http_session_ctx->request(); + int dummy[MAAT_SCAN_RESULT_]; + + /* 扫描IP地址,获取连接对应的四元组 */ + const auto & connection = http_session_ctx->connection(); + const auto * sockaddr_src = connection.SockAddrSource(); + const auto * sockaddr_dst = connection.SockAddrDest(); + + /* 转换为Sapp中的四元组结构体 */ + auto sapp_tuple4_ptr = sockaddr_to_sapp_ipaddr(sockaddr_src, sockaddr_dst); + + /* 扫描IP地址 */ + nr_maat_scan_result_ = Maat_scan_addr(httpscan_module_ref_.maat_feather_ref, + httpscan_module_ref_.table_id_ctrl_ip, sapp_tuple4_ptr.get(), + maat_scan_result_, MAAT_SCAN_RESULT_, &maat_scan_mid_, 0); + + if (nr_maat_scan_result_ > 0) + return hit_config_and_do_action(http_session_ctx); + else if (nr_maat_scan_result_ == -1) + return hit_scan_error(); + + /* 扫描HTTP URL */ + const auto & __url = http_request.Url(); + + nr_maat_scan_result_ = Maat_full_scan_string(httpscan_module_ref_.maat_feather_ref, + httpscan_module_ref_.table_id_ctrl_http_url, CHARSET_UTF8, __url.c_str(), (int) __url.length(), + maat_scan_result_, dummy, MAAT_SCAN_RESULT_, &maat_scan_mid_, 0); + + if (nr_maat_scan_result_ > 0) + return hit_config_and_do_action(http_session_ctx); + else if (nr_maat_scan_result_ == -1) + return hit_scan_error(); + + /* 未命中HTTP URL,继续扫描其他HTTP头部字段 */ + http_request.ForEachHeader([this, http_session_ctx](const std::string & field, const std::string & value) + { + /* 增强字符串表,设置区域字段,即Header字段 */ + int ret = Maat_set_scan_status(httpscan_module_ref_.maat_feather_ref, &maat_scan_mid_, + MAAT_SET_SCAN_DISTRICT, field.c_str(), (int) field.length()); + + /* 设置失败 */ + if (ret < 0) + return hit_scan_error(); + + int __dummy[MAAT_SCAN_RESULT_]; + + nr_maat_scan_result_ = Maat_full_scan_string(httpscan_module_ref_.maat_feather_ref, + httpscan_module_ref_.table_id_ctrl_http_req_hdr, MAAT_DEFAULT_CHARSET_, + value.c_str(), (int) value.length(), + maat_scan_result_, __dummy, MAAT_SCAN_RESULT_, &maat_scan_mid_, 0); + + if (nr_maat_scan_result_ > 0) + return hit_config_and_do_action(http_session_ctx); + else if (nr_maat_scan_result_ == -1) + return hit_scan_error(); + }); +} + +void HttpScanSession::ScanRequestBody(HttpSession *http_session_ctx) +{ + return; +} + +void HttpScanSession::ScanResponseHeader(HttpSession *http_session_ctx) +{ + return; +} + +void HttpScanSession::ScanResponseBody(HttpSession *http_session_ctx) +{ + return; +} + +void HttpScanSession::hit_config_and_do_action(HttpSession *http_session_ctx) +{ + /* 判断命中数量,若为多命中,选择优先级最高的动作执行 */ + enum HttpActionType action_type = HttpActionType::kActionMax; + unsigned int do_action_id = 0; + + /* 选择最小的动作ID为实际执行的配置ID */ + for (unsigned int i = 0; i < nr_maat_scan_result_; i++) + { + if (maat_scan_result_[i].action <= action_type) do_action_id = i; + } + + Maat_rule_t * hit_maat_rule = &maat_scan_result_[do_action_id]; + auto __action_type = (enum HttpActionType)hit_maat_rule->action; + const char * __action_string = hit_maat_rule->service_defined; + + /* 创建HttpAction的对象 */ + auto action_object = HttpActionFactory(__action_type, __action_string); + + /* 标记ConfigID和ServiceID,便于后面发送日志使用 */ + action_object->config_id(hit_maat_rule->config_id); + action_object->service_id(hit_maat_rule->service_id); + + /* 替换HttpSession的事件处理函数,以后的事件由HttpAction处理 */ + http_session_ctx->SetRequestHeaderCallback([action_object](HttpSession & session) + { + auto __action_object = action_object; + __action_object->OnRequestHeader(&session); + }); + + http_session_ctx->SetRequestBodyCallback([action_object](HttpSession & session) + { + auto __action_object = action_object; + __action_object->OnRequestBody(&session); + }); + + http_session_ctx->SetResponseHeaderCallback([action_object](HttpSession & session) + { + auto __action_object = action_object; + __action_object->OnResponseHeader(&session); + }); + + http_session_ctx->SetResponseBodyCallback([action_object](HttpSession & session) + { + auto __action_object = action_object; + __action_object->OnResponseBody(&session); + }); + + /* 当前Session的处理函数指向Action对应的处理函数 */ + log_dbg_printf("hit rule: service_id = %d, config_id = %d, action = %d\n", + hit_maat_rule->service_id, hit_maat_rule->config_id, hit_maat_rule->action); + + if (hit_maat_rule->do_blacklist) + { + + } + + if (hit_maat_rule->do_log) + { + + } + + return; +} + +void HttpScanSession::hit_scan_error() +{ + return; +} +#pragma clang diagnostic pop
\ No newline at end of file diff --git a/src/httpscan.h b/src/httpscan.h new file mode 100644 index 0000000..2665084 --- /dev/null +++ b/src/httpscan.h @@ -0,0 +1,89 @@ +// +// Created by luqiu on 2018-5-15. +// + +#ifndef TFE_HTTPSCAN_H +#define TFE_HTTPSCAN_H + +#include <Maat_rule.h> +#include "opts.h" +#include "httpaction.h" + +/* Forward Declare */ +class HttpScanSession; +class HttpScan; +class HttpSession; + +/* HttpScan Module Init/Deinit */ +class HttpScan +{ +public: + HttpScan(struct tfe_instance * instance, struct tfe_config *config); + ~HttpScan() = default; + + void handlerConnectionCreate(HttpConnection & ct); + void handlerConnectionClose(HttpConnection & ct); + + /* Table Symbols */ +protected: + /* Global Instance */ + tfe_instance * tfe_instance; + /* Global Config */ + tfe_config * tfe_config; + /* Maat扫描句柄 */ + Maat_feather_t maat_feather_ref; + /* 控制编译表ID */ + int table_id_ctrl_compile; + /* IP配置表ID */ + int table_id_ctrl_ip; + /* URL配置表ID */ + int table_id_ctrl_http_url; + /* HTTP请求头部配置表ID */ + int table_id_ctrl_http_req_hdr; + /* HTTP请求体配置表ID */ + int table_id_ctrl_http_req_body; + /* HTTP应答头部配置表ID */ + int table_id_ctrl_http_res_hdr; + /* HTTP应答体配置表ID */ + int table_id_ctrl_http_res_body; + + /* IP白名单扫描 */ + int connection_bypass_scan(); + int connection_bypass_do_action(); + + friend HttpScanSession; +}; + +/* Httpscan Ctx per HTTP Session */ +class HttpScanSession +{ +public: + explicit HttpScanSession(const HttpScan & httpscan_module); + ~HttpScanSession(); + + /* HTTP请求、应答扫描 */ + void ScanRequestHeader(HttpSession *http_session_ctx); + void ScanRequestBody(HttpSession *http_session_ctx); + void ScanResponseHeader(HttpSession *http_session_ctx); + void ScanResponseBody(HttpSession *http_session_ctx); + +private: + void hit_config_and_do_action(HttpSession *http_session_ctx); + void hit_scan_error(); + + /* 最大命中结果数量 */ + static constexpr int MAAT_SCAN_RESULT_ = 4; + /* 默认内容编码 */ + static constexpr auto MAAT_DEFAULT_CHARSET_ = CHARSET_GBK; + + /* HTTPSCAN Module句柄引用 */ + const HttpScan & httpscan_module_ref_; + /* 扫描中间句柄 */ + scan_status_t maat_scan_mid_{nullptr}; + /* 扫描命中结果 */ + Maat_rule_t maat_scan_result_[MAAT_SCAN_RESULT_]; + /* 扫描命中数量 */ + int nr_maat_scan_result_{0}; +}; + +#endif //TFE_HTTPSCAN_H diff --git a/src/main.cc b/src/main.cc index f1c1c54..9f4a510 100644 --- a/src/main.cc +++ b/src/main.cc @@ -26,11 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* silence daemon(3) deprecation warning on Mac OS X */ -#if __APPLE__ -#define daemon xdaemon -#endif /* __APPLE__ */ - #include "opts.h" #include "proxy.h" #include "privsep.h" @@ -47,27 +42,18 @@ #include <unistd.h> #include <signal.h> #include <string.h> - -#ifndef __BSD__ #include <getopt.h> -#endif /* !__BSD__ */ #include <event2/event.h> - #include <openssl/ssl.h> #include <openssl/x509.h> -#if __APPLE__ -#undef daemon -extern int daemon(int, int); -#endif /* __APPLE__ */ - +#include "httpscan.h" /* * Print version information to stderr. */ -static void -main_version(void) +static void main_version(void) { fprintf(stderr, "%s %s (built %s)\n", PKGLABEL, build_version, build_date); @@ -104,12 +90,6 @@ main_version(void) fprintf(stderr, "Features: %s\n", build_features); } nat_version(); - fprintf(stderr, "Local process info support: "); -#ifdef HAVE_LOCAL_PROCINFO - fprintf(stderr, "yes (" LOCAL_PROCINFO_STR ")\n"); -#else /* !HAVE_LOCAL_PROCINFO */ - fprintf(stderr, "no\n"); -#endif /* !HAVE_LOCAL_PROCINFO */ ssl_openssl_version(); fprintf(stderr, "compiled against libevent %s\n", LIBEVENT_VERSION); fprintf(stderr, "rtlinked against libevent %s\n", event_get_version()); @@ -283,6 +263,8 @@ oom_die(const char *argv0) exit(EXIT_FAILURE); } +struct tfe_instance * g_tfe_instance = new tfe_instance; + /* * Main entry point. */ @@ -788,18 +770,9 @@ main(int argc, char *argv[]) } if (!opts->dropuser && !geteuid() && !getuid() && sys_isuser(DFLT_DROPUSER)) { -#ifdef __APPLE__ - /* Apple broke ioctl(/dev/pf) for EUID != 0 so we do not - * want to automatically drop privileges to nobody there - * if pf has been used in any proxyspec */ - if (!nat_used("pf")) { -#endif /* __APPLE__ */ opts->dropuser = strdup(DFLT_DROPUSER); if (!opts->dropuser) oom_die(argv0); -#ifdef __APPLE__ - } -#endif /* __APPLE__ */ } if (tfe_config_has_ssl_spec(opts) && opts->cakey && !opts->key) { /* @@ -937,6 +910,8 @@ main(int argc, char *argv[]) return -1; } + g_tfe_instance->http_scan_module = new HttpScan(g_tfe_instance, opts); + /* Fork into parent monitor process and (potentially unprivileged) * child process doing the actual work. We request 3 privsep client * sockets: content logger thread, cert writer thread, and the child @@ -989,6 +964,7 @@ main(int argc, char *argv[]) log_err_printf("Failed to init NAT state table lookup.\n"); goto out_nat_failed; } + rv = EXIT_SUCCESS; proxy_run(proxy); diff --git a/src/opts.cc b/src/opts.cc index 067b40c..d0e2f43 100644 --- a/src/opts.cc +++ b/src/opts.cc @@ -41,22 +41,28 @@ #include <openssl/dh.h> #include <openssl/x509.h> -#include <MESA_prof_load.h> #include <assert.h> #include "cfgparser.h" +#include "util.h" -struct tfe_config *tfe_config_new() +extern "C" { - tfe_config *__config; +#include <MESA_prof_load.h> +#include <MESA_handle_logger.h> +} - __config = (tfe_config *) malloc(sizeof(tfe_config)); - memset(__config, 0, sizeof(tfe_config)); +#include <Maat_rule.h> + +struct tfe_config *tfe_config_new() +{ + struct tfe_config *__config; + __config = (struct tfe_config *)malloc(sizeof(struct tfe_config)); + memset(__config, 0, sizeof(struct tfe_config)); __config->sslcomp = 1; __config->chain = sk_X509_new_null(); __config->sslmethod = SSLv23_method; - return __config; } @@ -109,14 +115,14 @@ static int __proxyspec_parse_each_entry( assert(__spec->natengine != nullptr); int ret = sys_sockaddr_parse(&__spec->listen_addr, &__spec->listen_addrlen, str_listen_addr.c_str(), - str_listen_port.c_str(), AF_INET, EVUTIL_AI_PASSIVE); + str_listen_port.c_str(), AF_INET, EVUTIL_AI_PASSIVE); if (ret < 0) { - throw tfe_expection_cfg_invalid_format("", "", "", ""); + throw cfg_invalid_format("", "", "", ""); } log_dbg_printf("Proxyspec %s: Listen Address %s, Port %s, Protocol %s\n", str_proxyspec.c_str(), - str_listen_addr.c_str(), str_listen_port.c_str(), str_protocol.c_str()); + str_listen_addr.c_str(), str_listen_port.c_str(), str_protocol.c_str()); /* 插入到Spec链表头部 */ @@ -149,6 +155,102 @@ static int __ssl_protocol_load_from_file(tfe_config *cfg, TfeConfigParser &cfg_p return 0; } +static int __maatframe_load_from_file(tfe_config *cfg, TfeConfigParser &cfg_parser) +{ + if (cfg->maat_config == nullptr) + { + cfg->maat_config = new() tfe_maat_config; + } + + tfe_maat_config *__maat_config = cfg->maat_config; + + /* Maat配置加载来源 */ + __maat_config->cfg_load_from = (tfe_maat_config::cfg_load_from_t) + cfg_parser.GetValue<unsigned long>("maat", "pz_source_mode"); + + switch (__maat_config->cfg_load_from) + { + case tfe_maat_config::LOAD_FROM_JSON_FILE: + __maat_config->str_json_file_path = cfg_parser.GetValue<std::string>("maat", "pz_json_file"); + break; + case tfe_maat_config::LOAD_FROM_LOAD_IRIS: + __maat_config->str_redis_addr = cfg_parser.GetValue<std::string>("maat", "pz_redis_server"); + __maat_config->str_redir_port = cfg_parser.GetValue<std::string>("maat", "pz_redir_port"); + break; + case tfe_maat_config::LOAD_FROM_REDIS_SERVER: + __maat_config->str_full_cfg_dir = cfg_parser.GetValue<std::string>("maat", "pz_iris_full_dir"); + __maat_config->str_inc_cfg_dir = cfg_parser.GetValue<std::string>("maat", "pz_iris_inc_dir"); + break; + + default:assert(0); + } + + /* Maat表定义文件路径 */ + __maat_config->str_table_info_file = cfg_parser.GetValue<std::string>("maat", "table_info_file"); + __maat_config->str_log_file_path = cfg_parser.GetValue<std::string>("maat", "logfile"); + + log_dbg_printf("Maat pz source mode = %d", __maat_config->cfg_load_from); + log_dbg_printf("Maat json file path = %s", __maat_config->str_json_file_path.c_str()); + log_dbg_printf("Maat redis server = %s", __maat_config->str_redis_addr.c_str()); + log_dbg_printf("Maat redir port = %s", __maat_config->str_redir_port.c_str()); + log_dbg_printf("Maat iris full path = %s", __maat_config->str_log_file_path.c_str()); + log_dbg_printf("Maat iris inc path = %s", __maat_config->str_inc_cfg_dir.c_str()); + log_dbg_printf("Maat table info file = %s", __maat_config->str_table_info_file.c_str()); + log_dbg_printf("Maat log file = %s", __maat_config->str_log_file_path.c_str()); + + return 0; +} + +static int __maatframe_init(tfe_config *cfg) +{ + tfe_maat_config *__maat_config = cfg->maat_config; + + /* 创建Logger,该Logger仅供Maat输出日志使用 */ + void *logger = MESA_create_runtime_log_handle(__maat_config->str_log_file_path.c_str(), 0); + if (logger == nullptr) + { + throw std::runtime_error(string_format("Failed at creating runtime logger handle for MAAT: file %s", + __maat_config->str_log_file_path.c_str())); + } + + void * feather = Maat_feather(128, __maat_config->str_table_info_file.c_str(), logger); + Maat_set_feather_opt(feather, MAAT_OPT_INSTANCE_NAME, "Tfe2a", (int)strlen("Tfe2a") + 1); + + auto __maat_option_setup_helper = [feather](enum MAAT_INIT_OPT opt, const std::string value) + { + Maat_set_feather_opt(feather, opt, value.c_str(), (int)value.length() + 1); + }; + + switch (__maat_config->cfg_load_from) + { + case tfe_maat_config::LOAD_FROM_JSON_FILE: + __maat_option_setup_helper(MAAT_OPT_JSON_FILE_PATH, __maat_config->str_json_file_path); + break; + case tfe_maat_config::LOAD_FROM_LOAD_IRIS: + __maat_option_setup_helper(MAAT_OPT_FULL_CFG_DIR, __maat_config->str_full_cfg_dir); + __maat_option_setup_helper(MAAT_OPT_INC_CFG_DIR, __maat_config->str_inc_cfg_dir); + break; + + default: + assert(0); + } + + Maat_set_feather_opt(feather, MAAT_OPT_STAT_ON, nullptr, 0); + Maat_set_feather_opt(feather, MAAT_OPT_PERF_ON, nullptr, 0); + + Maat_initiate_feather(feather); + if (feather == nullptr) + { + MESA_destroy_runtime_log_handle(logger); + throw std::runtime_error(string_format("Failed at initiate maat feather.")); + } + + g_tfe_instance->maat_feather = feather; + g_tfe_instance->maat_logger = logger; + + return 0; +} + void tfe_config_load_from_file(tfe_config *cfg, const char *c_str_file) { TfeConfigParser __config_parser(c_str_file); @@ -168,18 +270,22 @@ void tfe_config_load_from_file(tfe_config *cfg, const char *c_str_file) /* 解析SSL/TLS版本功能开关 */ __ssl_protocol_load_from_file(cfg, __config_parser); + /* maat参数配置 */ + __maatframe_load_from_file(cfg, __config_parser); + /* 初始化Maat句柄 */ + __maatframe_init(cfg); } - catch (tfe_expection_cfg_invalid_format &e) + catch (cfg_invalid_format &e) { log_err_printf("Invalid format config entries in file %s, section %s, entry %s.", - e.file.c_str(), e.section.c_str(), e.item.c_str()); + e.file.c_str(), e.section.c_str(), e.item.c_str()); goto __errout; } - catch (tfe_expection_cfg_lost_entry &e) + catch (cfg_lost_entry &e) { log_err_printf("Required config entries is not existed in file %s, section %s, entry %s.", - e.file.c_str(), e.section.c_str(), e.item.c_str()); + e.file.c_str(), e.section.c_str(), e.item.c_str()); goto __errout; } @@ -370,7 +476,7 @@ tfe_config_proto_force(tfe_config *opts, const char *optarg, const char *argv0) #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ { fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); + argv0, optarg); exit(EXIT_FAILURE); } } @@ -413,7 +519,7 @@ tfe_config_proto_disable(tfe_config *opts, const char *optarg, const char *argv0 #endif /* HAVE_TLSV12 */ { fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n", - argv0, optarg); + argv0, optarg); exit(EXIT_FAILURE); } } @@ -430,19 +536,19 @@ tfe_config_proto_dbg_dump(tfe_config *opts) (opts->sslmethod == SSLv2_method) ? "ssl2" : #endif /* HAVE_SSLV2 */ #ifdef HAVE_SSLV3 - (opts->sslmethod == SSLv3_method) ? "ssl3" : - #endif /* HAVE_SSLV3 */ - #ifdef HAVE_TLSV10 - (opts->sslmethod == TLSv1_method) ? "tls10" : - #endif /* HAVE_TLSV10 */ - #ifdef HAVE_TLSV11 - (opts->sslmethod == TLSv1_1_method) ? "tls11" : - #endif /* HAVE_TLSV11 */ - #ifdef HAVE_TLSV12 - (opts->sslmethod == TLSv1_2_method) ? "tls12" : - #endif /* HAVE_TLSV12 */ - #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - #ifdef HAVE_SSLV3 + (opts->sslmethod == SSLv3_method) ? "ssl3" : + #endif /* HAVE_SSLV3 */ + #ifdef HAVE_TLSV10 + (opts->sslmethod == TLSv1_method) ? "tls10" : + #endif /* HAVE_TLSV10 */ + #ifdef HAVE_TLSV11 + (opts->sslmethod == TLSv1_1_method) ? "tls11" : + #endif /* HAVE_TLSV11 */ + #ifdef HAVE_TLSV12 + (opts->sslmethod == TLSv1_2_method) ? "tls12" : + #endif /* HAVE_TLSV12 */ + #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + #ifdef HAVE_SSLV3 (opts->sslversion == SSL3_VERSION) ? "ssl3" : #endif /* HAVE_SSLV3 */ #ifdef HAVE_TLSV10 @@ -454,28 +560,28 @@ tfe_config_proto_dbg_dump(tfe_config *opts) #ifdef HAVE_TLSV12 (opts->sslversion == TLS1_2_VERSION) ? "tls12" : #endif /* HAVE_TLSV12 */ - #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - "negotiate", + #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + "negotiate", #ifdef HAVE_SSLV2 opts->no_ssl2 ? " -ssl2" : #endif /* HAVE_SSLV2 */ - "", + "", #ifdef HAVE_SSLV3 - opts->no_ssl3 ? " -ssl3" : - #endif /* HAVE_SSLV3 */ - "", + opts->no_ssl3 ? " -ssl3" : + #endif /* HAVE_SSLV3 */ + "", #ifdef HAVE_TLSV10 - opts->no_tls10 ? " -tls10" : - #endif /* HAVE_TLSV10 */ - "", + opts->no_tls10 ? " -tls10" : + #endif /* HAVE_TLSV10 */ + "", #ifdef HAVE_TLSV11 - opts->no_tls11 ? " -tls11" : - #endif /* HAVE_TLSV11 */ - "", + opts->no_tls11 ? " -tls11" : + #endif /* HAVE_TLSV11 */ + "", #ifdef HAVE_TLSV12 - opts->no_tls12 ? " -tls12" : - #endif /* HAVE_TLSV12 */ - ""); + opts->no_tls12 ? " -tls12" : + #endif /* HAVE_TLSV12 */ + ""); } /* @@ -505,7 +611,7 @@ char *proxyspec_str(proxyspec *spec) char *lhbuf, *lpbuf; char *cbuf = NULL; if (sys_sockaddr_str((struct sockaddr *) &spec->listen_addr, - spec->listen_addrlen, &lhbuf, &lpbuf) != 0) + spec->listen_addrlen, &lhbuf, &lpbuf) != 0) { return NULL; } @@ -513,8 +619,8 @@ char *proxyspec_str(proxyspec *spec) { char *chbuf, *cpbuf; if (sys_sockaddr_str((struct sockaddr *) &spec->connect_addr, - spec->connect_addrlen, - &chbuf, &cpbuf) != 0) + spec->connect_addrlen, + &chbuf, &cpbuf) != 0) { return NULL; } @@ -533,10 +639,10 @@ char *proxyspec_str(proxyspec *spec) } } if (asprintf(&s, "[%s]:%s %s%s%s %s", lhbuf, lpbuf, - (spec->ssl ? "ssl" : "tcp"), - (spec->upgrade ? "|upgrade" : ""), - (spec->http ? "|http" : ""), - (spec->natengine ? spec->natengine : cbuf)) < 0) + (spec->ssl ? "ssl" : "tcp"), + (spec->upgrade ? "|upgrade" : ""), + (spec->http ? "|http" : ""), + (spec->natengine ? spec->natengine : cbuf)) < 0) { s = NULL; } @@ -35,6 +35,11 @@ #include <sys/types.h> #include <sys/socket.h> +#include <Maat_rule.h> +#include <string> + +class HttpScan; +class Http; struct proxyspec { @@ -56,6 +61,47 @@ struct proxyspec struct proxyspec *next; }; +/* TFE Runtime Instances */ +struct tfe_instance +{ + /* Global Maat Feather */ + Maat_feather_t maat_feather; + /* Maat Logger */ + void * maat_logger; + + /* HTTPSCAN */ + HttpScan * http_scan_module; + /* Http */ + Http * http_module; +}; + +struct tfe_maat_config +{ + /* Maat Params */ + std::string str_table_info_file; + std::string str_log_file_path; + std::string str__interface_symbol; + + /* Maat Config Source */ + enum cfg_load_from_t + { + LOAD_FROM_JSON_FILE, + LOAD_FROM_REDIS_SERVER, + LOAD_FROM_LOAD_IRIS + }; + + cfg_load_from_t cfg_load_from; + + /* from JSON FILE */ + std::string str_json_file_path; + /* from REDIR Server */ + std::string str_redis_addr; + std::string str_redir_port; + /* from IRIS */ + std::string str_full_cfg_dir; + std::string str_inc_cfg_dir; +}; + struct tfe_config { /* Configure Files */ @@ -98,8 +144,13 @@ struct tfe_config struct proxyspec * spec; char *crlurl; + + tfe_maat_config * maat_config; }; +extern tfe_instance * g_tfe_instance; +extern tfe_config * g_tfe_config; + struct tfe_config *tfe_config_new(void) MALLOC; void tfe_config_free(struct tfe_config *) NONNULL(1); int tfe_config_has_ssl_spec(struct tfe_config *) NONNULL(1) WUNRES; diff --git a/src/proxy.cc b/src/proxy.cc index 78f788a..bdd0dff 100644 --- a/src/proxy.cc +++ b/src/proxy.cc @@ -27,7 +27,6 @@ */ #include "proxy.h" - #include "privsep.h" #include "pxythrmgr.h" #include "pxyconn.h" @@ -35,6 +34,7 @@ #include "opts.h" #include "log.h" #include "attrib.h" +#include "util.h" #include <sys/types.h> #include <sys/socket.h> @@ -61,7 +61,7 @@ static int signals[] = { SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1 }; struct proxy_ctx { - pxy_thrmgr_ctx_t *thrmgr; + tfe_thread_manager_ctx *thrmgr; struct event_base *evbase; struct event *sev[sizeof(signals)/sizeof(int)]; struct event *gcev; @@ -69,13 +69,12 @@ struct proxy_ctx struct tfe_config *opts; }; - /* * Listener context. */ typedef struct proxy_listener_ctx { - pxy_thrmgr_ctx_t *thrmgr; + tfe_thread_manager_ctx *thrmgr; struct proxyspec *spec; struct tfe_config *opts; struct evconnlistener *evcl; @@ -84,10 +83,11 @@ typedef struct proxy_listener_ctx } proxy_listener_ctx_t; static proxy_listener_ctx_t * -proxy_listener_ctx_new(pxy_thrmgr_ctx_t *thrmgr, proxyspec *spec, +proxy_listener_ctx_new(tfe_thread_manager_ctx *thrmgr, proxyspec *spec, tfe_config *opts) MALLOC; + static proxy_listener_ctx_t * -proxy_listener_ctx_new(pxy_thrmgr_ctx_t *thrmgr, proxyspec *spec, +proxy_listener_ctx_new(tfe_thread_manager_ctx *thrmgr, proxyspec *spec, tfe_config *opts) { proxy_listener_ctx_t *ctx = (proxy_listener_ctx_t *)malloc(sizeof(proxy_listener_ctx_t)); @@ -164,7 +164,7 @@ proxy_debug_base(const struct event_base *ev_base) * Returns the proxy_listener_ctx_t pointer if successful, NULL otherwise. */ static proxy_listener_ctx_t * -proxy_listener_setup(struct event_base *evbase, pxy_thrmgr_ctx_t *thrmgr, +proxy_listener_setup(struct event_base *evbase, tfe_thread_manager_ctx *thrmgr, proxyspec *spec, tfe_config *opts, int clisock) { proxy_listener_ctx_t *plc; @@ -315,7 +315,7 @@ proxy_new(tfe_config *opts, int clisock) proxy_debug_base(ctx->evbase); } - ctx->thrmgr = pxy_thrmgr_new(opts); + ctx->thrmgr = tfe_thread_manager_new(opts); if (!ctx->thrmgr) { log_err_printf("Error creating thread manager\n"); goto leave1b; @@ -362,7 +362,7 @@ leave2: if (ctx->lctx) { proxy_listener_ctx_free(ctx->lctx); } - pxy_thrmgr_free(ctx->thrmgr); + tfe_thread_manager_free(ctx->thrmgr); leave1b: event_base_free(ctx->evbase); leave1: @@ -386,7 +386,7 @@ proxy_run(proxy_ctx_t *ctx) event_base_dump_events(ctx->evbase, stderr); } #endif /* PURIFY */ - if (pxy_thrmgr_run(ctx->thrmgr) == -1) { + if (tfe_thread_manager_run(ctx->thrmgr) == -1) { log_err_printf("Failed to start thread manager\n"); return; } @@ -426,7 +426,7 @@ proxy_free(proxy_ctx_t *ctx) } } if (ctx->thrmgr) { - pxy_thrmgr_free(ctx->thrmgr); + tfe_thread_manager_free(ctx->thrmgr); } if (ctx->evbase) { event_base_free(ctx->evbase); diff --git a/src/pxyconn.cc b/src/pxyconn.cc index f6b0d93..e5346c7 100644 --- a/src/pxyconn.cc +++ b/src/pxyconn.cc @@ -58,21 +58,19 @@ #include <openssl/rand.h> #include <openssl/x509.h> #include <openssl/x509v3.h> - - /* * Maximum size of data to buffer per connection direction before * temporarily stopping to read data from the other end. */ -#define OUTBUF_LIMIT (128*1024) +#define OUTBUF_LIMIT (128*1024) /* * Print helper for logging code. */ -#define STRORDASH(x) (((x)&&*(x))?(x):"-") +#define STRORDASH(x) (((x)&&*(x))?(x):"-") /* - * Context used for all server sessions. + * Context used for all server http_sessions_. */ #ifdef USE_SSL_SESSION_ID_CONTEXT static unsigned long ssl_session_context = 0x31415926; @@ -81,133 +79,140 @@ static unsigned long ssl_session_context = 0x31415926; #ifdef HAVE_LOCAL_PROCINFO /* local process data - filled in iff pid != -1 */ typedef struct pxy_conn_lproc_desc { - struct sockaddr_storage srcaddr; - socklen_t srcaddrlen; + struct sockaddr_storage srcaddr; + socklen_t srcaddrlen; - pid_t pid; - uid_t uid; - gid_t gid; + pid_t pid; + uid_t uid; + gid_t gid; - /* derived log strings */ - char *exec_path; - char *user; - char *group; + /* derived log strings */ + char *exec_path; + char *user; + char *group; } pxy_conn_lproc_desc_t; #endif /* HAVE_LOCAL_PROCINFO */ -#define WANT_CONNECT_LOG(ctx) ((ctx)->opts->connectlog||!(ctx)->opts->detach) -#define WANT_CONTENT_LOG(ctx) ((ctx)->opts->contentlog&&!(ctx)->passthrough) +#define WANT_CONNECT_LOG(ctx) ((ctx)->opts->connectlog||!(ctx)->opts->detach) +#define WANT_CONTENT_LOG(ctx) ((ctx)->opts->contentlog&&!(ctx)->passthrough) static pxy_conn_ctx_t * -pxy_conn_ctx_new(proxyspec *spec, tfe_config *opts, - pxy_thrmgr_ctx_t *thrmgr, evutil_socket_t fd) - MALLOC NONNULL(1,2,3); +pxy_conn_ctx_new( + proxyspec *spec, tfe_config *opts, + tfe_thread_manager_ctx *thrmgr, evutil_socket_t fd) +MALLOC NONNULL(1, 2, 3); static pxy_conn_ctx_t * -pxy_conn_ctx_new(proxyspec *spec, tfe_config *opts, - pxy_thrmgr_ctx_t *thrmgr, evutil_socket_t fd) +pxy_conn_ctx_new(proxyspec *spec, tfe_config *opts, tfe_thread_manager_ctx *thrmgr, evutil_socket_t fd) { - pxy_conn_ctx_t *ctx = malloc(sizeof(pxy_conn_ctx_t)); - if (!ctx) - return NULL; - memset(ctx, 0, sizeof(pxy_conn_ctx_t)); - ctx->spec = spec; - ctx->opts = opts; - ctx->clienthello_search = spec->upgrade; - ctx->fd = fd; - ctx->thridx = pxy_thrmgr_attach(thrmgr, &ctx->evbase, &ctx->dnsbase); - ctx->thrmgr = thrmgr; -#ifdef HAVE_LOCAL_PROCINFO - ctx->lproc.pid = -1; -#endif /* HAVE_LOCAL_PROCINFO */ + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)malloc(sizeof(pxy_conn_ctx_t)); + if (!ctx) return NULL; + + memset(ctx, 0, sizeof(pxy_conn_ctx_t)); + ctx->spec = spec; + ctx->opts = opts; + ctx->clienthello_search = spec->upgrade; + ctx->fd = fd; + ctx->thridx = tfe_thread_manager_attach(thrmgr, &ctx->evbase, &ctx->dnsbase); + ctx->thrmgr = thrmgr; + #ifdef DEBUG_PROXY - if (OPTS_DEBUG(opts)) { - log_dbg_printf("%p pxy_conn_ctx_new\n", - (void*)ctx); - } + if (OPTS_DEBUG(opts)) { + log_dbg_printf("%p pxy_conn_ctx_new\n", + (void*)ctx); + } #endif /* DEBUG_PROXY */ - return ctx; + return ctx; } static void NONNULL(1) pxy_conn_ctx_free(pxy_conn_ctx_t *ctx, int by_requestor) { #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("%p pxy_conn_ctx_free\n", - (void*)ctx); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("%p pxy_conn_ctx_free\n", + (void*)ctx); + } #endif /* DEBUG_PROXY */ - if (WANT_CONTENT_LOG(ctx) && ctx->logctx) { - if (log_content_close(&ctx->logctx, by_requestor) == -1) { - log_err_printf("Warning: Content log close failed\n"); - } - } - pxy_thrmgr_detach(ctx->thrmgr, ctx->thridx); - if (ctx->srchost_str) { - free(ctx->srchost_str); - } - if (ctx->srcport_str) { - free(ctx->srcport_str); - } - if (ctx->dsthost_str) { - free(ctx->dsthost_str); - } - if (ctx->dstport_str) { - free(ctx->dstport_str); - } - if (ctx->http_method) { - free(ctx->http_method); - } - if (ctx->http_uri) { - free(ctx->http_uri); - } - if (ctx->http_host) { - free(ctx->http_host); - } - if (ctx->http_content_type) { - free(ctx->http_content_type); - } - if (ctx->http_status_code) { - free(ctx->http_status_code); - } - if (ctx->http_status_text) { - free(ctx->http_status_text); - } - if (ctx->http_content_length) { - free(ctx->http_content_length); - } - if (ctx->ssl_names) { - free(ctx->ssl_names); - } - if (ctx->origcrtfpr) { - free(ctx->origcrtfpr); - } - if (ctx->usedcrtfpr) { - free(ctx->usedcrtfpr); - } -#ifdef HAVE_LOCAL_PROCINFO - if (ctx->lproc.exec_path) { - free(ctx->lproc.exec_path); - } - if (ctx->lproc.user) { - free(ctx->lproc.user); - } - if (ctx->lproc.group) { - free(ctx->lproc.group); - } -#endif /* HAVE_LOCAL_PROCINFO */ - if (ctx->origcrt) { - X509_free(ctx->origcrt); - } - if (ctx->ev) { - event_free(ctx->ev); - } - if (ctx->sni) { - free(ctx->sni); - } - free(ctx); -} + if (WANT_CONTENT_LOG(ctx) && ctx->logctx) + { + if (log_content_close(&ctx->logctx, by_requestor) == -1) + { + log_err_printf("Warning: Content log close failed\n"); + } + } + tfe_thread_manager_detach(ctx->thrmgr, ctx->thridx); + + if (ctx->srchost_str) + { + free(ctx->srchost_str); + } + if (ctx->srcport_str) + { + free(ctx->srcport_str); + } + if (ctx->dsthost_str) + { + free(ctx->dsthost_str); + } + if (ctx->dstport_str) + { + free(ctx->dstport_str); + } + if (ctx->http_method) + { + free(ctx->http_method); + } + if (ctx->http_uri) + { + free(ctx->http_uri); + } + if (ctx->http_host) + { + free(ctx->http_host); + } + if (ctx->http_content_type) + { + free(ctx->http_content_type); + } + if (ctx->http_status_code) + { + free(ctx->http_status_code); + } + if (ctx->http_status_text) + { + free(ctx->http_status_text); + } + if (ctx->http_content_length) + { + free(ctx->http_content_length); + } + if (ctx->ssl_names) + { + free(ctx->ssl_names); + } + if (ctx->origcrtfpr) + { + free(ctx->origcrtfpr); + } + if (ctx->usedcrtfpr) + { + free(ctx->usedcrtfpr); + } + if (ctx->origcrt) + { + X509_free(ctx->origcrt); + } + if (ctx->ev) + { + event_free(ctx->ev); + } + if (ctx->sni) + { + free(ctx->sni); + } + free(ctx); +} /* forward declaration of libevent callbacks */ static void pxy_bev_readcb(struct bufferevent *, void *); @@ -222,7 +227,7 @@ static int pxy_ossl_servername_cb(SSL *ssl, int *al, void *arg); static int pxy_ossl_sessnew_cb(SSL *, SSL_SESSION *); static void pxy_ossl_sessremove_cb(SSL_CTX *, SSL_SESSION *); #if OPENSSL_VERSION_NUMBER < 0x10100000L -static SSL_SESSION * pxy_ossl_sessget_cb(SSL *, unsigned char *, int, int *); +static SSL_SESSION *pxy_ossl_sessget_cb(SSL *, unsigned char *, int, int *); #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ static SSL_SESSION * pxy_ossl_sessget_cb(SSL *, const unsigned char *, int, int *); @@ -231,242 +236,228 @@ static SSL_SESSION * pxy_ossl_sessget_cb(SSL *, const unsigned char *, int, /* * Dump information on a certificate to the debug log. */ -static void -pxy_debug_crt(X509 *crt) +static void pxy_debug_crt(X509 *crt) { - char *sj = ssl_x509_subject(crt); - if (sj) { - log_dbg_printf("Subject DN: %s\n", sj); - free(sj); - } - - char *names = ssl_x509_names_to_str(crt); - if (names) { - log_dbg_printf("Common Names: %s\n", names); - free(names); - } - - char *fpr; - if (!(fpr = ssl_x509_fingerprint(crt, 1))) { - log_err_printf("Warning: Error generating X509 fingerprint\n"); - } else { - log_dbg_printf("Fingerprint: %s\n", fpr); - free(fpr); - } + char *sj = ssl_x509_subject(crt); + if (sj) + { + log_dbg_printf("Subject DN: %s\n", sj); + free(sj); + } + + char *names = ssl_x509_names_to_str(crt); + if (names) + { + log_dbg_printf("Common Names: %s\n", names); + free(names); + } + + char *fpr; + if (!(fpr = ssl_x509_fingerprint(crt, 1))) + { + log_err_printf("Warning: Error generating X509 fingerprint\n"); + } else + { + log_dbg_printf("Fingerprint: %s\n", fpr); + free(fpr); + } #ifdef DEBUG_CERTIFICATE - /* dump certificate */ - log_dbg_print_free(ssl_x509_to_str(crt)); - log_dbg_print_free(ssl_x509_to_pem(crt)); + /* dump certificate */ + log_dbg_print_free(ssl_x509_to_str(crt)); + log_dbg_print_free(ssl_x509_to_pem(crt)); #endif /* DEBUG_CERTIFICATE */ } static void pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) { - char *msg; + char *msg; #ifdef HAVE_LOCAL_PROCINFO - char *lpi = NULL; + char *lpi = NULL; #endif /* HAVE_LOCAL_PROCINFO */ - int rv; + int rv; #ifdef HAVE_LOCAL_PROCINFO - if (ctx->opts->lprocinfo) { - rv = asprintf(&lpi, "lproc:%i:%s:%s:%s", - ctx->lproc.pid, - STRORDASH(ctx->lproc.user), - STRORDASH(ctx->lproc.group), - STRORDASH(ctx->lproc.exec_path)); - if ((rv < 0) || !lpi) { - ctx->enomem = 1; - goto out; - } - } else { - lpi = ""; - } + if (ctx->opts->lprocinfo) { + rv = asprintf(&lpi, "lproc:%i:%s:%s:%s", + ctx->lproc.pid, + STRORDASH(ctx->lproc.user), + STRORDASH(ctx->lproc.group), + STRORDASH(ctx->lproc.exec_path)); + if ((rv < 0) || !lpi) { + ctx->enomem = 1; + goto out; + } + } else { + lpi = ""; + } #endif /* HAVE_LOCAL_PROCINFO */ - /* - * The following ifdef's within asprintf arguments list generates - * warnings with -Wembedded-directive on some compilers. - * Not fixing the code in order to avoid more code duplication. - */ + /* + * The following ifdef's within asprintf arguments list generates + * warnings with -Wembedded-directive on some compilers. + * Not fixing the code in order to avoid more code duplication. + */ - if (!ctx->src.ssl) { - rv = asprintf(&msg, "%s %s %s %s %s" -#ifdef HAVE_LOCAL_PROCINFO - " %s" -#endif /* HAVE_LOCAL_PROCINFO */ - "\n", - ctx->passthrough ? "passthrough" : "tcp", - STRORDASH(ctx->srchost_str), - STRORDASH(ctx->srcport_str), - STRORDASH(ctx->dsthost_str), - STRORDASH(ctx->dstport_str) -#ifdef HAVE_LOCAL_PROCINFO - , lpi -#endif /* HAVE_LOCAL_PROCINFO */ - ); - } else { - rv = asprintf(&msg, "%s %s %s %s %s " - "sni:%s names:%s " - "sproto:%s:%s dproto:%s:%s " - "origcrt:%s usedcrt:%s" + if (!ctx->src.ssl) + { + rv = asprintf(&msg, "%s %s %s %s %s" + #ifdef HAVE_LOCAL_PROCINFO + " %s" + #endif /* HAVE_LOCAL_PROCINFO */ + "\n", + ctx->passthrough ? "passthrough" : "tcp", + STRORDASH(ctx->srchost_str), + STRORDASH(ctx->srcport_str), + STRORDASH(ctx->dsthost_str), + STRORDASH(ctx->dstport_str) #ifdef HAVE_LOCAL_PROCINFO - " %s" + , lpi #endif /* HAVE_LOCAL_PROCINFO */ - "\n", - ctx->clienthello_found ? "upgrade" : "ssl", - STRORDASH(ctx->srchost_str), - STRORDASH(ctx->srcport_str), - STRORDASH(ctx->dsthost_str), - STRORDASH(ctx->dstport_str), - STRORDASH(ctx->sni), - STRORDASH(ctx->ssl_names), - SSL_get_version(ctx->src.ssl), - SSL_get_cipher(ctx->src.ssl), - SSL_get_version(ctx->dst.ssl), - SSL_get_cipher(ctx->dst.ssl), - STRORDASH(ctx->origcrtfpr), - STRORDASH(ctx->usedcrtfpr) + ); + } else + { + rv = asprintf(&msg, "%s %s %s %s %s " + "sni:%s names:%s " + "sproto:%s:%s dproto:%s:%s " + "origcrt:%s usedcrt:%s" + #ifdef HAVE_LOCAL_PROCINFO + " %s" + #endif /* HAVE_LOCAL_PROCINFO */ + "\n", + ctx->clienthello_found ? "upgrade" : "ssl", + STRORDASH(ctx->srchost_str), + STRORDASH(ctx->srcport_str), + STRORDASH(ctx->dsthost_str), + STRORDASH(ctx->dstport_str), + STRORDASH(ctx->sni), + STRORDASH(ctx->ssl_names), + SSL_get_version(ctx->src.ssl), + SSL_get_cipher(ctx->src.ssl), + SSL_get_version(ctx->dst.ssl), + SSL_get_cipher(ctx->dst.ssl), + STRORDASH(ctx->origcrtfpr), + STRORDASH(ctx->usedcrtfpr) #ifdef HAVE_LOCAL_PROCINFO - , lpi + , lpi #endif /* HAVE_LOCAL_PROCINFO */ - ); - } - if ((rv < 0) || !msg) { - ctx->enomem = 1; - goto out; - } - if (!ctx->opts->detach) { - log_err_printf("%s", msg); - } - if (ctx->opts->connectlog) { - if (log_connect_print_free(msg) == -1) { - free(msg); - log_err_printf("Warning: Connection logging failed\n"); - } - } else { - free(msg); - } + ); + } + if ((rv < 0) || !msg) + { + ctx->enomem = 1; + goto out; + } + if (!ctx->opts->detach) + { + log_err_printf("%s", msg); + } + if (ctx->opts->connectlog) + { + if (log_connect_print_free(msg) == -1) + { + free(msg); + log_err_printf("Warning: Connection logging failed\n"); + } + } else + { + free(msg); + } out: #ifdef HAVE_LOCAL_PROCINFO - if (lpi && ctx->opts->lprocinfo) { - free(lpi); - } + if (lpi && ctx->opts->lprocinfo) { + free(lpi); + } #endif /* HAVE_LOCAL_PROCINFO */ - return; + return; } static void pxy_log_connect_http(pxy_conn_ctx_t *ctx) { - char *msg; -#ifdef HAVE_LOCAL_PROCINFO - char *lpi = NULL; -#endif /* HAVE_LOCAL_PROCINFO */ - int rv; + char *msg; + int rv; #ifdef DEBUG_PROXY - if (ctx->passthrough) { - log_err_printf("Warning: pxy_log_connect_http called while in " - "passthrough mode\n"); - return; - } + if (ctx->passthrough) { + log_err_printf("Warning: pxy_log_connect_http called while in " + "passthrough mode\n"); + return; + } #endif -#ifdef HAVE_LOCAL_PROCINFO - if (ctx->opts->lprocinfo) { - rv = asprintf(&lpi, "lproc:%i:%s:%s:%s", - ctx->lproc.pid, - STRORDASH(ctx->lproc.user), - STRORDASH(ctx->lproc.group), - STRORDASH(ctx->lproc.exec_path)); - if ((rv < 0) || !lpi) { - ctx->enomem = 1; - goto out; - } - } -#endif /* HAVE_LOCAL_PROCINFO */ - /* - * The following ifdef's within asprintf arguments list generates - * warnings with -Wembedded-directive on some compilers. - * Not fixing the code in order to avoid more code duplication. - */ + /* + * The following ifdef's within asprintf arguments list generates + * warnings with -Wembedded-directive on some compilers. + * Not fixing the code in order to avoid more code duplication. + */ - if (!ctx->spec->ssl) { - rv = asprintf(&msg, "http %s %s %s %s %s %s %s %s %s" -#ifdef HAVE_LOCAL_PROCINFO - " %s" -#endif /* HAVE_LOCAL_PROCINFO */ - "%s\n", - STRORDASH(ctx->srchost_str), - STRORDASH(ctx->srcport_str), - STRORDASH(ctx->dsthost_str), - STRORDASH(ctx->dstport_str), - STRORDASH(ctx->http_host), - STRORDASH(ctx->http_method), - STRORDASH(ctx->http_uri), - STRORDASH(ctx->http_status_code), - STRORDASH(ctx->http_content_length), -#ifdef HAVE_LOCAL_PROCINFO - lpi, -#endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : ""); - } else { - rv = asprintf(&msg, "https %s %s %s %s %s %s %s %s %s " - "sni:%s names:%s " - "sproto:%s:%s dproto:%s:%s " - "origcrt:%s usedcrt:%s" -#ifdef HAVE_LOCAL_PROCINFO - " %s" -#endif /* HAVE_LOCAL_PROCINFO */ - "%s\n", - STRORDASH(ctx->srchost_str), - STRORDASH(ctx->srcport_str), - STRORDASH(ctx->dsthost_str), - STRORDASH(ctx->dstport_str), - STRORDASH(ctx->http_host), - STRORDASH(ctx->http_method), - STRORDASH(ctx->http_uri), - STRORDASH(ctx->http_status_code), - STRORDASH(ctx->http_content_length), - STRORDASH(ctx->sni), - STRORDASH(ctx->ssl_names), - SSL_get_version(ctx->src.ssl), - SSL_get_cipher(ctx->src.ssl), - SSL_get_version(ctx->dst.ssl), - SSL_get_cipher(ctx->dst.ssl), - STRORDASH(ctx->origcrtfpr), - STRORDASH(ctx->usedcrtfpr), -#ifdef HAVE_LOCAL_PROCINFO - lpi, -#endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : ""); - } - if ((rv < 0 ) || !msg) { - ctx->enomem = 1; - goto out; - } - if (!ctx->opts->detach) { - log_err_printf("%s", msg); - } - if (ctx->opts->connectlog) { - if (log_connect_print_free(msg) == -1) { - free(msg); - log_err_printf("Warning: Connection logging failed\n"); - } - } else { - free(msg); - } + if (!ctx->spec->ssl) + { + rv = asprintf(&msg, "http %s %s %s %s %s %s %s %s %s %s\n", + STRORDASH(ctx->srchost_str), + STRORDASH(ctx->srcport_str), + STRORDASH(ctx->dsthost_str), + STRORDASH(ctx->dstport_str), + STRORDASH(ctx->http_host), + STRORDASH(ctx->http_method), + STRORDASH(ctx->http_uri), + STRORDASH(ctx->http_status_code), + STRORDASH(ctx->http_content_length), + ctx->ocsp_denied ? " ocsp:denied" : ""); + } else + { + rv = asprintf(&msg, "https %s %s %s %s %s %s %s %s %s " + "sni:%s names:%s " + "sproto:%s:%s dproto:%s:%s " + "origcrt:%s usedcrt:%s" + #ifdef HAVE_LOCAL_PROCINFO + " %s" + #endif /* HAVE_LOCAL_PROCINFO */ + "%s\n", + STRORDASH(ctx->srchost_str), + STRORDASH(ctx->srcport_str), + STRORDASH(ctx->dsthost_str), + STRORDASH(ctx->dstport_str), + STRORDASH(ctx->http_host), + STRORDASH(ctx->http_method), + STRORDASH(ctx->http_uri), + STRORDASH(ctx->http_status_code), + STRORDASH(ctx->http_content_length), + STRORDASH(ctx->sni), + STRORDASH(ctx->ssl_names), + SSL_get_version(ctx->src.ssl), + SSL_get_cipher(ctx->src.ssl), + SSL_get_version(ctx->dst.ssl), + SSL_get_cipher(ctx->dst.ssl), + STRORDASH(ctx->origcrtfpr), + STRORDASH(ctx->usedcrtfpr), + ctx->ocsp_denied ? " ocsp:denied" : ""); + } + if ((rv < 0) || !msg) + { + ctx->enomem = 1; + goto out; + } + if (!ctx->opts->detach) + { + log_err_printf("%s", msg); + } + if (ctx->opts->connectlog) + { + if (log_connect_print_free(msg) == -1) + { + free(msg); + log_err_printf("Warning: Connection logging failed\n"); + } + } else + { + free(msg); + } out: -#ifdef HAVE_LOCAL_PROCINFO - if (lpi) { - free(lpi); - } -#endif /* HAVE_LOCAL_PROCINFO */ - return; + return; } /* @@ -486,26 +477,27 @@ pxy_ossl_sessnew_cb(MAYBE_UNUSED SSL *ssl, SSL_SESSION *sess) #undef MAYBE_UNUSED { #ifdef DEBUG_SESSION_CACHE - log_dbg_printf("===> OpenSSL new session callback:\n"); - if (sess) { - log_dbg_print_free(ssl_session_to_str(sess)); - } else { - log_dbg_printf("(null)\n"); - } + log_dbg_printf("===> OpenSSL new session callback:\n"); + if (sess) { + log_dbg_print_free(ssl_session_to_str(sess)); + } else { + log_dbg_printf("(null)\n"); + } #endif /* DEBUG_SESSION_CACHE */ #ifdef HAVE_SSLV2 - /* Session resumption seems to fail for SSLv2 with protocol - * parsing errors, so we disable caching for SSLv2. */ - if (SSL_version(ssl) == SSL2_VERSION) { - log_err_printf("Warning: Session resumption denied to SSLv2" - "client.\n"); - return 0; - } + /* Session resumption seems to fail for SSLv2 with protocol + * parsing errors, so we disable caching for SSLv2. */ + if (SSL_version(ssl) == SSL2_VERSION) { + log_err_printf("Warning: Session resumption denied to SSLv2" + "client.\n"); + return 0; + } #endif /* HAVE_SSLV2 */ - if (sess) { - cachemgr_ssess_set(sess); - } - return 0; + if (sess) + { + cachemgr_ssess_set(sess); + } + return 0; } /* @@ -517,16 +509,17 @@ static void pxy_ossl_sessremove_cb(UNUSED SSL_CTX *sslctx, SSL_SESSION *sess) { #ifdef DEBUG_SESSION_CACHE - log_dbg_printf("===> OpenSSL remove session callback:\n"); - if (sess) { - log_dbg_print_free(ssl_session_to_str(sess)); - } else { - log_dbg_printf("(null)\n"); - } + log_dbg_printf("===> OpenSSL remove session callback:\n"); + if (sess) { + log_dbg_print_free(ssl_session_to_str(sess)); + } else { + log_dbg_printf("(null)\n"); + } #endif /* DEBUG_SESSION_CACHE */ - if (sess) { - cachemgr_ssess_del(sess); - } + if (sess) + { + cachemgr_ssess_del(sess); + } } /* @@ -534,30 +527,28 @@ pxy_ossl_sessremove_cb(UNUSED SSL_CTX *sslctx, SSL_SESSION *sess) */ static SSL_SESSION * #if OPENSSL_VERSION_NUMBER < 0x10100000L -pxy_ossl_sessget_cb(UNUSED SSL *ssl, unsigned char *id, int idlen, - int *copy) +pxy_ossl_sessget_cb(UNUSED SSL *ssl, unsigned char *id, int idlen, int *copy) #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ -pxy_ossl_sessget_cb(UNUSED SSL *ssl, const unsigned char *id, int idlen, - int *copy) +pxy_ossl_sessget_cb(UNUSED SSL *ssl, const unsigned char *id, int idlen, int *copy) #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ { - SSL_SESSION *sess; + SSL_SESSION *sess; #ifdef DEBUG_SESSION_CACHE - log_dbg_printf("===> OpenSSL get session callback:\n"); + log_dbg_printf("===> OpenSSL get session callback:\n"); #endif /* DEBUG_SESSION_CACHE */ - *copy = 0; /* SSL should not increment reference count of session */ - sess = cachemgr_ssess_get(id, idlen); + *copy = 0; /* SSL should not increment reference count of session */ + sess = (SSL_SESSION *)cachemgr_ssess_get(id, idlen); #ifdef DEBUG_SESSION_CACHE - if (sess) { - log_dbg_print_free(ssl_session_to_str(sess)); - } + if (sess) { + log_dbg_print_free(ssl_session_to_str(sess)); + } #endif /* DEBUG_SESSION_CACHE */ - log_dbg_printf("SSL session cache: %s\n", sess ? "HIT" : "MISS"); - return sess; + log_dbg_printf("SSL session cache: %s\n", sess ? "HIT" : "MISS"); + return sess; } /* @@ -566,276 +557,308 @@ pxy_ossl_sessget_cb(UNUSED SSL *ssl, const unsigned char *id, int idlen, static void pxy_sslctx_setoptions(SSL_CTX *sslctx, pxy_conn_ctx_t *ctx) { - SSL_CTX_set_options(sslctx, SSL_OP_ALL); + SSL_CTX_set_options(sslctx, SSL_OP_ALL); #ifdef SSL_OP_TLS_ROLLBACK_BUG - SSL_CTX_set_options(sslctx, SSL_OP_TLS_ROLLBACK_BUG); + SSL_CTX_set_options(sslctx, SSL_OP_TLS_ROLLBACK_BUG); #endif /* SSL_OP_TLS_ROLLBACK_BUG */ #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - SSL_CTX_set_options(sslctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); + SSL_CTX_set_options(sslctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); #endif /* SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION */ #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); #endif /* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */ #ifdef SSL_OP_NO_TICKET - SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET); + SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET); #endif /* SSL_OP_NO_TICKET */ #ifdef SSL_OP_NO_SSLv2 #ifdef HAVE_SSLV2 - if (ctx->opts->no_ssl2) { + if (ctx->opts->no_ssl2) { #endif /* HAVE_SSLV2 */ - SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2); + SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2); #ifdef HAVE_SSLV2 - } + } #endif /* HAVE_SSLV2 */ #endif /* !SSL_OP_NO_SSLv2 */ #ifdef HAVE_SSLV3 - if (ctx->opts->no_ssl3) { - SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3); - } + if (ctx->opts->no_ssl3) + { + SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3); + } #endif /* HAVE_SSLV3 */ #ifdef HAVE_TLSV10 - if (ctx->opts->no_tls10) { - SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1); - } + if (ctx->opts->no_tls10) + { + SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1); + } #endif /* HAVE_TLSV10 */ #ifdef HAVE_TLSV11 - if (ctx->opts->no_tls11) { - SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1); - } + if (ctx->opts->no_tls11) + { + SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1); + } #endif /* HAVE_TLSV11 */ #ifdef HAVE_TLSV12 - if (ctx->opts->no_tls12) { - SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2); - } + if (ctx->opts->no_tls12) + { + SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2); + } #endif /* HAVE_TLSV12 */ #ifdef SSL_OP_NO_COMPRESSION - if (!ctx->opts->sslcomp) { - SSL_CTX_set_options(sslctx, SSL_OP_NO_COMPRESSION); - } + if (!ctx->opts->sslcomp) + { + SSL_CTX_set_options(sslctx, SSL_OP_NO_COMPRESSION); + } #endif /* SSL_OP_NO_COMPRESSION */ - SSL_CTX_set_cipher_list(sslctx, ctx->opts->ciphers); + SSL_CTX_set_cipher_list(sslctx, ctx->opts->ciphers); } /* * Create and set up a new SSL_CTX instance for terminating SSL. * Set up all the necessary callbacks, the certificate, the cert chain and key. */ -static SSL_CTX * -pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, - EVP_PKEY *key) +static SSL_CTX * pxy_srcsslctx_create( + pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, + EVP_PKEY *key) { - SSL_CTX *sslctx = SSL_CTX_new(ctx->opts->sslmethod()); - if (!sslctx) - return NULL; + SSL_CTX *sslctx = SSL_CTX_new(ctx->opts->sslmethod()); + if (!sslctx) + return NULL; - pxy_sslctx_setoptions(sslctx, ctx); + pxy_sslctx_setoptions(sslctx, ctx); #if OPENSSL_VERSION_NUMBER >= 0x10100000L - if (ctx->opts->sslversion) { - if (SSL_CTX_set_min_proto_version(sslctx, ctx->opts->sslversion) == 0 || - SSL_CTX_set_max_proto_version(sslctx, ctx->opts->sslversion) == 0) { - SSL_CTX_free(sslctx); - return NULL; - } - } + if (ctx->opts->sslversion) { + if (SSL_CTX_set_min_proto_version(sslctx, ctx->opts->sslversion) == 0 || + SSL_CTX_set_max_proto_version(sslctx, ctx->opts->sslversion) == 0) { + SSL_CTX_free(sslctx); + return NULL; + } + } #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - SSL_CTX_sess_set_new_cb(sslctx, pxy_ossl_sessnew_cb); - SSL_CTX_sess_set_remove_cb(sslctx, pxy_ossl_sessremove_cb); - SSL_CTX_sess_set_get_cb(sslctx, pxy_ossl_sessget_cb); - SSL_CTX_set_session_cache_mode(sslctx, SSL_SESS_CACHE_SERVER | - SSL_SESS_CACHE_NO_INTERNAL); + SSL_CTX_sess_set_new_cb(sslctx, pxy_ossl_sessnew_cb); + SSL_CTX_sess_set_remove_cb(sslctx, pxy_ossl_sessremove_cb); + SSL_CTX_sess_set_get_cb(sslctx, pxy_ossl_sessget_cb); + SSL_CTX_set_session_cache_mode(sslctx, SSL_SESS_CACHE_SERVER | + SSL_SESS_CACHE_NO_INTERNAL); #ifdef USE_SSL_SESSION_ID_CONTEXT - SSL_CTX_set_session_id_context(sslctx, (void *)(&ssl_session_context), - sizeof(ssl_session_context)); + SSL_CTX_set_session_id_context(sslctx, (void *)(&ssl_session_context), + sizeof(ssl_session_context)); #endif /* USE_SSL_SESSION_ID_CONTEXT */ #ifndef OPENSSL_NO_TLSEXT - SSL_CTX_set_tlsext_servername_callback(sslctx, pxy_ossl_servername_cb); - SSL_CTX_set_tlsext_servername_arg(sslctx, ctx); + SSL_CTX_set_tlsext_servername_callback(sslctx, pxy_ossl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(sslctx, ctx); #endif /* !OPENSSL_NO_TLSEXT */ #ifndef OPENSSL_NO_DH - if (ctx->opts->dh) { - SSL_CTX_set_tmp_dh(sslctx, ctx->opts->dh); - } else { - SSL_CTX_set_tmp_dh_callback(sslctx, ssl_tmp_dh_callback); - } + if (ctx->opts->dh) + { + SSL_CTX_set_tmp_dh(sslctx, ctx->opts->dh); + } else + { + SSL_CTX_set_tmp_dh_callback(sslctx, ssl_tmp_dh_callback); + } #endif /* !OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH - if (ctx->opts->ecdhcurve) { - EC_KEY *ecdh = ssl_ec_by_name(ctx->opts->ecdhcurve); - SSL_CTX_set_tmp_ecdh(sslctx, ecdh); - EC_KEY_free(ecdh); - } else { - EC_KEY *ecdh = ssl_ec_by_name(NULL); - SSL_CTX_set_tmp_ecdh(sslctx, ecdh); - EC_KEY_free(ecdh); - } + if (ctx->opts->ecdhcurve) + { + EC_KEY *ecdh = ssl_ec_by_name(ctx->opts->ecdhcurve); + SSL_CTX_set_tmp_ecdh(sslctx, ecdh); + EC_KEY_free(ecdh); + } else + { + EC_KEY *ecdh = ssl_ec_by_name(NULL); + SSL_CTX_set_tmp_ecdh(sslctx, ecdh); + EC_KEY_free(ecdh); + } #endif /* !OPENSSL_NO_ECDH */ - SSL_CTX_use_certificate(sslctx, crt); - SSL_CTX_use_PrivateKey(sslctx, key); - for (int i = 0; i < sk_X509_num(chain); i++) { - X509 *c = sk_X509_value(chain, i); - ssl_x509_refcount_inc(c); /* next call consumes a reference */ - SSL_CTX_add_extra_chain_cert(sslctx, c); - } + SSL_CTX_use_certificate(sslctx, crt); + SSL_CTX_use_PrivateKey(sslctx, key); + for (int i = 0; i < sk_X509_num(chain); i++) + { + X509 *c = sk_X509_value(chain, i); + ssl_x509_refcount_inc(c); /* next call consumes a reference */ + SSL_CTX_add_extra_chain_cert(sslctx, c); + } #ifdef DEBUG_SESSION_CACHE - if (OPTS_DEBUG(ctx->opts)) { - int mode = SSL_CTX_get_session_cache_mode(sslctx); - log_dbg_printf("SSL session cache mode: %08x\n", mode); - if (mode == SSL_SESS_CACHE_OFF) - log_dbg_printf("SSL_SESS_CACHE_OFF\n"); - if (mode & SSL_SESS_CACHE_CLIENT) - log_dbg_printf("SSL_SESS_CACHE_CLIENT\n"); - if (mode & SSL_SESS_CACHE_SERVER) - log_dbg_printf("SSL_SESS_CACHE_SERVER\n"); - if (mode & SSL_SESS_CACHE_NO_AUTO_CLEAR) - log_dbg_printf("SSL_SESS_CACHE_NO_AUTO_CLEAR\n"); - if (mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) - log_dbg_printf("SSL_SESS_CACHE_NO_INTERNAL_LOOKUP\n"); - if (mode & SSL_SESS_CACHE_NO_INTERNAL_STORE) - log_dbg_printf("SSL_SESS_CACHE_NO_INTERNAL_STORE\n"); - } + if (OPTS_DEBUG(ctx->opts)) { + int mode = SSL_CTX_get_session_cache_mode(sslctx); + log_dbg_printf("SSL session cache mode: %08x\n", mode); + if (mode == SSL_SESS_CACHE_OFF) + log_dbg_printf("SSL_SESS_CACHE_OFF\n"); + if (mode & SSL_SESS_CACHE_CLIENT) + log_dbg_printf("SSL_SESS_CACHE_CLIENT\n"); + if (mode & SSL_SESS_CACHE_SERVER) + log_dbg_printf("SSL_SESS_CACHE_SERVER\n"); + if (mode & SSL_SESS_CACHE_NO_AUTO_CLEAR) + log_dbg_printf("SSL_SESS_CACHE_NO_AUTO_CLEAR\n"); + if (mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) + log_dbg_printf("SSL_SESS_CACHE_NO_INTERNAL_LOOKUP\n"); + if (mode & SSL_SESS_CACHE_NO_INTERNAL_STORE) + log_dbg_printf("SSL_SESS_CACHE_NO_INTERNAL_STORE\n"); + } #endif /* DEBUG_SESSION_CACHE */ - return sslctx; + return sslctx; } static int pxy_srccert_write_to_gendir(pxy_conn_ctx_t *ctx, X509 *crt, int is_orig) { - char *fn; - int rv; - - if (!ctx->origcrtfpr) - return -1; - if (is_orig) { - rv = asprintf(&fn, "%s/%s.crt", ctx->opts->certgendir, - ctx->origcrtfpr); - } else { - if (!ctx->usedcrtfpr) - return -1; - rv = asprintf(&fn, "%s/%s-%s.crt", ctx->opts->certgendir, - ctx->origcrtfpr, ctx->usedcrtfpr); - } - if (rv == -1) { - ctx->enomem = 1; - return -1; - } - rv = log_cert_submit(fn, crt); - free(fn); - return rv; + char *fn; + int rv; + + if (!ctx->origcrtfpr) + return -1; + if (is_orig) + { + rv = asprintf(&fn, "%s/%s.crt", ctx->opts->certgendir, + ctx->origcrtfpr); + } else + { + if (!ctx->usedcrtfpr) + return -1; + rv = asprintf(&fn, "%s/%s-%s.crt", ctx->opts->certgendir, + ctx->origcrtfpr, ctx->usedcrtfpr); + } + if (rv == -1) + { + ctx->enomem = 1; + return -1; + } + rv = log_cert_submit(fn, crt); + free(fn); + return rv; } -static void -pxy_srccert_write(pxy_conn_ctx_t *ctx) +static void pxy_srccert_write(pxy_conn_ctx_t *ctx) { - if (ctx->opts->certgen_writeall || ctx->generated_cert) { - if (pxy_srccert_write_to_gendir(ctx, - SSL_get_certificate(ctx->src.ssl), 0) == -1) { - log_err_printf("Failed to write used certificate\n"); - } - } - if (ctx->opts->certgen_writeall) { - if (pxy_srccert_write_to_gendir(ctx, ctx->origcrt, 1) == -1) { - log_err_printf("Failed to write orig certificate\n"); - } - } + if (ctx->opts->certgen_writeall || ctx->generated_cert) + { + if (pxy_srccert_write_to_gendir(ctx, + SSL_get_certificate(ctx->src.ssl), 0) == -1) + { + log_err_printf("Failed to write used certificate\n"); + } + } + if (ctx->opts->certgen_writeall) + { + if (pxy_srccert_write_to_gendir(ctx, ctx->origcrt, 1) == -1) + { + log_err_printf("Failed to write orig certificate\n"); + } + } } -static cert_t * -pxy_srccert_create(pxy_conn_ctx_t *ctx) +static cert_t * pxy_srccert_create(pxy_conn_ctx_t *ctx) { - cert_t *cert = NULL; - - if (ctx->opts->tgcrtdir) { - if (ctx->sni) { - cert = cachemgr_tgcrt_get(ctx->sni); - if (!cert) { - char *wildcarded; - wildcarded = ssl_wildcardify(ctx->sni); - if (!wildcarded) { - ctx->enomem = 1; - return NULL; - } - cert = cachemgr_tgcrt_get(wildcarded); - free(wildcarded); - } - if (cert && OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Target cert by SNI\n"); - } - } else if (ctx->origcrt) { - char **names = ssl_x509_names(ctx->origcrt); - for (char **p = names; *p; p++) { - if (!cert) { - cert = cachemgr_tgcrt_get(*p); - } - if (!cert) { - char *wildcarded; - wildcarded = ssl_wildcardify(*p); - if (!wildcarded) { - ctx->enomem = 1; - } else { - cert = cachemgr_tgcrt_get( - wildcarded); - free(wildcarded); - } - } - free(*p); - } - free(names); - if (ctx->enomem) { - return NULL; - } - if (cert && OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Target cert by origcrt\n"); - } - } - - if (cert) { - ctx->immutable_cert = 1; - } - } - - if (!cert && ctx->origcrt && ctx->opts->key) { - cert = cert_new(); - - cert->crt = cachemgr_fkcrt_get(ctx->origcrt); - if (cert->crt) { - if (OPTS_DEBUG(ctx->opts)) - log_dbg_printf("Certificate cache: HIT\n"); - } else { - if (OPTS_DEBUG(ctx->opts)) - log_dbg_printf("Certificate cache: MISS\n"); - cert->crt = ssl_x509_forge(ctx->opts->cacrt, - ctx->opts->cakey, - ctx->origcrt, - ctx->opts->key, - NULL, - ctx->opts->crlurl); - cachemgr_fkcrt_set(ctx->origcrt, cert->crt); - } - cert_set_key(cert, ctx->opts->key); - cert_set_chain(cert, ctx->opts->chain); - ctx->generated_cert = 1; - } - - if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) && ctx->origcrt) { - ctx->origcrtfpr = ssl_x509_fingerprint(ctx->origcrt, 0); - if (!ctx->origcrtfpr) - ctx->enomem = 1; - } - if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) && - cert && cert->crt) { - ctx->usedcrtfpr = ssl_x509_fingerprint(cert->crt, 0); - if (!ctx->usedcrtfpr) - ctx->enomem = 1; - } - - return cert; + cert_t *cert = NULL; + if (ctx->opts->tgcrtdir) + { + if (ctx->sni) + { + cert = (cert_t *)cachemgr_tgcrt_get(ctx->sni); + if (!cert) + { + char *wildcarded = ssl_wildcardify(ctx->sni); + if (!wildcarded) + { + ctx->enomem = 1; + return NULL; + } + cert = (cert_t *)cachemgr_tgcrt_get(wildcarded); + free(wildcarded); + } + if (cert && OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Target cert by SNI\n"); + } + } + else if (ctx->origcrt) + { + char **names = ssl_x509_names(ctx->origcrt); + for (char **p = names; *p; p++) + { + if (!cert) + { + cert = (cert_t *)cachemgr_tgcrt_get(*p); + } + if (!cert) + { + char *wildcarded = ssl_wildcardify(*p); + if (!wildcarded) + { + ctx->enomem = 1; + } else + { + cert = (cert_t *) (wildcarded); + free(wildcarded); + } + } + free(*p); + } + free(names); + if (ctx->enomem) + { + return NULL; + } + if (cert && OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Target cert by origcrt\n"); + } + } + + if (cert) + { + ctx->immutable_cert = 1; + } + } + + if (!cert && ctx->origcrt && ctx->opts->key) + { + cert = cert_new(); + cert->crt = (X509 *)cachemgr_fkcrt_get(ctx->origcrt); + + if (cert->crt) + { + if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: HIT\n"); + } + else + { + if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: MISS\n"); + cert->crt = ssl_x509_forge(ctx->opts->cacrt, + ctx->opts->cakey, + ctx->origcrt, + ctx->opts->key, + NULL, + ctx->opts->crlurl); + cachemgr_fkcrt_set(ctx->origcrt, cert->crt); + } + + cert_set_key(cert, ctx->opts->key); + cert_set_chain(cert, ctx->opts->chain); + ctx->generated_cert = 1; + } + + if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) && ctx->origcrt) + { + ctx->origcrtfpr = ssl_x509_fingerprint(ctx->origcrt, 0); + if (!ctx->origcrtfpr) + ctx->enomem = 1; + } + + if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) && + cert && cert->crt) + { + ctx->usedcrtfpr = ssl_x509_fingerprint(cert->crt, 0); + if (!ctx->usedcrtfpr) + ctx->enomem = 1; + } + + return cert; } /* @@ -843,64 +866,69 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) * destination SSL certificate. * Returns NULL if no suitable certificate could be found. */ -static SSL * -pxy_srcssl_create(pxy_conn_ctx_t *ctx, SSL *origssl) +static SSL * pxy_srcssl_create(pxy_conn_ctx_t *ctx, SSL *origssl) { - cert_t *cert; - - cachemgr_dsess_set((struct sockaddr*)&ctx->addr, - ctx->addrlen, ctx->sni, - SSL_get0_session(origssl)); - - ctx->origcrt = SSL_get_peer_certificate(origssl); - - if (OPTS_DEBUG(ctx->opts)) { - if (ctx->origcrt) { - log_dbg_printf("===> Original server certificate:\n"); - pxy_debug_crt(ctx->origcrt); - } else { - log_dbg_printf("===> Original server has no cert!\n"); - } - } - - cert = pxy_srccert_create(ctx); - if (!cert) - return NULL; - - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("===> Forged server certificate:\n"); - pxy_debug_crt(cert->crt); - } - - if (WANT_CONNECT_LOG(ctx)) { - ctx->ssl_names = ssl_x509_names_to_str(ctx->origcrt ? - ctx->origcrt : - cert->crt); - if (!ctx->ssl_names) - ctx->enomem = 1; - } - - SSL_CTX *sslctx = pxy_srcsslctx_create(ctx, cert->crt, cert->chain, - cert->key); - cert_free(cert); - if (!sslctx) { - ctx->enomem = 1; - return NULL; - } - SSL *ssl = SSL_new(sslctx); - SSL_CTX_free(sslctx); /* SSL_new() increments refcount */ - if (!ssl) { - ctx->enomem = 1; - return NULL; - } + cert_t *cert; + + cachemgr_dsess_set((struct sockaddr *) &ctx->addr, + ctx->addrlen, ctx->sni, + SSL_get0_session(origssl)); + + ctx->origcrt = SSL_get_peer_certificate(origssl); + + if (OPTS_DEBUG(ctx->opts)) + { + if (ctx->origcrt) + { + log_dbg_printf("===> Original server certificate:\n"); + pxy_debug_crt(ctx->origcrt); + } else + { + log_dbg_printf("===> Original server has no cert!\n"); + } + } + + cert = pxy_srccert_create(ctx); + if (!cert) + return NULL; + + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("===> Forged server certificate:\n"); + pxy_debug_crt(cert->crt); + } + + if (WANT_CONNECT_LOG(ctx)) + { + ctx->ssl_names = ssl_x509_names_to_str(ctx->origcrt ? + ctx->origcrt : + cert->crt); + if (!ctx->ssl_names) + ctx->enomem = 1; + } + + SSL_CTX *sslctx = pxy_srcsslctx_create(ctx, cert->crt, cert->chain, + cert->key); + cert_free(cert); + if (!sslctx) + { + ctx->enomem = 1; + return NULL; + } + SSL *ssl = SSL_new(sslctx); + SSL_CTX_free(sslctx); /* SSL_new() increments refcount */ + if (!ssl) + { + ctx->enomem = 1; + return NULL; + } #ifdef SSL_MODE_RELEASE_BUFFERS - /* lower memory footprint for idle connections */ - SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS); + /* lower memory footprint for idle connections */ + SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS); #endif /* SSL_MODE_RELEASE_BUFFERS */ - return ssl; + return ssl; } -#ifndef OPENSSL_NO_TLSEXT /* * OpenSSL servername callback, called when OpenSSL receives a servername * TLS extension in the clientHello. Must switch to a new SSL_CTX with @@ -910,108 +938,123 @@ pxy_srcssl_create(pxy_conn_ctx_t *ctx, SSL *origssl) * server supplies a certificate which does not match the server name we * indicate to it. */ -static int -pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg) +static int pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg) { - pxy_conn_ctx_t *ctx = arg; - const char *sn; - X509 *sslcrt; - - if (!(sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) - return SSL_TLSEXT_ERR_NOACK; - - if (!ctx->sni) { - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Warning: SNI parser yielded no " - "hostname, copying OpenSSL one: " - "[NULL] != [%s]\n", sn); - } - ctx->sni = strdup(sn); - if (!ctx->sni) { - ctx->enomem = 1; - return SSL_TLSEXT_ERR_NOACK; - } - } - if (OPTS_DEBUG(ctx->opts)) { - if (!!strcmp(sn, ctx->sni)) { - /* - * This may happen if the client resumes a session, but - * uses a different SNI hostname when resuming than it - * used when the session was created. OpenSSL - * correctly ignores the SNI in the ClientHello in this - * case, but since we have already sent the SNI onwards - * to the original destination, there is no way back. - * We log an error and hope this never happens. - */ - log_dbg_printf("Warning: SNI parser yielded different " - "hostname than OpenSSL callback for " - "the same ClientHello message: " - "[%s] != [%s]\n", ctx->sni, sn); - } - } - - /* generate a new certificate with sn as additional altSubjectName - * and replace it both in the current SSL ctx and in the cert cache */ - if (!ctx->immutable_cert && - !ssl_x509_names_match((sslcrt = SSL_get_certificate(ssl)), sn)) { - X509 *newcrt; - SSL_CTX *newsslctx; - - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Certificate cache: UPDATE " - "(SNI mismatch)\n"); - } - newcrt = ssl_x509_forge(ctx->opts->cacrt, ctx->opts->cakey, - sslcrt, ctx->opts->key, - sn, ctx->opts->crlurl); - if (!newcrt) { - ctx->enomem = 1; - return SSL_TLSEXT_ERR_NOACK; - } - cachemgr_fkcrt_set(ctx->origcrt, newcrt); - ctx->generated_cert = 1; - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("===> Updated forged server " - "certificate:\n"); - pxy_debug_crt(newcrt); - } - if (WANT_CONNECT_LOG(ctx)) { - if (ctx->ssl_names) { - free(ctx->ssl_names); - } - ctx->ssl_names = ssl_x509_names_to_str(newcrt); - if (!ctx->ssl_names) { - ctx->enomem = 1; - } - } - if (WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) { - if (ctx->usedcrtfpr) { - free(ctx->usedcrtfpr); - } - ctx->usedcrtfpr = ssl_x509_fingerprint(newcrt, 0); - if (!ctx->usedcrtfpr) { - ctx->enomem = 1; - } - } - - newsslctx = pxy_srcsslctx_create(ctx, newcrt, ctx->opts->chain, - ctx->opts->key); - if (!newsslctx) { - X509_free(newcrt); - ctx->enomem = 1; - return SSL_TLSEXT_ERR_NOACK; - } - SSL_set_SSL_CTX(ssl, newsslctx); /* decr's old incr new refc */ - SSL_CTX_free(newsslctx); - X509_free(newcrt); - } else if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Certificate cache: KEEP (SNI match or " - "target mode)\n"); - } - - return SSL_TLSEXT_ERR_OK; + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; + const char *sn; + X509 *sslcrt; + + if (!(sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) + return SSL_TLSEXT_ERR_NOACK; + + if (!ctx->sni) + { + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Warning: SNI parser yielded no " + "hostname, copying OpenSSL one: " + "[NULL] != [%s]\n", sn); + } + ctx->sni = strdup(sn); + if (!ctx->sni) + { + ctx->enomem = 1; + return SSL_TLSEXT_ERR_NOACK; + } + } + if (OPTS_DEBUG(ctx->opts)) + { + if (strcmp(sn, ctx->sni) != 0) + { + /* + * This may happen if the client resumes a session, but + * uses a different SNI hostname when resuming than it + * used when the session was created. OpenSSL + * correctly ignores the SNI in the ClientHello in this + * case, but since we have already sent the SNI onwards + * to the original destination, there is no way back. + * We log an error and hope this never happens. + */ + log_dbg_printf("Warning: SNI parser yielded different " + "hostname than OpenSSL callback for " + "the same ClientHello message: " + "[%s] != [%s]\n", ctx->sni, sn); + } + } + + /* generate a new certificate with sn as additional altSubjectName + * and replace it both in the current SSL ctx and in the cert cache */ + if (!ctx->immutable_cert && + !ssl_x509_names_match((sslcrt = SSL_get_certificate(ssl)), sn)) + { + X509 *newcrt; + SSL_CTX *newsslctx; + + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Certificate cache: UPDATE " + "(SNI mismatch)\n"); + } + newcrt = ssl_x509_forge(ctx->opts->cacrt, ctx->opts->cakey, + sslcrt, ctx->opts->key, + sn, ctx->opts->crlurl); + if (!newcrt) + { + ctx->enomem = 1; + return SSL_TLSEXT_ERR_NOACK; + } + cachemgr_fkcrt_set(ctx->origcrt, newcrt); + ctx->generated_cert = 1; + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("===> Updated forged server " + "certificate:\n"); + pxy_debug_crt(newcrt); + } + if (WANT_CONNECT_LOG(ctx)) + { + if (ctx->ssl_names) + { + free(ctx->ssl_names); + } + ctx->ssl_names = ssl_x509_names_to_str(newcrt); + if (!ctx->ssl_names) + { + ctx->enomem = 1; + } + } + if (WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) + { + if (ctx->usedcrtfpr) + { + free(ctx->usedcrtfpr); + } + ctx->usedcrtfpr = ssl_x509_fingerprint(newcrt, 0); + if (!ctx->usedcrtfpr) + { + ctx->enomem = 1; + } + } + + newsslctx = pxy_srcsslctx_create(ctx, newcrt, ctx->opts->chain, + ctx->opts->key); + if (!newsslctx) + { + X509_free(newcrt); + ctx->enomem = 1; + return SSL_TLSEXT_ERR_NOACK; + } + SSL_set_SSL_CTX(ssl, newsslctx); /* decr's old incr new refc */ + SSL_CTX_free(newsslctx); + X509_free(newcrt); + } else if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Certificate cache: KEEP (SNI match or " + "target mode)\n"); + } + + return SSL_TLSEXT_ERR_OK; } -#endif /* !OPENSSL_NO_TLSEXT */ /* * Create new SSL context for outgoing connections to the original destination. @@ -1020,60 +1063,65 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg) static SSL * pxy_dstssl_create(pxy_conn_ctx_t *ctx) { - SSL_CTX *sslctx; - SSL *ssl; - SSL_SESSION *sess; + SSL_CTX *sslctx; + SSL *ssl; + SSL_SESSION *sess; - sslctx = SSL_CTX_new(ctx->opts->sslmethod()); - if (!sslctx) { - ctx->enomem = 1; - return NULL; - } + sslctx = SSL_CTX_new(ctx->opts->sslmethod()); + if (!sslctx) + { + ctx->enomem = 1; + return NULL; + } - pxy_sslctx_setoptions(sslctx, ctx); + pxy_sslctx_setoptions(sslctx, ctx); #if OPENSSL_VERSION_NUMBER >= 0x10100000L - if (ctx->opts->sslversion) { - if (SSL_CTX_set_min_proto_version(sslctx, ctx->opts->sslversion) == 0 || - SSL_CTX_set_max_proto_version(sslctx, ctx->opts->sslversion) == 0) { - SSL_CTX_free(sslctx); - ctx->enomem = 1; - return NULL; - } - } + if (ctx->opts->sslversion) { + if (SSL_CTX_set_min_proto_version(sslctx, ctx->opts->sslversion) == 0 || + SSL_CTX_set_max_proto_version(sslctx, ctx->opts->sslversion) == 0) { + SSL_CTX_free(sslctx); + ctx->enomem = 1; + return NULL; + } + } #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, NULL); - ssl = SSL_new(sslctx); - SSL_CTX_free(sslctx); /* SSL_new() increments refcount */ - if (!ssl) { - ctx->enomem = 1; - return NULL; - } + ssl = SSL_new(sslctx); + SSL_CTX_free(sslctx); /* SSL_new() increments refcount */ + if (!ssl) + { + ctx->enomem = 1; + return NULL; + } #ifndef OPENSSL_NO_TLSEXT - if (ctx->sni) { - SSL_set_tlsext_host_name(ssl, ctx->sni); - } + if (ctx->sni) + { + SSL_set_tlsext_host_name(ssl, ctx->sni); + } #endif /* !OPENSSL_NO_TLSEXT */ #ifdef SSL_MODE_RELEASE_BUFFERS - /* lower memory footprint for idle connections */ - SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS); + /* lower memory footprint for idle connections */ + SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS); #endif /* SSL_MODE_RELEASE_BUFFERS */ - /* session resuming based on remote endpoint address and port */ - sess = (SSL_SESSION *)cachemgr_dsess_get((struct sockaddr *)&ctx->addr, - ctx->addrlen, ctx->sni); /* new sess inst */ - if (sess) { - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Attempt reuse dst SSL session\n"); - } - SSL_set_session(ssl, sess); /* increments sess refcount */ - SSL_SESSION_free(sess); - } - - return ssl; + /* session resuming based on remote endpoint address and port */ + sess = (SSL_SESSION *) cachemgr_dsess_get((struct sockaddr *) &ctx->addr, + ctx->addrlen, ctx->sni); /* new sess inst */ + if (sess) + { + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Attempt reuse dst SSL session\n"); + } + SSL_set_session(ssl, sess); /* increments sess refcount */ + SSL_SESSION_free(sess); + } + + return ssl; } /* @@ -1083,27 +1131,30 @@ pxy_dstssl_create(pxy_conn_ctx_t *ctx) static void bufferevent_free_and_close_fd(struct bufferevent *bev, pxy_conn_ctx_t *ctx) { - evutil_socket_t fd = bufferevent_getfd(bev); - SSL *ssl = NULL; + evutil_socket_t fd = bufferevent_getfd(bev); + SSL *ssl = NULL; - if ((ctx->spec->ssl || ctx->clienthello_found) && !ctx->passthrough) { - ssl = bufferevent_openssl_get_ssl(bev); /* does not inc refc */ - } + if ((ctx->spec->ssl || ctx->clienthello_found) && !ctx->passthrough) + { + ssl = bufferevent_openssl_get_ssl(bev); /* does not inc refc */ + } #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf(" %p free_and_close_fd\n", - (void*)bev); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf(" %p free_and_close_fd\n", + (void*)bev); + } #endif /* DEBUG_PROXY */ - bufferevent_free(bev); /* does not free SSL unless the option + bufferevent_free(bev); /* does not free SSL unless the option BEV_OPT_CLOSE_ON_FREE was set */ - if (ssl) { - pxy_ssl_shutdown(ctx->opts, ctx->evbase, ssl, fd); - } else { - evutil_closesocket(fd); - } + if (ssl) + { + pxy_ssl_shutdown(ctx->opts, ctx->evbase, ssl, fd); + } else + { + evutil_closesocket(fd); + } } /* @@ -1120,259 +1171,91 @@ bufferevent_free_and_close_fd(struct bufferevent *bev, pxy_conn_ctx_t *ctx) static struct bufferevent * pxy_bufferevent_setup(pxy_conn_ctx_t *ctx, evutil_socket_t fd, SSL *ssl) { - struct bufferevent *bev; - - if (ssl) { - bev = bufferevent_openssl_socket_new(ctx->evbase, fd, ssl, - ((fd == -1) ? BUFFEREVENT_SSL_CONNECTING - : BUFFEREVENT_SSL_ACCEPTING), - BEV_OPT_DEFER_CALLBACKS); - } else { - bev = bufferevent_socket_new(ctx->evbase, fd, - BEV_OPT_DEFER_CALLBACKS); - } - if (!bev) { - log_err_printf("Error creating bufferevent socket\n"); - return NULL; - } + struct bufferevent *bev; + + if (ssl) + { + bev = bufferevent_openssl_socket_new(ctx->evbase, fd, ssl, + ((fd == -1) ? BUFFEREVENT_SSL_CONNECTING + : BUFFEREVENT_SSL_ACCEPTING), + BEV_OPT_DEFER_CALLBACKS); + } else + { + bev = bufferevent_socket_new(ctx->evbase, fd, + BEV_OPT_DEFER_CALLBACKS); + } + if (!bev) + { + log_err_printf("Error creating bufferevent socket\n"); + return NULL; + } #if LIBEVENT_VERSION_NUMBER >= 0x02010000 - if (ssl) { - /* Prevent unclean (dirty) shutdowns to cause error - * events on the SSL socket bufferevent. */ - bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); - } + if (ssl) + { + /* Prevent unclean (dirty) shutdowns to cause error + * events on the SSL socket bufferevent. */ + bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); + } #endif /* LIBEVENT_VERSION_NUMBER >= 0x02010000 */ - bufferevent_setcb(bev, pxy_bev_readcb, pxy_bev_writecb, - pxy_bev_eventcb, ctx); - bufferevent_enable(bev, EV_READ|EV_WRITE); + bufferevent_setcb(bev, pxy_bev_readcb, pxy_bev_writecb, + pxy_bev_eventcb, ctx); + bufferevent_enable(bev, EV_READ | EV_WRITE); #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf(" %p pxy_bufferevent_setup\n", - (void*)bev); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf(" %p pxy_bufferevent_setup\n", + (void*)bev); + } #endif /* DEBUG_PROXY */ - return bev; -} - -/* - * Filter a single line of HTTP request headers. - * Also fills in some context fields for logging. - * - * Returns NULL if the current line should be deleted from the request. - * Returns a newly allocated string if the current line should be replaced. - * Returns `line' if the line should be kept. - */ -static char * -pxy_http_reqhdr_filter_line(const char *line, pxy_conn_ctx_t *ctx) -{ - /* parse information for connect log */ - if (!ctx->http_method) { - /* first line */ - char *space1, *space2; - - space1 = strchr(line, ' '); - space2 = space1 ? strchr(space1 + 1, ' ') : NULL; - if (!space1) { - /* not HTTP */ - ctx->seen_req_header = 1; - } else { - ctx->http_method = malloc(space1 - line + 1); - if (ctx->http_method) { - memcpy(ctx->http_method, line, space1 - line); - ctx->http_method[space1 - line] = '\0'; - } else { - ctx->enomem = 1; - return NULL; - } - space1++; - if (!space2) { - /* HTTP/0.9 */ - ctx->seen_req_header = 1; - space2 = space1 + strlen(space1); - } - ctx->http_uri = malloc(space2 - space1 + 1); - if (ctx->http_uri) { - memcpy(ctx->http_uri, space1, space2 - space1); - ctx->http_uri[space2 - space1] = '\0'; - } else { - ctx->enomem = 1; - return NULL; - } - } - } else { - /* not first line */ - char *newhdr; - - if (!ctx->http_host && !strncasecmp(line, "Host:", 5)) { - ctx->http_host = strdup(util_skipws(line + 5)); - if (!ctx->http_host) { - ctx->enomem = 1; - return NULL; - } - } else if (!strncasecmp(line, "Content-Type:", 13)) { - ctx->http_content_type = strdup(util_skipws(line + 13)); - if (!ctx->http_content_type) { - ctx->enomem = 1; - return NULL; - } - /* Override Connection: keepalive and Connection: upgrade */ - } else if (!strncasecmp(line, "Connection:", 11)) { - ctx->sent_http_conn_close = 1; - if (!(newhdr = strdup("Connection: close"))) { - ctx->enomem = 1; - return NULL; - } - return newhdr; - /* Suppress upgrading to SSL/TLS, WebSockets or HTTP/2, - * unsupported encodings, and keep-alive */ - } else if (!strncasecmp(line, "Upgrade:", 8) || - !strncasecmp(line, "Accept-Encoding:", 16) || - !strncasecmp(line, "Keep-Alive:", 11)) { - return NULL; - } else if (line[0] == '\0') { - ctx->seen_req_header = 1; - if (!ctx->sent_http_conn_close) { - newhdr = strdup("Connection: close\r\n"); - if (!newhdr) { - ctx->enomem = 1; - return NULL; - } - return newhdr; - } - } - } - - return (char*)line; + return bev; } -/* - * Filter a single line of HTTP response headers. - * - * Returns NULL if the current line should be deleted from the response. - * Returns a newly allocated string if the current line should be replaced. - * Returns `line' if the line should be kept. - */ -static char * -pxy_http_resphdr_filter_line(const char *line, pxy_conn_ctx_t *ctx) +static int pxy_ocsp_is_valid_uri(const char *uri, pxy_conn_ctx_t *ctx) { - /* parse information for connect log */ - if (!ctx->http_status_code) { - /* first line */ - char *space1, *space2; - - space1 = strchr(line, ' '); - space2 = space1 ? strchr(space1 + 1, ' ') : NULL; - if (!space1 || !!strncmp(line, "HTTP", 4)) { - /* not HTTP or HTTP/0.9 */ - ctx->seen_resp_header = 1; - } else { - size_t len_code, len_text; - - if (space2) { - len_code = space2 - space1 - 1; - len_text = strlen(space2 + 1); - } else { - len_code = strlen(space1 + 1); - len_text = 0; - } - ctx->http_status_code = malloc(len_code + 1); - ctx->http_status_text = malloc(len_text + 1); - if (!ctx->http_status_code || !ctx->http_status_text) { - ctx->enomem = 1; - return NULL; - } - memcpy(ctx->http_status_code, space1 + 1, len_code); - ctx->http_status_code[len_code] = '\0'; - if (space2) { - memcpy(ctx->http_status_text, - space2 + 1, len_text); - } - ctx->http_status_text[len_text] = '\0'; - } - } else { - /* not first line */ - if (!ctx->http_content_length && - !strncasecmp(line, "Content-Length:", 15)) { - ctx->http_content_length = - strdup(util_skipws(line + 15)); - if (!ctx->http_content_length) { - ctx->enomem = 1; - return NULL; - } - } else if ( - /* HPKP: Public Key Pinning Extension for HTTP - * (draft-ietf-websec-key-pinning) - * remove to prevent public key pinning */ - !strncasecmp(line, "Public-Key-Pins:", 16) || - !strncasecmp(line, "Public-Key-Pins-Report-Only:", 28) || - /* HSTS: HTTP Strict Transport Security (RFC 6797) - * remove to allow users to accept bad certs */ - !strncasecmp(line, "Strict-Transport-Security:", 26) || - /* Alternate Protocol - * remove to prevent switching to QUIC, SPDY et al */ - !strncasecmp(line, "Alternate-Protocol:", 19) || - /* Upgrade header - * remove to prevent upgrading to HTTPS in unhandled ways, - * and more importantly, WebSockets and HTTP/2 */ - !strncasecmp(line, "Upgrade:", 8)) { - return NULL; - } else if (line[0] == '\0') { - ctx->seen_resp_header = 1; - } - } - - return (char*)line; -} - -/* - * Return 1 if uri is an OCSP GET URI, 0 if not. - */ -static int -pxy_ocsp_is_valid_uri(const char *uri, pxy_conn_ctx_t *ctx) -{ - char *buf_url; - size_t sz_url; - char *buf_b64; - size_t sz_b64; - unsigned char *buf_asn1; - size_t sz_asn1; - int ret; - - buf_url = strrchr(uri, '/'); - if (!buf_url) - return 0; - buf_url++; - - /* - * Do some quick checks to avoid unnecessary buffer allocations and - * decoding URL, Base64 and ASN.1: - * - OCSP requests begin with a SEQUENCE (0x30), so the first Base64 - * byte is 'M' or, unlikely but legal, the URL encoding thereof. - * - There should be no query string in OCSP GET requests. - * - Encoded OCSP request ASN.1 blobs are longer than 32 bytes. - */ - if (buf_url[0] != 'M' && buf_url[0] != '%') - return 0; - if (strchr(uri, '?')) - return 0; - sz_url = strlen(buf_url); - if (sz_url < 32) - return 0; - buf_b64 = url_dec(buf_url, sz_url, &sz_b64); - if (!buf_b64) { - ctx->enomem = 1; - return 0; - } - buf_asn1 = base64_dec(buf_b64, sz_b64, &sz_asn1); - if (!buf_asn1) { - ctx->enomem = 1; - free(buf_b64); - return 0; - } - ret = ssl_is_ocspreq(buf_asn1, sz_asn1); - free(buf_asn1); - free(buf_b64); - return ret; + char *buf_url; + size_t sz_url; + char *buf_b64; + size_t sz_b64; + unsigned char *buf_asn1; + size_t sz_asn1; + int ret; + + buf_url = (char *)strrchr(uri, '/'); + if (!buf_url) + return 0; + buf_url++; + + /* + * Do some quick checks to avoid unnecessary buffer allocations and + * decoding URL, Base64 and ASN.1: + * - OCSP requests begin with a SEQUENCE (0x30), so the first Base64 + * byte is 'M' or, unlikely but legal, the URL encoding thereof. + * - There should be no query string in OCSP GET requests. + * - Encoded OCSP request ASN.1 blobs are longer than 32 bytes. + */ + if (buf_url[0] != 'M' && buf_url[0] != '%') + return 0; + if (strchr(uri, '?')) + return 0; + sz_url = strlen(buf_url); + if (sz_url < 32) + return 0; + buf_b64 = url_dec(buf_url, sz_url, &sz_b64); + if (!buf_b64) + { + ctx->enomem = 1; + return 0; + } + buf_asn1 = base64_dec(buf_b64, sz_b64, &sz_asn1); + if (!buf_asn1) + { + ctx->enomem = 1; + free(buf_b64); + return 0; + } + ret = ssl_is_ocspreq(buf_asn1, sz_asn1); + free(buf_asn1); + free(buf_b64); + return ret; } /* @@ -1383,71 +1266,77 @@ pxy_ocsp_is_valid_uri(const char *uri, pxy_conn_ctx_t *ctx) * Reference: * RFC 2560: X.509 Internet PKI Online Certificate Status Protocol (OCSP) */ -static void -pxy_ocsp_deny(pxy_conn_ctx_t *ctx) +static void pxy_ocsp_deny(pxy_conn_ctx_t *ctx) { - struct evbuffer *inbuf, *outbuf; - static const char ocspresp[] = - "HTTP/1.0 200 OK\r\n" - "Content-Type: application/ocsp-response\r\n" - "Content-Length: 5\r\n" - "Connection: close\r\n" - "\r\n" - "\x30\x03" /* OCSPResponse: SEQUENCE */ - "\x0a\x01" /* OCSPResponseStatus: ENUMERATED */ - "\x03"; /* tryLater (3) */ - - if (!ctx->http_method) - return; - if (!strncasecmp(ctx->http_method, "GET", 3) && - pxy_ocsp_is_valid_uri(ctx->http_uri, ctx)) - goto deny; - if (!strncasecmp(ctx->http_method, "POST", 4) && - ctx->http_content_type && - !strncasecmp(ctx->http_content_type, - "application/ocsp-request", 24)) - goto deny; - return; + struct evbuffer *inbuf, *outbuf; + static const char ocspresp[] = + "HTTP/1.0 200 OK\r\n" + "Content-Type: application/ocsp-response\r\n" + "Content-Length: 5\r\n" + "Connection: close\r\n" + "\r\n" + "\x30\x03" /* OCSPResponse: SEQUENCE */ + "\x0a\x01" /* OCSPResponseStatus: ENUMERATED */ + "\x03"; /* tryLater (3) */ + + if (!ctx->http_method) + return; + if (!strncasecmp(ctx->http_method, "GET", 3) && + pxy_ocsp_is_valid_uri(ctx->http_uri, ctx)) + goto deny; + if (!strncasecmp(ctx->http_method, "POST", 4) && + ctx->http_content_type && + !strncasecmp(ctx->http_content_type, + "application/ocsp-request", 24)) + goto deny; + return; deny: - inbuf = bufferevent_get_input(ctx->src.bev); - outbuf = bufferevent_get_output(ctx->src.bev); - - if (evbuffer_get_length(inbuf) > 0) { - if (WANT_CONTENT_LOG(ctx)) { - logbuf_t *lb; - lb = logbuf_new_alloc(evbuffer_get_length(inbuf), - NULL, NULL); - if (lb && - (evbuffer_copyout(inbuf, lb->buf, lb->sz) != -1)) { - if (log_content_submit(ctx->logctx, lb, - 1/*req*/) == -1) { - logbuf_free(lb); - log_err_printf("Warning: Content log " - "submission failed\n"); - } - } - } - evbuffer_drain(inbuf, evbuffer_get_length(inbuf)); - } - bufferevent_free_and_close_fd(ctx->dst.bev, ctx); - ctx->dst.bev = NULL; - ctx->dst.closed = 1; - evbuffer_add_printf(outbuf, ocspresp); - ctx->ocsp_denied = 1; - if (WANT_CONTENT_LOG(ctx)) { - logbuf_t *lb; - lb = logbuf_new_copy(ocspresp, sizeof(ocspresp) - 1, - NULL, NULL); - if (lb) { - if (log_content_submit(ctx->logctx, lb, - 0/*resp*/) == -1) { - logbuf_free(lb); - log_err_printf("Warning: Content log " - "submission failed\n"); - } - } - } + inbuf = bufferevent_get_input(ctx->src.bev); + outbuf = bufferevent_get_output(ctx->src.bev); + + if (evbuffer_get_length(inbuf) > 0) + { + if (WANT_CONTENT_LOG(ctx)) + { + logbuf_t *lb; + lb = logbuf_new_alloc(evbuffer_get_length(inbuf), + NULL, NULL); + if (lb && + (evbuffer_copyout(inbuf, lb->buf, lb->sz) != -1)) + { + if (log_content_submit(ctx->logctx, lb, + 1/*req*/) == -1) + { + logbuf_free(lb); + log_err_printf("Warning: Content log " + "submission failed\n"); + } + } + } + evbuffer_drain(inbuf, evbuffer_get_length(inbuf)); + } + bufferevent_free_and_close_fd(ctx->dst.bev, ctx); + ctx->dst.bev = NULL; + ctx->dst.closed = 1; + evbuffer_add_printf(outbuf, ocspresp); + ctx->ocsp_denied = 1; + if (WANT_CONTENT_LOG(ctx)) + { + logbuf_t *lb; + lb = logbuf_new_copy(ocspresp, sizeof(ocspresp) - 1, + NULL, NULL); + if (lb) + { + if (log_content_submit(ctx->logctx, lb, + 0/*resp*/) == -1) + { + logbuf_free(lb); + log_err_printf("Warning: Content log " + "submission failed\n"); + } + } + } } /* @@ -1467,70 +1356,80 @@ deny: int pxy_conn_autossl_peek_and_upgrade(pxy_conn_ctx_t *ctx) { - struct evbuffer *inbuf; - struct evbuffer_iovec vec_out[1]; - const unsigned char *chello; - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Checking for a client hello\n"); - } - /* peek the buffer */ - inbuf = bufferevent_get_input(ctx->src.bev); - if (evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) { - if (ssl_tls_clienthello_parse(vec_out[0].iov_base, - vec_out[0].iov_len, - 0, &chello, &ctx->sni) == 0) { - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Peek found ClientHello\n"); - } - ctx->dst.ssl = pxy_dstssl_create(ctx); - if (!ctx->dst.ssl) { - log_err_printf("Error creating SSL for " - "upgrade\n"); - return 0; - } - ctx->dst.bev = bufferevent_openssl_filter_new( - ctx->evbase, ctx->dst.bev, ctx->dst.ssl, - BUFFEREVENT_SSL_CONNECTING, - BEV_OPT_DEFER_CALLBACKS); - if (!ctx->dst.bev) { - return 0; - } - bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, - pxy_bev_writecb, pxy_bev_eventcb, - ctx); - bufferevent_enable(ctx->dst.bev, EV_READ|EV_WRITE); - if (OPTS_DEBUG(ctx->opts)) { - log_err_printf("Replaced dst bufferevent, new " - "one is %p\n", - (void*)ctx->dst.bev); - } - ctx->clienthello_search = 0; - ctx->clienthello_found = 1; - return 1; - } else { - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Peek found no ClientHello\n"); - } - return 0; - } - } - return 0; + struct evbuffer *inbuf; + struct evbuffer_iovec vec_out[1]; + const unsigned char *chello; + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Checking for a client hello\n"); + } + /* peek the buffer */ + inbuf = bufferevent_get_input(ctx->src.bev); + if (evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) + { + if (ssl_tls_clienthello_parse((const unsigned char *)vec_out[0].iov_base, + vec_out[0].iov_len, 0, &chello, &ctx->sni) == 0) + { + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Peek found ClientHello\n"); + } + ctx->dst.ssl = pxy_dstssl_create(ctx); + if (!ctx->dst.ssl) + { + log_err_printf("Error creating SSL for " + "upgrade\n"); + return 0; + } + ctx->dst.bev = bufferevent_openssl_filter_new( + ctx->evbase, ctx->dst.bev, ctx->dst.ssl, + BUFFEREVENT_SSL_CONNECTING, + BEV_OPT_DEFER_CALLBACKS); + if (!ctx->dst.bev) + { + return 0; + } + bufferevent_setcb(ctx->dst.bev, pxy_bev_readcb, + pxy_bev_writecb, pxy_bev_eventcb, + ctx); + bufferevent_enable(ctx->dst.bev, EV_READ | EV_WRITE); + if (OPTS_DEBUG(ctx->opts)) + { + log_err_printf("Replaced dst bufferevent, new " + "one is %p\n", + (void *) ctx->dst.bev); + } + ctx->clienthello_search = 0; + ctx->clienthello_found = 1; + return 1; + } else + { + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Peek found no ClientHello\n"); + } + return 0; + } + } + return 0; } static void pxy_conn_terminate_free(pxy_conn_ctx_t *ctx, int is_requestor) { - log_err_printf("Terminating connection%s!\n", - ctx->enomem ? " (out of memory)" : ""); - if (ctx->dst.bev && !ctx->dst.closed) { - bufferevent_free_and_close_fd(ctx->dst.bev, ctx); - ctx->dst.bev = NULL; - } - if (ctx->src.bev && !ctx->src.closed) { - bufferevent_free_and_close_fd(ctx->src.bev, ctx); - ctx->src.bev = NULL; - } - pxy_conn_ctx_free(ctx, is_requestor); + log_err_printf("Terminating connection%s!\n", + ctx->enomem ? " (out of memory)" : ""); + if (ctx->dst.bev && !ctx->dst.closed) + { + bufferevent_free_and_close_fd(ctx->dst.bev, ctx); + ctx->dst.bev = NULL; + } + if (ctx->src.bev && !ctx->src.closed) + { + bufferevent_free_and_close_fd(ctx->src.bev, ctx); + ctx->src.bev = NULL; + } + pxy_conn_ctx_free(ctx, is_requestor); } extern int pxy_http_read_cb(pxy_conn_ctx_t *ctx, struct bufferevent *bev); @@ -1541,84 +1440,86 @@ extern int pxy_http_read_cb(pxy_conn_ctx_t *ctx, struct bufferevent *bev); */ static void pxy_bev_readcb(struct bufferevent *bev, void *arg) { - pxy_conn_ctx_t *ctx = arg; - pxy_conn_desc_t *other = (bev==ctx->src.bev) ? &ctx->dst : &ctx->src; + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; -#ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("%p %p %s readcb\n", arg, (void*)bev, - (bev == ctx->src.bev) ? "src" : "dst"); - } -#endif /* DEBUG_PROXY */ + pxy_conn_desc_t * conn_this = (bev == ctx->src.bev) ? &ctx->src : &ctx->dst; + pxy_conn_desc_t * conn_other = (bev == ctx->src.bev) ? &ctx->dst : &ctx->src; - if (!ctx->connected) - { - log_err_printf("readcb called when other end not connected - " - "aborting.\n"); - log_exceptcb(); - return; - } + if (!ctx->connected) + { + log_err_printf("readcb called when other end not connected - " + "aborting.\n"); + log_exceptcb(); + return; + } - if (ctx->clienthello_search && pxy_conn_autossl_peek_and_upgrade(ctx)) - { - return; - } + if (ctx->clienthello_search && pxy_conn_autossl_peek_and_upgrade(ctx)) + { + return; + } - struct evbuffer *inbuf = bufferevent_get_input(bev); - struct evbuffer *outbuf = bufferevent_get_output(other->bev); + struct evbuffer *inbuf = bufferevent_get_input(bev); + struct evbuffer *outbuf = bufferevent_get_output(conn_other->bev); - if (other->closed) + if (conn_other->closed) { log_dbg_printf("Warning: Drained %zu bytes (conn closed)\n", evbuffer_get_length(inbuf)); evbuffer_drain(inbuf, evbuffer_get_length(inbuf)); return; } - if (ctx->spec->http && !ctx->seen_req_header - && (bev == ctx->src.bev) && !ctx->passthrough) - { - pxy_http_read_cb(ctx, bev); - if (!ctx->seen_req_header) - return; - } - else if (ctx->spec->http && !ctx->seen_resp_header - && (bev == ctx->dst.bev) && !ctx->passthrough) - { - pxy_http_read_cb(ctx, bev); - if (!ctx->seen_resp_header) - return; - } - - /* out of memory condition? */ - if (ctx->enomem) { - pxy_conn_terminate_free(ctx, (bev == ctx->src.bev)); - return; - } - - /* no data left after parsing headers? */ - if (evbuffer_get_length(inbuf) == 0) - return; - - if (WANT_CONTENT_LOG(ctx)) { - logbuf_t *lb; - lb = logbuf_new_alloc(evbuffer_get_length(inbuf), NULL, NULL); - if (lb && (evbuffer_copyout(inbuf, lb->buf, lb->sz) != -1)) { - if (log_content_submit(ctx->logctx, lb, - (bev == ctx->src.bev)) == -1) { - logbuf_free(lb); - log_err_printf("Warning: Content log " - "submission failed\n"); - } - } - } - evbuffer_add_buffer(outbuf, inbuf); - if (evbuffer_get_length(outbuf) >= OUTBUF_LIMIT) { - /* temporarily disable data source; - * set an appropriate watermark. */ - bufferevent_setwatermark(other->bev, EV_WRITE, - OUTBUF_LIMIT/2, OUTBUF_LIMIT); - bufferevent_disable(bev, EV_READ); - } + if (ctx->spec->http && ctx->protocol_conn_ctx == nullptr) + { + ctx->protocol_conn_ctx = new Http1Connection; + } + + if (ctx->spec->http && (bev == ctx->src.bev) && !ctx->passthrough) + { + auto * http1_connection = reinterpret_cast<Http1Connection *>(ctx->protocol_conn_ctx); + http1_connection->on_connection_read_request(ctx, conn_this, conn_other); + } + + if (ctx->spec->http && (bev == ctx->dst.bev) && !ctx->passthrough) + { + auto * http1_connection = reinterpret_cast<Http1Connection *>(ctx->protocol_conn_ctx); + http1_connection->on_connection_read_response(ctx, bev); + } + + /* out of memory condition? */ + if (ctx->enomem) + { + pxy_conn_terminate_free(ctx, (bev == ctx->src.bev)); + return; + } + + /* no data left after parsing headers? */ + if (evbuffer_get_length(inbuf) == 0) + return; + + if (WANT_CONTENT_LOG(ctx)) + { + logbuf_t *lb; + lb = logbuf_new_alloc(evbuffer_get_length(inbuf), NULL, NULL); + if (lb && (evbuffer_copyout(inbuf, lb->buf, lb->sz) != -1)) + { + if (log_content_submit(ctx->logctx, lb, + (bev == ctx->src.bev)) == -1) + { + logbuf_free(lb); + log_err_printf("Warning: Content log " + "submission failed\n"); + } + } + } + evbuffer_add_buffer(outbuf, inbuf); + if (evbuffer_get_length(outbuf) >= OUTBUF_LIMIT) + { + /* temporarily disable data source; + * set an appropriate watermark. */ + bufferevent_setwatermark(conn_other->bev, EV_WRITE, + OUTBUF_LIMIT / 2, OUTBUF_LIMIT); + bufferevent_disable(bev, EV_READ); + } } /* @@ -1629,506 +1530,522 @@ static void pxy_bev_readcb(struct bufferevent *bev, void *arg) static void pxy_bev_writecb(struct bufferevent *bev, void *arg) { - pxy_conn_ctx_t *ctx = arg; - pxy_conn_desc_t *other = (bev==ctx->src.bev) ? &ctx->dst : &ctx->src; + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; + pxy_conn_desc_t *other = (bev == ctx->src.bev) ? &ctx->dst : &ctx->src; #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("%p %p %s writecb\n", arg, (void*)bev, - (bev == ctx->src.bev) ? "src" : "dst"); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("%p %p %s writecb\n", arg, (void*)bev, + (bev == ctx->src.bev) ? "src" : "dst"); + } #endif /* DEBUG_PROXY */ - if (other->closed) { - struct evbuffer *outbuf = bufferevent_get_output(bev); - if (evbuffer_get_length(outbuf) == 0) { - /* finished writing and other end is closed; - * close this end too and clean up memory */ - bufferevent_free_and_close_fd(bev, ctx); - pxy_conn_ctx_free(ctx, (bev == ctx->dst.bev)); - } - return; - } - - if (other->bev && !(bufferevent_get_enabled(other->bev) & EV_READ)) { - /* data source temporarily disabled; - * re-enable and reset watermark to 0. */ - bufferevent_setwatermark(bev, EV_WRITE, 0, 0); - bufferevent_enable(other->bev, EV_READ); - } + if (other->closed) + { + struct evbuffer *outbuf = bufferevent_get_output(bev); + if (evbuffer_get_length(outbuf) == 0) + { + /* finished writing and other end is closed; + * close this end too and clean up memory */ + bufferevent_free_and_close_fd(bev, ctx); + pxy_conn_ctx_free(ctx, (bev == ctx->dst.bev)); + } + return; + } + + if (other->bev && !(bufferevent_get_enabled(other->bev) & EV_READ)) + { + /* data source temporarily disabled; + * re-enable and reset watermark to 0. */ + bufferevent_setwatermark(bev, EV_WRITE, 0, 0); + bufferevent_enable(other->bev, EV_READ); + } } /* * Callback for meta events on the up- and downstream connection bufferevents. * Called when EOF has been reached, a connection has been made, and on errors. */ -static void -pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg) +static void pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg) { - pxy_conn_ctx_t *ctx = arg; - pxy_conn_desc_t *__this = (bev==ctx->src.bev) ? &ctx->src : &ctx->dst; - pxy_conn_desc_t *other = (bev==ctx->src.bev) ? &ctx->dst : &ctx->src; - int is_requestor = (bev == ctx->src.bev); + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; + pxy_conn_desc_t *this_conn = (bev == ctx->src.bev) ? &ctx->src : &ctx->dst; + pxy_conn_desc_t *other_conn = (bev == ctx->src.bev) ? &ctx->dst : &ctx->src; + + int is_requestor = (bev == ctx->src.bev); #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("%p %p eventcb %s %s%s%s%s\n", arg, (void*)bev, - (bev == ctx->src.bev) ? "src" : "dst", - events & BEV_EVENT_CONNECTED ? "connected" : "", - events & BEV_EVENT_ERROR ? "error" : "", - events & BEV_EVENT_TIMEOUT ? "timeout" : "", - events & BEV_EVENT_EOF ? "eof" : ""); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("%p %p eventcb %s %s%s%s%s\n", arg, (void*)bev, + (bev == ctx->src.bev) ? "src" : "dst", + events & BEV_EVENT_CONNECTED ? "connected" : "", + events & BEV_EVENT_ERROR ? "error" : "", + events & BEV_EVENT_TIMEOUT ? "timeout" : "", + events & BEV_EVENT_EOF ? "eof" : ""); + } #endif /* DEBUG_PROXY */ - if (events & BEV_EVENT_CONNECTED) { - if (bev != ctx->dst.bev) { + if (events & BEV_EVENT_CONNECTED) + { + if (bev != ctx->dst.bev) + { #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("src buffer event connected: " - "ignoring event\n"); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("src buffer event connected: " + "ignoring event\n"); + } #endif /* DEBUG_PROXY */ - goto connected; - } - - /* dst has connected */ - ctx->connected = 1; - - /* wrap client-side socket in an eventbuffer */ - if ((ctx->spec->ssl || ctx->clienthello_found) && - !ctx->passthrough) { - ctx->src.ssl = pxy_srcssl_create(ctx, __this->ssl); - if (!ctx->src.ssl) { - bufferevent_free_and_close_fd(bev, ctx); - ctx->dst.bev = NULL; - ctx->dst.ssl = NULL; - if (ctx->opts->passthrough && !ctx->enomem) { - ctx->passthrough = 1; - ctx->connected = 0; - log_dbg_printf("No cert found; " - "falling back " - "to passthrough\n"); - pxy_fd_readcb(ctx->fd, 0, ctx); - return; - } - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - } - if (ctx->clienthello_found) { - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Completing autossl upgrade\n"); - } - ctx->src.bev = bufferevent_openssl_filter_new( - ctx->evbase, ctx->src.bev, ctx->src.ssl, - BUFFEREVENT_SSL_ACCEPTING, - BEV_OPT_DEFER_CALLBACKS); - if (ctx->src.bev) { - bufferevent_setcb(ctx->src.bev, - pxy_bev_readcb, - pxy_bev_writecb, - pxy_bev_eventcb, - ctx); - bufferevent_enable(ctx->src.bev, - EV_READ|EV_WRITE); - } - } else { - ctx->src.bev = pxy_bufferevent_setup(ctx, ctx->fd, - ctx->src.ssl); - } - if (!ctx->src.bev) { - if (ctx->src.ssl) { - SSL_free(ctx->src.ssl); - ctx->src.ssl = NULL; - } - bufferevent_free_and_close_fd(bev, ctx); - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - - /* prepare logging, part 2 */ - if (WANT_CONNECT_LOG(ctx) || WANT_CONTENT_LOG(ctx)) { - if (sys_sockaddr_str((struct sockaddr *) - &ctx->addr, ctx->addrlen, - &ctx->dsthost_str, - &ctx->dstport_str) != 0) { - ctx->enomem = 1; - pxy_conn_terminate_free(ctx, 1); - return; - } - -#ifdef HAVE_LOCAL_PROCINFO - if (ctx->opts->lprocinfo) { - /* fetch process info */ - if (proc_pid_for_addr(&ctx->lproc.pid, - (struct sockaddr*)&ctx->lproc.srcaddr, - ctx->lproc.srcaddrlen) == 0 && - ctx->lproc.pid != -1 && - proc_get_info(ctx->lproc.pid, - &ctx->lproc.exec_path, - &ctx->lproc.uid, - &ctx->lproc.gid) == 0) { - /* fetch user/group names */ - ctx->lproc.user = sys_user_str( - ctx->lproc.uid); - ctx->lproc.group = sys_group_str( - ctx->lproc.gid); - if (!ctx->lproc.user || - !ctx->lproc.group) { - ctx->enomem = 1; - pxy_conn_terminate_free(ctx, 1); - return; - } - } - } -#endif /* HAVE_LOCAL_PROCINFO */ - } - if (WANT_CONTENT_LOG(ctx)) { - if (log_content_open(&ctx->logctx, ctx->opts, - ctx->srchost_str, ctx->srcport_str, - ctx->dsthost_str, ctx->dstport_str, -#ifdef HAVE_LOCAL_PROCINFO - ctx->lproc.exec_path, - ctx->lproc.user, - ctx->lproc.group -#else /* HAVE_LOCAL_PROCINFO */ - NULL, NULL, NULL -#endif /* HAVE_LOCAL_PROCINFO */ - ) == -1) { - if (errno == ENOMEM) - ctx->enomem = 1; - pxy_conn_terminate_free(ctx, 1); - return; - } - } + goto connected; + } + + /* dst has connected */ + ctx->connected = 1; + + /* wrap client-side socket in an eventbuffer */ + if ((ctx->spec->ssl || ctx->clienthello_found) && + !ctx->passthrough) + { + ctx->src.ssl = pxy_srcssl_create(ctx, this_conn->ssl); + if (!ctx->src.ssl) + { + bufferevent_free_and_close_fd(bev, ctx); + ctx->dst.bev = NULL; + ctx->dst.ssl = NULL; + if (ctx->opts->passthrough && !ctx->enomem) + { + ctx->passthrough = 1; + ctx->connected = 0; + log_dbg_printf("No cert found; " + "falling back " + "to passthrough\n"); + pxy_fd_readcb(ctx->fd, 0, ctx); + return; + } + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + } + if (ctx->clienthello_found) + { + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("Completing autossl upgrade\n"); + } + ctx->src.bev = bufferevent_openssl_filter_new( + ctx->evbase, ctx->src.bev, ctx->src.ssl, + BUFFEREVENT_SSL_ACCEPTING, + BEV_OPT_DEFER_CALLBACKS); + if (ctx->src.bev) + { + bufferevent_setcb(ctx->src.bev, + pxy_bev_readcb, + pxy_bev_writecb, + pxy_bev_eventcb, + ctx); + bufferevent_enable(ctx->src.bev, + EV_READ | EV_WRITE); + } + } else + { + ctx->src.bev = pxy_bufferevent_setup(ctx, ctx->fd, + ctx->src.ssl); + } + if (!ctx->src.bev) + { + if (ctx->src.ssl) + { + SSL_free(ctx->src.ssl); + ctx->src.ssl = NULL; + } + bufferevent_free_and_close_fd(bev, ctx); + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + + /* prepare logging, part 2 */ + if (WANT_CONNECT_LOG(ctx) || WANT_CONTENT_LOG(ctx)) + { + if (sys_sockaddr_str((struct sockaddr *) + &ctx->addr, ctx->addrlen, + &ctx->dsthost_str, + &ctx->dstport_str) != 0) + { + ctx->enomem = 1; + pxy_conn_terminate_free(ctx, 1); + return; + } + + } + if (WANT_CONTENT_LOG(ctx)) + { + if (log_content_open(&ctx->logctx, ctx->opts, + ctx->srchost_str, ctx->srcport_str, + ctx->dsthost_str, ctx->dstport_str, NULL, NULL, NULL) == -1) + { + if (errno == ENOMEM) + ctx->enomem = 1; + pxy_conn_terminate_free(ctx, 1); + return; + } + } connected: - /* log connection if we don't analyze any headers */ - if ((!__this->ssl || (bev == ctx->src.bev)) && - (!ctx->spec->http || ctx->passthrough) && - WANT_CONNECT_LOG(ctx)) { - pxy_log_connect_nonhttp(ctx); - } - - if (__this->ssl) { - /* write SSL certificates to gendir */ - if ((bev == ctx->src.bev) && ctx->opts->certgendir) { - pxy_srccert_write(ctx); - } - - /* log master key */ - if (ctx->opts->masterkeylog) { - char *keystr; - keystr = ssl_ssl_masterkey_to_str(__this->ssl); - if ((keystr == NULL) || - (log_masterkey_print_free(keystr) == -1)) { - if (errno == ENOMEM) - ctx->enomem = 1; - pxy_conn_terminate_free(ctx, 1); - return; - } - } - } - - if (OPTS_DEBUG(ctx->opts)) { - if (__this->ssl) { - char *keystr; - /* for SSL, we get two connect events */ - log_dbg_printf("SSL connected %s [%s]:%s" - " %s %s\n", - bev == ctx->dst.bev ? - "to" : "from", - bev == ctx->dst.bev ? - ctx->dsthost_str : - ctx->srchost_str, - bev == ctx->dst.bev ? - ctx->dstport_str : - ctx->srcport_str, - SSL_get_version(__this->ssl), - SSL_get_cipher(__this->ssl), __this); - - keystr = ssl_ssl_masterkey_to_str(__this->ssl); - if (keystr) { - log_dbg_print_free(keystr); - } - } else { - /* for TCP, we get only a dst connect event, - * since src was already connected from the - * beginning; mirror SSL debug output anyway - * in order not to confuse anyone who might be - * looking closely at the output */ - log_dbg_printf("TCP connected to [%s]:%s\n", - ctx->dsthost_str, - ctx->dstport_str); - log_dbg_printf("TCP connected from [%s]:%s\n", - ctx->srchost_str, - ctx->srcport_str); - } - } - - return; - } - - if (events & BEV_EVENT_ERROR) { - unsigned long sslerr; - int have_sslerr = 0; - - /* Can happen for socket errs, ssl errs; - * may happen for unclean ssl socket shutdowns. */ - sslerr = bufferevent_get_openssl_error(bev); - if (sslerr) - have_sslerr = 1; - if (!errno && !sslerr) { + /* log connection if we don't analyze any headers */ + if ((!this_conn->ssl || (bev == ctx->src.bev)) && + (!ctx->spec->http || ctx->passthrough) && + WANT_CONNECT_LOG(ctx)) + { + pxy_log_connect_nonhttp(ctx); + } + + if (this_conn->ssl) + { + /* write SSL certificates to gendir */ + if ((bev == ctx->src.bev) && ctx->opts->certgendir) + { + pxy_srccert_write(ctx); + } + + /* log master key */ + if (ctx->opts->masterkeylog) + { + char *keystr; + keystr = ssl_ssl_masterkey_to_str(this_conn->ssl); + if ((keystr == NULL) || + (log_masterkey_print_free(keystr) == -1)) + { + if (errno == ENOMEM) + ctx->enomem = 1; + pxy_conn_terminate_free(ctx, 1); + return; + } + } + } + + if (OPTS_DEBUG(ctx->opts)) + { + if (this_conn->ssl) + { + char *keystr; + /* for SSL, we get two connect events */ + log_dbg_printf("SSL connected %s [%s]:%s" + " %s %s\n", + bev == ctx->dst.bev ? + "to" : "from", + bev == ctx->dst.bev ? + ctx->dsthost_str : + ctx->srchost_str, + bev == ctx->dst.bev ? + ctx->dstport_str : + ctx->srcport_str, + SSL_get_version(this_conn->ssl), + SSL_get_cipher(this_conn->ssl), this_conn); + + keystr = ssl_ssl_masterkey_to_str(this_conn->ssl); + if (keystr) + { + log_dbg_print_free(keystr); + } + } else + { + /* for TCP, we get only a dst connect event, + * since src was already connected from the + * beginning; mirror SSL debug output anyway + * in order not to confuse anyone who might be + * looking closely at the output */ + log_dbg_printf("TCP connected to [%s]:%s\n", + ctx->dsthost_str, + ctx->dstport_str); + log_dbg_printf("TCP connected from [%s]:%s\n", + ctx->srchost_str, + ctx->srcport_str); + } + } + + return; + } + + if (events & BEV_EVENT_ERROR) + { + unsigned long sslerr; + int have_sslerr = 0; + + /* Can happen for socket errs, ssl errs; + * may happen for unclean ssl socket shutdowns. */ + sslerr = bufferevent_get_openssl_error(bev); + if (sslerr) + have_sslerr = 1; + if (!errno && !sslerr) + { #if LIBEVENT_VERSION_NUMBER >= 0x02010000 - /* We have disabled notification for unclean shutdowns - * so this should not happen; log a warning. */ - log_err_printf("Warning: Spurious error from " - "bufferevent (errno=0,sslerr=0)\n"); + /* We have disabled notification for unclean shutdowns + * so this should not happen; log a warning. */ + log_err_printf("Warning: Spurious error from " + "bufferevent (errno=0,sslerr=0)\n"); #else /* LIBEVENT_VERSION_NUMBER < 0x02010000 */ - /* Older versions of libevent will report these. */ - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("Unclean SSL shutdown.\n"); - } + /* Older versions of libevent will report these. */ + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("Unclean SSL shutdown.\n"); + } #endif /* LIBEVENT_VERSION_NUMBER < 0x02010000 */ - } else if (ERR_GET_REASON(sslerr) == - SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) { - /* these can happen due to client cert auth, - * only log error if debugging is activated */ - log_dbg_printf("Error from %s bufferevent: " - "%i:%s %lu:%i:%s:%i:%s:%i:%s\n", - (bev == ctx->src.bev) ? "src" : "dst", - errno, - errno ? strerror(errno) : "-", - sslerr, - ERR_GET_REASON(sslerr), - sslerr ? - ERR_reason_error_string(sslerr) : "-", - ERR_GET_LIB(sslerr), - sslerr ? - ERR_lib_error_string(sslerr) : "-", - ERR_GET_FUNC(sslerr), - sslerr ? - ERR_func_error_string(sslerr) : "-"); - while ((sslerr = bufferevent_get_openssl_error(bev))) { - log_dbg_printf("Additional SSL error: " - "%lu:%i:%s:%i:%s:%i:%s\n", - sslerr, - ERR_GET_REASON(sslerr), - ERR_reason_error_string(sslerr), - ERR_GET_LIB(sslerr), - ERR_lib_error_string(sslerr), - ERR_GET_FUNC(sslerr), - ERR_func_error_string(sslerr)); - } - } else { - /* real errors */ - log_err_printf("Error from %s bufferevent: " - "%i:%s %lu:%i:%s:%i:%s:%i:%s\n", - (bev == ctx->src.bev) ? "src" : "dst", - errno, - errno ? strerror(errno) : "-", - sslerr, - ERR_GET_REASON(sslerr), - sslerr ? - ERR_reason_error_string(sslerr) : "-", - ERR_GET_LIB(sslerr), - sslerr ? - ERR_lib_error_string(sslerr) : "-", - ERR_GET_FUNC(sslerr), - sslerr ? - ERR_func_error_string(sslerr) : "-"); - while ((sslerr = bufferevent_get_openssl_error(bev))) { - log_err_printf("Additional SSL error: " - "%lu:%i:%s:%i:%s:%i:%s\n", - sslerr, - ERR_GET_REASON(sslerr), - ERR_reason_error_string(sslerr), - ERR_GET_LIB(sslerr), - ERR_lib_error_string(sslerr), - ERR_GET_FUNC(sslerr), - ERR_func_error_string(sslerr)); - } - } - - if (!ctx->connected) { - /* the callout to the original destination failed, - * e.g. because it asked for client cert auth, so - * close the accepted socket and clean up */ - if (bev == ctx->dst.bev && ctx->dst.ssl && - ctx->opts->passthrough && have_sslerr) { - /* ssl callout failed, fall back to plain - * TCP passthrough of SSL connection */ - bufferevent_free_and_close_fd(bev, ctx); - ctx->dst.bev = NULL; - ctx->dst.ssl = NULL; - ctx->passthrough = 1; - log_dbg_printf("SSL dst connection failed; fal" - "ling back to passthrough\n"); - pxy_fd_readcb(ctx->fd, 0, ctx); - return; - } - evutil_closesocket(ctx->fd); - other->closed = 1; - } else if (!other->closed) { - /* if the other end is still open and doesn't have data - * to send, close it, otherwise its writecb will close - * it after writing what's left in the output buffer */ - struct evbuffer *outbuf; - outbuf = bufferevent_get_output(other->bev); - if (evbuffer_get_length(outbuf) == 0) { - bufferevent_free_and_close_fd(other->bev, ctx); - other->bev = NULL; - other->closed = 1; - } - } - goto leave; - } - - if (events & BEV_EVENT_EOF) { + } else if (ERR_GET_REASON(sslerr) == + SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) + { + /* these can happen due to client cert auth, + * only log error if debugging is activated */ + log_dbg_printf("Error from %s bufferevent: " + "%i:%s %lu:%i:%s:%i:%s:%i:%s\n", + (bev == ctx->src.bev) ? "src" : "dst", + errno, + errno ? strerror(errno) : "-", + sslerr, + ERR_GET_REASON(sslerr), + sslerr ? + ERR_reason_error_string(sslerr) : "-", + ERR_GET_LIB(sslerr), + sslerr ? + ERR_lib_error_string(sslerr) : "-", + ERR_GET_FUNC(sslerr), + sslerr ? + ERR_func_error_string(sslerr) : "-"); + while ((sslerr = bufferevent_get_openssl_error(bev))) + { + log_dbg_printf("Additional SSL error: " + "%lu:%i:%s:%i:%s:%i:%s\n", + sslerr, + ERR_GET_REASON(sslerr), + ERR_reason_error_string(sslerr), + ERR_GET_LIB(sslerr), + ERR_lib_error_string(sslerr), + ERR_GET_FUNC(sslerr), + ERR_func_error_string(sslerr)); + } + } else + { + /* real errors */ + log_err_printf("Error from %s bufferevent: " + "%i:%s %lu:%i:%s:%i:%s:%i:%s\n", + (bev == ctx->src.bev) ? "src" : "dst", + errno, + errno ? strerror(errno) : "-", + sslerr, + ERR_GET_REASON(sslerr), + sslerr ? + ERR_reason_error_string(sslerr) : "-", + ERR_GET_LIB(sslerr), + sslerr ? + ERR_lib_error_string(sslerr) : "-", + ERR_GET_FUNC(sslerr), + sslerr ? + ERR_func_error_string(sslerr) : "-"); + while ((sslerr = bufferevent_get_openssl_error(bev))) + { + log_err_printf("Additional SSL error: " + "%lu:%i:%s:%i:%s:%i:%s\n", + sslerr, + ERR_GET_REASON(sslerr), + ERR_reason_error_string(sslerr), + ERR_GET_LIB(sslerr), + ERR_lib_error_string(sslerr), + ERR_GET_FUNC(sslerr), + ERR_func_error_string(sslerr)); + } + } + + if (!ctx->connected) + { + /* the callout to the original destination failed, + * e.g. because it asked for client cert auth, so + * close the accepted socket and clean up */ + if (bev == ctx->dst.bev && ctx->dst.ssl && + ctx->opts->passthrough && have_sslerr) + { + /* ssl callout failed, fall back to plain + * TCP passthrough of SSL connection */ + bufferevent_free_and_close_fd(bev, ctx); + ctx->dst.bev = NULL; + ctx->dst.ssl = NULL; + ctx->passthrough = 1; + log_dbg_printf("SSL dst connection failed; fal" + "ling back to passthrough\n"); + pxy_fd_readcb(ctx->fd, 0, ctx); + return; + } + evutil_closesocket(ctx->fd); + other_conn->closed = 1; + } else if (!other_conn->closed) + { + /* if the other end is still open and doesn't have data + * to send, close it, otherwise its writecb will close + * it after writing what's left in the output buffer */ + struct evbuffer *outbuf; + outbuf = bufferevent_get_output(other_conn->bev); + if (evbuffer_get_length(outbuf) == 0) + { + bufferevent_free_and_close_fd(other_conn->bev, ctx); + other_conn->bev = NULL; + other_conn->closed = 1; + } + } + goto leave; + } + + if (events & BEV_EVENT_EOF) + { #ifdef DEBUG_PROXY - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("evbuffer size at EOF: " - "i:%zu o:%zu i:%zu o:%zu\n", - evbuffer_get_length( - bufferevent_get_input(bev)), - evbuffer_get_length( - bufferevent_get_output(bev)), - evbuffer_get_length( - other->closed ? 0 : - bufferevent_get_input(other->bev)), - evbuffer_get_length( - other->closed ? 0 : - bufferevent_get_output(other->bev)) - ); - } + if (OPTS_DEBUG(ctx->opts)) { + log_dbg_printf("evbuffer size at EOF: " + "i:%zu o:%zu i:%zu o:%zu\n", + evbuffer_get_length( + bufferevent_get_input(bev)), + evbuffer_get_length( + bufferevent_get_output(bev)), + evbuffer_get_length( + other->closed ? 0 : + bufferevent_get_input(other->bev)), + evbuffer_get_length( + other->closed ? 0 : + bufferevent_get_output(other->bev)) + ); + } #endif /* DEBUG_PROXY */ - if (!ctx->connected) { - log_dbg_printf("EOF on outbound connection before " - "connection establishment\n"); - evutil_closesocket(ctx->fd); - other->closed = 1; - } else if (!other->closed) { - /* if there is data pending in the closed connection, - * handle it here, otherwise it will be lost. */ - if (evbuffer_get_length(bufferevent_get_input(bev))) { - pxy_bev_readcb(bev, ctx); - } - /* if the other end is still open and doesn't - * have data to send, close it, otherwise its - * writecb will close it after writing what's - * left in the output buffer. */ - if (evbuffer_get_length( - bufferevent_get_output(other->bev)) == 0) { - bufferevent_free_and_close_fd(other->bev, ctx); - other->bev = NULL; - other->closed = 1; - } - } - goto leave; - } - - log_err_printf("Unknown bufferevent 0x%02X\n", (int)events); - return; + if (!ctx->connected) + { + log_dbg_printf("EOF on outbound connection before " + "connection establishment\n"); + evutil_closesocket(ctx->fd); + other_conn->closed = 1; + } else if (!other_conn->closed) + { + /* if there is data pending in the closed connection, + * handle it here, otherwise it will be lost. */ + if (evbuffer_get_length(bufferevent_get_input(bev))) + { + pxy_bev_readcb(bev, ctx); + } + /* if the other end is still open and doesn't + * have data to send, close it, otherwise its + * writecb will close it after writing what's + * left in the output buffer. */ + if (evbuffer_get_length( + bufferevent_get_output(other_conn->bev)) == 0) + { + bufferevent_free_and_close_fd(other_conn->bev, ctx); + other_conn->bev = NULL; + other_conn->closed = 1; + } + } + goto leave; + } + + log_err_printf("Unknown bufferevent 0x%02X\n", (int) events); + return; leave: - /* we only get a single disconnect event here for both connections */ - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("%s disconnected to [%s]:%s\n", - __this->ssl ? "SSL" : "TCP", - ctx->dsthost_str, ctx->dstport_str); - log_dbg_printf("%s disconnected from [%s]:%s\n", - __this->ssl ? "SSL" : "TCP", - ctx->srchost_str, ctx->srcport_str); - } - - __this->closed = 1; - bufferevent_free_and_close_fd(bev, ctx); - __this->bev = NULL; - if (other->closed) { - pxy_conn_ctx_free(ctx, is_requestor); - } + /* we only get a single disconnect event here for both connections */ + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("%s disconnected to [%s]:%s\n", + this_conn->ssl ? "SSL" : "TCP", + ctx->dsthost_str, ctx->dstport_str); + log_dbg_printf("%s disconnected from [%s]:%s\n", + this_conn->ssl ? "SSL" : "TCP", + ctx->srchost_str, ctx->srcport_str); + } + + this_conn->closed = 1; + bufferevent_free_and_close_fd(bev, ctx); + this_conn->bev = NULL; + if (other_conn->closed) + { + pxy_conn_ctx_free(ctx, is_requestor); + } } /* * Complete the connection. This gets called after finding out where to * connect to. */ -static void -pxy_conn_connect(pxy_conn_ctx_t *ctx) +static void pxy_conn_connect(pxy_conn_ctx_t *ctx) { - if (!ctx->addrlen) { - log_err_printf("No target address; aborting connection\n"); - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - - /* create server-side socket and eventbuffer */ - if (ctx->spec->ssl && !ctx->passthrough) { - ctx->dst.ssl = pxy_dstssl_create(ctx); - if (!ctx->dst.ssl) { - log_err_printf("Error creating SSL\n"); - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - } - ctx->dst.bev = pxy_bufferevent_setup(ctx, -1, ctx->dst.ssl); - if (!ctx->dst.bev) { - if (ctx->dst.ssl) { - SSL_free(ctx->dst.ssl); - ctx->dst.ssl = NULL; - } - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - - if (OPTS_DEBUG(ctx->opts)) { - char *host, *port; - if (sys_sockaddr_str((struct sockaddr *)&ctx->addr, - ctx->addrlen, &host, &port) != 0) { - log_dbg_printf("Connecting to [?]:?\n"); - } else { - log_dbg_printf("Connecting to [%s]:%s\n", host, port); - free(host); - free(port); - } - } - - /* initiate connection */ - bufferevent_socket_connect(ctx->dst.bev, - (struct sockaddr *)&ctx->addr, - ctx->addrlen); + if (!ctx->addrlen) + { + log_err_printf("No target address; aborting connection\n"); + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + + /* create server-side socket and eventbuffer */ + if (ctx->spec->ssl && !ctx->passthrough) + { + ctx->dst.ssl = pxy_dstssl_create(ctx); + if (!ctx->dst.ssl) + { + log_err_printf("Error creating SSL\n"); + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + } + ctx->dst.bev = pxy_bufferevent_setup(ctx, -1, ctx->dst.ssl); + if (!ctx->dst.bev) + { + if (ctx->dst.ssl) + { + SSL_free(ctx->dst.ssl); + ctx->dst.ssl = NULL; + } + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + + if (OPTS_DEBUG(ctx->opts)) + { + char *host, *port; + if (sys_sockaddr_str((struct sockaddr *) &ctx->addr, + ctx->addrlen, &host, &port) != 0) + { + log_dbg_printf("Connecting to [?]:?\n"); + } else + { + log_dbg_printf("Connecting to [%s]:%s\n", host, port); + free(host); + free(port); + } + } + + /* initiate connection */ + bufferevent_socket_connect(ctx->dst.bev, + (struct sockaddr *) &ctx->addr, + ctx->addrlen); } -#ifndef OPENSSL_NO_TLSEXT /* * The SNI hostname has been resolved. Fill the first resolved address into * the context and continue connecting. */ -static void -pxy_sni_resolve_cb(int errcode, struct evutil_addrinfo *ai, void *arg) +static void pxy_sni_resolve_cb(int errcode, struct evutil_addrinfo *ai, void *arg) { - pxy_conn_ctx_t *ctx = arg; - - if (errcode) { - log_err_printf("Cannot resolve SNI hostname '%s': %s\n", - ctx->sni, evutil_gai_strerror(errcode)); - evutil_closesocket(ctx->fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - - memcpy(&ctx->addr, ai->ai_addr, ai->ai_addrlen); - ctx->addrlen = ai->ai_addrlen; - evutil_freeaddrinfo(ai); - pxy_conn_connect(ctx); + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; + + if (errcode) + { + log_err_printf("Cannot resolve SNI hostname '%s': %s\n", + ctx->sni, evutil_gai_strerror(errcode)); + evutil_closesocket(ctx->fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + + memcpy(&ctx->addr, ai->ai_addr, ai->ai_addrlen); + ctx->addrlen = ai->ai_addrlen; + evutil_freeaddrinfo(ai); + pxy_conn_connect(ctx); } -#endif /* !OPENSSL_NO_TLSEXT */ /* * The src fd is readable. This is used to sneak-preview the SNI on SSL @@ -2136,102 +2053,101 @@ pxy_sni_resolve_cb(int errcode, struct evutil_addrinfo *ai, void *arg) * connection. If ctx->passthrough is set, it was called a second time * after the first ssl callout failed because of client cert auth. */ -#ifndef OPENSSL_NO_TLSEXT -#define MAYBE_UNUSED -#else /* OPENSSL_NO_TLSEXT */ -#define MAYBE_UNUSED UNUSED -#endif /* OPENSSL_NO_TLSEXT */ -static void -pxy_fd_readcb(MAYBE_UNUSED evutil_socket_t fd, UNUSED short what, void *arg) -#undef MAYBE_UNUSED +static void pxy_fd_readcb(evutil_socket_t fd, short what, void *arg) { - pxy_conn_ctx_t *ctx = arg; + pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg; -#ifndef OPENSSL_NO_TLSEXT - /* for SSL, peek ClientHello and parse SNI from it */ - if (ctx->spec->ssl && !ctx->passthrough /*&& ctx->ev*/) { - unsigned char buf[1024]; - ssize_t n; - const unsigned char *chello; - int rv; - - n = recv(fd, buf, sizeof(buf), MSG_PEEK); - if (n == -1) { - log_err_printf("Error peeking on fd, aborting " - "connection\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - if (n == 0) { - /* socket got closed while we were waiting */ - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - - rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni); - if ((rv == 1) && !chello) { - log_err_printf("Peeking did not yield a (truncated) " - "ClientHello message, " - "aborting connection\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - if (OPTS_DEBUG(ctx->opts)) { - log_dbg_printf("SNI peek: [%s] [%s]\n", - ctx->sni ? ctx->sni : "n/a", - ((rv == 1) && chello) ? - "incomplete" : "complete"); - } - if ((rv == 1) && chello && (ctx->sni_peek_retries++ < 50)) { - /* ssl_tls_clienthello_parse indicates that we - * should retry later when we have more data, and we - * haven't reached the maximum retry count yet. - * Reschedule this event as timeout-only event in - * order to prevent busy looping over the read event. - * Because we only peeked at the pending bytes and - * never actually read them, fd is still ready for - * reading now. We use 25 * 0.2 s = 5 s timeout. */ - struct timeval retry_delay = {0, 100}; - - event_free(ctx->ev); - ctx->ev = event_new(ctx->evbase, fd, 0, - pxy_fd_readcb, ctx); - if (!ctx->ev) { - log_err_printf("Error creating retry " - "event, aborting " - "connection\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - event_add(ctx->ev, &retry_delay); - return; - } - event_free(ctx->ev); - ctx->ev = NULL; - } - - if (ctx->sni && !ctx->addrlen && ctx->spec->sni_port) { - char sniport[6]; - struct evutil_addrinfo hints; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = ctx->af; - hints.ai_flags = EVUTIL_AI_ADDRCONFIG; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - snprintf(sniport, sizeof(sniport), "%i", ctx->spec->sni_port); - evdns_getaddrinfo(ctx->dnsbase, ctx->sni, sniport, &hints, - pxy_sni_resolve_cb, ctx); - return; - } -#endif /* !OPENSSL_NO_TLSEXT */ + /* for SSL, peek ClientHello and parse SNI from it */ + if (ctx->spec->ssl && !ctx->passthrough /*&& ctx->ev*/) + { + unsigned char buf[1024]; + ssize_t n; + const unsigned char *chello; + int rv; + + n = recv(fd, buf, sizeof(buf), MSG_PEEK); + if (n == -1) + { + log_err_printf("Error peeking on fd, aborting " + "connection\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + if (n == 0) + { + /* socket got closed while we were waiting */ + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + + rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni); + if ((rv == 1) && !chello) + { + log_err_printf("Peeking did not yield a (truncated) " + "ClientHello message, " + "aborting connection\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + if (OPTS_DEBUG(ctx->opts)) + { + log_dbg_printf("SNI peek: [%s] [%s]\n", + ctx->sni ? ctx->sni : "n/a", + ((rv == 1) && chello) ? + "incomplete" : "complete"); + } + if ((rv == 1) && chello && (ctx->sni_peek_retries++ < 50)) + { + /* ssl_tls_clienthello_parse indicates that we + * should retry later when we have more data, and we + * haven't reached the maximum retry count yet. + * Reschedule this event as timeout-only event in + * order to prevent busy looping over the read event. + * Because we only peeked at the pending bytes and + * never actually read them, fd is still ready for + * reading now. We use 25 * 0.2 s = 5 s timeout. */ + struct timeval retry_delay = {0, 100}; + + event_free(ctx->ev); + ctx->ev = event_new(ctx->evbase, fd, 0, + pxy_fd_readcb, ctx); + if (!ctx->ev) + { + log_err_printf("Error creating retry " + "event, aborting " + "connection\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + event_add(ctx->ev, &retry_delay); + return; + } + event_free(ctx->ev); + ctx->ev = NULL; + } - pxy_conn_connect(ctx); + if (ctx->sni && !ctx->addrlen && ctx->spec->sni_port) + { + char sniport[6]; + struct evutil_addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ctx->af; + hints.ai_flags = EVUTIL_AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + snprintf(sniport, sizeof(sniport), "%i", ctx->spec->sni_port); + evdns_getaddrinfo(ctx->dnsbase, ctx->sni, sniport, &hints, + pxy_sni_resolve_cb, ctx); + return; + } + + pxy_conn_connect(ctx); } /* @@ -2245,83 +2161,85 @@ pxy_fd_readcb(MAYBE_UNUSED evutil_socket_t fd, UNUSED short what, void *arg) * start reading from the client while waiting on the connection to * the server to connect. */ -void -pxy_conn_setup(evutil_socket_t fd, - struct sockaddr *peeraddr, int peeraddrlen, - pxy_thrmgr_ctx_t *thrmgr, - proxyspec *spec, tfe_config *opts) +void pxy_conn_setup(evutil_socket_t fd, struct sockaddr *peeraddr, int peeraddrlen, + tfe_thread_manager_ctx *thrmgr, proxyspec *spec, tfe_config *opts) { - pxy_conn_ctx_t *ctx; - - /* create per connection pair state and attach to thread */ - ctx = pxy_conn_ctx_new(spec, opts, thrmgr, fd); - if (!ctx) { - log_err_printf("Error allocating memory\n"); - evutil_closesocket(fd); - return; - } - - ctx->af = peeraddr->sa_family; - - /* determine original destination of connection */ - if (spec->natlookup) { - /* NAT engine lookup */ - ctx->addrlen = sizeof(struct sockaddr_storage); - if (spec->natlookup((struct sockaddr *)&ctx->addr, &ctx->addrlen, - fd, peeraddr, peeraddrlen) == -1) { - log_err_printf("Connection not found in NAT " - "state table, aborting connection\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - } else if (spec->connect_addrlen > 0) { - /* static forwarding */ - ctx->addrlen = spec->connect_addrlen; - memcpy(&ctx->addr, &spec->connect_addr, ctx->addrlen); - } else { - /* SNI mode */ - if (!ctx->spec->ssl) { - /* if this happens, the proxyspec parser is broken */ - log_err_printf("SNI mode used for non-SSL connection; " - "aborting connection\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; - } - } - - /* prepare logging, part 1 */ - if (WANT_CONNECT_LOG(ctx) || WANT_CONTENT_LOG(ctx)) { - if (sys_sockaddr_str(peeraddr, peeraddrlen, - &ctx->srchost_str, - &ctx->srcport_str) != 0) - goto memout; -#ifdef HAVE_LOCAL_PROCINFO - if (ctx->opts->lprocinfo) { - memcpy(&ctx->lproc.srcaddr, peeraddr, peeraddrlen); - ctx->lproc.srcaddrlen = peeraddrlen; - } -#endif /* HAVE_LOCAL_PROCINFO */ - } - - /* for SSL, defer dst connection setup to initial_readcb */ - if (ctx->spec->ssl) { - ctx->ev = event_new(ctx->evbase, fd, EV_READ, pxy_fd_readcb, - ctx); - if (!ctx->ev) - goto memout; - event_add(ctx->ev, NULL); - } else { - pxy_fd_readcb(fd, 0, ctx); - } - return; + pxy_conn_ctx_t *ctx; + + /* create per connection pair state and attach to thread */ + ctx = pxy_conn_ctx_new(spec, opts, thrmgr, fd); + if (!ctx) + { + log_err_printf("Error allocating memory\n"); + evutil_closesocket(fd); + return; + } + + ctx->af = peeraddr->sa_family; + + /* determine original destination of connection */ + if (spec->natlookup) + { + /* NAT engine lookup */ + ctx->addrlen = sizeof(struct sockaddr_storage); + if (spec->natlookup((struct sockaddr *) &ctx->addr, &ctx->addrlen, + fd, peeraddr, peeraddrlen) == -1) + { + log_err_printf("Connection not found in NAT " + "state table, aborting connection\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + } + else if (spec->connect_addrlen > 0) + { + /* static forwarding */ + ctx->addrlen = spec->connect_addrlen; + memcpy(&ctx->addr, &spec->connect_addr, ctx->addrlen); + } + else + { + /* SNI mode */ + if (!ctx->spec->ssl) + { + /* if this happens, the proxyspec parser is broken */ + log_err_printf("SNI mode used for non-SSL connection; " + "aborting connection\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; + } + } + + /* prepare logging, part 1 */ + if (WANT_CONNECT_LOG(ctx) || WANT_CONTENT_LOG(ctx)) + { + if (sys_sockaddr_str(peeraddr, peeraddrlen, + &ctx->srchost_str, + &ctx->srcport_str) != 0) + goto memout; + } + + /* for SSL, defer dst connection setup to initial_readcb */ + if (ctx->spec->ssl) + { + ctx->ev = event_new(ctx->evbase, fd, EV_READ, pxy_fd_readcb, + ctx); + if (!ctx->ev) + goto memout; + event_add(ctx->ev, NULL); + } else + { + pxy_fd_readcb(fd, 0, ctx); + } + return; memout: - log_err_printf("Aborting connection setup (out of memory)!\n"); - evutil_closesocket(fd); - pxy_conn_ctx_free(ctx, 1); - return; + log_err_printf("Aborting connection setup (out of memory)!\n"); + evutil_closesocket(fd); + pxy_conn_ctx_free(ctx, 1); + return; } /* vim: set noet ft=c: */ diff --git a/src/pxyconn.h b/src/pxyconn.h index 13c0583..9a64593 100644 --- a/src/pxyconn.h +++ b/src/pxyconn.h @@ -79,11 +79,6 @@ typedef struct pxy_conn_ctx { unsigned int clienthello_search : 1; /* 1 if waiting for hello */ unsigned int clienthello_found : 1; /* 1 if conn upgrade to SSL */ - /* http request parser ctx */ - void * http_request_parser_ctx; - /* http response parser ctx */ - void * http_response_parser_ctx; - /* server name indicated by client in SNI TLS extension */ char *sni; @@ -109,11 +104,6 @@ typedef struct pxy_conn_ctx { char *origcrtfpr; char *usedcrtfpr; -#ifdef HAVE_LOCAL_PROCINFO - /* local process information */ - pxy_conn_lproc_desc_t lproc; -#endif /* HAVE_LOCAL_PROCINFO */ - /* content log context */ log_content_ctx_t *logctx; @@ -131,13 +121,18 @@ typedef struct pxy_conn_ctx { struct event_base *evbase; struct evdns_base *dnsbase; int thridx; - pxy_thrmgr_ctx_t *thrmgr; + tfe_thread_manager_ctx *thrmgr; proxyspec *spec; + tfe_config *opts; + tfe_instance * instance; + + /* Protocol Ctxs*/ + void * protocol_conn_ctx; } pxy_conn_ctx_t; void pxy_conn_setup(evutil_socket_t, struct sockaddr *, int, - pxy_thrmgr_ctx_t *, proxyspec *, tfe_config *) + tfe_thread_manager_ctx *, proxyspec *, tfe_config *) NONNULL(2,4,5,6); #endif /* !PXYCONN_H */ diff --git a/src/pxyhttp.cc b/src/pxyhttp.cc deleted file mode 100644 index 1424fb4..0000000 --- a/src/pxyhttp.cc +++ /dev/null @@ -1,182 +0,0 @@ -/* HTTP/HTTP2 Protocol Handler - * - * Author: Lu Qiuwen<[email protected]> - * Date: 2018-04-08 - * - */ - -#include <assert.h> -#include <http_parser.h> -#include <event2/bufferevent.h> -#include <evdns.h> - -#include "pxyhttp.h" -#include "pxyconn.h" - -static int __http_request_cb_on_url(http_parser *parser, const char *at, size_t length) -{ - pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *) parser->data; - - /* 复制URI,注意补齐String的\0结尾 */ - ctx->http_uri = (char *) malloc(length + 1); - strncpy(ctx->http_uri, at, length); - ctx->http_uri[length] = '\0'; - - return 0; -} - -static int __http_request_cb_on_header_field(http_parser *parser, const char *at, size_t length) -{ - pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *) parser->data; - assert(ctx != NULL && at != NULL); - - /* 处理Host字段,置Host为0xffffffff,在value回调函数中处理的value即为host字段 */ - if (strncasecmp(at, "Host", length) == 0) - { - ctx->http_host = (char *) 0xffffffff; - goto __leave; - } - -__leave: - return 0; -} - -static int __http_request_cb_on_header_value(http_parser *parser, const char *at, size_t length) -{ - pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *) parser->data; - assert(ctx != NULL && at != NULL); - - /* 处理Host字段的值 */ - if (ctx->http_host == (void *) 0xffffffff) - { - ctx->http_host = (char *) malloc(length + 1); - strncpy(ctx->http_host, at, length); - ctx->http_host[length] = '\0'; - } - - return 0; -} - -static int __http_request_cb_on_headers_complete(http_parser *parser) -{ - pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *) parser->data; - ctx->seen_req_header = 1; - return 0; -} - -static int __http_resp_cb_on_status(http_parser *parser, const char *at, size_t length) -{ - return 0; -} - -static int __http_resp_cb_on_headers_complete(http_parser *parser) -{ - pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *) parser->data; - - /* HTTP状态码 */ - asprintf(&ctx->http_status_code, "%d", parser->status_code); - ctx->seen_resp_header = 1; - return 0; -} - -/* HTTP Request Handlers */ -const static struct http_parser_settings __setting_http_parser_request = -{ - nullptr, /* on_message_begin */ - __http_request_cb_on_url, /* on_url */ - nullptr, /* on_status */ - __http_request_cb_on_header_field, /* on_header_field */ - __http_request_cb_on_header_value, /* on_header_value */ - __http_request_cb_on_headers_complete, /* on_headers_complete */ - nullptr, /* on_body */ - nullptr /* on_message_complete */ -}; - -/* HTTP Response Handlers */ -const static struct http_parser_settings __setting_http_parser_resp = -{ - nullptr, /* on_message_begin */ - nullptr, /* on_url */ - __http_resp_cb_on_status, /* on_status */ - nullptr, /* on_header_field */ - nullptr, /* on_header_value */ - __http_resp_cb_on_headers_complete, /* on_headers_complete */ - nullptr, /* on_body */ - nullptr /* on_message_complete */ -}; - -int pxy_http_read_cb(pxy_conn_ctx_t *ctx, struct bufferevent *bev) -{ - pxy_conn_desc_t *other = (bev == ctx->src.bev) ? &ctx->dst : &ctx->src; - int is_http_request = (bev == ctx->src.bev); - - /* HTTP Parser Handler */ - http_parser *http_parser_ctx = is_http_request ? - (http_parser *)ctx->http_request_parser_ctx : - (http_parser *)ctx->http_response_parser_ctx; - - void **http_parser_ctx_ref = is_http_request ? - &ctx->http_request_parser_ctx : - &ctx->http_response_parser_ctx; - - /* HTTP Passer Type */ - enum http_parser_type http_parser_work_mode = is_http_request ? - HTTP_REQUEST : - HTTP_RESPONSE; - - const struct http_parser_settings *http_parser_cb = is_http_request ? - &__setting_http_parser_request : - &__setting_http_parser_resp; - - /* 第一次请求,解析器句柄为空,创建新的解析器上下文 */ - if (http_parser_ctx == NULL) - { - http_parser_ctx = (http_parser *)malloc(sizeof(http_parser)); - *http_parser_ctx_ref = http_parser_ctx; - - http_parser_ctx->data = ctx; - http_parser_init(http_parser_ctx, http_parser_work_mode); - } - - /* 已经处理了HTTP Header,转发其他数据 */ - if (is_http_request && ctx->seen_req_header) - return 0; - if (!is_http_request && ctx->seen_resp_header) - return 0; - - struct evbuffer *input_buffer = bufferevent_get_input(bev); - size_t input_buffer_len = evbuffer_get_length(input_buffer); - - if (input_buffer_len == 0) - return 0; - - /* 连续的副本,供http_parser扫描使用 */ - char *__buffer_copy = (char *)malloc(input_buffer_len); - assert(__buffer_copy != NULL); - - /* 从buffer中拷贝出来一个副本 */ - ssize_t __buffer_len = evbuffer_copyout(input_buffer, __buffer_copy, input_buffer_len); - if (__buffer_len < 0) goto __error; - - /* 送入HTTP解析器处理 */ - if (http_parser_execute(http_parser_ctx, http_parser_cb, __buffer_copy, __buffer_len) - != __buffer_len) - { - goto __error; - } - - /* 判断此时HTTP头部是否完整,若完整,即可调用业务层处理, - * 每个HTTP事务仅在此调用一次业务层处理逻辑,调用结束后即可进入转发流程 */ - if(is_http_request && ctx->seen_req_header) - { - //TODO: Call Biz - } - if(!is_http_request && ctx->seen_resp_header) - { - //TODO: Call Biz - } - -__error: - free(__buffer_copy); - return -1; -}
\ No newline at end of file diff --git a/src/pxyhttp.h b/src/pxyhttp.h deleted file mode 100644 index 2ad3c13..0000000 --- a/src/pxyhttp.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef TFE_PXYHTTP_H -#define TFE_PXYHTTP_H - -#endif //TFE_PXYHTTP_H diff --git a/src/pxysslshut.cc b/src/pxysslshut.cc index c48767f..ecde031 100644 --- a/src/pxysslshut.cc +++ b/src/pxysslshut.cc @@ -30,10 +30,10 @@ #include "log.h" #include "attrib.h" +#include "util.h" -#include <stdlib.h> -#include <errno.h> - +#include <cstdlib> +#include <cerrno> #include <openssl/ssl.h> #include <openssl/err.h> diff --git a/src/pxythrmgr.cc b/src/pxythrmgr.cc index a670732..25aff4d 100644 --- a/src/pxythrmgr.cc +++ b/src/pxythrmgr.cc @@ -34,6 +34,11 @@ #include <string.h> #include <pthread.h> +#include <tuple> +#include <vector> +#include <thread> +#include <mutex> + /* * Proxy thread manager: manages the connection handling worker threads * and the per-thread resources (i.e. event bases). The load is shared @@ -43,195 +48,151 @@ * The attach and detach functions are thread-safe. */ -typedef struct pxy_thr_ctx { - pthread_t thr; - size_t load; - struct event_base *evbase; - struct evdns_base *dnsbase; - int running; -} pxy_thr_ctx_t; - -struct pxy_thrmgr_ctx { - int num_thr; - tfe_config *opts; - pxy_thr_ctx_t **thr; - pthread_mutex_t mutex; +struct tfe_thread_ctx +{ + pthread_t thr; + + int thread_id; + size_t load; + struct event_base *evbase; + struct evdns_base *dnsbase; + bool running; + + tfe_thread_ctx(int thread_id, bool en_dns_base); + ~tfe_thread_ctx(); +}; + +tfe_thread_ctx::tfe_thread_ctx(int thread_id, bool en_dns_base) : thread_id(thread_id), running(false) +{ + evbase = event_base_new(); + + if (evbase == nullptr) + { + throw std::runtime_error("Failed at create event_base on thread " + std::to_string(thread_id)); + } + + if (en_dns_base) + { + dnsbase = evdns_base_new(evbase, 1); + } + + if (en_dns_base && dnsbase == nullptr) + { + throw std::runtime_error("Failed at create dnsbase on thread " + std::to_string(thread_id)); + } +} + +tfe_thread_ctx::~tfe_thread_ctx() +{ + if (dnsbase != nullptr) evdns_base_free(dnsbase, 0); + if (evbase != nullptr) event_base_free(evbase); +} + +struct tfe_thread_manager_ctx +{ + tfe_config *opts{nullptr}; + unsigned int nr_thread{0}; + + std::mutex lock; + std::vector<tfe_thread_ctx *> thr_ctx; }; /* * Dummy recurring timer event to prevent the event loops from exiting when * they run out of events. */ -static void -pxy_thrmgr_timer_cb(UNUSED evutil_socket_t fd, UNUSED short what, - UNUSED void *arg) +static void __dummy_event_handler( + UNUSED evutil_socket_t fd, UNUSED short what, + UNUSED void *arg) { - /* do nothing */ + /* do nothing */ } /* * Thread entry point; runs the event loop of the event base. * Does not exit until the libevent loop is broken explicitly. */ -static void * -pxy_thrmgr_thr(void *arg) +static void *__tfe_thrmgr_thread_entry(void *arg) { - pxy_thr_ctx_t *ctx = arg; - struct timeval timer_delay = {60, 0}; - struct event *ev; - - ev = event_new(ctx->evbase, -1, EV_PERSIST, pxy_thrmgr_timer_cb, NULL); - if (!ev) - return NULL; - evtimer_add(ev, &timer_delay); - ctx->running = 1; - event_base_dispatch(ctx->evbase); - event_free(ev); - - return NULL; + struct tfe_thread_ctx *ctx = (struct tfe_thread_ctx *) arg; + struct timeval timer_delay = {60, 0}; + + struct event *ev; + ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL); + + if (!ev) + return NULL; + + evtimer_add(ev, &timer_delay); + ctx->running = 1; + event_base_dispatch(ctx->evbase); + event_free(ev); + + return NULL; } /* * Create new thread manager but do not start any threads yet. * This gets called before forking to background. */ -pxy_thrmgr_ctx_t * -pxy_thrmgr_new(tfe_config *opts) +struct tfe_thread_manager_ctx *tfe_thread_manager_new(tfe_config *opts) { - pxy_thrmgr_ctx_t *ctx; - - if (!(ctx = malloc(sizeof(pxy_thrmgr_ctx_t)))) - return NULL; - memset(ctx, 0, sizeof(pxy_thrmgr_ctx_t)); + struct tfe_thread_manager_ctx *ctx = new tfe_thread_manager_ctx; - ctx->opts = opts; - ctx->num_thr = 2 * sys_get_cpu_cores(); - return ctx; + //TODO: 用户配置线程数量 + //TODO: 用户配置线程亲和性 + ctx->opts = opts; + ctx->nr_thread = 2 * sys_get_cpu_cores(); + return ctx; } -/* - * Start the thread manager and associated threads. - * This must be called after forking. - * - * Returns -1 on failure, 0 on success. - */ -int -pxy_thrmgr_run(pxy_thrmgr_ctx_t *ctx) +int tfe_thread_manager_run(struct tfe_thread_manager_ctx *ctx) { - int idx = -1, dns = 0; - - dns = tfe_config_has_dns_spec(ctx->opts); - - if (pthread_mutex_init(&ctx->mutex, NULL)) { - log_dbg_printf("Failed to initialize mutex\n"); - goto leave; - } - - if (!(ctx->thr = malloc(ctx->num_thr * sizeof(pxy_thr_ctx_t*)))) { - log_dbg_printf("Failed to allocate memory\n"); - goto leave; - } - memset(ctx->thr, 0, ctx->num_thr * sizeof(pxy_thr_ctx_t*)); - - for (idx = 0; idx < ctx->num_thr; idx++) { - if (!(ctx->thr[idx] = malloc(sizeof(pxy_thr_ctx_t)))) { - log_dbg_printf("Failed to allocate memory\n"); - goto leave; - } - memset(ctx->thr[idx], 0, sizeof(pxy_thr_ctx_t)); - ctx->thr[idx]->evbase = event_base_new(); - if (!ctx->thr[idx]->evbase) { - log_dbg_printf("Failed to create evbase %d\n", idx); - goto leave; - } - if (dns) { - /* only create dns base if we actually need it later */ - ctx->thr[idx]->dnsbase = evdns_base_new( - ctx->thr[idx]->evbase, 1); - if (!ctx->thr[idx]->dnsbase) { - log_dbg_printf("Failed to create dnsbase %d\n", - idx); - goto leave; - } - } - ctx->thr[idx]->load = 0; - ctx->thr[idx]->running = 0; - } - - log_dbg_printf("Initialized %d connection handling threads\n", - ctx->num_thr); - - for (idx = 0; idx < ctx->num_thr; idx++) { - if (pthread_create(&ctx->thr[idx]->thr, NULL, - pxy_thrmgr_thr, ctx->thr[idx])) - goto leave_thr; - while (!ctx->thr[idx]->running) { - sched_yield(); - } - } - - log_dbg_printf("Started %d connection handling threads\n", - ctx->num_thr); - - return 0; - -leave_thr: - idx--; - while (idx >= 0) { - pthread_cancel(ctx->thr[idx]->thr); - pthread_join(ctx->thr[idx]->thr, NULL); - idx--; - } - idx = ctx->num_thr - 1; - -leave: - while (idx >= 0) { - if (ctx->thr[idx]) { - if (ctx->thr[idx]->dnsbase) { - evdns_base_free(ctx->thr[idx]->dnsbase, 0); - } - if (ctx->thr[idx]->evbase) { - event_base_free(ctx->thr[idx]->evbase); - } - free(ctx->thr[idx]); - } - idx--; - } - pthread_mutex_destroy(&ctx->mutex); - if (ctx->thr) { - free(ctx->thr); - ctx->thr = NULL; - } - return -1; + unsigned int thread_id; + bool dns = (bool)tfe_config_has_dns_spec(ctx->opts); + + for (thread_id = 0; thread_id < ctx->nr_thread; thread_id++) + { + auto *__thread_ctx = new tfe_thread_ctx(thread_id, dns); + ctx->thr_ctx.push_back(__thread_ctx); + } + + log_dbg_printf("Initialized %d connection handling threads\n", ctx->nr_thread); + + for (thread_id = 0; thread_id < ctx->nr_thread; thread_id++) + { + if (pthread_create(&ctx->thr_ctx[thread_id]->thr, NULL, + __tfe_thrmgr_thread_entry, ctx->thr_ctx[thread_id])) + { + throw std::runtime_error("Failed at creating thread " + std::to_string(thread_id) + + " :" + std::string(strerror(errno))); + } + + while (!ctx->thr_ctx[thread_id]->running) + { + sched_yield(); + } + } + + log_dbg_printf("Started %d connection handling threads\n", ctx->nr_thread); + return 0; } /* * Destroy the event manager and stop all threads. */ -void -pxy_thrmgr_free(pxy_thrmgr_ctx_t *ctx) +void tfe_thread_manager_free(struct tfe_thread_manager_ctx *ctx) { - pthread_mutex_destroy(&ctx->mutex); - if (ctx->thr) { - for (int idx = 0; idx < ctx->num_thr; idx++) { - event_base_loopbreak(ctx->thr[idx]->evbase); - sched_yield(); - } - for (int idx = 0; idx < ctx->num_thr; idx++) { - pthread_join(ctx->thr[idx]->thr, NULL); - } - for (int idx = 0; idx < ctx->num_thr; idx++) { - if (ctx->thr[idx]->dnsbase) { - evdns_base_free(ctx->thr[idx]->dnsbase, 0); - } - if (ctx->thr[idx]->evbase) { - event_base_free(ctx->thr[idx]->evbase); - } - free(ctx->thr[idx]); - } - free(ctx->thr); - } - free(ctx); + delete ctx; +} + +void tfe_thread_manager_attach_by_thread_id( + tfe_thread_manager_ctx *ctx, int thread_id, + struct event_base **ev_base_out, struct evdns_base **evdns_base_out) +{ + std::lock_guard<decltype(ctx->lock)> __lock_guard(ctx->lock); + *ev_base_out = ctx->thr_ctx[thread_id]->evbase; + *evdns_base_out = ctx->thr_ctx[thread_id]->dnsbase; } /* @@ -240,51 +201,38 @@ pxy_thrmgr_free(pxy_thrmgr_ctx_t *ctx) * Returns the index of the chosen thread (for passing to _detach later). * This function cannot fail. */ -int -pxy_thrmgr_attach(pxy_thrmgr_ctx_t *ctx, struct event_base **evbase, - struct evdns_base **dnsbase) +int tfe_thread_manager_attach(tfe_thread_manager_ctx *ctx, + struct event_base **evbase, struct evdns_base **dnsbase) { - int thridx; - size_t minload; - - thridx = 0; - pthread_mutex_lock(&ctx->mutex); - minload = ctx->thr[thridx]->load; -#ifdef DEBUG_THREAD - log_dbg_printf("===> Proxy connection handler thread status:\n" - "thr[%d]: %zu\n", thridx, minload); -#endif /* DEBUG_THREAD */ - for (int idx = 1; idx < ctx->num_thr; idx++) { -#ifdef DEBUG_THREAD - log_dbg_printf("thr[%d]: %zu\n", idx, ctx->thr[idx]->load); -#endif /* DEBUG_THREAD */ - if (minload > ctx->thr[idx]->load) { - minload = ctx->thr[idx]->load; - thridx = idx; - } - } - *evbase = ctx->thr[thridx]->evbase; - *dnsbase = ctx->thr[thridx]->dnsbase; - ctx->thr[thridx]->load++; - pthread_mutex_unlock(&ctx->mutex); - -#ifdef DEBUG_THREAD - log_dbg_printf("thridx: %d\n", thridx); -#endif /* DEBUG_THREAD */ - - return thridx; + std::lock_guard<decltype(ctx->lock)> __lock_guard(ctx->lock); + + int min_thread_id = 0; + size_t min_load = ctx->thr_ctx[min_thread_id]->load; + + for (unsigned thread_id = 1; thread_id < ctx->nr_thread; thread_id++) + { + if (min_load > ctx->thr_ctx[min_thread_id]->load) + { + min_load = ctx->thr_ctx[thread_id]->load; + min_thread_id = thread_id; + } + } + + *evbase = ctx->thr_ctx[min_thread_id]->evbase; + *dnsbase = ctx->thr_ctx[min_thread_id]->dnsbase; + + ctx->thr_ctx[min_thread_id]->load++; + return min_thread_id; } /* * Detach a connection from a thread by index. * This function cannot fail. */ -void -pxy_thrmgr_detach(pxy_thrmgr_ctx_t *ctx, int thridx) +void tfe_thread_manager_detach(tfe_thread_manager_ctx *ctx, int thread_id) { - pthread_mutex_lock(&ctx->mutex); - ctx->thr[thridx]->load--; - pthread_mutex_unlock(&ctx->mutex); + std::lock_guard<decltype(ctx->lock)> __lock_guard(ctx->lock); + ctx->thr_ctx[thread_id]->load--; } -/* vim: set noet ft=c: */ +/* vim: set noet ft=c: */
\ No newline at end of file diff --git a/src/pxythrmgr.h b/src/pxythrmgr.h index 88f142d..782ead2 100644 --- a/src/pxythrmgr.h +++ b/src/pxythrmgr.h @@ -38,15 +38,16 @@ #include <event2/event.h> #include <event2/dns.h> -typedef struct pxy_thrmgr_ctx pxy_thrmgr_ctx_t; +struct tfe_thread_manager_ctx; -pxy_thrmgr_ctx_t * pxy_thrmgr_new(tfe_config *) MALLOC; -int pxy_thrmgr_run(pxy_thrmgr_ctx_t *) NONNULL(1) WUNRES; -void pxy_thrmgr_free(pxy_thrmgr_ctx_t *) NONNULL(1); +tfe_thread_manager_ctx * tfe_thread_manager_new(tfe_config *) MALLOC; +int tfe_thread_manager_run(tfe_thread_manager_ctx *) NONNULL(1) WUNRES; +void tfe_thread_manager_free(tfe_thread_manager_ctx *) NONNULL(1); -int pxy_thrmgr_attach(pxy_thrmgr_ctx_t *, struct event_base **, +int tfe_thread_manager_attach(tfe_thread_manager_ctx *, struct event_base **, struct evdns_base **) WUNRES; -void pxy_thrmgr_detach(pxy_thrmgr_ctx_t *, int); + +void tfe_thread_manager_detach(tfe_thread_manager_ctx *, int); #endif /* !PXYTHRMGR_H */ @@ -68,15 +68,15 @@ * OpenSSL internal declarations from ssl_locl.h, reduced to what is needed. */ struct cert_pkey_st { - X509 *x509; - /* - EVP_PKEY *privatekey; - const EVP_MD *digest; - */ + X509 *x509; + /* + EVP_PKEY *privatekey; + const EVP_MD *digest; + */ }; struct cert_st { - struct cert_pkey_st *key; - /* ... */ + struct cert_pkey_st *key; + /* ... */ }; /* @@ -85,13 +85,12 @@ struct cert_st { X509 * ssl_ssl_cert_get(SSL *s) { - return s->cert ? s->cert->key->x509 : NULL; + return s->cert ? s->cert->key->x509 : NULL; } #endif /* OpenSSL 0.9.8y, 1.0.0k or 1.0.1e */ #if OPENSSL_VERSION_NUMBER < 0x10100000L -int -DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { /* If the fields p and g in d are NULL, the corresponding input * parameters MUST be non-NULL. q may remain NULL. @@ -100,20 +99,24 @@ DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) || (dh->g == NULL && g == NULL)) return 0; - if (p != NULL) { + if (p != NULL) + { BN_free(dh->p); dh->p = p; } - if (q != NULL) { + if (q != NULL) + { BN_free(dh->q); dh->q = q; } - if (g != NULL) { + if (g != NULL) + { BN_free(dh->g); dh->g = g; } - if (q != NULL) { + if (q != NULL) + { dh->length = BN_num_bits(q); } @@ -121,7 +124,6 @@ DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) } #endif - /* * Print OpenSSL version and build-time configuration to standard error and * return. @@ -129,132 +131,133 @@ DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) void ssl_openssl_version(void) { - fprintf(stderr, "compiled against %s (%lx)\n", - OPENSSL_VERSION_TEXT, - (long unsigned int)OPENSSL_VERSION_NUMBER); - fprintf(stderr, "rtlinked against %s (%lx)\n", - SSLeay_version(SSLEAY_VERSION), - SSLeay()); - if ((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xfffff000L) { - fprintf(stderr, "---------------------------------------" - "---------------------------------------\n"); - fprintf(stderr, "WARNING: OpenSSL version mismatch may " - "lead to crashes or other problems!\n"); - fprintf(stderr, "If there are multiple versions of " - "OpenSSL available, make sure to use\n"); - fprintf(stderr, "the same version of the library at " - "runtime as well as for compiling against.\n"); - fprintf(stderr, "---------------------------------------" - "---------------------------------------\n"); - } + fprintf(stderr, "compiled against %s (%lx)\n", + OPENSSL_VERSION_TEXT, + (long unsigned int) OPENSSL_VERSION_NUMBER); + fprintf(stderr, "rtlinked against %s (%lx)\n", + SSLeay_version(SSLEAY_VERSION), + SSLeay()); + if ((OPENSSL_VERSION_NUMBER ^ SSLeay()) & 0xfffff000L) + { + fprintf(stderr, "---------------------------------------" + "---------------------------------------\n"); + fprintf(stderr, "WARNING: OpenSSL version mismatch may " + "lead to crashes or other problems!\n"); + fprintf(stderr, "If there are multiple versions of " + "OpenSSL available, make sure to use\n"); + fprintf(stderr, "the same version of the library at " + "runtime as well as for compiling against.\n"); + fprintf(stderr, "---------------------------------------" + "---------------------------------------\n"); + } #ifdef LIBRESSL_VERSION_NUMBER - fprintf(stderr, "LibreSSL detected: %s (%lx)\n", - LIBRESSL_VERSION_TEXT, - (long unsigned int)LIBRESSL_VERSION_NUMBER); + fprintf(stderr, "LibreSSL detected: %s (%lx)\n", + LIBRESSL_VERSION_TEXT, + (long unsigned int)LIBRESSL_VERSION_NUMBER); #endif /* LIBRESSL_VERSION_NUMBER */ #ifdef OPENSSL_IS_BORINGSSL - fprintf(stderr, "BoringSSL detected\n") + fprintf(stderr, "BoringSSL detected\n") #endif /* OPENSSL_IS_BORINGSSL */ #ifndef OPENSSL_NO_TLSEXT - fprintf(stderr, "OpenSSL has support for TLS extensions\n" - "TLS Server Name Indication (SNI) supported\n"); + fprintf(stderr, "OpenSSL has support for TLS extensions\n" + "TLS Server Name Indication (SNI) supported\n"); #else /* OPENSSL_NO_TLSEXT */ - fprintf(stderr, "OpenSSL has no support for TLS extensions\n" - "TLS Server Name Indication (SNI) not supported\n"); + fprintf(stderr, "OpenSSL has no support for TLS extensions\n" + "TLS Server Name Indication (SNI) not supported\n"); #endif /* OPENSSL_NO_TLSEXT */ #ifdef OPENSSL_THREADS #ifndef OPENSSL_NO_THREADID - fprintf(stderr, "OpenSSL is thread-safe with THREADID\n"); + fprintf(stderr, "OpenSSL is thread-safe with THREADID\n"); #else /* OPENSSL_NO_THREADID */ - fprintf(stderr, "OpenSSL is thread-safe without THREADID\n"); + fprintf(stderr, "OpenSSL is thread-safe without THREADID\n"); #endif /* OPENSSL_NO_THREADID */ #else /* !OPENSSL_THREADS */ - fprintf(stderr, "OpenSSL is not thread-safe\n"); + fprintf(stderr, "OpenSSL is not thread-safe\n"); #endif /* !OPENSSL_THREADS */ #ifdef SSL_MODE_RELEASE_BUFFERS - fprintf(stderr, "Using SSL_MODE_RELEASE_BUFFERS\n"); + fprintf(stderr, "Using SSL_MODE_RELEASE_BUFFERS\n"); #else /* !SSL_MODE_RELEASE_BUFFERS */ - fprintf(stderr, "Not using SSL_MODE_RELEASE_BUFFERS\n"); + fprintf(stderr, "Not using SSL_MODE_RELEASE_BUFFERS\n"); #endif /* !SSL_MODE_RELEASE_BUFFERS */ #if (OPENSSL_VERSION_NUMBER == 0x0090819fL) || \ (OPENSSL_VERSION_NUMBER == 0x100000bfL) || \ (OPENSSL_VERSION_NUMBER == 0x1000105fL) - fprintf(stderr, "Using direct access workaround when loading certs\n"); + fprintf(stderr, "Using direct access workaround when loading certs\n"); #endif /* OpenSSL 0.9.8y, 1.0.0k or 1.0.1e */ - fprintf(stderr, "SSL/TLS protocol availability: %s\n", - SSL_PROTO_SUPPORT_S); + fprintf(stderr, "SSL/TLS protocol availability: %s\n", + SSL_PROTO_SUPPORT_S); - fprintf(stderr, "SSL/TLS algorithm availability:"); + fprintf(stderr, "SSL/TLS algorithm availability:"); #ifndef OPENSSL_NO_SHA0 - fprintf(stderr, " SHA0"); + fprintf(stderr, " SHA0"); #else /* !OPENSSL_NO_SHA0 */ - fprintf(stderr, " !SHA0"); + fprintf(stderr, " !SHA0"); #endif /* !OPENSSL_NO_SHA0 */ #ifndef OPENSSL_NO_RSA - fprintf(stderr, " RSA"); + fprintf(stderr, " RSA"); #else /* !OPENSSL_NO_RSA */ - fprintf(stderr, " !RSA"); + fprintf(stderr, " !RSA"); #endif /* !OPENSSL_NO_RSA */ #ifndef OPENSSL_NO_DSA - fprintf(stderr, " DSA"); + fprintf(stderr, " DSA"); #else /* !OPENSSL_NO_DSA */ - fprintf(stderr, " !DSA"); + fprintf(stderr, " !DSA"); #endif /* !OPENSSL_NO_DSA */ #ifndef OPENSSL_NO_ECDSA - fprintf(stderr, " ECDSA"); + fprintf(stderr, " ECDSA"); #else /* !OPENSSL_NO_ECDSA */ - fprintf(stderr, " !ECDSA"); + fprintf(stderr, " !ECDSA"); #endif /* !OPENSSL_NO_ECDSA */ #ifndef OPENSSL_NO_DH - fprintf(stderr, " DH"); + fprintf(stderr, " DH"); #else /* !OPENSSL_NO_DH */ - fprintf(stderr, " !DH"); + fprintf(stderr, " !DH"); #endif /* !OPENSSL_NO_DH */ #ifndef OPENSSL_NO_ECDH - fprintf(stderr, " ECDH"); + fprintf(stderr, " ECDH"); #else /* !OPENSSL_NO_ECDH */ - fprintf(stderr, " !ECDH"); + fprintf(stderr, " !ECDH"); #endif /* !OPENSSL_NO_ECDH */ #ifndef OPENSSL_NO_EC - fprintf(stderr, " EC"); + fprintf(stderr, " EC"); #else /* !OPENSSL_NO_EC */ - fprintf(stderr, " !EC"); + fprintf(stderr, " !EC"); #endif /* !OPENSSL_NO_EC */ - fprintf(stderr, "\n"); + fprintf(stderr, "\n"); - fprintf(stderr, "OpenSSL option availability:"); + fprintf(stderr, "OpenSSL option availability:"); #ifdef SSL_OP_NO_COMPRESSION - fprintf(stderr, " SSL_OP_NO_COMPRESSION"); + fprintf(stderr, " SSL_OP_NO_COMPRESSION"); #else /* !SSL_OP_NO_COMPRESSION */ - fprintf(stderr, " !SSL_OP_NO_COMPRESSION"); + fprintf(stderr, " !SSL_OP_NO_COMPRESSION"); #endif /* SSL_OP_NO_COMPRESSION */ #ifdef SSL_OP_NO_TICKET - fprintf(stderr, " SSL_OP_NO_TICKET"); + fprintf(stderr, " SSL_OP_NO_TICKET"); #else /* !SSL_OP_NO_TICKET */ - fprintf(stderr, " !SSL_OP_NO_TICKET"); + fprintf(stderr, " !SSL_OP_NO_TICKET"); #endif /* SSL_OP_NO_TICKET */ #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - fprintf(stderr, " SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"); + fprintf(stderr, " SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"); #else /* !SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION */ - fprintf(stderr, " !SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"); + fprintf(stderr, " !SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"); #endif /* !SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION */ #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - fprintf(stderr, " SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"); + fprintf(stderr, " SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"); #else /* !SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */ - fprintf(stderr, " !SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"); + fprintf(stderr, " !SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"); #endif /* !SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */ #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - fprintf(stderr, " SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"); + fprintf(stderr, " SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"); #else /* !SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION */ - fprintf(stderr, " !SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"); + fprintf(stderr, " !SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"); #endif /* !SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION */ #ifdef SSL_OP_TLS_ROLLBACK_BUG - fprintf(stderr, " SSL_OP_TLS_ROLLBACK_BUG"); + fprintf(stderr, " SSL_OP_TLS_ROLLBACK_BUG"); #else /* !SSL_OP_TLS_ROLLBACK_BUG */ - fprintf(stderr, " !SSL_OP_TLS_ROLLBACK_BUG"); + fprintf(stderr, " !SSL_OP_TLS_ROLLBACK_BUG"); #endif /* !SSL_OP_TLS_ROLLBACK_BUG */ - fprintf(stderr, "\n"); + fprintf(stderr, "\n"); } /* @@ -265,8 +268,9 @@ ssl_openssl_version(void) static int ssl_initialized = 0; #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L -struct CRYPTO_dynlock_value { - pthread_mutex_t mutex; +struct CRYPTO_dynlock_value +{ + pthread_mutex_t mutex; }; static pthread_mutex_t *ssl_mutex; static int ssl_mutex_num; @@ -275,14 +279,17 @@ static int ssl_mutex_num; * OpenSSL thread-safety locking callback, #1. */ static void -ssl_thr_locking_cb(int mode, int type, UNUSED const char *file, - UNUSED int line) { - if (type < ssl_mutex_num) { - if (mode & CRYPTO_LOCK) - pthread_mutex_lock(&ssl_mutex[type]); - else - pthread_mutex_unlock(&ssl_mutex[type]); - } +ssl_thr_locking_cb( + int mode, int type, UNUSED const char *file, + UNUSED int line) +{ + if (type < ssl_mutex_num) + { + if (mode & CRYPTO_LOCK) + pthread_mutex_lock(&ssl_mutex[type]); + else + pthread_mutex_unlock(&ssl_mutex[type]); + } } /* @@ -291,40 +298,44 @@ ssl_thr_locking_cb(int mode, int type, UNUSED const char *file, static struct CRYPTO_dynlock_value * ssl_thr_dyn_create_cb(UNUSED const char *file, UNUSED int line) { - struct CRYPTO_dynlock_value *dl; - - if ((dl = malloc(sizeof(struct CRYPTO_dynlock_value)))) { - if (pthread_mutex_init(&dl->mutex, NULL)) { - free(dl); - return NULL; - } - } - return dl; + struct CRYPTO_dynlock_value *dl; + + if ((dl = (CRYPTO_dynlock_value *)malloc(sizeof(struct CRYPTO_dynlock_value)))) + { + if (pthread_mutex_init(&dl->mutex, NULL)) + { + free(dl); + return NULL; + } + } + return dl; } /* * OpenSSL thread-safety locking callback, #3. */ -static void -ssl_thr_dyn_lock_cb(int mode, struct CRYPTO_dynlock_value *dl, - UNUSED const char *file, UNUSED int line) +static void ssl_thr_dyn_lock_cb( + int mode, struct CRYPTO_dynlock_value *dl, + UNUSED const char *file, UNUSED int line) { - if (mode & CRYPTO_LOCK) { - pthread_mutex_lock(&dl->mutex); - } else { - pthread_mutex_unlock(&dl->mutex); - } + if (mode & CRYPTO_LOCK) + { + pthread_mutex_lock(&dl->mutex); + } else + { + pthread_mutex_unlock(&dl->mutex); + } } /* * OpenSSL thread-safety locking callback, #4. */ -static void -ssl_thr_dyn_destroy_cb(struct CRYPTO_dynlock_value *dl, - UNUSED const char *file, UNUSED int line) +static void ssl_thr_dyn_destroy_cb( + struct CRYPTO_dynlock_value *dl, + UNUSED const char *file, UNUSED int line) { - pthread_mutex_destroy(&dl->mutex); - free(dl); + pthread_mutex_destroy(&dl->mutex); + free(dl); } #ifdef OPENSSL_NO_THREADID @@ -333,7 +344,7 @@ ssl_thr_dyn_destroy_cb(struct CRYPTO_dynlock_value *dl, */ static unsigned long ssl_thr_id_cb(void) { - return (unsigned long) pthread_self(); + return (unsigned long) pthread_self(); } #else /* !OPENSSL_NO_THREADID */ /* @@ -342,7 +353,7 @@ ssl_thr_id_cb(void) { static void ssl_thr_id_cb(CRYPTO_THREADID *id) { - CRYPTO_THREADID_set_numeric(id, (unsigned long) pthread_self()); + CRYPTO_THREADID_set_numeric(id, (unsigned long) pthread_self()); } #endif /* !OPENSSL_NO_THREADID */ #endif /* OPENSSL_THREADS */ @@ -355,81 +366,88 @@ int ssl_init(void) { #ifndef PURIFY - int fd; + int fd; #endif /* !PURIFY */ - char buf[256]; + char buf[256]; - if (ssl_initialized) - return 0; + if (ssl_initialized) + return 0; - /* general initialization */ - SSL_library_init(); + /* general initialization */ + SSL_library_init(); #ifdef PURIFY - CRYPTO_malloc_init(); - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + CRYPTO_malloc_init(); + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); #endif /* PURIFY */ - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); - /* thread-safety */ + /* thread-safety */ #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - ssl_mutex_num = CRYPTO_num_locks(); - ssl_mutex = malloc(ssl_mutex_num * sizeof(*ssl_mutex)); - for (int i = 0; i < ssl_mutex_num; i++) { - if (pthread_mutex_init(&ssl_mutex[i], NULL)) { - log_err_printf("Failed to initialize mutex\n"); - return -1; - } - } - CRYPTO_set_locking_callback(ssl_thr_locking_cb); - CRYPTO_set_dynlock_create_callback(ssl_thr_dyn_create_cb); - CRYPTO_set_dynlock_lock_callback(ssl_thr_dyn_lock_cb); - CRYPTO_set_dynlock_destroy_callback(ssl_thr_dyn_destroy_cb); + ssl_mutex_num = CRYPTO_num_locks(); + ssl_mutex = (pthread_mutex_t *)malloc(ssl_mutex_num * sizeof(*ssl_mutex)); + + for (int i = 0; i < ssl_mutex_num; i++) + { + if (pthread_mutex_init(&ssl_mutex[i], NULL)) + { + log_err_printf("Failed to initialize mutex\n"); + return -1; + } + } + CRYPTO_set_locking_callback(ssl_thr_locking_cb); + CRYPTO_set_dynlock_create_callback(ssl_thr_dyn_create_cb); + CRYPTO_set_dynlock_lock_callback(ssl_thr_dyn_lock_cb); + CRYPTO_set_dynlock_destroy_callback(ssl_thr_dyn_destroy_cb); #ifdef OPENSSL_NO_THREADID - CRYPTO_set_id_callback(ssl_thr_id_cb); + CRYPTO_set_id_callback(ssl_thr_id_cb); #else /* !OPENSSL_NO_THREADID */ - CRYPTO_THREADID_set_callback(ssl_thr_id_cb); + CRYPTO_THREADID_set_callback(ssl_thr_id_cb); #endif /* !OPENSSL_NO_THREADID */ #endif /* OPENSSL_THREADS */ - /* randomness */ + /* randomness */ #ifndef PURIFY - if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { - log_err_printf("Error opening /dev/urandom for reading: %s\n", - strerror(errno)); - return -1; - } - while (!RAND_status()) { - if (read(fd, buf, sizeof(buf)) == -1) { - log_err_printf("Error reading from /dev/urandom: %s\n", - strerror(errno)); - close(fd); - return -1; - } - RAND_seed(buf, sizeof(buf)); - } - close(fd); - if (!RAND_poll()) { - log_err_printf("RAND_poll() failed.\n"); - return -1; - } + if ((fd = open("/dev/urandom", O_RDONLY)) == -1) + { + log_err_printf("Error opening /dev/urandom for reading: %s\n", + strerror(errno)); + return -1; + } + while (!RAND_status()) + { + if (read(fd, buf, sizeof(buf)) == -1) + { + log_err_printf("Error reading from /dev/urandom: %s\n", + strerror(errno)); + close(fd); + return -1; + } + RAND_seed(buf, sizeof(buf)); + } + close(fd); + if (!RAND_poll()) + { + log_err_printf("RAND_poll() failed.\n"); + return -1; + } #else /* PURIFY */ - log_err_printf("Warning: not seeding OpenSSL RAND due to PURITY!\n"); - memset(buf, 0, sizeof(buf)); - while (!RAND_status()) { - RAND_seed(buf, sizeof(buf)); - } + log_err_printf("Warning: not seeding OpenSSL RAND due to PURITY!\n"); + memset(buf, 0, sizeof(buf)); + while (!RAND_status()) { + RAND_seed(buf, sizeof(buf)); + } #endif /* PURIFY */ #ifdef USE_FOOTPRINT_HACKS - /* HACK: disable compression by zeroing the global comp algo stack. - * This lowers the per-connection memory footprint by ~500k. */ - STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_methods(); - sk_SSL_COMP_zero(comp_methods); + /* HACK: disable compression by zeroing the global comp algo stack. + * This lowers the per-connection memory footprint by ~500k. */ + STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_methods(); + sk_SSL_COMP_zero(comp_methods); #endif /* USE_FOOTPRINT_HACKS */ - ssl_initialized = 1; - return 0; + ssl_initialized = 1; + return 0; } /* @@ -438,18 +456,20 @@ ssl_init(void) int ssl_reinit(void) { - if (!ssl_initialized) - return 0; + if (!ssl_initialized) + return 0; #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - for (int i = 0; i < ssl_mutex_num; i++) { - if (pthread_mutex_init(&ssl_mutex[i], NULL)) { - return -1; - } - } + for (int i = 0; i < ssl_mutex_num; i++) + { + if (pthread_mutex_init(&ssl_mutex[i], NULL)) + { + return -1; + } + } #endif /* OPENSSL_THREADS */ - return 0; + return 0; } /* @@ -459,37 +479,38 @@ ssl_reinit(void) void ssl_fini(void) { - if (!ssl_initialized) - return; + if (!ssl_initialized) + return; #if OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_state(0); /* current thread */ + ERR_remove_state(0); /* current thread */ #endif #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_dynlock_create_callback(NULL); - CRYPTO_set_dynlock_lock_callback(NULL); - CRYPTO_set_dynlock_destroy_callback(NULL); + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_dynlock_create_callback(NULL); + CRYPTO_set_dynlock_lock_callback(NULL); + CRYPTO_set_dynlock_destroy_callback(NULL); #ifdef OPENSSL_NO_THREADID - CRYPTO_set_id_callback(NULL); + CRYPTO_set_id_callback(NULL); #else /* !OPENSSL_NO_THREADID */ - CRYPTO_THREADID_set_callback(NULL); + CRYPTO_THREADID_set_callback(NULL); #endif /* !OPENSSL_NO_THREADID */ - for (int i = 0; i < ssl_mutex_num; i++) { - pthread_mutex_destroy(&ssl_mutex[i]); - } - free(ssl_mutex); + for (int i = 0; i < ssl_mutex_num; i++) + { + pthread_mutex_destroy(&ssl_mutex[i]); + } + free(ssl_mutex); #endif - ENGINE_cleanup(); - CONF_modules_finish(); - CONF_modules_unload(1); - CONF_modules_free(); + ENGINE_cleanup(); + CONF_modules_finish(); + CONF_modules_unload(1); + CONF_modules_free(); - EVP_cleanup(); - ERR_free_strings(); - CRYPTO_cleanup_all_ex_data(); + EVP_cleanup(); + ERR_free_strings(); + CRYPTO_cleanup_all_ex_data(); } /* @@ -498,22 +519,22 @@ ssl_fini(void) char * ssl_sha1_to_str(unsigned char *rawhash, int colons) { - char *str; - int rv; - - rv = asprintf(&str, colons ? - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" - "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" : - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - rawhash[ 0], rawhash[ 1], rawhash[ 2], rawhash[ 3], - rawhash[ 4], rawhash[ 5], rawhash[ 6], rawhash[ 7], - rawhash[ 8], rawhash[ 9], rawhash[10], rawhash[11], - rawhash[12], rawhash[13], rawhash[14], rawhash[15], - rawhash[16], rawhash[17], rawhash[18], rawhash[19]); - if (rv == -1) - return NULL; - return str; + char *str; + int rv; + + rv = asprintf(&str, colons ? + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" : + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + rawhash[0], rawhash[1], rawhash[2], rawhash[3], + rawhash[4], rawhash[5], rawhash[6], rawhash[7], + rawhash[8], rawhash[9], rawhash[10], rawhash[11], + rawhash[12], rawhash[13], rawhash[14], rawhash[15], + rawhash[16], rawhash[17], rawhash[18], rawhash[19]); + if (rv == -1) + return NULL; + return str; } /* @@ -523,19 +544,19 @@ ssl_sha1_to_str(unsigned char *rawhash, int colons) char * ssl_ssl_state_to_str(SSL *ssl) { - char *str = NULL; - int rv; - - rv = asprintf(&str, "%08x = %s%s%04x = %s (%s) [%s]", - SSL_get_state(ssl), - (SSL_get_state(ssl) & SSL_ST_CONNECT) ? "SSL_ST_CONNECT|" : "", - (SSL_get_state(ssl) & SSL_ST_ACCEPT) ? "SSL_ST_ACCEPT|" : "", - SSL_get_state(ssl) & SSL_ST_MASK, - SSL_state_string(ssl), - SSL_state_string_long(ssl), - SSL_is_server(ssl) ? "accept socket" : "connect socket"); - - return (rv < 0) ? NULL : str; + char *str = NULL; + int rv; + + rv = asprintf(&str, "%08x = %s%s%04x = %s (%s) [%s]", + SSL_get_state(ssl), + (SSL_get_state(ssl) & SSL_ST_CONNECT) ? "SSL_ST_CONNECT|" : "", + (SSL_get_state(ssl) & SSL_ST_ACCEPT) ? "SSL_ST_ACCEPT|" : "", + SSL_get_state(ssl) & SSL_ST_MASK, + SSL_state_string(ssl), + SSL_state_string_long(ssl), + SSL_is_server(ssl) ? "accept socket" : "connect socket"); + + return (rv < 0) ? NULL : str; } /* @@ -547,212 +568,213 @@ ssl_ssl_state_to_str(SSL *ssl) * * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format */ -char * -ssl_ssl_masterkey_to_str(SSL *ssl) +char * ssl_ssl_masterkey_to_str(SSL *ssl) { - char *str = NULL; - int rv; - unsigned char *k, *r; + char *str = NULL; + int rv; + unsigned char *k, *r; #if OPENSSL_VERSION_NUMBER >= 0x10100000L - unsigned char kbuf[48], rbuf[32]; - k = &kbuf[0]; - r = &rbuf[0]; - SSL_SESSION_get_master_key(SSL_get0_session(ssl), k, sizeof(kbuf)); - SSL_get_client_random(ssl, r, sizeof(rbuf)); + unsigned char kbuf[48], rbuf[32]; + k = &kbuf[0]; + r = &rbuf[0]; + SSL_SESSION_get_master_key(SSL_get0_session(ssl), k, sizeof(kbuf)); + SSL_get_client_random(ssl, r, sizeof(rbuf)); #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ - k = ssl->session->master_key; - r = ssl->s3->client_random; + k = ssl->session->master_key; + r = ssl->s3->client_random; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ - rv = asprintf(&str, - "CLIENT_RANDOM " - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - " " - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X" - "\n", - r[ 0], r[ 1], r[ 2], r[ 3], r[ 4], r[ 5], r[ 6], r[ 7], - r[ 8], r[ 9], r[10], r[11], r[12], r[13], r[14], r[15], - r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23], - r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31], - k[ 0], k[ 1], k[ 2], k[ 3], k[ 4], k[ 5], k[ 6], k[ 7], - k[ 8], k[ 9], k[10], k[11], k[12], k[13], k[14], k[15], - k[16], k[17], k[18], k[19], k[20], k[21], k[22], k[23], - k[24], k[25], k[26], k[27], k[28], k[29], k[30], k[31], - k[32], k[33], k[34], k[35], k[36], k[37], k[38], k[39], - k[40], k[41], k[42], k[43], k[44], k[45], k[46], k[47]); - - return (rv < 0) ? NULL : str; + rv = asprintf(&str, + "CLIENT_RANDOM " + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + " " + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X" + "\n", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], + r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15], + r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23], + r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31], + k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7], + k[8], k[9], k[10], k[11], k[12], k[13], k[14], k[15], + k[16], k[17], k[18], k[19], k[20], k[21], k[22], k[23], + k[24], k[25], k[26], k[27], k[28], k[29], k[30], k[31], + k[32], k[33], k[34], k[35], k[36], k[37], k[38], k[39], + k[40], k[41], k[42], k[43], k[44], k[45], k[46], k[47]); + + return (rv < 0) ? NULL : str; } #ifndef OPENSSL_NO_DH -static unsigned char dh_g[] = { 0x02 }; +static unsigned char dh_g[] = {0x02}; static unsigned char dh512_p[] = { - 0xAB, 0xC0, 0x34, 0x16, 0x95, 0x8B, 0x57, 0xE5, 0x5C, 0xB3, 0x4E, 0x6E, - 0x16, 0x0B, 0x35, 0xC5, 0x6A, 0xCC, 0x4F, 0xD3, 0xE5, 0x46, 0xE2, 0x23, - 0x6A, 0x5B, 0xBB, 0x5D, 0x3D, 0x52, 0xEA, 0xCE, 0x4F, 0x7D, 0xCA, 0xFF, - 0xB4, 0x8B, 0xC9, 0x78, 0xDC, 0xA0, 0xFC, 0xBE, 0xF3, 0xB5, 0xE6, 0x61, - 0xA6, 0x6D, 0x58, 0xFC, 0xA0, 0x0F, 0xF7, 0x9B, 0x97, 0xE6, 0xC7, 0xE8, - 0x1F, 0xCD, 0x16, 0x73 }; + 0xAB, 0xC0, 0x34, 0x16, 0x95, 0x8B, 0x57, 0xE5, 0x5C, 0xB3, 0x4E, 0x6E, + 0x16, 0x0B, 0x35, 0xC5, 0x6A, 0xCC, 0x4F, 0xD3, 0xE5, 0x46, 0xE2, 0x23, + 0x6A, 0x5B, 0xBB, 0x5D, 0x3D, 0x52, 0xEA, 0xCE, 0x4F, 0x7D, 0xCA, 0xFF, + 0xB4, 0x8B, 0xC9, 0x78, 0xDC, 0xA0, 0xFC, 0xBE, 0xF3, 0xB5, 0xE6, 0x61, + 0xA6, 0x6D, 0x58, 0xFC, 0xA0, 0x0F, 0xF7, 0x9B, 0x97, 0xE6, 0xC7, 0xE8, + 0x1F, 0xCD, 0x16, 0x73}; static unsigned char dh1024_p[] = { - 0x99, 0x28, 0x34, 0x48, 0x9E, 0xB7, 0xD1, 0x4F, 0x0D, 0x17, 0x09, 0x97, - 0xB9, 0x9B, 0x20, 0xFE, 0xE5, 0x65, 0xE0, 0xE2, 0x56, 0x37, 0x80, 0xA2, - 0x9F, 0x2C, 0x2D, 0x87, 0x10, 0x58, 0x39, 0xAD, 0xF3, 0xC5, 0xA9, 0x08, - 0x24, 0xC7, 0xAA, 0xA9, 0x29, 0x3A, 0x13, 0xDF, 0x4E, 0x0A, 0x6D, 0x11, - 0x39, 0xB1, 0x1C, 0x3F, 0xFE, 0xFE, 0x0A, 0x5E, 0xAD, 0x2E, 0x5C, 0x10, - 0x97, 0x38, 0xAC, 0xE8, 0xEB, 0xAA, 0x4A, 0xA1, 0xC0, 0x5C, 0x1D, 0x27, - 0x65, 0x9C, 0xC8, 0x53, 0xAC, 0x35, 0xDD, 0x84, 0x1F, 0x47, 0x0E, 0x04, - 0xF1, 0x90, 0x61, 0x62, 0x2E, 0x29, 0x2C, 0xC6, 0x28, 0x91, 0x6D, 0xF0, - 0xE2, 0x5E, 0xCE, 0x60, 0x3E, 0xF7, 0xF8, 0x37, 0x99, 0x4D, 0x9F, 0xFB, - 0x68, 0xEC, 0x7F, 0x9D, 0x32, 0x74, 0xD1, 0xAA, 0xD4, 0x4C, 0xF5, 0xCD, - 0xC2, 0xD7, 0xD7, 0xAC, 0xDA, 0x69, 0xF5, 0x2B }; + 0x99, 0x28, 0x34, 0x48, 0x9E, 0xB7, 0xD1, 0x4F, 0x0D, 0x17, 0x09, 0x97, + 0xB9, 0x9B, 0x20, 0xFE, 0xE5, 0x65, 0xE0, 0xE2, 0x56, 0x37, 0x80, 0xA2, + 0x9F, 0x2C, 0x2D, 0x87, 0x10, 0x58, 0x39, 0xAD, 0xF3, 0xC5, 0xA9, 0x08, + 0x24, 0xC7, 0xAA, 0xA9, 0x29, 0x3A, 0x13, 0xDF, 0x4E, 0x0A, 0x6D, 0x11, + 0x39, 0xB1, 0x1C, 0x3F, 0xFE, 0xFE, 0x0A, 0x5E, 0xAD, 0x2E, 0x5C, 0x10, + 0x97, 0x38, 0xAC, 0xE8, 0xEB, 0xAA, 0x4A, 0xA1, 0xC0, 0x5C, 0x1D, 0x27, + 0x65, 0x9C, 0xC8, 0x53, 0xAC, 0x35, 0xDD, 0x84, 0x1F, 0x47, 0x0E, 0x04, + 0xF1, 0x90, 0x61, 0x62, 0x2E, 0x29, 0x2C, 0xC6, 0x28, 0x91, 0x6D, 0xF0, + 0xE2, 0x5E, 0xCE, 0x60, 0x3E, 0xF7, 0xF8, 0x37, 0x99, 0x4D, 0x9F, 0xFB, + 0x68, 0xEC, 0x7F, 0x9D, 0x32, 0x74, 0xD1, 0xAA, 0xD4, 0x4C, 0xF5, 0xCD, + 0xC2, 0xD7, 0xD7, 0xAC, 0xDA, 0x69, 0xF5, 0x2B}; static unsigned char dh2048_p[] = { - 0xAB, 0x88, 0x97, 0xCA, 0xF1, 0xE1, 0x60, 0x39, 0xFA, 0xB1, 0xA8, 0x7D, - 0xB3, 0x7A, 0x38, 0x08, 0xF0, 0x7A, 0x3D, 0x21, 0xC4, 0xE6, 0xB8, 0x32, - 0x3D, 0xAB, 0x0F, 0xE7, 0x8C, 0xA1, 0x59, 0x47, 0xB2, 0x0A, 0x7A, 0x3A, - 0x20, 0x2A, 0x1B, 0xD4, 0xBA, 0xFC, 0x4C, 0xC5, 0xEE, 0xA2, 0xB9, 0xB9, - 0x65, 0x47, 0xCC, 0x13, 0x99, 0xD7, 0xA6, 0xCA, 0xFF, 0x23, 0x05, 0x91, - 0xAB, 0x5C, 0x82, 0xB8, 0xB4, 0xFD, 0xB1, 0x2E, 0x5B, 0x0F, 0x8E, 0x03, - 0x3C, 0x23, 0xD6, 0x6A, 0xE2, 0x83, 0x95, 0xD2, 0x8E, 0xEB, 0xDF, 0x3A, - 0xAF, 0x89, 0xF0, 0xA0, 0x14, 0x09, 0x12, 0xF6, 0x54, 0x54, 0x93, 0xF4, - 0xD4, 0x41, 0x56, 0x7A, 0x0E, 0x56, 0x20, 0x1F, 0x1D, 0xBA, 0x3F, 0x07, - 0xD2, 0x89, 0x1B, 0x40, 0xD0, 0x1C, 0x08, 0xDF, 0x00, 0x7F, 0x34, 0xF4, - 0x28, 0x4E, 0xF7, 0x53, 0x8D, 0x4A, 0x00, 0xC3, 0xC0, 0x89, 0x9E, 0x63, - 0x96, 0xE9, 0x52, 0xDF, 0xA5, 0x2C, 0x00, 0x4E, 0xB0, 0x82, 0x6A, 0x10, - 0x28, 0x8D, 0xB9, 0xE7, 0x7A, 0xCB, 0xC3, 0xD6, 0xC1, 0xC0, 0x4D, 0x91, - 0xC4, 0x6F, 0xD3, 0x99, 0xD1, 0x86, 0x71, 0x67, 0x0A, 0xA1, 0xFC, 0xF4, - 0x7D, 0x40, 0x88, 0x8D, 0xAC, 0xCB, 0xBC, 0xEA, 0x17, 0x85, 0x0B, 0xC6, - 0x12, 0x3E, 0x4A, 0xB9, 0x60, 0x74, 0x93, 0x54, 0x14, 0x39, 0x10, 0xBF, - 0x21, 0xB0, 0x8B, 0xB1, 0x55, 0x3F, 0xBB, 0x6A, 0x1F, 0x42, 0x82, 0x0A, - 0x40, 0x3A, 0x15, 0xCD, 0xD3, 0x79, 0xD0, 0x02, 0xA4, 0xF5, 0x79, 0x78, - 0x03, 0xBD, 0x47, 0xCC, 0xD5, 0x08, 0x6A, 0x46, 0xAE, 0x36, 0xE4, 0xCD, - 0xB1, 0x17, 0x48, 0x30, 0xB4, 0x02, 0xBC, 0x50, 0x68, 0xE3, 0xA2, 0x76, - 0xD0, 0x5C, 0xB9, 0xE6, 0xBE, 0x4C, 0xFD, 0x50, 0xEF, 0xD0, 0x3F, 0x39, - 0x4F, 0x53, 0x16, 0x3B }; + 0xAB, 0x88, 0x97, 0xCA, 0xF1, 0xE1, 0x60, 0x39, 0xFA, 0xB1, 0xA8, 0x7D, + 0xB3, 0x7A, 0x38, 0x08, 0xF0, 0x7A, 0x3D, 0x21, 0xC4, 0xE6, 0xB8, 0x32, + 0x3D, 0xAB, 0x0F, 0xE7, 0x8C, 0xA1, 0x59, 0x47, 0xB2, 0x0A, 0x7A, 0x3A, + 0x20, 0x2A, 0x1B, 0xD4, 0xBA, 0xFC, 0x4C, 0xC5, 0xEE, 0xA2, 0xB9, 0xB9, + 0x65, 0x47, 0xCC, 0x13, 0x99, 0xD7, 0xA6, 0xCA, 0xFF, 0x23, 0x05, 0x91, + 0xAB, 0x5C, 0x82, 0xB8, 0xB4, 0xFD, 0xB1, 0x2E, 0x5B, 0x0F, 0x8E, 0x03, + 0x3C, 0x23, 0xD6, 0x6A, 0xE2, 0x83, 0x95, 0xD2, 0x8E, 0xEB, 0xDF, 0x3A, + 0xAF, 0x89, 0xF0, 0xA0, 0x14, 0x09, 0x12, 0xF6, 0x54, 0x54, 0x93, 0xF4, + 0xD4, 0x41, 0x56, 0x7A, 0x0E, 0x56, 0x20, 0x1F, 0x1D, 0xBA, 0x3F, 0x07, + 0xD2, 0x89, 0x1B, 0x40, 0xD0, 0x1C, 0x08, 0xDF, 0x00, 0x7F, 0x34, 0xF4, + 0x28, 0x4E, 0xF7, 0x53, 0x8D, 0x4A, 0x00, 0xC3, 0xC0, 0x89, 0x9E, 0x63, + 0x96, 0xE9, 0x52, 0xDF, 0xA5, 0x2C, 0x00, 0x4E, 0xB0, 0x82, 0x6A, 0x10, + 0x28, 0x8D, 0xB9, 0xE7, 0x7A, 0xCB, 0xC3, 0xD6, 0xC1, 0xC0, 0x4D, 0x91, + 0xC4, 0x6F, 0xD3, 0x99, 0xD1, 0x86, 0x71, 0x67, 0x0A, 0xA1, 0xFC, 0xF4, + 0x7D, 0x40, 0x88, 0x8D, 0xAC, 0xCB, 0xBC, 0xEA, 0x17, 0x85, 0x0B, 0xC6, + 0x12, 0x3E, 0x4A, 0xB9, 0x60, 0x74, 0x93, 0x54, 0x14, 0x39, 0x10, 0xBF, + 0x21, 0xB0, 0x8B, 0xB1, 0x55, 0x3F, 0xBB, 0x6A, 0x1F, 0x42, 0x82, 0x0A, + 0x40, 0x3A, 0x15, 0xCD, 0xD3, 0x79, 0xD0, 0x02, 0xA4, 0xF5, 0x79, 0x78, + 0x03, 0xBD, 0x47, 0xCC, 0xD5, 0x08, 0x6A, 0x46, 0xAE, 0x36, 0xE4, 0xCD, + 0xB1, 0x17, 0x48, 0x30, 0xB4, 0x02, 0xBC, 0x50, 0x68, 0xE3, 0xA2, 0x76, + 0xD0, 0x5C, 0xB9, 0xE6, 0xBE, 0x4C, 0xFD, 0x50, 0xEF, 0xD0, 0x3F, 0x39, + 0x4F, 0x53, 0x16, 0x3B}; static unsigned char dh4096_p[] = { - 0xB1, 0xCC, 0x09, 0x86, 0xEE, 0xF9, 0xB9, 0xC9, 0xB9, 0x87, 0xC4, 0xB9, - 0xD7, 0x31, 0x95, 0x84, 0x94, 0x65, 0xED, 0x82, 0x64, 0x11, 0xA7, 0x0A, - 0xFE, 0xC2, 0x60, 0xAE, 0x7C, 0x74, 0xFB, 0x72, 0x8F, 0x0D, 0xA6, 0xDD, - 0x02, 0x49, 0x5B, 0x69, 0xD6, 0x96, 0x05, 0xBE, 0x5E, 0x9B, 0x09, 0x83, - 0xD8, 0xF3, 0x91, 0x55, 0x30, 0x86, 0x97, 0x6C, 0x48, 0x7B, 0x99, 0x82, - 0xCC, 0x1E, 0x1E, 0x25, 0xE6, 0x25, 0xCC, 0xA3, 0x66, 0xDE, 0x8A, 0x78, - 0xEE, 0x7F, 0x4F, 0x86, 0x95, 0x06, 0xBE, 0x64, 0x86, 0xFD, 0x60, 0x6A, - 0x3F, 0x0D, 0x8F, 0x62, 0x17, 0x89, 0xDB, 0xE1, 0x01, 0xC1, 0x75, 0x3A, - 0x78, 0x42, 0xA8, 0x26, 0xEC, 0x00, 0x78, 0xF3, 0xDA, 0x40, 0x8D, 0x0D, - 0x4D, 0x53, 0x82, 0xD7, 0x21, 0xC8, 0x46, 0xC9, 0xE3, 0x80, 0xB4, 0xCF, - 0xEA, 0x46, 0x85, 0xE9, 0xC4, 0x9D, 0xD0, 0xC0, 0x4D, 0x27, 0x0F, 0xF8, - 0x34, 0x3B, 0x86, 0x8F, 0xFC, 0x40, 0x56, 0x49, 0x64, 0x76, 0x61, 0xBC, - 0x35, 0x6A, 0xB8, 0xC5, 0x32, 0x19, 0x00, 0x5E, 0x21, 0x1C, 0x34, 0xCB, - 0x74, 0x5B, 0x60, 0x85, 0x8C, 0x38, 0x52, 0x50, 0x4D, 0xAA, 0x25, 0xE4, - 0x1A, 0xE6, 0xE4, 0xDF, 0x0A, 0xD2, 0x8F, 0x2B, 0xD1, 0x35, 0xC7, 0x92, - 0x7D, 0x6F, 0x54, 0x61, 0x8E, 0x3F, 0xFB, 0xE2, 0xC8, 0x81, 0xD0, 0xAC, - 0x64, 0xE2, 0xA8, 0x30, 0xEA, 0x8E, 0xAD, 0xFE, 0xC0, 0x9E, 0x0B, 0xBF, - 0x34, 0xAC, 0x79, 0x96, 0x38, 0x31, 0x1E, 0xEA, 0xF2, 0x7E, 0xEE, 0x0A, - 0x10, 0x34, 0x7C, 0x1A, 0x30, 0x5F, 0xAF, 0x96, 0x2F, 0x7F, 0xB5, 0x1D, - 0xA7, 0x3D, 0x35, 0x7A, 0x30, 0x70, 0x40, 0xE7, 0xD6, 0x22, 0x1E, 0xD0, - 0x9A, 0x34, 0xC7, 0x6B, 0xE4, 0xF1, 0x78, 0xED, 0xD9, 0xCD, 0x18, 0xBF, - 0x2A, 0x1A, 0x98, 0xB7, 0x6C, 0x6E, 0x18, 0x40, 0xB5, 0xBE, 0xDF, 0xE4, - 0x78, 0x8E, 0x34, 0xB2, 0x7B, 0xE5, 0x88, 0xE6, 0xFD, 0x24, 0xBD, 0xBB, - 0x2E, 0x30, 0x72, 0x54, 0xC7, 0xF4, 0xA0, 0xF1, 0x25, 0xFF, 0xB1, 0x37, - 0x42, 0x07, 0x8C, 0xF2, 0xB9, 0xA1, 0xA4, 0xA7, 0x76, 0x39, 0xB8, 0x11, - 0x17, 0xF3, 0xA8, 0x2E, 0x78, 0x68, 0xF4, 0xBF, 0x98, 0x25, 0x59, 0x17, - 0x59, 0x9B, 0x0D, 0x0B, 0x9B, 0xE3, 0x0F, 0xFF, 0xDC, 0xC8, 0x47, 0x21, - 0xE1, 0x0B, 0x9A, 0x44, 0x79, 0xC7, 0x5F, 0x8E, 0x83, 0x1E, 0x04, 0xA1, - 0xB2, 0x9F, 0x9B, 0xFC, 0xB3, 0x4E, 0xD9, 0xF9, 0x8F, 0x03, 0xBC, 0x0A, - 0x04, 0x00, 0x5C, 0x59, 0xB7, 0x51, 0xAA, 0x75, 0xF8, 0x7A, 0x03, 0x07, - 0x81, 0x6D, 0x67, 0x3E, 0x28, 0x37, 0xE4, 0x74, 0x5B, 0x8C, 0x2A, 0x4B, - 0x6C, 0x10, 0x92, 0x75, 0xA5, 0x79, 0x4B, 0x6D, 0x30, 0xB7, 0x6E, 0xD6, - 0x9E, 0x16, 0xC2, 0x87, 0x69, 0x34, 0xFE, 0xD7, 0x2A, 0x4F, 0xD6, 0xC0, - 0xF3, 0xCD, 0x9C, 0x46, 0xED, 0xC0, 0xB2, 0x84, 0x8D, 0x7E, 0x93, 0xD2, - 0xE9, 0xBE, 0x59, 0x18, 0x92, 0xC1, 0x2C, 0xD6, 0x6C, 0x71, 0x50, 0xA1, - 0x98, 0xDA, 0xD1, 0xAC, 0xDB, 0x88, 0x40, 0x1F, 0x69, 0xDC, 0xDB, 0xB2, - 0xA0, 0x90, 0x01, 0x8E, 0x12, 0xD6, 0x40, 0x1A, 0x8E, 0xC5, 0x69, 0x9C, - 0x91, 0x67, 0xAC, 0xD8, 0x4C, 0x27, 0xCD, 0x08, 0xB8, 0x32, 0x97, 0xE1, - 0x13, 0x0C, 0xFF, 0xB1, 0x06, 0x65, 0x03, 0x98, 0x6F, 0x9E, 0xF7, 0xB8, - 0xA8, 0x75, 0xBA, 0x59, 0xFD, 0x23, 0x98, 0x94, 0x80, 0x9C, 0xA7, 0x46, - 0x32, 0x98, 0x28, 0x7A, 0x0A, 0x3A, 0xA6, 0x95, 0x16, 0x6A, 0x52, 0x8E, - 0x8F, 0x2C, 0xC9, 0x49, 0xB7, 0x59, 0x99, 0x2A, 0xE6, 0xCA, 0x82, 0x88, - 0x36, 0xD3, 0x2B, 0xA4, 0x73, 0xFA, 0x89, 0xBB, + 0xB1, 0xCC, 0x09, 0x86, 0xEE, 0xF9, 0xB9, 0xC9, 0xB9, 0x87, 0xC4, 0xB9, + 0xD7, 0x31, 0x95, 0x84, 0x94, 0x65, 0xED, 0x82, 0x64, 0x11, 0xA7, 0x0A, + 0xFE, 0xC2, 0x60, 0xAE, 0x7C, 0x74, 0xFB, 0x72, 0x8F, 0x0D, 0xA6, 0xDD, + 0x02, 0x49, 0x5B, 0x69, 0xD6, 0x96, 0x05, 0xBE, 0x5E, 0x9B, 0x09, 0x83, + 0xD8, 0xF3, 0x91, 0x55, 0x30, 0x86, 0x97, 0x6C, 0x48, 0x7B, 0x99, 0x82, + 0xCC, 0x1E, 0x1E, 0x25, 0xE6, 0x25, 0xCC, 0xA3, 0x66, 0xDE, 0x8A, 0x78, + 0xEE, 0x7F, 0x4F, 0x86, 0x95, 0x06, 0xBE, 0x64, 0x86, 0xFD, 0x60, 0x6A, + 0x3F, 0x0D, 0x8F, 0x62, 0x17, 0x89, 0xDB, 0xE1, 0x01, 0xC1, 0x75, 0x3A, + 0x78, 0x42, 0xA8, 0x26, 0xEC, 0x00, 0x78, 0xF3, 0xDA, 0x40, 0x8D, 0x0D, + 0x4D, 0x53, 0x82, 0xD7, 0x21, 0xC8, 0x46, 0xC9, 0xE3, 0x80, 0xB4, 0xCF, + 0xEA, 0x46, 0x85, 0xE9, 0xC4, 0x9D, 0xD0, 0xC0, 0x4D, 0x27, 0x0F, 0xF8, + 0x34, 0x3B, 0x86, 0x8F, 0xFC, 0x40, 0x56, 0x49, 0x64, 0x76, 0x61, 0xBC, + 0x35, 0x6A, 0xB8, 0xC5, 0x32, 0x19, 0x00, 0x5E, 0x21, 0x1C, 0x34, 0xCB, + 0x74, 0x5B, 0x60, 0x85, 0x8C, 0x38, 0x52, 0x50, 0x4D, 0xAA, 0x25, 0xE4, + 0x1A, 0xE6, 0xE4, 0xDF, 0x0A, 0xD2, 0x8F, 0x2B, 0xD1, 0x35, 0xC7, 0x92, + 0x7D, 0x6F, 0x54, 0x61, 0x8E, 0x3F, 0xFB, 0xE2, 0xC8, 0x81, 0xD0, 0xAC, + 0x64, 0xE2, 0xA8, 0x30, 0xEA, 0x8E, 0xAD, 0xFE, 0xC0, 0x9E, 0x0B, 0xBF, + 0x34, 0xAC, 0x79, 0x96, 0x38, 0x31, 0x1E, 0xEA, 0xF2, 0x7E, 0xEE, 0x0A, + 0x10, 0x34, 0x7C, 0x1A, 0x30, 0x5F, 0xAF, 0x96, 0x2F, 0x7F, 0xB5, 0x1D, + 0xA7, 0x3D, 0x35, 0x7A, 0x30, 0x70, 0x40, 0xE7, 0xD6, 0x22, 0x1E, 0xD0, + 0x9A, 0x34, 0xC7, 0x6B, 0xE4, 0xF1, 0x78, 0xED, 0xD9, 0xCD, 0x18, 0xBF, + 0x2A, 0x1A, 0x98, 0xB7, 0x6C, 0x6E, 0x18, 0x40, 0xB5, 0xBE, 0xDF, 0xE4, + 0x78, 0x8E, 0x34, 0xB2, 0x7B, 0xE5, 0x88, 0xE6, 0xFD, 0x24, 0xBD, 0xBB, + 0x2E, 0x30, 0x72, 0x54, 0xC7, 0xF4, 0xA0, 0xF1, 0x25, 0xFF, 0xB1, 0x37, + 0x42, 0x07, 0x8C, 0xF2, 0xB9, 0xA1, 0xA4, 0xA7, 0x76, 0x39, 0xB8, 0x11, + 0x17, 0xF3, 0xA8, 0x2E, 0x78, 0x68, 0xF4, 0xBF, 0x98, 0x25, 0x59, 0x17, + 0x59, 0x9B, 0x0D, 0x0B, 0x9B, 0xE3, 0x0F, 0xFF, 0xDC, 0xC8, 0x47, 0x21, + 0xE1, 0x0B, 0x9A, 0x44, 0x79, 0xC7, 0x5F, 0x8E, 0x83, 0x1E, 0x04, 0xA1, + 0xB2, 0x9F, 0x9B, 0xFC, 0xB3, 0x4E, 0xD9, 0xF9, 0x8F, 0x03, 0xBC, 0x0A, + 0x04, 0x00, 0x5C, 0x59, 0xB7, 0x51, 0xAA, 0x75, 0xF8, 0x7A, 0x03, 0x07, + 0x81, 0x6D, 0x67, 0x3E, 0x28, 0x37, 0xE4, 0x74, 0x5B, 0x8C, 0x2A, 0x4B, + 0x6C, 0x10, 0x92, 0x75, 0xA5, 0x79, 0x4B, 0x6D, 0x30, 0xB7, 0x6E, 0xD6, + 0x9E, 0x16, 0xC2, 0x87, 0x69, 0x34, 0xFE, 0xD7, 0x2A, 0x4F, 0xD6, 0xC0, + 0xF3, 0xCD, 0x9C, 0x46, 0xED, 0xC0, 0xB2, 0x84, 0x8D, 0x7E, 0x93, 0xD2, + 0xE9, 0xBE, 0x59, 0x18, 0x92, 0xC1, 0x2C, 0xD6, 0x6C, 0x71, 0x50, 0xA1, + 0x98, 0xDA, 0xD1, 0xAC, 0xDB, 0x88, 0x40, 0x1F, 0x69, 0xDC, 0xDB, 0xB2, + 0xA0, 0x90, 0x01, 0x8E, 0x12, 0xD6, 0x40, 0x1A, 0x8E, 0xC5, 0x69, 0x9C, + 0x91, 0x67, 0xAC, 0xD8, 0x4C, 0x27, 0xCD, 0x08, 0xB8, 0x32, 0x97, 0xE1, + 0x13, 0x0C, 0xFF, 0xB1, 0x06, 0x65, 0x03, 0x98, 0x6F, 0x9E, 0xF7, 0xB8, + 0xA8, 0x75, 0xBA, 0x59, 0xFD, 0x23, 0x98, 0x94, 0x80, 0x9C, 0xA7, 0x46, + 0x32, 0x98, 0x28, 0x7A, 0x0A, 0x3A, 0xA6, 0x95, 0x16, 0x6A, 0x52, 0x8E, + 0x8F, 0x2C, 0xC9, 0x49, 0xB7, 0x59, 0x99, 0x2A, 0xE6, 0xCA, 0x82, 0x88, + 0x36, 0xD3, 0x2B, 0xA4, 0x73, 0xFA, 0x89, 0xBB, }; /* * OpenSSL temporary DH callback which loads DH parameters from static memory. */ -DH * -ssl_tmp_dh_callback(UNUSED SSL *s, int is_export, int keylength) +DH * ssl_tmp_dh_callback(UNUSED SSL *s, int is_export, int keylength) { - DH *dh; - int rv = 0; - - if (!(dh = DH_new())) { - log_err_printf("DH_new() failed\n"); - return NULL; - } - switch (keylength) { - case 512: - rv = DH_set0_pqg(dh, - BN_bin2bn(dh512_p, sizeof(dh512_p), NULL), - NULL, - BN_bin2bn(dh_g, sizeof(dh_g), NULL)); - break; - case 1024: - rv = DH_set0_pqg(dh, - BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL), - NULL, - BN_bin2bn(dh_g, sizeof(dh_g), NULL)); - break; - case 2048: - rv = DH_set0_pqg(dh, - BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL), - NULL, - BN_bin2bn(dh_g, sizeof(dh_g), NULL)); - break; - case 4096: - rv = DH_set0_pqg(dh, - BN_bin2bn(dh4096_p, sizeof(dh4096_p), NULL), - NULL, - BN_bin2bn(dh_g, sizeof(dh_g), NULL)); - break; - default: - log_err_printf("Unhandled DH keylength %i%s\n", - keylength, - (is_export ? " (export)" : "")); - DH_free(dh); - return NULL; - } - if (!rv) { - log_err_printf("Failed to load DH p and g from memory\n"); - DH_free(dh); - return NULL; - } - return(dh); + DH *dh; + int rv = 0; + + if (!(dh = DH_new())) + { + log_err_printf("DH_new() failed\n"); + return NULL; + } + switch (keylength) + { + case 512: + rv = DH_set0_pqg(dh, + BN_bin2bn(dh512_p, sizeof(dh512_p), NULL), + NULL, + BN_bin2bn(dh_g, sizeof(dh_g), NULL)); + break; + case 1024: + rv = DH_set0_pqg(dh, + BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL), + NULL, + BN_bin2bn(dh_g, sizeof(dh_g), NULL)); + break; + case 2048: + rv = DH_set0_pqg(dh, + BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL), + NULL, + BN_bin2bn(dh_g, sizeof(dh_g), NULL)); + break; + case 4096: + rv = DH_set0_pqg(dh, + BN_bin2bn(dh4096_p, sizeof(dh4096_p), NULL), + NULL, + BN_bin2bn(dh_g, sizeof(dh_g), NULL)); + break; + default: + log_err_printf("Unhandled DH keylength %i%s\n", + keylength, + (is_export ? " (export)" : "")); + DH_free(dh); + return NULL; + } + if (!rv) + { + log_err_printf("Failed to load DH p and g from memory\n"); + DH_free(dh); + return NULL; + } + return (dh); } /* * Load DH parameters from a PEM file. * Not thread-safe. */ -DH * -ssl_dh_load(const char *filename) +DH * ssl_dh_load(const char *filename) { - DH *dh; - FILE *fh; - - if (ssl_init() == -1) - return NULL; - - if (!(fh = fopen(filename, "r"))) { - return NULL; - } - dh = PEM_read_DHparams(fh, NULL, NULL, NULL); - fclose(fh); - return dh; + DH *dh; + FILE *fh; + + if (ssl_init() == -1) + return NULL; + + if (!(fh = fopen(filename, "r"))) + { + return NULL; + } + dh = PEM_read_DHparams(fh, NULL, NULL, NULL); + fclose(fh); + return dh; } #endif /* !OPENSSL_NO_DH */ @@ -761,18 +783,18 @@ ssl_dh_load(const char *filename) * Load an Elliptic Curve by name. If curvename is NULL, a default curve is * loaded. */ -EC_KEY * -ssl_ec_by_name(const char *curvename) +EC_KEY * ssl_ec_by_name(const char *curvename) { - int nid; + int nid; - if (!curvename) - curvename = DFLT_CURVE; + if (!curvename) + curvename = DFLT_CURVE; - if ((nid = OBJ_sn2nid(curvename)) == NID_undef) { - return NULL; - } - return EC_KEY_new_by_curve_name(nid); + if ((nid = OBJ_sn2nid(curvename)) == NID_undef) + { + return NULL; + } + return EC_KEY_new_by_curve_name(nid); } #endif /* !OPENSSL_NO_EC */ @@ -780,20 +802,21 @@ ssl_ec_by_name(const char *curvename) * Add a X509v3 extension to a certificate and handle errors. * Returns -1 on errors, 0 on success. */ -int -ssl_x509_v3ext_add(X509V3_CTX *ctx, X509 *crt, char *k, char *v) +int ssl_x509_v3ext_add(X509V3_CTX *ctx, X509 *crt, char *k, char *v) { - X509_EXTENSION *ext; - - if (!(ext = X509V3_EXT_conf(NULL, ctx, k, v))) { - return -1; - } - if (X509_add_ext(crt, ext, -1) != 1) { - X509_EXTENSION_free(ext); - return -1; - } - X509_EXTENSION_free(ext); - return 0; + X509_EXTENSION *ext; + + if (!(ext = X509V3_EXT_conf(NULL, ctx, k, v))) + { + return -1; + } + if (X509_add_ext(crt, ext, -1) != 1) + { + X509_EXTENSION_free(ext); + return -1; + } + X509_EXTENSION_free(ext); + return 0; } /* @@ -802,21 +825,20 @@ ssl_x509_v3ext_add(X509V3_CTX *ctx, X509 *crt, char *k, char *v) * the extension will not be added to the destination certificate. * Returns 1 if ext was copied, 0 if not present in origcrt, -1 on error. */ -int -ssl_x509_v3ext_copy_by_nid(X509 *crt, X509 *origcrt, int nid) +int ssl_x509_v3ext_copy_by_nid(X509 *crt, X509 *origcrt, int nid) { - X509_EXTENSION *ext; - int pos; - - pos = X509_get_ext_by_NID(origcrt, nid, -1); - if (pos == -1) - return 0; - ext = X509_get_ext(origcrt, pos); - if (!ext) - return -1; - if (X509_add_ext(crt, ext, -1) != 1) - return -1; - return 1; + X509_EXTENSION *ext; + int pos; + + pos = X509_get_ext_by_NID(origcrt, nid, -1); + if (pos == -1) + return 0; + ext = X509_get_ext(origcrt, pos); + if (!ext) + return -1; + if (X509_add_ext(crt, ext, -1) != 1) + return -1; + return 1; } /* @@ -824,20 +846,19 @@ ssl_x509_v3ext_copy_by_nid(X509 *crt, X509 *origcrt, int nid) * Not for real life cryptography applications. * Returns 0 on success, -1 on failure. */ -int -ssl_rand(void *p, size_t sz) +int ssl_rand(void *p, size_t sz) { - int rv; + int rv; #if OPENSSL_VERSION_NUMBER < 0x10100000L - rv = RAND_pseudo_bytes((unsigned char*)p, sz); - if (rv == 1) - return 0; + rv = RAND_pseudo_bytes((unsigned char *) p, sz); + if (rv == 1) + return 0; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ - rv = RAND_bytes((unsigned char*)p, sz); - if (rv == 1) - return 0; - return -1; + rv = RAND_bytes((unsigned char *) p, sz); + if (rv == 1) + return 0; + return -1; } /* @@ -849,35 +870,36 @@ ssl_rand(void *p, size_t sz) * check for duplicate certificate serials. * Returns 0 on success, -1 on error. */ -int -ssl_x509_serial_copyrand(X509 *dstcrt, X509 *srccrt) +int ssl_x509_serial_copyrand(X509 *dstcrt, X509 *srccrt) { - ASN1_INTEGER *srcptr, *dstptr; - BIGNUM *bnserial; - unsigned int rand; - int rv; + ASN1_INTEGER *srcptr, *dstptr; + BIGNUM *bnserial; + unsigned int rand; + int rv; #ifndef PURIFY - rv = ssl_rand(&rand, sizeof(rand)); + rv = ssl_rand(&rand, sizeof(rand)); #else /* PURIFY */ - rand = 0xF001; - rv = 0; + rand = 0xF001; + rv = 0; #endif /* PURIFY */ - dstptr = X509_get_serialNumber(dstcrt); - srcptr = X509_get_serialNumber(srccrt); - if ((rv == -1) || !dstptr || !srcptr) - return -1; - bnserial = ASN1_INTEGER_to_BN(srcptr, NULL); - if (!bnserial) { - /* random 32-bit serial */ - ASN1_INTEGER_set(dstptr, rand); - } else { - /* original serial plus random 32-bit offset */ - BN_add_word(bnserial, rand); - BN_to_ASN1_INTEGER(bnserial, dstptr); - BN_free(bnserial); - } - return 0; + dstptr = X509_get_serialNumber(dstcrt); + srcptr = X509_get_serialNumber(srccrt); + if ((rv == -1) || !dstptr || !srcptr) + return -1; + bnserial = ASN1_INTEGER_to_BN(srcptr, NULL); + if (!bnserial) + { + /* random 32-bit serial */ + ASN1_INTEGER_set(dstptr, rand); + } else + { + /* original serial plus random 32-bit offset */ + BN_add_word(bnserial, rand); + BN_to_ASN1_INTEGER(bnserial, dstptr); + BN_free(bnserial); + } + return 0; } /* @@ -891,225 +913,217 @@ X509 * ssl_x509_forge(X509 *cacrt, EVP_PKEY *cakey, X509 *origcrt, EVP_PKEY *key, const char *extraname, const char *crlurl) { - X509_NAME *subject, *issuer; - GENERAL_NAMES *names; - GENERAL_NAME *gn; - X509 *crt; - int rv; - - subject = X509_get_subject_name(origcrt); - issuer = X509_get_subject_name(cacrt); - if (!subject || !issuer) - return NULL; - - crt = X509_new(); - if (!crt) - return NULL; - - if (!X509_set_version(crt, 0x02) || - !X509_set_subject_name(crt, subject) || - !X509_set_issuer_name(crt, issuer) || - ssl_x509_serial_copyrand(crt, origcrt) == -1 || - !X509_gmtime_adj(X509_get_notBefore(crt), (long)-60*60*24) || - !X509_gmtime_adj(X509_get_notAfter(crt), (long)60*60*24*364) || - !X509_set_pubkey(crt, key)) - goto errout; - - /* add standard v3 extensions; cf. RFC 2459 */ - - X509V3_CTX ctx; - X509V3_set_ctx(&ctx, cacrt, crt, NULL, NULL, 0); - if (ssl_x509_v3ext_add(&ctx, crt, "subjectKeyIdentifier", - "hash") == -1 || - ssl_x509_v3ext_add(&ctx, crt, "authorityKeyIdentifier", - "keyid,issuer:always") == -1) - goto errout; - - rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, - NID_basic_constraints); - if (rv == 0) - rv = ssl_x509_v3ext_add(&ctx, crt, "basicConstraints", - "CA:FALSE"); - if (rv == -1) - goto errout; - - rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, - NID_key_usage); - if (rv == 0) - rv = ssl_x509_v3ext_add(&ctx, crt, "keyUsage", - "digitalSignature," - "keyEncipherment"); - if (rv == -1) - goto errout; - - rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, - NID_ext_key_usage); - if (rv == 0) - rv = ssl_x509_v3ext_add(&ctx, crt, "extendedKeyUsage", - "serverAuth"); - if (rv == -1) - goto errout; - - if (crlurl) { - char *crlurlval; - if (asprintf(&crlurlval, "URI:%s", crlurl) < 0) - goto errout; - if (ssl_x509_v3ext_add(&ctx, crt, "crlDistributionPoints", - crlurlval) == -1) { - free(crlurlval); - goto errout; - } - free(crlurlval); - } - - if (!extraname) { - /* no extraname provided: copy original subjectAltName ext */ - if (ssl_x509_v3ext_copy_by_nid(crt, origcrt, - NID_subject_alt_name) == -1) - goto errout; - } else { - names = X509_get_ext_d2i(origcrt, NID_subject_alt_name, 0, 0); - if (!names) { - /* no subjectAltName present: add new one */ - char *cfval; - if (asprintf(&cfval, "DNS:%s", extraname) < 0) - goto errout; - if (ssl_x509_v3ext_add(&ctx, crt, "subjectAltName", - cfval) == -1) { - free(cfval); - goto errout; - } - free(cfval); - } else { - /* add extraname to original subjectAltName - * and add it to the new certificate */ - gn = GENERAL_NAME_new(); - if (!gn) - goto errout2; - gn->type = GEN_DNS; - gn->d.dNSName = ASN1_IA5STRING_new(); - if (!gn->d.dNSName) - goto errout3; - ASN1_STRING_set(gn->d.dNSName, - (unsigned char *)extraname, - strlen(extraname)); - sk_GENERAL_NAME_push(names, gn); - X509_EXTENSION *ext = X509V3_EXT_i2d( - NID_subject_alt_name, 0, names); - if (!X509_add_ext(crt, ext, -1)) { - if (ext) { - X509_EXTENSION_free(ext); - } - goto errout3; - } - X509_EXTENSION_free(ext); - sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); - } - } + X509_NAME *subject, *issuer; + GENERAL_NAMES *names; + GENERAL_NAME *gn; + X509 *crt; + int rv; + + subject = X509_get_subject_name(origcrt); + issuer = X509_get_subject_name(cacrt); + if (!subject || !issuer) + return NULL; + + crt = X509_new(); + if (!crt) + return NULL; + + if (!X509_set_version(crt, 0x02) || + !X509_set_subject_name(crt, subject) || + !X509_set_issuer_name(crt, issuer) || + ssl_x509_serial_copyrand(crt, origcrt) == -1 || + !X509_gmtime_adj(X509_get_notBefore(crt), (long) -60 * 60 * 24) || + !X509_gmtime_adj(X509_get_notAfter(crt), (long) 60 * 60 * 24 * 364) || + !X509_set_pubkey(crt, key)) + goto errout; + + /* add standard v3 extensions; cf. RFC 2459 */ + + X509V3_CTX ctx; + X509V3_set_ctx(&ctx, cacrt, crt, NULL, NULL, 0); + if (ssl_x509_v3ext_add(&ctx, crt, "subjectKeyIdentifier", + "hash") == -1 || + ssl_x509_v3ext_add(&ctx, crt, "authorityKeyIdentifier", + "keyid,issuer:always") == -1) + goto errout; + + rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, + NID_basic_constraints); + if (rv == 0) + rv = ssl_x509_v3ext_add(&ctx, crt, "basicConstraints", + "CA:FALSE"); + if (rv == -1) + goto errout; + + rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, + NID_key_usage); + if (rv == 0) + rv = ssl_x509_v3ext_add(&ctx, crt, "keyUsage", + "digitalSignature," + "keyEncipherment"); + if (rv == -1) + goto errout; + + rv = ssl_x509_v3ext_copy_by_nid(crt, origcrt, + NID_ext_key_usage); + if (rv == 0) + rv = ssl_x509_v3ext_add(&ctx, crt, "extendedKeyUsage", + "serverAuth"); + if (rv == -1) + goto errout; + + if (crlurl) + { + char *crlurlval; + if (asprintf(&crlurlval, "URI:%s", crlurl) < 0) + goto errout; + if (ssl_x509_v3ext_add(&ctx, crt, "crlDistributionPoints", + crlurlval) == -1) + { + free(crlurlval); + goto errout; + } + free(crlurlval); + } + + if (!extraname) + { + /* no extraname provided: copy original subjectAltName ext */ + if (ssl_x509_v3ext_copy_by_nid(crt, origcrt, + NID_subject_alt_name) == -1) + goto errout; + } else + { + names = (GENERAL_NAMES *)X509_get_ext_d2i(origcrt, NID_subject_alt_name, 0, 0); + if (!names) + { + /* no subjectAltName present: add new one */ + char *cfval; + if (asprintf(&cfval, "DNS:%s", extraname) < 0) + goto errout; + if (ssl_x509_v3ext_add(&ctx, crt, "subjectAltName", + cfval) == -1) + { + free(cfval); + goto errout; + } + free(cfval); + } else + { + /* add extraname to original subjectAltName + * and add it to the new certificate */ + gn = GENERAL_NAME_new(); + if (!gn) + goto errout2; + gn->type = GEN_DNS; + gn->d.dNSName = ASN1_IA5STRING_new(); + if (!gn->d.dNSName) + goto errout3; + ASN1_STRING_set(gn->d.dNSName, + (unsigned char *) extraname, + strlen(extraname)); + sk_GENERAL_NAME_push(names, gn); + X509_EXTENSION *ext = X509V3_EXT_i2d( + NID_subject_alt_name, 0, names); + if (!X509_add_ext(crt, ext, -1)) + { + if (ext) + { + X509_EXTENSION_free(ext); + } + goto errout3; + } + X509_EXTENSION_free(ext); + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + } + } #ifdef DEBUG_CERTIFICATE - ssl_x509_v3ext_add(&ctx, crt, "nsComment", "Generated by " PKGLABEL); + ssl_x509_v3ext_add(&ctx, crt, "nsComment", "Generated by " PKGLABEL); #endif /* DEBUG_CERTIFICATE */ - const EVP_MD *md; - switch (EVP_PKEY_type(EVP_PKEY_base_id(cakey))) { + const EVP_MD *md; + switch (EVP_PKEY_type(EVP_PKEY_base_id(cakey))) + { #ifndef OPENSSL_NO_RSA - case EVP_PKEY_RSA: - switch (X509_get_signature_nid(origcrt)) { - case NID_md5WithRSAEncryption: - md = EVP_md5(); - break; - case NID_ripemd160WithRSA: - md = EVP_ripemd160(); - break; - case NID_sha1WithRSAEncryption: - md = EVP_sha1(); - break; - case NID_sha224WithRSAEncryption: - md = EVP_sha224(); - break; - case NID_sha256WithRSAEncryption: - md = EVP_sha256(); - break; - case NID_sha384WithRSAEncryption: - md = EVP_sha384(); - break; - case NID_sha512WithRSAEncryption: - md = EVP_sha512(); - break; + case EVP_PKEY_RSA: + switch (X509_get_signature_nid(origcrt)) + { + case NID_md5WithRSAEncryption: md = EVP_md5(); + break; + case NID_ripemd160WithRSA: md = EVP_ripemd160(); + break; + case NID_sha1WithRSAEncryption: md = EVP_sha1(); + break; + case NID_sha224WithRSAEncryption: md = EVP_sha224(); + break; + case NID_sha256WithRSAEncryption: md = EVP_sha256(); + break; + case NID_sha384WithRSAEncryption: md = EVP_sha384(); + break; + case NID_sha512WithRSAEncryption: md = EVP_sha512(); + break; #ifndef OPENSSL_NO_SHA0 - case NID_shaWithRSAEncryption: - md = EVP_sha(); - break; + case NID_shaWithRSAEncryption: md = EVP_sha(); + break; #endif /* !OPENSSL_NO_SHA0 */ - default: - md = EVP_sha256(); - break; - } - break; + default: md = EVP_sha256(); + break; + } + break; #endif /* !OPENSSL_NO_RSA */ #ifndef OPENSSL_NO_DSA - case EVP_PKEY_DSA: - switch (X509_get_signature_nid(origcrt)) { - case NID_dsaWithSHA1: - case NID_dsaWithSHA1_2: - md = EVP_sha1(); - break; - case NID_dsa_with_SHA224: - md = EVP_sha224(); - break; - case NID_dsa_with_SHA256: - md = EVP_sha256(); - break; + case EVP_PKEY_DSA: + switch (X509_get_signature_nid(origcrt)) + { + case NID_dsaWithSHA1: + case NID_dsaWithSHA1_2: md = EVP_sha1(); + break; + case NID_dsa_with_SHA224: md = EVP_sha224(); + break; + case NID_dsa_with_SHA256: md = EVP_sha256(); + break; #ifndef OPENSSL_NO_SHA0 - case NID_dsaWithSHA: - md = EVP_sha(); - break; + case NID_dsaWithSHA: md = EVP_sha(); + break; #endif /* !OPENSSL_NO_SHA0 */ - default: - md = EVP_sha256(); - break; - } - break; + default: md = EVP_sha256(); + break; + } + break; #endif /* !OPENSSL_NO_DSA */ #ifndef OPENSSL_NO_ECDSA - case EVP_PKEY_EC: - switch (X509_get_signature_nid(origcrt)) { - case NID_ecdsa_with_SHA1: - md = EVP_sha1(); - break; - case NID_ecdsa_with_SHA224: - md = EVP_sha224(); - break; - case NID_ecdsa_with_SHA256: - md = EVP_sha256(); - break; - case NID_ecdsa_with_SHA384: - md = EVP_sha384(); - break; - case NID_ecdsa_with_SHA512: - md = EVP_sha512(); - break; - default: - md = EVP_sha256(); - break; - } - break; + case EVP_PKEY_EC: + switch (X509_get_signature_nid(origcrt)) + { + case NID_ecdsa_with_SHA1: md = EVP_sha1(); + break; + case NID_ecdsa_with_SHA224: md = EVP_sha224(); + break; + case NID_ecdsa_with_SHA256: md = EVP_sha256(); + break; + case NID_ecdsa_with_SHA384: md = EVP_sha384(); + break; + case NID_ecdsa_with_SHA512: md = EVP_sha512(); + break; + default: md = EVP_sha256(); + break; + } + break; #endif /* !OPENSSL_NO_ECDSA */ - default: - goto errout; - } - if (!X509_sign(crt, cakey, md)) - goto errout; + default: goto errout; + } + if (!X509_sign(crt, cakey, md)) + goto errout; - return crt; + return crt; errout3: - GENERAL_NAME_free(gn); + GENERAL_NAME_free(gn); errout2: - sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); errout: - X509_free(crt); - return NULL; + X509_free(crt); + return NULL; } /* @@ -1125,69 +1139,72 @@ errout: * depend on OpenSSL internals in this function. OpenSSL 1.0.2 introduced * the SSL_get0_chain_certs() API for accessing the certificate chain. */ -int -ssl_x509chain_load(X509 **crt, STACK_OF(X509) **chain, const char *filename) +int ssl_x509chain_load(X509 **crt, STACK_OF(X509) **chain, const char *filename) { - X509 *tmpcrt; - SSL_CTX *tmpctx; - SSL *tmpssl; - STACK_OF(X509) *tmpchain; - int rv; - - if (ssl_init() == -1) - return -1; - - tmpctx = SSL_CTX_new(SSLv23_server_method()); - if (!tmpctx) - goto leave1; - - rv = SSL_CTX_use_certificate_chain_file(tmpctx, filename); - if (rv != 1) - goto leave2; - tmpssl = SSL_new(tmpctx); - if (!tmpssl) - goto leave2; - - tmpcrt = SSL_get_certificate(tmpssl); - if (!tmpcrt) - goto leave3; - - if (!*chain) { - *chain = sk_X509_new_null(); - if (!*chain) - goto leave3; - } + X509 *tmpcrt; + SSL_CTX *tmpctx; + SSL *tmpssl; + STACK_OF(X509) *tmpchain; + int rv; + + if (ssl_init() == -1) + return -1; + + tmpctx = SSL_CTX_new(SSLv23_server_method()); + if (!tmpctx) + goto leave1; + + rv = SSL_CTX_use_certificate_chain_file(tmpctx, filename); + if (rv != 1) + goto leave2; + tmpssl = SSL_new(tmpctx); + if (!tmpssl) + goto leave2; + + tmpcrt = SSL_get_certificate(tmpssl); + if (!tmpcrt) + goto leave3; + + if (!*chain) + { + *chain = sk_X509_new_null(); + if (!*chain) + goto leave3; + } #if (OPENSSL_VERSION_NUMBER < 0x1000200fL) || defined(LIBRESSL_VERSION_NUMBER) - tmpchain = tmpctx->extra_certs; + tmpchain = tmpctx->extra_certs; #else /* OpenSSL >= 1.0.2 */ - rv = SSL_CTX_get0_chain_certs(tmpctx, &tmpchain); - if (rv != 1) - goto leave3; + rv = SSL_CTX_get0_chain_certs(tmpctx, &tmpchain); + if (rv != 1) + goto leave3; #endif /* OpenSSL >= 1.0.2 */ - if (crt) { - *crt = tmpcrt; - } else { - sk_X509_push(*chain, tmpcrt); - } - ssl_x509_refcount_inc(tmpcrt); - - for (int i = 0; i < sk_X509_num(tmpchain); i++) { - tmpcrt = sk_X509_value(tmpchain, i); - ssl_x509_refcount_inc(tmpcrt); - sk_X509_push(*chain, tmpcrt); - } - SSL_free(tmpssl); - SSL_CTX_free(tmpctx); - return 0; + if (crt) + { + *crt = tmpcrt; + } else + { + sk_X509_push(*chain, tmpcrt); + } + ssl_x509_refcount_inc(tmpcrt); + + for (int i = 0; i < sk_X509_num(tmpchain); i++) + { + tmpcrt = sk_X509_value(tmpchain, i); + ssl_x509_refcount_inc(tmpcrt); + sk_X509_push(*chain, tmpcrt); + } + SSL_free(tmpssl); + SSL_CTX_free(tmpctx); + return 0; leave3: - SSL_free(tmpssl); + SSL_free(tmpssl); leave2: - SSL_CTX_free(tmpctx); + SSL_CTX_free(tmpctx); leave1: - return -1; + return -1; } /* @@ -1195,18 +1212,18 @@ leave1: * Copies the certificate stack to the SSL_CTX internal data structures * and increases reference counts accordingly. */ -void -ssl_x509chain_use(SSL_CTX *sslctx, X509 *crt, STACK_OF(X509) *chain) +void ssl_x509chain_use(SSL_CTX *sslctx, X509 *crt, STACK_OF(X509) *chain) { - SSL_CTX_use_certificate(sslctx, crt); + SSL_CTX_use_certificate(sslctx, crt); - for (int i = 0; i < sk_X509_num(chain); i++) { - X509 *tmpcrt; + for (int i = 0; i < sk_X509_num(chain); i++) + { + X509 *tmpcrt; - tmpcrt = sk_X509_value(chain, i); - ssl_x509_refcount_inc(tmpcrt); - SSL_CTX_add_extra_chain_cert(sslctx, tmpcrt); - } + tmpcrt = sk_X509_value(chain, i); + ssl_x509_refcount_inc(tmpcrt); + SSL_CTX_add_extra_chain_cert(sslctx, tmpcrt); + } } /* @@ -1214,34 +1231,33 @@ ssl_x509chain_use(SSL_CTX *sslctx, X509 *crt, STACK_OF(X509) *chain) * Returned X509 must be freed using X509_free() by the caller. * Not thread-safe. */ -X509 * -ssl_x509_load(const char *filename) +X509 *ssl_x509_load(const char *filename) { - X509 *crt = NULL; - SSL_CTX *tmpctx; - SSL *tmpssl; - int rv; - - if (ssl_init() == -1) - return NULL; - - tmpctx = SSL_CTX_new(SSLv23_server_method()); - if (!tmpctx) - goto leave1; - rv = SSL_CTX_use_certificate_file(tmpctx, filename, SSL_FILETYPE_PEM); - if (rv != 1) - goto leave2; - tmpssl = SSL_new(tmpctx); - if (!tmpssl) - goto leave2; - crt = SSL_get_certificate(tmpssl); - if (crt) - ssl_x509_refcount_inc(crt); - SSL_free(tmpssl); + X509 *crt = NULL; + SSL_CTX *tmpctx; + SSL *tmpssl; + int rv; + + if (ssl_init() == -1) + return NULL; + + tmpctx = SSL_CTX_new(SSLv23_server_method()); + if (!tmpctx) + goto leave1; + rv = SSL_CTX_use_certificate_file(tmpctx, filename, SSL_FILETYPE_PEM); + if (rv != 1) + goto leave2; + tmpssl = SSL_new(tmpctx); + if (!tmpssl) + goto leave2; + crt = SSL_get_certificate(tmpssl); + if (crt) + ssl_x509_refcount_inc(crt); + SSL_free(tmpssl); leave2: - SSL_CTX_free(tmpctx); + SSL_CTX_free(tmpctx); leave1: - return crt; + return crt; } /* @@ -1249,66 +1265,64 @@ leave1: * Returned EVP_PKEY must be freed using EVP_PKEY_free() by the caller. * Not thread-safe. */ -EVP_PKEY * -ssl_key_load(const char *filename) +EVP_PKEY *ssl_key_load(const char *filename) { - EVP_PKEY *key = NULL; - SSL_CTX *tmpctx; - SSL *tmpssl; - int rv; - - if (ssl_init() == -1) - return NULL; - - tmpctx = SSL_CTX_new(SSLv23_server_method()); - if (!tmpctx) - goto leave1; - rv = SSL_CTX_use_PrivateKey_file(tmpctx, filename, SSL_FILETYPE_PEM); - if (rv != 1) - goto leave2; - tmpssl = SSL_new(tmpctx); - if (!tmpssl) - goto leave2; - key = SSL_get_privatekey(tmpssl); - if (key) - ssl_key_refcount_inc(key); - SSL_free(tmpssl); + EVP_PKEY *key = NULL; + SSL_CTX *tmpctx; + SSL *tmpssl; + int rv; + + if (ssl_init() == -1) + return NULL; + + tmpctx = SSL_CTX_new(SSLv23_server_method()); + if (!tmpctx) + goto leave1; + rv = SSL_CTX_use_PrivateKey_file(tmpctx, filename, SSL_FILETYPE_PEM); + if (rv != 1) + goto leave2; + tmpssl = SSL_new(tmpctx); + if (!tmpssl) + goto leave2; + key = SSL_get_privatekey(tmpssl); + if (key) + ssl_key_refcount_inc(key); + SSL_free(tmpssl); leave2: - SSL_CTX_free(tmpctx); + SSL_CTX_free(tmpctx); leave1: - return key; + return key; } /* * Generate a new RSA key. * Returned EVP_PKEY must be freed using EVP_PKEY_free() by the caller. */ -EVP_PKEY * -ssl_key_genrsa(const int keysize) +EVP_PKEY *ssl_key_genrsa(const int keysize) { - EVP_PKEY *pkey; - RSA *rsa; + EVP_PKEY *pkey; + RSA *rsa; #if OPENSSL_VERSION_NUMBER >= 0x10100000L - BIGNUM *bn; - int rv; - rsa = RSA_new(); - bn = BN_new(); - BN_dec2bn(&bn, "3"); - rv = RSA_generate_key_ex(rsa, keysize, bn, NULL); - BN_free(bn); - if (rv != 1) { - RSA_free(rsa); - return NULL; - } + BIGNUM *bn; + int rv; + rsa = RSA_new(); + bn = BN_new(); + BN_dec2bn(&bn, "3"); + rv = RSA_generate_key_ex(rsa, keysize, bn, NULL); + BN_free(bn); + if (rv != 1) { + RSA_free(rsa); + return NULL; + } #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */ - rsa = RSA_generate_key(keysize, 3, NULL, NULL); - if (!rsa) - return NULL; + rsa = RSA_generate_key(keysize, 3, NULL, NULL); + if (!rsa) + return NULL; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ - pkey = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(pkey, rsa); /* does not increment refcount */ - return pkey; + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); /* does not increment refcount */ + return pkey; } /* @@ -1316,41 +1330,39 @@ ssl_key_genrsa(const int keysize) * keyid will receive a binary SHA-1 hash of SSL_KEY_IDSZ bytes. * Returns 0 on success, -1 on failure. */ -int -ssl_key_identifier_sha1(EVP_PKEY *key, unsigned char *keyid) +int ssl_key_identifier_sha1(EVP_PKEY *key, unsigned char *keyid) { - X509_PUBKEY *pubkey = NULL; - const unsigned char *pk; - int length; - - /* X509_PUBKEY_set() will attempt to free pubkey if != NULL */ - if (X509_PUBKEY_set(&pubkey, key) != 1 || !pubkey) - return -1; - if (!X509_PUBKEY_get0_param(NULL, &pk, &length, NULL, pubkey)) - goto errout; - if (!EVP_Digest(pk, length, keyid, NULL, EVP_sha1(), NULL)) - goto errout; - X509_PUBKEY_free(pubkey); - return 0; + X509_PUBKEY *pubkey = NULL; + const unsigned char *pk; + int length; + + /* X509_PUBKEY_set() will attempt to free pubkey if != NULL */ + if (X509_PUBKEY_set(&pubkey, key) != 1 || !pubkey) + return -1; + if (!X509_PUBKEY_get0_param(NULL, &pk, &length, NULL, pubkey)) + goto errout; + if (!EVP_Digest(pk, length, keyid, NULL, EVP_sha1(), NULL)) + goto errout; + X509_PUBKEY_free(pubkey); + return 0; errout: - X509_PUBKEY_free(pubkey); - return -1; + X509_PUBKEY_free(pubkey); + return -1; } /* * Returns the result of ssl_key_identifier_sha1() as hex characters with or * without colons in a newly allocated string. */ -char * -ssl_key_identifier(EVP_PKEY *key, int colons) +char *ssl_key_identifier(EVP_PKEY *key, int colons) { - unsigned char id[SSL_KEY_IDSZ]; + unsigned char id[SSL_KEY_IDSZ]; - if (ssl_key_identifier_sha1(key, id) == -1) - return NULL; + if (ssl_key_identifier_sha1(key, id) == -1) + return NULL; - return ssl_sha1_to_str(id, colons); + return ssl_sha1_to_str(id, colons); } /* @@ -1360,7 +1372,7 @@ ssl_key_identifier(EVP_PKEY *key, int colons) char * ssl_x509_subject(X509 *crt) { - return X509_NAME_oneline(X509_get_subject_name(crt), NULL, 0); + return X509_NAME_oneline(X509_get_subject_name(crt), NULL, 0); } /* @@ -1371,22 +1383,24 @@ ssl_x509_subject(X509 *crt) char * ssl_x509_subject_cn(X509 *crt, size_t *psz) { - X509_NAME *ptr; - char *cn; - size_t sz; - - ptr = X509_get_subject_name(crt); /* does not inc refcounts */ - if (!ptr) - return NULL; - sz = X509_NAME_get_text_by_NID(ptr, NID_commonName, NULL, 0) + 1; - if ((sz == 0) || !(cn = malloc(sz))) - return NULL; - if (X509_NAME_get_text_by_NID(ptr, NID_commonName, cn, sz) == -1) { - free(cn); - return NULL; - } - *psz = sz; - return cn; + X509_NAME *ptr; + char *cn; + size_t sz; + + ptr = X509_get_subject_name(crt); /* does not inc refcounts */ + if (!ptr) + return NULL; + sz = (size_t) X509_NAME_get_text_by_NID(ptr, NID_commonName, NULL, 0) + 1; + + if ((sz == 0) || !(cn = (char *) malloc(sz))) + return NULL; + if (X509_NAME_get_text_by_NID(ptr, NID_commonName, cn, sz) == -1) + { + free(cn); + return NULL; + } + *psz = sz; + return cn; } /* @@ -1397,9 +1411,9 @@ ssl_x509_subject_cn(X509 *crt, size_t *psz) int ssl_x509_fingerprint_sha1(X509 *crt, unsigned char *fpr) { - unsigned int sz = SSL_X509_FPRSZ; + unsigned int sz = SSL_X509_FPRSZ; - return X509_digest(crt, EVP_sha1(), fpr, &sz) ? 0 : -1; + return X509_digest(crt, EVP_sha1(), fpr, &sz) ? 0 : -1; } /* @@ -1409,12 +1423,12 @@ ssl_x509_fingerprint_sha1(X509 *crt, unsigned char *fpr) char * ssl_x509_fingerprint(X509 *crt, int colons) { - unsigned char fpr[SSL_X509_FPRSZ]; + unsigned char fpr[SSL_X509_FPRSZ]; - if (ssl_x509_fingerprint_sha1(crt, fpr) == -1) - return NULL; + if (ssl_x509_fingerprint_sha1(crt, fpr) == -1) + return NULL; - return ssl_sha1_to_str(fpr, colons); + return ssl_sha1_to_str(fpr, colons); } #ifndef OPENSSL_NO_DH @@ -1426,9 +1440,9 @@ void ssl_dh_refcount_inc(DH *dh) { #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - CRYPTO_add(&dh->references, 1, CRYPTO_LOCK_DH); + CRYPTO_add(&dh->references, 1, CRYPTO_LOCK_DH); #else /* !OPENSSL_THREADS */ - DH_up_ref(dh); + DH_up_ref(dh); #endif /* !OPENSSL_THREADS */ } #endif /* !OPENSSL_NO_DH */ @@ -1441,9 +1455,9 @@ void ssl_key_refcount_inc(EVP_PKEY *key) { #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - CRYPTO_add(&key->references, 1, CRYPTO_LOCK_EVP_PKEY); + CRYPTO_add(&key->references, 1, CRYPTO_LOCK_EVP_PKEY); #else /* !OPENSSL_THREADS */ - EVP_PKEY_up_ref(key); + EVP_PKEY_up_ref(key); #endif /* !OPENSSL_THREADS */ } @@ -1456,9 +1470,9 @@ void ssl_x509_refcount_inc(X509 *crt) { #if defined(OPENSSL_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L - CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509); + CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509); #else /* !OPENSSL_THREADS */ - X509_up_ref(crt); + X509_up_ref(crt); #endif /* !OPENSSL_THREADS */ } @@ -1489,27 +1503,28 @@ ssl_x509_refcount_inc(X509 *crt) * Returns 1 on match, 0 on no match. */ int -ssl_dnsname_match(const char *certname, size_t certnamesz, - const char *hostname, size_t hostnamesz) +ssl_dnsname_match( + const char *certname, size_t certnamesz, + const char *hostname, size_t hostnamesz) { - if (hostnamesz < certnamesz) - return 0; - if ((hostnamesz == certnamesz) && - !memcmp(certname, hostname, certnamesz)) - return 1; - if (!memcmp(certname, "xn--", 4)) - return 0; - if ((certnamesz == 1) && (certname[0] == '*') && - !memchr(hostname, '.', hostnamesz)) - return 1; - if ((certnamesz > 2) && (certname[0] == '*') && (certname[1] == '.') && - !memcmp(&certname[1], - &hostname[hostnamesz - (certnamesz - 1)], - certnamesz - 1) && - (memchr(hostname, '.', hostnamesz) == - &hostname[hostnamesz - (certnamesz - 1)])) - return 1; - return 0; + if (hostnamesz < certnamesz) + return 0; + if ((hostnamesz == certnamesz) && + !memcmp(certname, hostname, certnamesz)) + return 1; + if (!memcmp(certname, "xn--", 4)) + return 0; + if ((certnamesz == 1) && (certname[0] == '*') && + !memchr(hostname, '.', hostnamesz)) + return 1; + if ((certnamesz > 2) && (certname[0] == '*') && (certname[1] == '.') && + !memcmp(&certname[1], + &hostname[hostnamesz - (certnamesz - 1)], + certnamesz - 1) && + (memchr(hostname, '.', hostnamesz) == + &hostname[hostnamesz - (certnamesz - 1)])) + return 1; + return 0; } /* @@ -1520,20 +1535,21 @@ ssl_dnsname_match(const char *certname, size_t certnamesz, char * ssl_wildcardify(const char *hostname) { - char *dot, *wildcarded; - size_t dotsz; - - if (!(dot = strchr(hostname, '.'))) - return strdup("*"); - dotsz = strlen(dot); - if (!(wildcarded = malloc(dotsz + 2))) - return NULL; - wildcarded[0] = '*'; - for (size_t i = 0; i < dotsz; i++) { - wildcarded[i+1] = dot[i]; - } - wildcarded[dotsz+1] = '\0'; - return wildcarded; + char *dot, *wildcarded; + size_t dotsz; + + if (!(dot = (char *) strchr(hostname, '.'))) + return strdup("*"); + dotsz = strlen(dot); + if (!(wildcarded = (char *) malloc(dotsz + 2))) + return NULL; + wildcarded[0] = '*'; + for (size_t i = 0; i < dotsz; i++) + { + wildcarded[i + 1] = dot[i]; + } + wildcarded[dotsz + 1] = '\0'; + return wildcarded; } /* @@ -1543,45 +1559,50 @@ ssl_wildcardify(const char *hostname) int ssl_x509_names_match(X509 *crt, const char *dnsname) { - GENERAL_NAMES *altnames; - char *cn; - size_t cnsz, dnsnamesz; - - dnsnamesz = strlen(dnsname); - - cn = ssl_x509_subject_cn(crt, &cnsz); - if (cn && ssl_dnsname_match(cn, cnsz, dnsname, dnsnamesz)) { - free(cn); - return 1; - } - if (cn) { - free(cn); - } - - altnames = X509_get_ext_d2i(crt, NID_subject_alt_name, 0, 0); - if (!altnames) - return 0; - for (int i = 0; i < sk_GENERAL_NAME_num(altnames); i++) { - GENERAL_NAME *gn = sk_GENERAL_NAME_value(altnames, i); - if (gn->type == GEN_DNS) { - unsigned char *altname; - int altnamesz; - ASN1_STRING_to_UTF8(&altname, gn->d.dNSName); - altnamesz = ASN1_STRING_length(gn->d.dNSName); - if (altnamesz < 0) - break; - if (ssl_dnsname_match((char *)altname, - (size_t)altnamesz, - dnsname, dnsnamesz)) { - OPENSSL_free((char*)altname); - GENERAL_NAMES_free(altnames); - return 1; - } - OPENSSL_free((char*)altname); - } - } - GENERAL_NAMES_free(altnames); - return 0; + GENERAL_NAMES *altnames; + char *cn; + size_t cnsz, dnsnamesz; + + dnsnamesz = strlen(dnsname); + + cn = ssl_x509_subject_cn(crt, &cnsz); + if (cn && ssl_dnsname_match(cn, cnsz, dnsname, dnsnamesz)) + { + free(cn); + return 1; + } + if (cn) + { + free(cn); + } + + altnames = (GENERAL_NAMES *) X509_get_ext_d2i(crt, NID_subject_alt_name, 0, 0); + if (!altnames) + return 0; + for (int i = 0; i < sk_GENERAL_NAME_num(altnames); i++) + { + GENERAL_NAME *gn = sk_GENERAL_NAME_value(altnames, i); + if (gn->type == GEN_DNS) + { + unsigned char *altname; + int altnamesz; + ASN1_STRING_to_UTF8(&altname, gn->d.dNSName); + altnamesz = ASN1_STRING_length(gn->d.dNSName); + if (altnamesz < 0) + break; + if (ssl_dnsname_match((char *) altname, + (size_t) altnamesz, + dnsname, dnsnamesz)) + { + OPENSSL_free((char *) altname); + GENERAL_NAMES_free(altnames); + return 1; + } + OPENSSL_free((char *) altname); + } + } + GENERAL_NAMES_free(altnames); + return 0; } /* @@ -1590,63 +1611,69 @@ ssl_x509_names_match(X509 *crt, const char *dnsname) * Caller must free returned buffer and all pointers within. * Embedded NULL characters in hostnames are replaced with '!'. */ -char ** -ssl_x509_names(X509 *crt) +char **ssl_x509_names(X509 *crt) { - GENERAL_NAMES *altnames; - char *cn; - size_t cnsz; - char **res, **p; - size_t count; - - cn = ssl_x509_subject_cn(crt, &cnsz); - altnames = X509_get_ext_d2i(crt, NID_subject_alt_name, NULL, NULL); - - count = (altnames ? sk_GENERAL_NAME_num(altnames) : 0) + (cn ? 2 : 1); - res = malloc(count * sizeof(char*)); - if (!res) - return NULL; - p = res; - if (cn) - *(p++) = cn; - if (!altnames) { - *p = NULL; - return res; - } - for (int i = 0; i < sk_GENERAL_NAME_num(altnames); i++) { - GENERAL_NAME *gn = sk_GENERAL_NAME_value(altnames, i); - if (gn->type == GEN_DNS) { - unsigned char *altname; - int altnamesz; - - ASN1_STRING_to_UTF8(&altname, gn->d.dNSName); - if (!altname) - break; - altnamesz = ASN1_STRING_length(gn->d.dNSName); - if (altnamesz < 0) { - OPENSSL_free((char*)altname); - break; - } - *p = malloc(altnamesz + 1); - if (!*p) { - OPENSSL_free((char*)altname); - GENERAL_NAMES_free(altnames); - for (p = res; *p; p++) - free(*p); - free(res); - return NULL; - } - for (int j = 0; j < altnamesz; j++) { - (*p)[j] = altname[j] ? altname[j] : '!'; - } - (*p)[altnamesz] = '\0'; - OPENSSL_free((char*)altname); - p++; - } - } - *p = NULL; - GENERAL_NAMES_free(altnames); - return res; + GENERAL_NAMES *altnames; + char *cn; + size_t cnsz; + char **res, **p; + size_t count; + + cn = ssl_x509_subject_cn(crt, &cnsz); + altnames = (GENERAL_NAMES *) X509_get_ext_d2i(crt, NID_subject_alt_name, NULL, NULL); + + count = (size_t) (altnames ? sk_GENERAL_NAME_num(altnames) : 0) + (cn ? 2 : 1); + res = (char **) malloc(count * sizeof(char *)); + + if (!res) + return NULL; + p = res; + if (cn) + *(p++) = cn; + if (!altnames) + { + *p = NULL; + return res; + } + for (int i = 0; i < sk_GENERAL_NAME_num(altnames); i++) + { + GENERAL_NAME *gn = sk_GENERAL_NAME_value(altnames, i); + if (gn->type == GEN_DNS) + { + unsigned char *altname; + int altnamesz; + + ASN1_STRING_to_UTF8(&altname, gn->d.dNSName); + if (!altname) + break; + altnamesz = ASN1_STRING_length(gn->d.dNSName); + if (altnamesz < 0) + { + OPENSSL_free((char *) altname); + break; + } + *p = (char *) malloc(altnamesz + 1); + if (!*p) + { + OPENSSL_free((char *) altname); + GENERAL_NAMES_free(altnames); + for (p = res; *p; p++) + free(*p); + free(res); + return NULL; + } + for (int j = 0; j < altnamesz; j++) + { + (*p)[j] = altname[j] ? altname[j] : '!'; + } + (*p)[altnamesz] = '\0'; + OPENSSL_free((char *) altname); + p++; + } + } + *p = NULL; + GENERAL_NAMES_free(altnames); + return res; } /* @@ -1656,61 +1683,64 @@ ssl_x509_names(X509 *crt) * Embedded NULL characters in hostnames are replaced with '!'. * If no CN and no subjectAltNames are found, returns "-". */ -char * -ssl_x509_names_to_str(X509 *crt) +char *ssl_x509_names_to_str(X509 *crt) { - char **names; - size_t sz; - char *buf = NULL, *next; - - names = ssl_x509_names(crt); - if (!names) - return strdup("-"); - - sz = 0; - for (char **p = names; *p; p++) { - sz += strlen(*p) + 1; - } - if (!sz) { - goto out1; - } - - if (!(buf = malloc(sz))) - goto out2; - next = buf; - for (char **p = names; *p; p++) { - char *src = *p; - while (*src) { - *next++ = *src++; - } - *next++ = '/'; - } - *--next = '\0'; + char **names; + size_t sz; + char *buf = NULL, *next; + + names = ssl_x509_names(crt); + if (!names) + return strdup("-"); + + sz = 0; + for (char **p = names; *p; p++) + { + sz += strlen(*p) + 1; + } + if (!sz) + { + goto out1; + } + + if (!(buf = (char *) malloc(sz))) + goto out2; + next = buf; + for (char **p = names; *p; p++) + { + char *src = *p; + while (*src) + { + *next++ = *src++; + } + *next++ = '/'; + } + *--next = '\0'; out2: - for (char **p = names; *p; p++) - free(*p); + for (char **p = names; *p; p++) + free(*p); out1: - free(names); - return buf; + free(names); + return buf; } /* * Returns a zero-terminated buffer containing the ASN1 IA5 string. * Returned buffer must be free()'d by caller. */ -static char * -ssl_ia5string_strdup(ASN1_IA5STRING *ia5) +static char *ssl_ia5string_strdup(ASN1_IA5STRING *ia5) { - char *str; - - if (!ia5 || !ia5->length) - return NULL; - str = malloc(ia5->length + 1); - if (!str) - return NULL; - memcpy(str, ia5->data, ia5->length); - str[ia5->length] = 0; - return str; + char *str; + + if (!ia5 || !ia5->length) + return NULL; + + str = (char *) malloc(ia5->length + 1); + if (!str) + return NULL; + memcpy(str, ia5->data, ia5->length); + str[ia5->length] = 0; + return str; } /* @@ -1718,38 +1748,40 @@ ssl_ia5string_strdup(ASN1_IA5STRING *ia5) * Information Access (AIA) URLs of a given type contained in the certificate. * Caller must free returned buffer and all pointers within. */ -char ** -ssl_x509_aias(X509 *crt, const int type) +char **ssl_x509_aias(X509 *crt, const int type) { - AUTHORITY_INFO_ACCESS *aias; - char **res; - int count, i, j; - - aias = X509_get_ext_d2i(crt, NID_info_access, NULL, NULL); - if (!aias || !(count = sk_ACCESS_DESCRIPTION_num(aias))) - return NULL; - - res = malloc((count + 1) * sizeof(char *)); - if (!res) { - sk_ACCESS_DESCRIPTION_pop_free(aias, ACCESS_DESCRIPTION_free); - return NULL; - } - - for (i = 0, j = 0; i < count; i++) { - ACCESS_DESCRIPTION *aia; - - aia = sk_ACCESS_DESCRIPTION_value(aias, i); - if (aia && - OBJ_obj2nid(aia->method) == type && - aia->location->type == GEN_URI) { - res[j] = ssl_ia5string_strdup(aia->location->d.ia5); - if (res[j]) - j++; - } - } - res[j] = NULL; - sk_ACCESS_DESCRIPTION_pop_free(aias, ACCESS_DESCRIPTION_free); - return res; + AUTHORITY_INFO_ACCESS *aias; + char **res; + int count, i, j; + + aias = (AUTHORITY_INFO_ACCESS *) X509_get_ext_d2i(crt, NID_info_access, NULL, NULL); + if (!aias || !(count = sk_ACCESS_DESCRIPTION_num(aias))) + return NULL; + + res = (char **) malloc((count + 1) * sizeof(char *)); + if (!res) + { + sk_ACCESS_DESCRIPTION_pop_free(aias, ACCESS_DESCRIPTION_free); + return NULL; + } + + for (i = 0, j = 0; i < count; i++) + { + ACCESS_DESCRIPTION *aia; + + aia = sk_ACCESS_DESCRIPTION_value(aias, i); + if (aia && + OBJ_obj2nid(aia->method) == type && + aia->location->type == GEN_URI) + { + res[j] = ssl_ia5string_strdup(aia->location->d.ia5); + if (res[j]) + j++; + } + } + res[j] = NULL; + sk_ACCESS_DESCRIPTION_pop_free(aias, ACCESS_DESCRIPTION_free); + return res; } /* @@ -1757,24 +1789,22 @@ ssl_x509_aias(X509 *crt, const int type) * Information Access (AIA) URLs of type OCSP contained in the certificate. * Caller must free returned buffer and all pointers within. */ -char ** -ssl_x509_ocsps(X509 *crt) +char **ssl_x509_ocsps(X509 *crt) { - return ssl_x509_aias(crt, NID_ad_OCSP); + return ssl_x509_aias(crt, NID_ad_OCSP); } /* * Check whether the certificate is valid based on current time. * Return 1 if valid, 0 otherwise. */ -int -ssl_x509_is_valid(X509 *crt) +int ssl_x509_is_valid(X509 *crt) { - if (X509_cmp_current_time(X509_get_notAfter(crt)) <= 0) - return 0; - if (X509_cmp_current_time(X509_get_notBefore(crt)) > 0) - return 0; - return 1; + if (X509_cmp_current_time(X509_get_notAfter(crt)) <= 0) + return 0; + if (X509_cmp_current_time(X509_get_notBefore(crt)) > 0) + return 0; + return 1; } /* @@ -1785,23 +1815,26 @@ ssl_x509_is_valid(X509 *crt) char * ssl_x509_to_str(X509 *crt) { - BIO *bio; - char *p, *ret; - size_t sz; - - bio = BIO_new(BIO_s_mem()); - if (!bio) - return NULL; - X509_print(bio, crt); - sz = BIO_get_mem_data(bio, &p); - if (!(ret = malloc(sz + 1))) { - BIO_free(bio); - return NULL; - } - memcpy(ret, p, sz); - ret[sz] = '\0'; - BIO_free(bio); - return ret; + BIO *bio; + char *p, *ret; + size_t sz; + + bio = BIO_new(BIO_s_mem()); + if (!bio) + return NULL; + + X509_print(bio, crt); + sz = (size_t) BIO_get_mem_data(bio, &p); + + if (!(ret = (char *) malloc(sz + 1))) + { + BIO_free(bio); + return NULL; + } + memcpy(ret, p, sz); + ret[sz] = '\0'; + BIO_free(bio); + return ret; } /* @@ -1809,26 +1842,29 @@ ssl_x509_to_str(X509 *crt) * Caller must free returned string. * Returns NULL on errors. */ -char * -ssl_x509_to_pem(X509 *crt) +char *ssl_x509_to_pem(X509 *crt) { - BIO *bio; - char *p, *ret; - size_t sz; - - bio = BIO_new(BIO_s_mem()); - if (!bio) - return NULL; - PEM_write_bio_X509(bio, crt); - sz = BIO_get_mem_data(bio, &p); - if (!(ret = malloc(sz + 1))) { - BIO_free(bio); - return NULL; - } - memcpy(ret, p, sz); - ret[sz] = '\0'; - BIO_free(bio); - return ret; + BIO *bio; + char *p, *ret; + size_t sz; + + bio = BIO_new(BIO_s_mem()); + if (!bio) + return NULL; + + PEM_write_bio_X509(bio, crt); + sz = (size_t) BIO_get_mem_data(bio, &p); + + if (!(ret = (char *) malloc(sz + 1))) + { + BIO_free(bio); + return NULL; + } + + memcpy(ret, p, sz); + ret[sz] = '\0'; + BIO_free(bio); + return ret; } /* @@ -1836,66 +1872,66 @@ ssl_x509_to_pem(X509 *crt) * Caller must free returned string. * Returns NULL on errors. */ -char * -ssl_session_to_str(SSL_SESSION *sess) +char *ssl_session_to_str(SSL_SESSION *sess) { - BIO *bio; - char *p, *ret; - size_t sz; - - bio = BIO_new(BIO_s_mem()); - if (!bio) - return NULL; - SSL_SESSION_print(bio, sess); - sz = BIO_get_mem_data(bio, &p); /* sets p to internal buffer */ - if (!(ret = malloc(sz + 1))) { - BIO_free(bio); - return NULL; - } - memcpy(ret, p, sz); - ret[sz] = '\0'; - BIO_free(bio); - return ret; + BIO *bio; + char *p, *ret; + size_t sz; + + bio = BIO_new(BIO_s_mem()); + if (!bio) + return NULL; + + SSL_SESSION_print(bio, sess); + sz = (size_t) BIO_get_mem_data(bio, &p); /* sets p to internal buffer */ + + if (!(ret = (char *) malloc(sz + 1))) + { + BIO_free(bio); + return NULL; + } + memcpy(ret, p, sz); + ret[sz] = '\0'; + BIO_free(bio); + return ret; } /* * Returns non-zero if the session timeout has not expired yet, * zero if the session has expired or an error occured. */ -int -ssl_session_is_valid(SSL_SESSION *sess) +int ssl_session_is_valid(SSL_SESSION *sess) { - time_t curtimet; - long curtime, timeout; - - curtimet = time(NULL); - if (curtimet == (time_t)-1) - return 0; - curtime = curtimet; - if ((curtime < 0) || ((time_t)curtime != curtimet)) - return 0; - timeout = SSL_SESSION_get_timeout(sess); - if (curtime < timeout) - return 0; - return (SSL_SESSION_get_time(sess) > curtime - timeout); + time_t curtimet; + long curtime, timeout; + + curtimet = time(NULL); + if (curtimet == (time_t) -1) + return 0; + curtime = curtimet; + if ((curtime < 0) || ((time_t) curtime != curtimet)) + return 0; + timeout = SSL_SESSION_get_timeout(sess); + if (curtime < timeout) + return 0; + return (SSL_SESSION_get_time(sess) > curtime - timeout); } /* * Returns 1 if buf contains a DER encoded OCSP request which can be parsed. * Returns 0 otherwise. */ -int -ssl_is_ocspreq(const unsigned char *buf, size_t sz) +int ssl_is_ocspreq(const unsigned char *buf, size_t sz) { - OCSP_REQUEST *req; - const unsigned char *p; - - p = (const unsigned char *)buf; - req = d2i_OCSP_REQUEST(NULL, &p, sz); /* increments p */ - if (!req) - return 0; - OCSP_REQUEST_free(req); - return 1; + OCSP_REQUEST *req; + const unsigned char *p; + + p = (const unsigned char *) buf; + req = d2i_OCSP_REQUEST(NULL, &p, sz); /* increments p */ + if (!req) + return 0; + OCSP_REQUEST_free(req); + return 1; } /* @@ -1946,19 +1982,20 @@ ssl_is_ocspreq(const unsigned char *buf, size_t sz) * RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions */ int -ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search, - const unsigned char **clienthello, char **servername) +ssl_tls_clienthello_parse( + const unsigned char *buf, ssize_t sz, int search, + const unsigned char **clienthello, char **servername) { #ifdef DEBUG_CLIENTHELLO_PARSER #define DBG_printf(...) log_dbg_printf("ClientHello parser: " __VA_ARGS__) #else /* !DEBUG_CLIENTHELLO_PARSER */ -#define DBG_printf(...) +#define DBG_printf(...) #endif /* !DEBUG_CLIENTHELLO_PARSER */ - const unsigned char *p = buf; - ssize_t n = sz; - char *sn = NULL; + const unsigned char *p = buf; + ssize_t n = sz; + char *sn = NULL; - ssize_t tlsextslen; + ssize_t tlsextslen; ssize_t sidlen; ssize_t suiteslen; ssize_t compslen; @@ -1967,334 +2004,373 @@ ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search, //===== - *clienthello = NULL; - - DBG_printf("parsing buffer of sz %zd\n", sz); - - do { - if (*clienthello) { - /* - * Rewind after skipping an invalid ClientHello by - * restarting the search one byte after the beginning - * of the last candidate - */ - p = (*clienthello) + 1; - n = sz - (p - buf); - if (sn) { - free(sn); - sn = NULL; - } - } - - if (search) { - /* Search for a potential ClientHello */ - while ((n > 0) && (*p != 0x16) && (*p != 0x80)) { - p++; n--; - } - if (n <= 0) { - /* Search completed without a match; reset - * clienthello to NULL to indicate to the - * caller that this buffer does not need to be - * retried */ - DBG_printf("===> No match:" - " rv 1, *clienthello NULL\n"); - *clienthello = NULL; - return 1; - } - } - *clienthello = p; - DBG_printf("candidate at offset %td\n", p - buf); - - DBG_printf("byte 0: %02x\n", *p); - /* +0 0x80 +2 0x01 SSLv2 short header, clientHello; - * +0 0x16 +1 0x03 SSLv3/TLSv1.x handshake, clientHello */ - if (*p == 0x80) { - /* SSLv2 handled here */ - p++; n--; - - if (n < 10) { /* length + 9 */ - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - - DBG_printf("length: %02x\n", p[0]); - if (n - 1 < p[0]) { - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - p++; n--; - - DBG_printf("msgtype: %02x\n", p[0]); - if (*p != 0x01) - continue; - p++; n--; - - DBG_printf("version: %02x %02x\n", p[0], p[1]); - /* byte order is actually swapped for SSLv2 */ - if (!( + *clienthello = NULL; + + DBG_printf("parsing buffer of sz %zd\n", sz); + + do + { + if (*clienthello) + { + /* + * Rewind after skipping an invalid ClientHello by + * restarting the search one byte after the beginning + * of the last candidate + */ + p = (*clienthello) + 1; + n = sz - (p - buf); + if (sn) + { + free(sn); + sn = NULL; + } + } + + if (search) + { + /* Search for a potential ClientHello */ + while ((n > 0) && (*p != 0x16) && (*p != 0x80)) + { + p++; + n--; + } + if (n <= 0) + { + /* Search completed without a match; reset + * clienthello to NULL to indicate to the + * caller that this buffer does not need to be + * retried */ + DBG_printf("===> No match:" + " rv 1, *clienthello NULL\n"); + *clienthello = NULL; + return 1; + } + } + *clienthello = p; + DBG_printf("candidate at offset %td\n", p - buf); + + DBG_printf("byte 0: %02x\n", *p); + /* +0 0x80 +2 0x01 SSLv2 short header, clientHello; + * +0 0x16 +1 0x03 SSLv3/TLSv1.x handshake, clientHello */ + if (*p == 0x80) + { + /* SSLv2 handled here */ + p++; + n--; + + if (n < 10) + { /* length + 9 */ + DBG_printf("===> [SSLv2] Truncated:" + " rv 1, *clienthello set\n"); + return 1; + } + + DBG_printf("length: %02x\n", p[0]); + if (n - 1 < p[0]) + { + DBG_printf("===> [SSLv2] Truncated:" + " rv 1, *clienthello set\n"); + return 1; + } + p++; + n--; + + DBG_printf("msgtype: %02x\n", p[0]); + if (*p != 0x01) + continue; + p++; + n--; + + DBG_printf("version: %02x %02x\n", p[0], p[1]); + /* byte order is actually swapped for SSLv2 */ + if (!( #ifdef HAVE_SSLV2 - (p[0] == 0x00 && p[1] == 0x02) || + (p[0] == 0x00 && p[1] == 0x02) || #endif /* HAVE_SSLV2 */ - (p[0] == 0x03 && p[1] <= 0x03))) - continue; - p += 2; n -= 2; - - DBG_printf("cipher-spec-len: %02x %02x\n", p[0], p[1]); - ssize_t cipherspec_len = p[0] << 8 | p[1]; - p += 2; n -= 2; - - DBG_printf("session-id-len: %02x %02x\n", p[0], p[1]); - ssize_t sessionid_len = p[0] << 8 | p[1]; - p += 2; n -= 2; - - DBG_printf("challenge-len: %02x %02x\n", p[0], p[1]); - ssize_t challenge_len = p[0] << 8 | p[1]; - p += 2; n -= 2; - if (challenge_len < 16 || challenge_len > 32) - continue; - - if (n < cipherspec_len - + sessionid_len - + challenge_len) { - DBG_printf("===> [SSLv2] Truncated:" - " rv 1, *clienthello set\n"); - return 1; - } - - p += cipherspec_len + sessionid_len + challenge_len; - n -= cipherspec_len + sessionid_len + challenge_len; - goto done_parsing; - } else - if (*p != 0x16) { - /* this can only happen if search is 0 */ - DBG_printf("===> No match: rv 1, *clienthello NULL\n"); - *clienthello = NULL; - return 1; - } - p++; n--; - - if (n < 2) { - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - DBG_printf("version: %02x %02x\n", p[0], p[1]); - /* This supports up to TLS 1.2 (0x03 0x03) and will need to be - * updated for TLS 1.3 once that is standardized and still - * compatible with this parser; remember to also update the - * inner version check below */ - if (p[0] != 0x03 || p[1] > 0x03) - continue; - p += 2; n -= 2; - - if (n < 2) { - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - DBG_printf("length: %02x %02x\n", p[0], p[1]); - - recordlen = p[1] + (p[0] << 8); - DBG_printf("recordlen=%zd\n", recordlen); - p += 2; n -= 2; - if (recordlen < 36) /* arbitrary size too small for a c-h */ - continue; - if (n < recordlen) { - DBG_printf("n < recordlen: n=%zd\n", n); - DBG_printf("===> Truncated: rv 1, *clienthello set\n"); - return 1; - } - - /* from here we give up on a candidate if there is not enough - * data available in the buffer, because we already checked the - * availability of the whole record. */ - - if (n < 1) - continue; - DBG_printf("message type: %i\n", *p); - if (*p != 0x01) /* message type: ClientHello */ - continue; - p++; n--; - - if (n < 3) - continue; - DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]); - msglen = p[2] + (p[1] << 8) + (p[0] << 16); - DBG_printf("msglen=%zd\n", msglen); - p += 3; n -= 3; - if (msglen < 32) /* arbitrary size too small for a c-h */ - continue; - if (msglen != recordlen - 4) { - DBG_printf("msglen != recordlen - 4\n"); - continue; - } - if (n < msglen) - continue; - n = msglen; /* only parse first message */ - - if (n < 2) - continue; - DBG_printf("clienthello version %02x %02x\n", p[0], p[1]); - /* inner version check, see outer one above */ - if (p[0] != 0x03 || p[1] > 0x03) - continue; - p += 2; n -= 2; - - if (n < 32) - continue; - DBG_printf("clienthello random %02x %02x %02x %02x ...\n", - p[0], p[1], p[2], p[3]); - DBG_printf("compare localtime: %08x\n", - (unsigned int)time(NULL)); - p += 32; n -= 32; - - if (n < 1) - continue; - DBG_printf("clienthello sidlen %02x\n", *p); - sidlen = *p; /* session id length, 0..32 */ - p += 1; n -= 1; - if (n < sidlen) - continue; - p += sidlen; n -= sidlen; - - if (n < 2) - continue; - DBG_printf("clienthello cipher suites length %02x %02x\n", - p[0], p[1]); - - suiteslen = p[1] + (p[0] << 8); - p += 2; n -= 2; - if (n < suiteslen) - continue; - p += suiteslen; - n -= suiteslen; - - if (n < 1) - continue; - DBG_printf("clienthello compress methods length %02x\n", *p); - - compslen = *p; - p++; n--; - if (n < compslen) - continue; - p += compslen; - n -= compslen; - - /* begin of extensions */ - - if (n == 0) { - /* valid ClientHello without extensions */ - DBG_printf("===> Match: rv 0, *clienthello set\n"); - if (servername) - *servername = NULL; - return 0; - } - if (n < 2) - continue; - DBG_printf("tlsexts length %02x %02x\n", p[0], p[1]); + (p[0] == 0x03 && p[1] <= 0x03))) + continue; + p += 2; + n -= 2; + + DBG_printf("cipher-spec-len: %02x %02x\n", p[0], p[1]); + ssize_t cipherspec_len = p[0] << 8 | p[1]; + p += 2; + n -= 2; + + DBG_printf("session-id-len: %02x %02x\n", p[0], p[1]); + ssize_t sessionid_len = p[0] << 8 | p[1]; + p += 2; + n -= 2; + + DBG_printf("challenge-len: %02x %02x\n", p[0], p[1]); + ssize_t challenge_len = p[0] << 8 | p[1]; + p += 2; + n -= 2; + if (challenge_len < 16 || challenge_len > 32) + continue; + + if (n < cipherspec_len + + sessionid_len + + challenge_len) + { + DBG_printf("===> [SSLv2] Truncated:" + " rv 1, *clienthello set\n"); + return 1; + } + + p += cipherspec_len + sessionid_len + challenge_len; + n -= cipherspec_len + sessionid_len + challenge_len; + goto done_parsing; + } else if (*p != 0x16) + { + /* this can only happen if search is 0 */ + DBG_printf("===> No match: rv 1, *clienthello NULL\n"); + *clienthello = NULL; + return 1; + } + p++; + n--; + + if (n < 2) + { + DBG_printf("===> Truncated: rv 1, *clienthello set\n"); + return 1; + } + DBG_printf("version: %02x %02x\n", p[0], p[1]); + /* This supports up to TLS 1.2 (0x03 0x03) and will need to be + * updated for TLS 1.3 once that is standardized and still + * compatible with this parser; remember to also update the + * inner version check below */ + if (p[0] != 0x03 || p[1] > 0x03) + continue; + p += 2; + n -= 2; + + if (n < 2) + { + DBG_printf("===> Truncated: rv 1, *clienthello set\n"); + return 1; + } + DBG_printf("length: %02x %02x\n", p[0], p[1]); + + recordlen = p[1] + (p[0] << 8); + DBG_printf("recordlen=%zd\n", recordlen); + p += 2; + n -= 2; + if (recordlen < 36) /* arbitrary size too small for a c-h */ + continue; + if (n < recordlen) + { + DBG_printf("n < recordlen: n=%zd\n", n); + DBG_printf("===> Truncated: rv 1, *clienthello set\n"); + return 1; + } + + /* from here we give up on a candidate if there is not enough + * data available in the buffer, because we already checked the + * availability of the whole record. */ + + if (n < 1) + continue; + DBG_printf("message type: %i\n", *p); + if (*p != 0x01) /* message type: ClientHello */ + continue; + p++; + n--; + + if (n < 3) + continue; + DBG_printf("message len: %02x %02x %02x\n", p[0], p[1], p[2]); + msglen = p[2] + (p[1] << 8) + (p[0] << 16); + DBG_printf("msglen=%zd\n", msglen); + p += 3; + n -= 3; + if (msglen < 32) /* arbitrary size too small for a c-h */ + continue; + if (msglen != recordlen - 4) + { + DBG_printf("msglen != recordlen - 4\n"); + continue; + } + if (n < msglen) + continue; + n = msglen; /* only parse first message */ + + if (n < 2) + continue; + DBG_printf("clienthello version %02x %02x\n", p[0], p[1]); + /* inner version check, see outer one above */ + if (p[0] != 0x03 || p[1] > 0x03) + continue; + p += 2; + n -= 2; + + if (n < 32) + continue; + DBG_printf("clienthello random %02x %02x %02x %02x ...\n", + p[0], p[1], p[2], p[3]); + DBG_printf("compare localtime: %08x\n", + (unsigned int) time(NULL)); + p += 32; + n -= 32; + + if (n < 1) + continue; + DBG_printf("clienthello sidlen %02x\n", *p); + sidlen = *p; /* session id length, 0..32 */ + p += 1; + n -= 1; + if (n < sidlen) + continue; + p += sidlen; + n -= sidlen; + + if (n < 2) + continue; + DBG_printf("clienthello cipher suites length %02x %02x\n", + p[0], p[1]); + + suiteslen = p[1] + (p[0] << 8); + p += 2; + n -= 2; + if (n < suiteslen) + continue; + p += suiteslen; + n -= suiteslen; + + if (n < 1) + continue; + DBG_printf("clienthello compress methods length %02x\n", *p); + + compslen = *p; + p++; + n--; + if (n < compslen) + continue; + p += compslen; + n -= compslen; + + /* begin of extensions */ + + if (n == 0) + { + /* valid ClientHello without extensions */ + DBG_printf("===> Match: rv 0, *clienthello set\n"); + if (servername) + *servername = NULL; + return 0; + } + if (n < 2) + continue; + DBG_printf("tlsexts length %02x %02x\n", p[0], p[1]); tlsextslen = p[1] + (p[0] << 8); - DBG_printf("tlsextslen %zd\n", tlsextslen); - p += 2; n -= 2; - if (n < tlsextslen) - continue; - n = tlsextslen; /* only parse exts, ignore trailing bits */ - - while (n > 0) { - if (n < 4) - goto continue_search; - DBG_printf("tlsext type %02x %02x len %02x %02x\n", - p[0], p[1], p[2], p[3]); - unsigned short exttype = p[1] + (p[0] << 8); - ssize_t extlen = p[3] + (p[2] << 8); - p += 4; n -= 4; - if (n < extlen) - goto continue_search; - switch (exttype) { - case 0: { - ssize_t extn = extlen; - const unsigned char *extp = p; - - if (extn < 2) - goto continue_search; - DBG_printf("list length %02x %02x\n", - extp[0], extp[1]); - ssize_t namelistlen = extp[1] + (extp[0] << 8); - DBG_printf("namelistlen = %zd\n", namelistlen); - extp += 2; - extn -= 2; - - if (namelistlen != extn) - goto continue_search; - - while (extn > 0) { - if (extn < 3) - goto continue_search; - DBG_printf("ServerName type %02x" - " len %02x %02x\n", - extp[0], extp[1], extp[2]); - unsigned char sntype = extp[0]; - ssize_t snlen = extp[2] + (extp[1]<<8); - extp += 3; - extn -= 3; - if (snlen > extn) - goto continue_search; - if (snlen > TLSEXT_MAXLEN_host_name) - goto continue_search; - /* - * We copy the first name only. - * RFC 6066: "The ServerNameList MUST - * NOT contain more than one name of - * the same name_type." - */ - if (servername && - sntype == 0 && sn == NULL) { - sn = malloc(snlen + 1); - memcpy(sn, extp, snlen); - sn[snlen] = '\0'; - /* deliberately not checking - * for malformed hostnames - * containing invalid chars */ - } - extp += snlen; - extn -= snlen; - } - break; - } - default: - DBG_printf("skipped\n"); - break; - } - p += extlen; - n -= extlen; - } /* while have more extensions */ - -done_parsing: - ; + DBG_printf("tlsextslen %zd\n", tlsextslen); + p += 2; + n -= 2; + if (n < tlsextslen) + continue; + n = tlsextslen; /* only parse exts, ignore trailing bits */ + + while (n > 0) + { + if (n < 4) + goto continue_search; + DBG_printf("tlsext type %02x %02x len %02x %02x\n", + p[0], p[1], p[2], p[3]); + unsigned short exttype = p[1] + (p[0] << 8); + ssize_t extlen = p[3] + (p[2] << 8); + p += 4; + n -= 4; + if (n < extlen) + goto continue_search; + switch (exttype) + { + case 0: + { + ssize_t extn = extlen; + const unsigned char *extp = p; + + if (extn < 2) + goto continue_search; + DBG_printf("list length %02x %02x\n", + extp[0], extp[1]); + ssize_t namelistlen = extp[1] + (extp[0] << 8); + DBG_printf("namelistlen = %zd\n", namelistlen); + extp += 2; + extn -= 2; + + if (namelistlen != extn) + goto continue_search; + + while (extn > 0) + { + if (extn < 3) + goto continue_search; + DBG_printf("ServerName type %02x" + " len %02x %02x\n", + extp[0], extp[1], extp[2]); + unsigned char sntype = extp[0]; + ssize_t snlen = extp[2] + (extp[1] << 8); + extp += 3; + extn -= 3; + if (snlen > extn) + goto continue_search; + if (snlen > TLSEXT_MAXLEN_host_name) + goto continue_search; + /* + * We copy the first name only. + * RFC 6066: "The ServerNameList MUST + * NOT contain more than one name of + * the same name_type." + */ + if (servername && + sntype == 0 && sn == NULL) + { + sn = malloc(snlen + 1); + memcpy(sn, extp, snlen); + sn[snlen] = '\0'; + /* deliberately not checking + * for malformed hostnames + * containing invalid chars */ + } + extp += snlen; + extn -= snlen; + } + break; + } + default: DBG_printf("skipped\n"); + break; + } + p += extlen; + n -= extlen; + } /* while have more extensions */ + +done_parsing:; #ifdef DEBUG_CLIENTHELLO_PARSER - if (n > 0) { - DBG_printf("unparsed next bytes %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3]); - } + if (n > 0) { + DBG_printf("unparsed next bytes %02x %02x %02x %02x\n", + p[0], p[1], p[2], p[3]); + } #endif /* DEBUG_CLIENTHELLO_PARSER */ - DBG_printf("%zd bytes unparsed\n", n); - - /* Valid ClientHello with or without server name */ - DBG_printf("===> Match: rv 0, *clienthello set\n"); - if (servername) - *servername = sn; - return 0; -continue_search: - ; - } while (search && n > 0); - - /* No valid ClientHello messages found, not even a truncated one */ - DBG_printf("===> No match: rv 1, *clienthello NULL\n"); - *clienthello = NULL; - if (sn) { - free(sn); - sn = NULL; - } - return 1; + DBG_printf("%zd bytes unparsed\n", n); + + /* Valid ClientHello with or without server name */ + DBG_printf("===> Match: rv 0, *clienthello set\n"); + if (servername) + *servername = sn; + return 0; +continue_search:; + } while (search && n > 0); + + /* No valid ClientHello messages found, not even a truncated one */ + DBG_printf("===> No match: rv 1, *clienthello NULL\n"); + *clienthello = NULL; + if (sn) + { + free(sn); + sn = NULL; + } + return 1; } /* vim: set noet ft=c: */ diff --git a/src/util.cc b/src/util.cc index d16036c..82104f6 100644 --- a/src/util.cc +++ b/src/util.cc @@ -41,5 +41,4 @@ util_skipws(const char *s) { return (char*) s + strspn(s, " \t"); } - /* vim: set noet ft=c: */ @@ -1,40 +1,120 @@ -/*- - * SSLsplit - transparent SSL/TLS interception - * https://www.roe.ch/SSLsplit - * - * Copyright (c) 2009-2018, Daniel Roethlisberger <[email protected]>. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UTIL_H -#define UTIL_H +#pragma once #include "attrib.h" +#define util_max(a, b) ((a) > (b) ? (a) : (b)) +char *util_skipws(const char *) NONNULL(1) PURE; -char * util_skipws(const char *) NONNULL(1) PURE; +#include <memory> +#include <string> +#include <cstring> -#define util_max(a,b) ((a) > (b) ? (a) : (b)) +struct cfg_invalid_format : std::invalid_argument +{ + explicit cfg_invalid_format( + const std::string &file, + const std::string §ion, + const std::string &item, + const std::string &what) : file(file), section(section), item(item), invalid_argument(what) + {} -#endif /* !UTIL_H */ + std::string file; + std::string section; + std::string item; +}; -/* vim: set noet ft=c: */ +struct cfg_lost_entry : std::invalid_argument +{ + explicit cfg_lost_entry( + const std::string &file, + const std::string §ion, + const std::string &item, + const std::string &what) : file(file), section(section), item(item), invalid_argument(what) + {} + + std::string file; + std::string section; + std::string item; +}; + +struct invalid_input_format : std::invalid_argument +{ + explicit invalid_input_format(const std::string &what, const std::string &raw_input = "") : + input_raw(raw_input), std::invalid_argument(what) + {} + + std::string input_raw; + std::string input_source; +}; + +template<typename ... Args> +std::string string_format(const std::string &format, Args ... args) +{ + size_t size = static_cast<size_t >(snprintf(nullptr, 0, format.c_str(), args...) + 1); // Extra space for '\0' + std::unique_ptr<char[]> buf(new char[size]); + snprintf(buf.get(), size, format.c_str(), args ...); + return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside +} + +template<class ContainerT> +void tokenize( + const std::string &str, ContainerT &tokens, + const std::string &delimiters = " ", bool trimEmpty = false, + const std::function<bool(const std::string &, std::string::size_type)> cb_is_delimiter = nullptr) +{ + std::string::size_type pos, lastPos = 0, length = str.length(); + + using value_type = typename ContainerT::value_type; + using size_type = typename ContainerT::size_type; + + while (lastPos < length + 1) + { + pos = str.find_first_of(delimiters, lastPos); + if (cb_is_delimiter != nullptr && !cb_is_delimiter(str, pos)) + { + lastPos = pos + 1; + continue; + } + + if (pos == std::string::npos) + { + pos = length; + } + + if (pos != lastPos || !trimEmpty) + tokens.push_back(value_type(str.data() + lastPos, + (size_type) pos - lastPos)); + + lastPos = pos + 1; + } +} + +class NonCopyable +{ +protected: + constexpr NonCopyable() = default; + NonCopyable(const NonCopyable &) = delete; + NonCopyable &operator=(const NonCopyable &) = delete; +}; + +#if __cplusplus <= 201103L +namespace std +{ +template<typename T, typename... U> +typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type +make_unique(U &&... u) +{ + return std::unique_ptr<T>(new T(std::forward<U>(u)...)); +} + +template<typename T> +typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type +make_unique(size_t size) +{ + return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]()); +} +} + +#endif + +#define likely(expr) __builtin_expect((expr), 1) +#define unlikely(expr) __builtin_expect((expr), 0)
\ No newline at end of file |
