summaryrefslogtreecommitdiff
path: root/src/httpscan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/httpscan.cc')
-rw-r--r--src/httpscan.cc253
1 files changed, 253 insertions, 0 deletions
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