From af3e8a16570fe1202a1e891b487742f866ee5958 Mon Sep 17 00:00:00 2001 From: Lu Date: Fri, 25 May 2018 10:27:28 +0800 Subject: HTTP解析层接口改进,增加功能。 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/httpscan.cc | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 src/httpscan.cc (limited to 'src/httpscan.cc') 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 + * \date 2018-5-15 + */ + + +#include +#include +#include + +#include +#include + +#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(*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 -- cgit v1.2.3