summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLu <[email protected]>2018-05-25 10:27:28 +0800
committerLu <[email protected]>2018-05-25 10:27:28 +0800
commitaf3e8a16570fe1202a1e891b487742f866ee5958 (patch)
tree7f59a4a8a8640e76a193339e381a5a496b6b5c78
parentb73c659f33fcad83f03841a2ca63f51184f663d6 (diff)
HTTP解析层接口改进,增加功能。
-rw-r--r--.idea/codeStyles/Project.xml2
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/CMakeLists.txt14
-rw-r--r--src/attrib.h13
-rw-r--r--src/cachedsess.cc2
-rw-r--r--src/cachemgr.cc2
-rw-r--r--src/cachessess.cc2
-rw-r--r--src/certstore.cc145
-rw-r--r--src/certstore.h9
-rw-r--r--src/cfgparser.h38
-rw-r--r--src/compat.cc57
-rw-r--r--src/compat.h52
-rw-r--r--src/http.cc5
-rw-r--r--src/http.h168
-rw-r--r--src/http1.cc503
-rw-r--r--src/httpaction.cc325
-rw-r--r--src/httpaction.h60
-rw-r--r--src/httpscan.cc253
-rw-r--r--src/httpscan.h89
-rw-r--r--src/main.cc38
-rw-r--r--src/opts.cc206
-rw-r--r--src/opts.h51
-rw-r--r--src/proxy.cc22
-rw-r--r--src/pxyconn.cc3580
-rw-r--r--src/pxyconn.h19
-rw-r--r--src/pxyhttp.cc182
-rw-r--r--src/pxyhttp.h4
-rw-r--r--src/pxysslshut.cc6
-rw-r--r--src/pxythrmgr.cc340
-rw-r--r--src/pxythrmgr.h13
-rw-r--r--src/ssl.cc3056
-rw-r--r--src/util.cc1
-rw-r--r--src/util.h148
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 &section,
- 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 &section,
- 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;
}
diff --git a/src/opts.h b/src/opts.h
index 72d81a7..5ff3ac1 100644
--- a/src/opts.h
+++ b/src/opts.h
@@ -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 */
diff --git a/src/ssl.cc b/src/ssl.cc
index 4ef9ee7..bd0151e 100644
--- a/src/ssl.cc
+++ b/src/ssl.cc
@@ -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: */
diff --git a/src/util.h b/src/util.h
index 91be6b2..1195c26 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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 &section,
+ 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 &section,
+ 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