TSG-1531 TFE 新增 DOH 插件
1.DOH 协议解析 2.DOH 协议还原 3.DOH POST请求 early response 4.DOH 策略扫描 5.tfe plugin 支持多个 bussiness 插件调用 6.Maat_feather 的创建从 pangu 剥离(涉及pangu/doh/ssl-policy) 7.增加 kafka 日志 8.增加测试用例
This commit is contained in:
@@ -26,6 +26,7 @@ option(ENABLE_SANITIZE_THREAD "Enable ThreadSanitizer" FALSE)
|
||||
# Plugins
|
||||
option(ENABLE_PLUGIN_HTTP "Enable HTTP support" TRUE)
|
||||
option(ENABLE_PLUGIN_TRAFFIC_MIRROR "Enable traffic mirror" TRUE)
|
||||
option(ENABLE_PLUGIN_DOH "Enable Doh business" TRUE)
|
||||
option(ENABLE_PLUGIN_PANGU_HTTP "Enable Pangu-HTTP business" TRUE)
|
||||
option(ENABLE_PLUGIN_HTTP2 "Enable HTTP2 business" TRUE)
|
||||
option(ENABLE_PLUGIN_SSL_POLICY "Enable SSL policy support" TRUE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
add_library(common src/tfe_utils.cpp src/tfe_types.cpp src/tfe_future.cpp src/tfe_http.cpp src/tfe_plugin.cpp src/tfe_rpc.cpp src/tfe_cmsg.cpp src/tfe_kafka_logger.cpp)
|
||||
add_library(common src/tfe_utils.cpp src/tfe_types.cpp src/tfe_future.cpp src/tfe_http.cpp src/tfe_plugin.cpp src/tfe_rpc.cpp src/tfe_cmsg.cpp src/tfe_kafka_logger.cpp src/tfe_resource.cpp)
|
||||
target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_link_libraries(common PUBLIC libevent-static libevent-static-openssl libevent-static-pthreads)
|
||||
target_link_libraries(common PUBLIC MESA_handle_logger)
|
||||
|
||||
@@ -282,10 +282,13 @@ struct http_field_name
|
||||
const char * field_name;
|
||||
};
|
||||
|
||||
#define CALL_NEXT_PLUGIN 0
|
||||
#define NO_CALL_NEXT_PLUGIN -1
|
||||
|
||||
typedef void (http_session_begin_cb)(const struct tfe_stream * stream,
|
||||
const struct tfe_http_session * session, unsigned int thread_id, void ** pme);
|
||||
|
||||
typedef void (http_session_data_cb)(const struct tfe_stream * stream,
|
||||
typedef int (http_session_data_cb)(const struct tfe_stream * stream,
|
||||
const struct tfe_http_session * session, enum tfe_http_event event, const unsigned char * data,
|
||||
size_t datalen, unsigned int thread_id, void ** pme);
|
||||
|
||||
|
||||
10
common/include/tfe_resource.h
Normal file
10
common/include/tfe_resource.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
enum RESOURCE_TYPE
|
||||
{
|
||||
STATIC_MAAT,
|
||||
DYNAMINC_MAAT,
|
||||
};
|
||||
|
||||
int tfe_bussiness_resouce_init();
|
||||
void *tfe_bussiness_resouce_get(enum RESOURCE_TYPE type);
|
||||
@@ -175,4 +175,5 @@ char *tfe_read_file(const char *filename, size_t *filelen);
|
||||
const char * tfe_version();
|
||||
int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, unsigned value);
|
||||
int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, void * val, size_t len);
|
||||
int tfe_decode_base64url(u_char *dst, u_char *src);
|
||||
|
||||
|
||||
@@ -153,11 +153,12 @@ int http_frame_raise_session_begin(struct http_frame_session_ctx * ht_frame,
|
||||
struct tfe_plugin * plugin_info_iter;
|
||||
TFE_PLUGIN_FOREACH(plugin_info_iter, &__for_each_iterator)
|
||||
{
|
||||
__plugin_id++;
|
||||
if (plugin_info_iter->on_session_begin == NULL) continue;
|
||||
|
||||
/* Calling ctx, in callback can fetch by calling frame_plugin_status_get_XXX */
|
||||
ht_frame->calling_plugin = plugin_info_iter;
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id];
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id - 1];
|
||||
|
||||
/* Call session begin */
|
||||
void ** calling_pme = &ht_frame->calling_plugin_status->pme;
|
||||
@@ -179,11 +180,12 @@ void http_frame_raise_session_end(struct http_frame_session_ctx * ht_frame, cons
|
||||
|
||||
TFE_PLUGIN_FOREACH(plugin_info_iter, &__for_each_iterator)
|
||||
{
|
||||
__plugin_id++;
|
||||
if (plugin_info_iter->on_session_end == NULL) continue;
|
||||
|
||||
/* Calling ctx, in callback can fetch by calling frame_plugin_status_get_XXX */
|
||||
ht_frame->calling_plugin = plugin_info_iter;
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id];
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id - 1];
|
||||
|
||||
/* Call session end */
|
||||
void ** calling_pme = &ht_frame->calling_plugin_status->pme;
|
||||
@@ -207,6 +209,7 @@ void http_frame_raise_event(struct http_frame_session_ctx * ht_frame,
|
||||
struct tfe_plugin * plugin_info_iter;
|
||||
TFE_PLUGIN_FOREACH(plugin_info_iter, &__for_each_iterator)
|
||||
{
|
||||
__plugin_id++;
|
||||
if (plugin_info_iter->on_session_data == NULL)
|
||||
{
|
||||
continue;
|
||||
@@ -214,7 +217,7 @@ void http_frame_raise_event(struct http_frame_session_ctx * ht_frame,
|
||||
|
||||
/* Calling ctx, in callback can fetch by calling frame_plugin_status_get_XXX */
|
||||
ht_frame->calling_plugin = plugin_info_iter;
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id];
|
||||
ht_frame->calling_plugin_status = &ht_frame->plugin_status[__plugin_id - 1];
|
||||
|
||||
if (ht_frame->calling_plugin_status->detached)
|
||||
{
|
||||
@@ -222,7 +225,10 @@ void http_frame_raise_event(struct http_frame_session_ctx * ht_frame,
|
||||
}
|
||||
|
||||
void ** calling_pme = &ht_frame->calling_plugin_status->pme;
|
||||
plugin_info_iter->on_session_data(stream, ht_session, event, data, datalen, thread_id, calling_pme);
|
||||
if (plugin_info_iter->on_session_data(stream, ht_session, event, data, datalen, thread_id, calling_pme) == NO_CALL_NEXT_PLUGIN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ht_frame->calling_plugin = NULL;
|
||||
|
||||
169
common/src/tfe_resource.cpp
Normal file
169
common/src/tfe_resource.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_resource.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include <MESA/Maat_rule.h>
|
||||
#include <MESA/MESA_prof_load.h>
|
||||
|
||||
#define MAAT_INPUT_JSON 0
|
||||
#define MAAT_INPUT_REDIS 1
|
||||
#define MAAT_INPUT_FILE 2
|
||||
|
||||
static Maat_feather_t static_maat = NULL;
|
||||
static Maat_feather_t dynamic_maat = NULL;
|
||||
|
||||
static Maat_feather_t create_maat_feather(const char *instance_name, const char *profile, const char *section, int max_thread, void *logger)
|
||||
{
|
||||
Maat_feather_t target;
|
||||
int input_mode = 0, maat_stat_on = 0, maat_perf_on = 0;
|
||||
int ret = 0, scan_detail = 0, effect_interval = 60;
|
||||
char table_info[TFE_STRING_MAX] = {0}, inc_cfg_dir[TFE_STRING_MAX] = {0}, ful_cfg_dir[TFE_STRING_MAX] = {0};
|
||||
char redis_server[TFE_STRING_MAX] = {0};
|
||||
char redis_port_range[TFE_STRING_MAX] = {0};
|
||||
char accept_tags[TFE_STRING_MAX] = {0};
|
||||
int redis_port_begin = 0, redis_port_end = 0;
|
||||
int redis_port_select = 0;
|
||||
int redis_db_idx = 0;
|
||||
char json_cfg_file[TFE_STRING_MAX] = {0}, maat_stat_file[TFE_STRING_MAX] = {0};
|
||||
|
||||
MESA_load_profile_int_def(profile, section, "maat_input_mode", &(input_mode), 0);
|
||||
MESA_load_profile_int_def(profile, section, "stat_switch", &(maat_stat_on), 1);
|
||||
MESA_load_profile_int_def(profile, section, "perf_switch", &(maat_perf_on), 1);
|
||||
MESA_load_profile_string_def(profile, section, "table_info", table_info, sizeof(table_info), "");
|
||||
MESA_load_profile_string_def(profile, section, "accept_tags", accept_tags, sizeof(accept_tags), "");
|
||||
MESA_load_profile_string_def(profile, section, "json_cfg_file", json_cfg_file, sizeof(json_cfg_file), "");
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_server", redis_server, sizeof(redis_server), "");
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_port_range", redis_port_range, sizeof(redis_server), "6379");
|
||||
MESA_load_profile_int_def(profile, section, "maat_redis_db_index", &(redis_db_idx), 0);
|
||||
MESA_load_profile_string_def(profile, section, "inc_cfg_dir", inc_cfg_dir, sizeof(inc_cfg_dir), "");
|
||||
MESA_load_profile_string_def(profile, section, "full_cfg_dir", ful_cfg_dir, sizeof(ful_cfg_dir), "");
|
||||
MESA_load_profile_string_def(profile, section, "stat_file", maat_stat_file, sizeof(maat_stat_file), "");
|
||||
MESA_load_profile_int_def(profile, section, "effect_interval_s", &(effect_interval), 60);
|
||||
|
||||
effect_interval *= 1000; //convert s to ms
|
||||
|
||||
target = Maat_feather(max_thread, table_info, logger);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INSTANCE_NAME, instance_name, strlen(instance_name) + 1);
|
||||
switch (input_mode)
|
||||
{
|
||||
case MAAT_INPUT_JSON:
|
||||
if (!strlen(json_cfg_file))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid json_cfg_file, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_JSON_FILE_PATH, json_cfg_file, strlen(json_cfg_file) + 1);
|
||||
break;
|
||||
case MAAT_INPUT_REDIS:
|
||||
if (!strlen(redis_server))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid maat_redis_server, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
ret = sscanf(redis_port_range, "%d-%d", &redis_port_begin, &redis_port_end);
|
||||
if (ret == 1)
|
||||
{
|
||||
redis_port_select = redis_port_begin;
|
||||
}
|
||||
else if (ret == 2)
|
||||
{
|
||||
srand(time(NULL));
|
||||
redis_port_select = redis_port_begin + rand() % (redis_port_end - redis_port_begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid redis port range %s, MAAT init failed.", redis_port_range);
|
||||
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_IP, redis_server, strlen(redis_server) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_PORT, &redis_port_select, sizeof(redis_port_select));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_INDEX, &redis_db_idx, sizeof(redis_db_idx));
|
||||
break;
|
||||
case MAAT_INPUT_FILE:
|
||||
if (!strlen(ful_cfg_dir))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid ful_cfg_dir, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!strlen(inc_cfg_dir))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid inc_cfg_dir, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_FULL_CFG_DIR, ful_cfg_dir, strlen(ful_cfg_dir) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INC_CFG_DIR, inc_cfg_dir, strlen(inc_cfg_dir) + 1);
|
||||
break;
|
||||
default:
|
||||
TFE_LOG_ERROR(logger, "Invalid MAAT Input Mode: %d.", input_mode);
|
||||
goto error_out;
|
||||
break;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_FOREIGN_CONT_DIR, "./pangu_files", strlen("./pangu_files") + 1);
|
||||
if (maat_stat_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_FILE_PATH, maat_stat_file, strlen(maat_stat_file) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_ON, NULL, 0);
|
||||
if (maat_perf_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_PERF_ON, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail));
|
||||
if (strlen(accept_tags) > 0)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_ACCEPT_TAGS, &accept_tags, sizeof(accept_tags));
|
||||
}
|
||||
|
||||
ret = Maat_initiate_feather(target);
|
||||
if (ret < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "%s MAAT init failed.", __FUNCTION__);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return target;
|
||||
error_out:
|
||||
Maat_burn_feather(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tfe_bussiness_resouce_init()
|
||||
{
|
||||
const char *profile_path = "./conf/pangu/pangu_pxy.conf";
|
||||
unsigned int thread_num = tfe_proxy_get_work_thread_count();
|
||||
static_maat = create_maat_feather("static", profile_path, "MAAT", thread_num, g_default_logger);
|
||||
if (!static_maat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dynamic_maat = create_maat_feather("dyn", profile_path, "DYNAMIC_MAAT", thread_num, g_default_logger);
|
||||
if (!dynamic_maat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tfe_bussiness_resouce_get(enum RESOURCE_TYPE type)
|
||||
{
|
||||
if (type == STATIC_MAAT)
|
||||
{
|
||||
return static_maat;
|
||||
}
|
||||
if (type == DYNAMINC_MAAT)
|
||||
{
|
||||
return dynamic_maat;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -154,4 +154,76 @@ cleanup:
|
||||
return content;
|
||||
}
|
||||
|
||||
static int tfe_decode_base64_internal(u_char *dst, u_char *src, const u_char *basis)
|
||||
{
|
||||
size_t len;
|
||||
u_char *d, *s;
|
||||
|
||||
for (len = 0; len < strlen((char *)src); len++)
|
||||
{
|
||||
if (src[len] == '=')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (basis[src[len]] == 77)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (len % 4 == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = src;
|
||||
d = dst;
|
||||
|
||||
while (len > 3)
|
||||
{
|
||||
*d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
|
||||
*d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
|
||||
*d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
|
||||
|
||||
s += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len > 1)
|
||||
{
|
||||
*d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
|
||||
}
|
||||
|
||||
if (len > 2)
|
||||
{
|
||||
*d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
|
||||
}
|
||||
|
||||
return d - dst;
|
||||
}
|
||||
|
||||
int tfe_decode_base64url(u_char *dst, u_char *src)
|
||||
{
|
||||
static u_char basis64[] = {
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
|
||||
77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
|
||||
77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
|
||||
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
|
||||
};
|
||||
|
||||
return tfe_decode_base64_internal(dst, src, basis64);
|
||||
}
|
||||
|
||||
34
conf/doh/doh.conf
Normal file
34
conf/doh/doh.conf
Normal file
@@ -0,0 +1,34 @@
|
||||
[doh]
|
||||
# default 1
|
||||
enable=1
|
||||
|
||||
[log]
|
||||
# default 10
|
||||
# RLOG_LV_DEBUG : 10
|
||||
# RLOG_LV_INFO : 20
|
||||
# RLOG_LV_FATAL : 30
|
||||
log_level=10
|
||||
|
||||
[maat]
|
||||
# default TSG_OBJ_APP_ID
|
||||
table_appid=TSG_OBJ_APP_ID
|
||||
# default TSG_SECURITY_ADDR
|
||||
table_addr=TSG_SECURITY_ADDR
|
||||
# default TSG_FIELD_DOH_QNAME
|
||||
table_qname=TSG_FIELD_DOH_QNAME
|
||||
# default TSG_FIELD_HTTP_HOST
|
||||
table_host=TSG_FIELD_HTTP_HOST
|
||||
|
||||
[kafka]
|
||||
# default NULL
|
||||
device_id_filepath==/opt/tsg/etc/tsg_sn.json
|
||||
# default 0
|
||||
ENTRANCE_ID=0
|
||||
# default 1
|
||||
en_sendlog=1
|
||||
# default eth0
|
||||
NIC_NAME=eth0
|
||||
# defautl empty
|
||||
kafka_brokerlist=192.168.40.224:9092
|
||||
# default POLICY-DOH-LOG
|
||||
kafka_topic=POLICY-DOH-LOG
|
||||
@@ -35,6 +35,10 @@ if(ENABLE_PLUGIN_HTTP2)
|
||||
target_link_libraries(tfe -Wl,--whole-archive http2 -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PLUGIN_DOH)
|
||||
target_link_libraries(tfe -Wl,--whole-archive doh -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PLUGIN_PANGU_HTTP)
|
||||
target_link_libraries(tfe -Wl,--whole-archive pangu-http -Wl,--no-whole-archive)
|
||||
endif()
|
||||
|
||||
10
platform/include/internal/resource.h
Normal file
10
platform/include/internal/resource.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
enum RESOURCE_TYPE
|
||||
{
|
||||
STATIC_MAAT,
|
||||
DYNAMINC_MAAT,
|
||||
};
|
||||
|
||||
int tfe_bussiness_resouce_init();
|
||||
void *tfe_bussiness_resouce_get(enum RESOURCE_TYPE type);
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <tfe_proxy.h>
|
||||
#include <tfe_plugin.h>
|
||||
#include <tfe_cmsg.h>
|
||||
#include <tfe_resource.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include <proxy.h>
|
||||
@@ -729,6 +730,10 @@ int main(int argc, char * argv[])
|
||||
g_default_proxy->scm_sender = sender_scm_init(main_profile, "kni", g_default_logger);
|
||||
CHECK_OR_EXIT(g_default_proxy->scm_sender != NULL, "Failed at creating scm sender, Exit.");
|
||||
|
||||
/* RESOURCE INIT */
|
||||
ret = tfe_bussiness_resouce_init();
|
||||
CHECK_OR_EXIT(ret == 0, "TFE bussiness resource init failed. Exit.");
|
||||
|
||||
/* PLUGIN INIT */
|
||||
unsigned int plugin_iterator = 0;
|
||||
for (struct tfe_plugin * plugin_iter = tfe_plugin_iterate(&plugin_iterator);
|
||||
@@ -739,7 +744,6 @@ int main(int argc, char * argv[])
|
||||
TFE_LOG_INFO(g_default_logger, "Plugin %s initialized. ", plugin_iter->symbol);
|
||||
}
|
||||
|
||||
//ugly here. g_business_maat is available after plugin initiate.
|
||||
g_default_proxy->ssl_ply_enforcer=ssl_policy_enforcer_create(g_default_logger);
|
||||
ssl_manager_set_new_upstream_cb(g_default_proxy->ssl_mgr_handler, ssl_policy_enforce, g_default_proxy->ssl_ply_enforcer);
|
||||
ret = tfe_proxy_work_thread_run(g_default_proxy);
|
||||
|
||||
168
platform/src/resource.cpp
Normal file
168
platform/src/resource.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <resource.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include <MESA/Maat_rule.h>
|
||||
#include <MESA/MESA_prof_load.h>
|
||||
|
||||
#define MAAT_INPUT_JSON 0
|
||||
#define MAAT_INPUT_REDIS 1
|
||||
#define MAAT_INPUT_FILE 2
|
||||
|
||||
static Maat_feather_t static_maat = NULL;
|
||||
static Maat_feather_t dynamic_maat = NULL;
|
||||
|
||||
static Maat_feather_t create_maat_feather(const char *instance_name, const char *profile, const char *section, int max_thread, void *logger)
|
||||
{
|
||||
Maat_feather_t target;
|
||||
int input_mode = 0, maat_stat_on = 0, maat_perf_on = 0;
|
||||
int ret = 0, scan_detail = 0, effect_interval = 60;
|
||||
char table_info[TFE_STRING_MAX] = {0}, inc_cfg_dir[TFE_STRING_MAX] = {0}, ful_cfg_dir[TFE_STRING_MAX] = {0};
|
||||
char redis_server[TFE_STRING_MAX] = {0};
|
||||
char redis_port_range[TFE_STRING_MAX] = {0};
|
||||
char accept_tags[TFE_STRING_MAX] = {0};
|
||||
int redis_port_begin = 0, redis_port_end = 0;
|
||||
int redis_port_select = 0;
|
||||
int redis_db_idx = 0;
|
||||
char json_cfg_file[TFE_STRING_MAX] = {0}, maat_stat_file[TFE_STRING_MAX] = {0};
|
||||
|
||||
MESA_load_profile_int_def(profile, section, "maat_input_mode", &(input_mode), 0);
|
||||
MESA_load_profile_int_def(profile, section, "stat_switch", &(maat_stat_on), 1);
|
||||
MESA_load_profile_int_def(profile, section, "perf_switch", &(maat_perf_on), 1);
|
||||
MESA_load_profile_string_def(profile, section, "table_info", table_info, sizeof(table_info), "");
|
||||
MESA_load_profile_string_def(profile, section, "accept_tags", accept_tags, sizeof(accept_tags), "");
|
||||
MESA_load_profile_string_def(profile, section, "json_cfg_file", json_cfg_file, sizeof(json_cfg_file), "");
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_server", redis_server, sizeof(redis_server), "");
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_port_range", redis_port_range, sizeof(redis_server), "6379");
|
||||
MESA_load_profile_int_def(profile, section, "maat_redis_db_index", &(redis_db_idx), 0);
|
||||
MESA_load_profile_string_def(profile, section, "inc_cfg_dir", inc_cfg_dir, sizeof(inc_cfg_dir), "");
|
||||
MESA_load_profile_string_def(profile, section, "full_cfg_dir", ful_cfg_dir, sizeof(ful_cfg_dir), "");
|
||||
MESA_load_profile_string_def(profile, section, "stat_file", maat_stat_file, sizeof(maat_stat_file), "");
|
||||
MESA_load_profile_int_def(profile, section, "effect_interval_s", &(effect_interval), 60);
|
||||
|
||||
effect_interval *= 1000; //convert s to ms
|
||||
|
||||
target = Maat_feather(max_thread, table_info, logger);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INSTANCE_NAME, instance_name, strlen(instance_name) + 1);
|
||||
switch (input_mode)
|
||||
{
|
||||
case MAAT_INPUT_JSON:
|
||||
if (!strlen(json_cfg_file))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid json_cfg_file, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_JSON_FILE_PATH, json_cfg_file, strlen(json_cfg_file) + 1);
|
||||
break;
|
||||
case MAAT_INPUT_REDIS:
|
||||
if (!strlen(redis_server))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid maat_redis_server, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
ret = sscanf(redis_port_range, "%d-%d", &redis_port_begin, &redis_port_end);
|
||||
if (ret == 1)
|
||||
{
|
||||
redis_port_select = redis_port_begin;
|
||||
}
|
||||
else if (ret == 2)
|
||||
{
|
||||
srand(time(NULL));
|
||||
redis_port_select = redis_port_begin + rand() % (redis_port_end - redis_port_begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid redis port range %s, MAAT init failed.", redis_port_range);
|
||||
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_IP, redis_server, strlen(redis_server) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_PORT, &redis_port_select, sizeof(redis_port_select));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_INDEX, &redis_db_idx, sizeof(redis_db_idx));
|
||||
break;
|
||||
case MAAT_INPUT_FILE:
|
||||
if (!strlen(ful_cfg_dir))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid ful_cfg_dir, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!strlen(inc_cfg_dir))
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid inc_cfg_dir, MAAT init failed.");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_FULL_CFG_DIR, ful_cfg_dir, strlen(ful_cfg_dir) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INC_CFG_DIR, inc_cfg_dir, strlen(inc_cfg_dir) + 1);
|
||||
break;
|
||||
default:
|
||||
TFE_LOG_ERROR(logger, "Invalid MAAT Input Mode: %d.", input_mode);
|
||||
goto error_out;
|
||||
break;
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_FOREIGN_CONT_DIR, "./pangu_files", strlen("./pangu_files") + 1);
|
||||
if (maat_stat_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_FILE_PATH, maat_stat_file, strlen(maat_stat_file) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_ON, NULL, 0);
|
||||
if (maat_perf_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_PERF_ON, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail));
|
||||
if (strlen(accept_tags) > 0)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_ACCEPT_TAGS, &accept_tags, sizeof(accept_tags));
|
||||
}
|
||||
|
||||
ret = Maat_initiate_feather(target);
|
||||
if (ret < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "%s MAAT init failed.", __FUNCTION__);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return target;
|
||||
error_out:
|
||||
Maat_burn_feather(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tfe_bussiness_resouce_init()
|
||||
{
|
||||
const char *profile_path = "./conf/pangu/pangu_pxy.conf";
|
||||
unsigned int thread_num = tfe_proxy_get_work_thread_count();
|
||||
static_maat = create_maat_feather("static", profile_path, "MAAT", thread_num, g_default_logger);
|
||||
if (!static_maat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dynamic_maat = create_maat_feather("dyn", profile_path, "DYNAMIC_MAAT", thread_num, g_default_logger);
|
||||
if (!dynamic_maat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tfe_bussiness_resouce_get(enum RESOURCE_TYPE type)
|
||||
{
|
||||
if (type == STATIC)
|
||||
{
|
||||
return static_maat;
|
||||
}
|
||||
if (type == DYNAMINC)
|
||||
{
|
||||
return dynamic_maat;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
add_subdirectory(traffic-mirror)
|
||||
add_subdirectory(doh)
|
||||
add_subdirectory(pangu-http)
|
||||
add_subdirectory(ssl-policy)
|
||||
|
||||
9
plugin/business/doh/CMakeLists.txt
Normal file
9
plugin/business/doh/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
add_library(doh src/doh.cpp src/dns.cpp src/logger.cpp src/pub.cpp)
|
||||
target_link_libraries(doh PUBLIC cjson)
|
||||
target_link_libraries(doh PUBLIC maatframe)
|
||||
target_link_libraries(doh PUBLIC common)
|
||||
target_link_libraries(doh PUBLIC http)
|
||||
|
||||
add_executable(dns_test test/dns_test.cpp src/dns.cpp src/pub.cpp)
|
||||
target_link_libraries(dns_test PUBLIC cjson)
|
||||
target_link_libraries(dns_test PUBLIC common)
|
||||
1250
plugin/business/doh/src/dns.cpp
Normal file
1250
plugin/business/doh/src/dns.cpp
Normal file
File diff suppressed because it is too large
Load Diff
388
plugin/business/doh/src/dns.h
Normal file
388
plugin/business/doh/src/dns.h
Normal file
@@ -0,0 +1,388 @@
|
||||
#ifndef DNS_ANALYSE_H
|
||||
#define DNS_ANALYSE_H
|
||||
|
||||
#include <MESA/cJSON.h>
|
||||
|
||||
#ifndef u_char
|
||||
#define u_char unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef u_int16_t
|
||||
#define u_int16_t unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef u_int32_t
|
||||
#define u_int32_t unsigned int //adjust by lqy 20070521 long to int
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
#define DNS_MAX_SALT 256
|
||||
#define DNS_MAX_OWNER 256
|
||||
#define DNS_MAX_MAPS 256
|
||||
#define DNS_MAX_PUBLIC_KEY 256
|
||||
#define DNS_MAX_SIGNER_NAME 256
|
||||
#define DNS_MAX_SIGNATURE 256
|
||||
#define DNS_MAX_DIGEST 256
|
||||
#define DNS_MAX_TARGET 256
|
||||
|
||||
#define DNS_HINFO_MAX_CPU 40
|
||||
#define DNS_HINFO_MAX_OS 40
|
||||
#define DNS_MAX_NAME 255
|
||||
|
||||
#define DNS_RR_TYPE_ALL 0
|
||||
#define DNS_RR_TYPE_ANS 1
|
||||
#define DNS_RR_TYPE_AUTH 2
|
||||
#define DNS_RR_TYPE_ADD 3
|
||||
|
||||
#define NS_INT8SZ 1
|
||||
#define NS_INT16SZ 2
|
||||
#define NS_INT32SZ 4
|
||||
|
||||
#define NS_GET32(l, cp) \
|
||||
do \
|
||||
{ \
|
||||
register u_char *t_cp = (u_char *)(cp); \
|
||||
(l) = ((u_int32_t)t_cp[0] << 24) | ((u_int32_t)t_cp[1] << 16) | ((u_int32_t)t_cp[2] << 8) | ((u_int32_t)t_cp[3]); \
|
||||
(cp) += NS_INT32SZ; \
|
||||
} while (0)
|
||||
|
||||
#define NS_GET16(s, cp) \
|
||||
do \
|
||||
{ \
|
||||
register u_char *t_cp = (u_char *)(cp); \
|
||||
(s) = ((u_int16_t)t_cp[0] << 8) | ((u_int16_t)t_cp[1]); \
|
||||
(cp) += NS_INT16SZ; \
|
||||
} while (0)
|
||||
|
||||
#define NS_GET8(s, cp) \
|
||||
do \
|
||||
{ \
|
||||
register u_char *t_cp = (u_char *)(cp); \
|
||||
(s) = ((u_char)t_cp[0]); \
|
||||
(cp) += NS_INT8SZ; \
|
||||
} while (0)
|
||||
|
||||
#define NS_SET8(data, payload, used_len) \
|
||||
do \
|
||||
{ \
|
||||
u_char seg_8 = (data); \
|
||||
memcpy(((payload) + (used_len)), &seg_8, sizeof(seg_8)); \
|
||||
(used_len) += sizeof(seg_8); \
|
||||
} while (0)
|
||||
|
||||
#define NS_SET16(data, payload, used_len) \
|
||||
do \
|
||||
{ \
|
||||
u_int16_t seg_16 = htons(data); \
|
||||
memcpy(((payload) + (used_len)), &seg_16, sizeof(seg_16)); \
|
||||
(used_len) += sizeof(seg_16); \
|
||||
} while (0)
|
||||
|
||||
#define NS_SET32(data, payload, used_len) \
|
||||
do \
|
||||
{ \
|
||||
u_int32_t seg_32 = htonl(data); \
|
||||
memcpy(((payload) + (used_len)), &seg_32, sizeof(seg_32)); \
|
||||
(used_len) += sizeof(seg_32); \
|
||||
} while (0)
|
||||
|
||||
#define NS_SETLEN(data, len, payload, used_len) \
|
||||
do \
|
||||
{ \
|
||||
memcpy(((payload) + (used_len)), (data), (len)); \
|
||||
(used_len) += (len); \
|
||||
} while (0)
|
||||
|
||||
/* RR type */
|
||||
#define DNS_TYPE_A 1
|
||||
#define DNS_TYPE_NS 2
|
||||
#define DNS_TYPE_MD 3
|
||||
#define DNS_TYPE_MF 4
|
||||
#define DNS_TYPE_CNAME 5
|
||||
#define DNS_TYPE_SOA 6
|
||||
#define DNS_TYPE_MB 7
|
||||
#define DNS_TYPE_MG 8
|
||||
#define DNS_TYPE_MR 9
|
||||
#define DNS_TYPE_NULL 10
|
||||
#define DNS_TYPE_WKS 11
|
||||
#define DNS_TYPE_PTR 12
|
||||
#define DNS_TYPE_HINFO 13
|
||||
#define DNS_TYPE_MINFO 14
|
||||
#define DNS_TYPE_MX 15
|
||||
#define DNS_TYPE_TXT 16
|
||||
#define DNS_TYPE_RP 17
|
||||
#define DNS_TYPE_ISDN 20
|
||||
#define DNS_TYPE_AAAA 28
|
||||
#define DNS_TYPE_SRV 33
|
||||
#define DNS_TYPE_DNAME 39
|
||||
#define DNS_TYPE_OPT 41
|
||||
#define DNS_TYPE_DS 43
|
||||
#define DNS_TYPE_RRSIG 46
|
||||
#define DNS_TYPE_NSEC 47
|
||||
#define DNS_TYPE_DNSKEY 48
|
||||
#define DNS_TYPE_NSEC3 50
|
||||
#define DNS_TYPE_NSEC3PARAM 51
|
||||
#define DNS_QTYPE_AXFR 252
|
||||
#define DNS_QTYPE_MAILB 253
|
||||
#define DNS_QTYPE_MAILA 254
|
||||
#define DNS_QTYPE_ANY 255
|
||||
#define DNS_TYPE_DLV 32769 /* DSNSEC Lokkaside Validation */
|
||||
#define DNS_TYPE_UNKNOWN 65534
|
||||
|
||||
#define DNS_CLASS_UNKNOWN 0
|
||||
#define DNS_CLASS_IN 1
|
||||
#define DNS_CLASS_CS 2
|
||||
#define DNS_CLASS_CH 3
|
||||
#define DNS_CLASS_HS 4
|
||||
#define DNS_QCLASS_ANY 255
|
||||
|
||||
// <20>洢 DNS ͷ<><CDB7><EFBFBD><EFBFBD>Ϣ<EFBFBD>Ľṹ<C4BD><E1B9B9>
|
||||
typedef struct _dns_hdr
|
||||
{
|
||||
u_int16_t id;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
u_char rd : 1;
|
||||
u_char tc : 1;
|
||||
u_char aa : 1;
|
||||
u_char opcode : 4;
|
||||
u_char qr : 1;
|
||||
u_char rcode : 4;
|
||||
u_char z : 3;
|
||||
u_char ra : 1;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
u_char qr : 1;
|
||||
u_char opcode : 4;
|
||||
u_char aa : 1;
|
||||
u_char tc : 1;
|
||||
u_char rd : 1;
|
||||
u_char ra : 1;
|
||||
u_char z : 3;
|
||||
u_char rcode : 4;
|
||||
#endif
|
||||
u_int16_t qdcount;
|
||||
u_int16_t ancount;
|
||||
u_int16_t aucount; //authority count
|
||||
u_int16_t adcount; //additional count
|
||||
} dns_hdr_t;
|
||||
|
||||
typedef struct _hinfo
|
||||
{
|
||||
u_char os_len;
|
||||
u_char cpu_len;
|
||||
u_char cpu[DNS_HINFO_MAX_CPU + 1];
|
||||
u_char os[DNS_HINFO_MAX_OS + 1];
|
||||
} hinfo_t;
|
||||
|
||||
typedef struct _minfo
|
||||
{
|
||||
u_char rmailbx[DNS_MAX_NAME + 1];
|
||||
u_char emailbx[DNS_MAX_NAME + 1];
|
||||
} minfo_t;
|
||||
|
||||
typedef struct _mx
|
||||
{
|
||||
u_int16_t preference;
|
||||
u_char exchange[DNS_MAX_NAME + 1];
|
||||
} mx_t;
|
||||
|
||||
typedef struct _soa
|
||||
{
|
||||
u_char mname[DNS_MAX_NAME + 1];
|
||||
u_char rname[DNS_MAX_NAME + 1];
|
||||
u_int32_t serial;
|
||||
u_int32_t refresh;
|
||||
u_int32_t retry;
|
||||
u_int32_t expire;
|
||||
u_int32_t minimum;
|
||||
} soa_t;
|
||||
|
||||
typedef struct _rp_t
|
||||
{
|
||||
u_char mailbox[DNS_MAX_NAME + 1];
|
||||
u_char txt_rr[DNS_MAX_NAME + 1];
|
||||
} rp_t;
|
||||
|
||||
typedef struct _txt_t
|
||||
{
|
||||
u_char txt[DNS_MAX_NAME + 1];
|
||||
u_char size;
|
||||
} txt_t;
|
||||
|
||||
typedef struct _null
|
||||
{
|
||||
u_char null[DNS_MAX_NAME + 1];
|
||||
u_char size;
|
||||
} null_t;
|
||||
|
||||
typedef struct _wks
|
||||
{
|
||||
u_char protocol;
|
||||
u_int32_t addr;
|
||||
u_int32_t size;
|
||||
u_char *bitmap;
|
||||
} wks_t;
|
||||
|
||||
typedef struct _srv
|
||||
{
|
||||
u_int16_t priority;
|
||||
u_int16_t weight;
|
||||
u_int16_t port;
|
||||
u_char target[DNS_MAX_TARGET];
|
||||
} srv_t;
|
||||
|
||||
typedef struct _ds
|
||||
{
|
||||
u_int16_t key_tag;
|
||||
u_char algo;
|
||||
u_char digest_type;
|
||||
u_int32_t digest_len;
|
||||
u_char *digest;
|
||||
} ds_t;
|
||||
|
||||
typedef struct _rrsig
|
||||
{
|
||||
u_int16_t type_covered;
|
||||
u_char algo;
|
||||
u_char labels;
|
||||
u_int32_t original_ttl;
|
||||
u_int32_t sig_expiration;
|
||||
u_int32_t sig_inception;
|
||||
u_int32_t key_tag;
|
||||
u_int32_t signature_len;
|
||||
u_char signer_name[DNS_MAX_SIGNER_NAME];
|
||||
u_char *signature;
|
||||
} rrsig_t;
|
||||
|
||||
typedef struct _nsec
|
||||
{
|
||||
u_int16_t maps_temp_len;
|
||||
u_int16_t maps_len;
|
||||
u_char next_domain[DNS_MAX_OWNER];
|
||||
u_char type_bit_maps[DNS_MAX_MAPS];
|
||||
} nsec_t;
|
||||
|
||||
typedef struct _dnskey
|
||||
{
|
||||
u_int16_t flags;
|
||||
u_char protocol;
|
||||
u_char algo;
|
||||
u_int32_t public_key_len;
|
||||
u_char *public_key;
|
||||
} dnskey_t;
|
||||
|
||||
typedef struct _nsec3
|
||||
{
|
||||
u_char hash_algo;
|
||||
u_char flags;
|
||||
u_char salt_len;
|
||||
u_char hash_len;
|
||||
u_int16_t iteration;
|
||||
u_int16_t maps_temp_len;
|
||||
u_int16_t maps_len;
|
||||
u_char *salt_value;
|
||||
u_char *next_hash_owner;
|
||||
u_char type_bit_maps[DNS_MAX_MAPS];
|
||||
} nsec3_t;
|
||||
|
||||
typedef struct _nsec3param
|
||||
{
|
||||
u_char hash_algo;
|
||||
u_char flags;
|
||||
u_char salt_len;
|
||||
u_int16_t iteration;
|
||||
u_char *salt_value;
|
||||
} nsec3param_t;
|
||||
|
||||
// <20>洢 DNS <20><>Դ<EFBFBD><D4B4>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>(<28>ش<EFBFBD><D8B4><EFBFBD><EFBFBD><EFBFBD> / <20><>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD> / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29>Ľṹ<C4BD><E1B9B9>
|
||||
typedef struct _dns_rr
|
||||
{
|
||||
u_char name[DNS_MAX_NAME + 1];
|
||||
u_int16_t type;
|
||||
u_int16_t rr_class;
|
||||
u_int32_t ttl; /* 1byte: extended RCODE; 1byte: version; 2bytes: Z(upper bit) if type is OPT */
|
||||
u_int16_t rdlength;
|
||||
union {
|
||||
u_char cname[DNS_MAX_NAME + 1]; /* cname[DNS_MAX_NAME + 1]; */
|
||||
hinfo_t hinfo;
|
||||
u_char mb[DNS_MAX_NAME + 1]; /* mb[DNS_MAX_NAME + 1]; */
|
||||
u_char md[DNS_MAX_NAME + 1]; /* md[DNS_MAX_NAME + 1]; */
|
||||
u_char mf[DNS_MAX_NAME + 1]; /* mf[DNS_MAX_NAME + 1]; */
|
||||
u_char mg[DNS_MAX_NAME + 1]; /* mg[DNS_MAX_NAME + 1]; */
|
||||
minfo_t minfo;
|
||||
u_char mr[DNS_MAX_NAME + 1]; /* mr[DNS_MAX_NAME + 1]; */
|
||||
mx_t mx;
|
||||
u_char ns[DNS_MAX_NAME + 1]; /* ns[DNS_MAX_NAME + 1]; */
|
||||
u_char ptr[DNS_MAX_NAME + 1]; /* ptr[DNS_MAX_NAME + 1]; */
|
||||
soa_t soa;
|
||||
u_char a[DNS_MAX_NAME + 1];
|
||||
u_char aaaa[DNS_MAX_NAME + 1]; /* aaaa[16]; */
|
||||
u_char dname[DNS_MAX_NAME + 1];
|
||||
u_char isdn[DNS_MAX_NAME + 1];
|
||||
u_char unknown_data[DNS_MAX_NAME + 1];
|
||||
txt_t txt;
|
||||
rp_t rp;
|
||||
null_t null;
|
||||
wks_t wks;
|
||||
srv_t srv;
|
||||
ds_t ds;
|
||||
rrsig_t rrsig;
|
||||
nsec_t nsec;
|
||||
dnskey_t dnskey;
|
||||
nsec3_t nsec3;
|
||||
nsec3param_t nsec3param;
|
||||
} rdata;
|
||||
} dns_rr_t;
|
||||
|
||||
typedef struct _fake_packet_opt
|
||||
{
|
||||
u_int16_t cfg_type; /* IP or STR */
|
||||
u_int16_t res_type;
|
||||
u_int32_t ttl;
|
||||
u_int32_t res_len;
|
||||
u_char res_info[DNS_MAX_NAME + 1];
|
||||
} cheat_pkt_opt_t;
|
||||
|
||||
// <20>洢 DNS Queries <20><><EFBFBD><EFBFBD><EFBFBD>Ľṹ<C4BD><E1B9B9>
|
||||
typedef struct
|
||||
{
|
||||
u_int16_t qtype;
|
||||
u_int16_t qclass;
|
||||
u_char qname[DNS_MAX_NAME + 1];
|
||||
} dns_query_question_t;
|
||||
|
||||
#define MAX_RR_NUM 256
|
||||
|
||||
// <20>洢<EFBFBD><E6B4A2><EFBFBD><EFBFBD> DNS <20><>Ϣ<EFBFBD>Ľṹ<C4BD><E1B9B9>
|
||||
typedef struct _dns_info
|
||||
{
|
||||
// <20>洢 DNS ͷ<><CDB7><EFBFBD><EFBFBD>Ϣ<EFBFBD>Ľṹ<C4BD><E1B9B9>
|
||||
dns_hdr_t hdr_info;
|
||||
|
||||
// RR <20><>¼<EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD>
|
||||
int rr_count;
|
||||
// <20>洢 DNS <20><>Դ<EFBFBD><D4B4>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>(<28>ش<EFBFBD><D8B4><EFBFBD><EFBFBD><EFBFBD> / <20><>Ȩ<EFBFBD><C8A8><EFBFBD><EFBFBD> / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<29>Ľṹ<C4BD><E1B9B9>
|
||||
dns_rr_t rr[MAX_RR_NUM];
|
||||
|
||||
// <20>洢 DNS Queries <20><><EFBFBD><EFBFBD><EFBFBD>Ľṹ<C4BD><E1B9B9>
|
||||
dns_query_question_t query_question;
|
||||
} dns_info_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
dns_info_t *dns_new(void);
|
||||
void dns_free(dns_info_t *dns_info);
|
||||
|
||||
int dns_parser(dns_info_t *dns_info, char *in_buff, int buff_len);
|
||||
int dns_package(dns_info_t *dns_info, char *out_buff, int buff_size);
|
||||
int dns_cheat_response(dns_info_t *dns_info, cheat_pkt_opt_t *cheat_opt, int cheat_opt_num, char *out_buff, int buff_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
758
plugin/business/doh/src/doh.cpp
Normal file
758
plugin/business/doh/src/doh.cpp
Normal file
@@ -0,0 +1,758 @@
|
||||
#include "logger.h"
|
||||
|
||||
#define MAX_SCAN_RESULT 128
|
||||
#define DOH_CTX_MAGIC_NUM 20200601
|
||||
|
||||
#define REQ_METHOD_IS_GET(method) ((method == TFE_HTTP_METHOD_GET) ? 1 : 0)
|
||||
#define REQ_METHOD_IS_POST(method) ((method == TFE_HTTP_METHOD_POST) ? 1 : 0)
|
||||
|
||||
struct dns_str2idx
|
||||
{
|
||||
int index;
|
||||
int len;
|
||||
char *type;
|
||||
};
|
||||
|
||||
struct dns_str2idx str2index[] = {
|
||||
{DNS_TYPE_CNAME, 5, (char *)"CNAME"},
|
||||
{DNS_TYPE_MX, 2, (char *)"MX"},
|
||||
{DNS_TYPE_A, 1, (char *)"A"},
|
||||
{DNS_TYPE_NS, 2, (char *)"NS"},
|
||||
{DNS_TYPE_AAAA, 4, (char *)"AAAA"},
|
||||
{DNS_TYPE_TXT, 3, (char *)"TXT"},
|
||||
{DNS_TYPE_PTR, 3, (char *)"PTR"}};
|
||||
|
||||
static struct doh_conf *g_doh_conf = NULL;
|
||||
|
||||
static int doh_type2index(char *type)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < (int)(sizeof(str2index) / sizeof(struct dns_str2idx)); i++)
|
||||
{
|
||||
if (str2index[i].len == (int)strlen(type) && (strncasecmp(str2index[i].type, type, str2index[i].len)) == 0)
|
||||
{
|
||||
return str2index[i].index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void doh_addr_tfe2sapp(const struct tfe_stream_addr *tfe_addr, struct ipaddr *sapp_addr)
|
||||
{
|
||||
if (tfe_addr->addrtype == TFE_ADDR_STREAM_TUPLE4_V4 || tfe_addr->addrtype == TFE_ADDR_IPV4)
|
||||
{
|
||||
sapp_addr->addrtype = ADDR_TYPE_IPV4;
|
||||
}
|
||||
else
|
||||
{
|
||||
sapp_addr->addrtype = ADDR_TYPE_IPV6;
|
||||
}
|
||||
sapp_addr->paddr = (char *)tfe_addr->paddr;
|
||||
}
|
||||
|
||||
static int doh_get_answer_ttl(cJSON *object)
|
||||
{
|
||||
int min = 0;
|
||||
int max = 0;
|
||||
cJSON *item = NULL;
|
||||
|
||||
item = cJSON_GetObjectItem(object, "min");
|
||||
if (item)
|
||||
{
|
||||
min = item->valueint;
|
||||
}
|
||||
|
||||
item = cJSON_GetObjectItem(object, "max");
|
||||
if (item)
|
||||
{
|
||||
max = item->valueint;
|
||||
}
|
||||
|
||||
return (rand() % (max - min + 1) + min);
|
||||
}
|
||||
|
||||
static cJSON *doh_get_answer_records(cJSON *object, int qtype)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
cJSON *resolution = cJSON_GetObjectItem(object, "resolution");
|
||||
int size = cJSON_GetArraySize(resolution);
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
cJSON *item = cJSON_GetArrayItem(resolution, i);
|
||||
cJSON *tmp = cJSON_GetObjectItem(item, "qtype");
|
||||
|
||||
if (doh_type2index(tmp->valuestring) == qtype)
|
||||
{
|
||||
return cJSON_GetObjectItem(item, "answer");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void doh_get_cheat_data(Maat_rule_t *p_result, int qtype, struct doh_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
int answer_size = 0;
|
||||
char *tmp = NULL;
|
||||
cJSON *items = NULL;
|
||||
cJSON *item = NULL;
|
||||
cJSON *object = NULL;
|
||||
cJSON *answer_array = NULL;
|
||||
|
||||
tmp = (char *)calloc(1, p_result->serv_def_len + 1);
|
||||
Maat_read_rule(g_doh_conf->maat, p_result, MAAT_RULE_SERV_DEFINE, tmp, p_result->serv_def_len);
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "%s hit %d %s", ctx->addr_string, p_result->config_id, tmp);
|
||||
|
||||
object = cJSON_Parse(tmp);
|
||||
if (object == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
answer_array = doh_get_answer_records(object, qtype);
|
||||
if (answer_array != NULL)
|
||||
{
|
||||
answer_size = cJSON_GetArraySize(answer_array);
|
||||
ctx->opts = ALLOC(cheat_pkt_opt_t, answer_size);
|
||||
ctx->opts_num = answer_size;
|
||||
|
||||
for (i = 0; i < answer_size; i++)
|
||||
{
|
||||
items = cJSON_GetArrayItem(answer_array, i);
|
||||
|
||||
item = cJSON_GetObjectItem(items, "atype");
|
||||
ctx->opts[i].res_type = doh_type2index(item->valuestring);
|
||||
|
||||
item = cJSON_GetObjectItem(items, "ttl");
|
||||
ctx->opts[i].ttl = doh_get_answer_ttl(item);
|
||||
|
||||
if (ctx->min_ttl == 0)
|
||||
{
|
||||
ctx->min_ttl = ctx->opts[i].ttl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx->min_ttl > ctx->opts[i].ttl)
|
||||
{
|
||||
ctx->min_ttl = ctx->opts[i].ttl;
|
||||
}
|
||||
}
|
||||
|
||||
item = cJSON_GetObjectItem(items, "value");
|
||||
if (item)
|
||||
{
|
||||
switch (ctx->opts[i].res_type)
|
||||
{
|
||||
case DNS_TYPE_A:
|
||||
ctx->opts[i].res_len = sizeof(unsigned int);
|
||||
inet_pton(AF_INET, item->valuestring, (void *)ctx->opts[i].res_info);
|
||||
break;
|
||||
case DNS_TYPE_AAAA:
|
||||
ctx->opts[i].res_len = IPV6_ADDR_LEN;
|
||||
inet_pton(AF_INET6, item->valuestring, (void *)ctx->opts[i].res_info);
|
||||
break;
|
||||
default:
|
||||
ctx->opts[i].res_len = (strlen(item->valuestring) > sizeof(ctx->opts[i].res_info) - 1) ? sizeof(ctx->opts[i].res_info) - 1 : strlen(item->valuestring);
|
||||
memcpy(ctx->opts[i].res_info, item->valuestring, ctx->opts[i].res_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (object)
|
||||
{
|
||||
cJSON_Delete(object);
|
||||
object = NULL;
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct Maat_rule_t *doh_fetch_rule(Maat_rule_t *result, int result_num)
|
||||
{
|
||||
int i = 0;
|
||||
Maat_rule_t *p_result = NULL;
|
||||
|
||||
for (i = 0; i < result_num; i++)
|
||||
{
|
||||
if (p_result == NULL)
|
||||
{
|
||||
p_result = &result[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result[i].config_id > p_result->config_id)
|
||||
{
|
||||
p_result = &result[i];
|
||||
}
|
||||
}
|
||||
|
||||
return p_result;
|
||||
}
|
||||
|
||||
static void doh_maat_scan(const struct tfe_stream *stream, const struct tfe_http_session *session, struct doh_ctx *ctx, char *qname, int qtype)
|
||||
{
|
||||
int hit_cnt = 0;
|
||||
int scan_ret = 0;
|
||||
const char *app_id = "doh.";
|
||||
struct ipaddr sapp_addr;
|
||||
struct Maat_rule_t *p_result = NULL;
|
||||
struct Maat_rule_t result[MAX_SCAN_RESULT];
|
||||
|
||||
// scan server host
|
||||
const char *host = session->req->req_spec.host;
|
||||
if (host)
|
||||
{
|
||||
scan_ret = Maat_full_scan_string(g_doh_conf->maat, g_doh_conf->tables[TYPE_HOST].id, CHARSET_UTF8,
|
||||
host, strlen(host), result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
|
||||
if (scan_ret > 0)
|
||||
{
|
||||
hit_cnt += scan_ret;
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_HOST, Hit host: %s scan ret: %d policy_id: %d service: %d action: %d addr: %s",
|
||||
host, scan_ret, result[hit_cnt].config_id, result[hit_cnt].service_id, result[hit_cnt].action, ctx->addr_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_HOST, NO hit host: %s scan ret: %d addr: %s",
|
||||
host, scan_ret, ctx->addr_string);
|
||||
}
|
||||
}
|
||||
|
||||
// scan addr
|
||||
doh_addr_tfe2sapp(stream->addr, &sapp_addr);
|
||||
scan_ret = Maat_scan_proto_addr(g_doh_conf->maat, g_doh_conf->tables[TYPE_ADDR].id, &sapp_addr,
|
||||
0, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
|
||||
if (scan_ret > 0)
|
||||
{
|
||||
hit_cnt += scan_ret;
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_ADDR, Hit addr: %s scan ret: %d policy_id: %d service: %d action: %d",
|
||||
ctx->addr_string, scan_ret, result[hit_cnt].config_id, result[hit_cnt].service_id, result[hit_cnt].action);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_ADDR, NO hit addr: %s scan ret: %d",
|
||||
ctx->addr_string, scan_ret);
|
||||
}
|
||||
|
||||
// scan appid
|
||||
scan_ret = Maat_full_scan_string(g_doh_conf->maat, g_doh_conf->tables[TYPE_APPID].id, CHARSET_UTF8,
|
||||
app_id, strlen(app_id), result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
|
||||
if (scan_ret > 0)
|
||||
{
|
||||
hit_cnt += scan_ret;
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_APPID, Hit proto: %s scan ret: %d policy_id: %d service: %d action: %d addr: %s",
|
||||
app_id, scan_ret, result[hit_cnt].config_id, result[hit_cnt].service_id, result[hit_cnt].action, ctx->addr_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_APPID, NO hit proto: %s scan ret: %d addr: %s",
|
||||
app_id, scan_ret, ctx->addr_string);
|
||||
}
|
||||
|
||||
// scan qname
|
||||
scan_ret = Maat_full_scan_string(g_doh_conf->maat, g_doh_conf->tables[TYPE_QNAME].id, CHARSET_UTF8,
|
||||
qname, strlen(qname), result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
|
||||
if (scan_ret > 0)
|
||||
{
|
||||
hit_cnt += scan_ret;
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_QNAME, Hit domain: %s scan ret: %d qtype: %d policy_id: %d service: %d action: %d addr: %s",
|
||||
qname, scan_ret, qtype, result[hit_cnt].config_id, result[hit_cnt].service_id, result[hit_cnt].action, ctx->addr_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "SCAN_QNAME, NO hit domain: %s scan ret: %d addr: %s",
|
||||
qname, scan_ret, ctx->addr_string);
|
||||
}
|
||||
|
||||
if (hit_cnt)
|
||||
{
|
||||
p_result = doh_fetch_rule(result, hit_cnt);
|
||||
if (p_result)
|
||||
{
|
||||
ctx->result_num = 1;
|
||||
ctx->result = ALLOC(struct Maat_rule_t, ctx->result_num);
|
||||
memcpy(ctx->result, p_result, sizeof(struct Maat_rule_t));
|
||||
doh_get_cheat_data(p_result, qtype, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int doh_maat_init(const char *profile, const char *section)
|
||||
{
|
||||
g_doh_conf->maat = (Maat_feather_t)tfe_bussiness_resouce_get(STATIC_MAAT);
|
||||
MESA_load_profile_string_def(profile, section, "table_appid", g_doh_conf->tables[TYPE_APPID].name, TFE_STRING_MAX, "TSG_OBJ_APP_ID");
|
||||
MESA_load_profile_string_def(profile, section, "table_addr", g_doh_conf->tables[TYPE_ADDR].name, TFE_STRING_MAX, "TSG_SECURITY_ADDR");
|
||||
MESA_load_profile_string_def(profile, section, "table_qname", g_doh_conf->tables[TYPE_QNAME].name, TFE_STRING_MAX, "TSG_FIELD_DOH_QNAME");
|
||||
MESA_load_profile_string_def(profile, section, "table_host", g_doh_conf->tables[TYPE_HOST].name, TFE_STRING_MAX, "TSG_FIELD_HTTP_HOST");
|
||||
|
||||
for (int i = 0; i < TYPE_MAX; i++)
|
||||
{
|
||||
g_doh_conf->tables[i].id = Maat_table_register(g_doh_conf->maat, g_doh_conf->tables[i].name);
|
||||
if (g_doh_conf->tables[i].id < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(g_doh_conf->local_logger, "Maat_table_register failed, table_name: %s", g_doh_conf->tables[i].name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void doh_gc_cb(evutil_socket_t fd, short what, void *arg)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < DOH_STAT_MAX; i++)
|
||||
{
|
||||
FS_operate(g_doh_conf->fs_handle, g_doh_conf->fs_id[i], 0, FS_OP_SET, ATOMIC_READ(&(g_doh_conf->stat_val[i])));
|
||||
}
|
||||
}
|
||||
|
||||
static int doh_field_init()
|
||||
{
|
||||
int i = 0;
|
||||
struct timeval gc_delay = {0, 500 * 1000}; //Microseconds, we set 500 miliseconds here.
|
||||
const char *spec[DOH_STAT_MAX] = {0};
|
||||
|
||||
spec[STAT_SESSION] = "doh_sess";
|
||||
spec[STAT_LOG_NUM] = "doh_log";
|
||||
spec[STAT_ACTION_HIJACK] = "doh_hijack";
|
||||
|
||||
for (i = 0; i < DOH_STAT_MAX; i++)
|
||||
{
|
||||
if (spec[i] != NULL)
|
||||
{
|
||||
g_doh_conf->fs_id[i] = FS_register(g_doh_conf->fs_handle, FS_STYLE_FIELD, FS_CALC_CURRENT, spec[i]);
|
||||
}
|
||||
}
|
||||
g_doh_conf->gcev = event_new(g_doh_conf->gc_evbase, -1, EV_PERSIST, doh_gc_cb, NULL);
|
||||
evtimer_add(g_doh_conf->gcev, &gc_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct doh_ctx *doh_ctx_new(unsigned int thread_id)
|
||||
{
|
||||
struct doh_ctx *ctx = ALLOC(struct doh_ctx, 1);
|
||||
assert(ctx);
|
||||
|
||||
ctx->magic_num = DOH_CTX_MAGIC_NUM;
|
||||
ctx->thread_id = (int)thread_id;
|
||||
ctx->scan_mid = NULL;
|
||||
ctx->opts_num = 0;
|
||||
ctx->opts = NULL;
|
||||
ctx->min_ttl = 0;
|
||||
ctx->doh_req = NULL;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void doh_ctx_free(struct doh_ctx *ctx)
|
||||
{
|
||||
assert(ctx->magic_num == DOH_CTX_MAGIC_NUM);
|
||||
|
||||
if (ctx->result)
|
||||
{
|
||||
free(ctx->result);
|
||||
ctx->result = NULL;
|
||||
}
|
||||
if (ctx->doh_req)
|
||||
{
|
||||
dns_free(ctx->doh_req);
|
||||
ctx->doh_req = NULL;
|
||||
}
|
||||
|
||||
if (ctx->opts_num)
|
||||
{
|
||||
free(ctx->opts);
|
||||
ctx->opts = NULL;
|
||||
}
|
||||
|
||||
if (ctx->http_req_body)
|
||||
{
|
||||
evbuffer_free(ctx->http_req_body);
|
||||
ctx->http_req_body = NULL;
|
||||
}
|
||||
|
||||
if (ctx->addr_string)
|
||||
{
|
||||
free(ctx->addr_string);
|
||||
ctx->addr_string = NULL;
|
||||
}
|
||||
|
||||
FREE(&ctx);
|
||||
}
|
||||
|
||||
static int req_session_is_doh(const struct tfe_http_session *session, struct doh_ctx *ctx)
|
||||
{
|
||||
// https://tools.ietf.org/html/rfc8484
|
||||
|
||||
// https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-10.html
|
||||
// Registration of application/dns-message Media Type
|
||||
|
||||
// https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-05.html
|
||||
// Registration of application/dns-udpwireformat Media Type
|
||||
|
||||
// POST
|
||||
const char *cont_type_val = tfe_http_std_field_read(session->req, TFE_HTTP_CONT_TYPE);
|
||||
if (cont_type_val && strncasecmp(cont_type_val, "application/dns-message", strlen("application/dns-message")) == 0)
|
||||
{
|
||||
ctx->type = DOH_TYPE_MESSAGE;
|
||||
return 1;
|
||||
}
|
||||
if (cont_type_val && strncasecmp(cont_type_val, "application/dns-udpwireformat", strlen("application/dns-udpwireformat")) == 0)
|
||||
{
|
||||
ctx->type = DOH_TYPE_UDPWIREFORMAT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// GET
|
||||
const char *accept_type_val = tfe_http_nonstd_field_read(session->req, "Accept");
|
||||
if (accept_type_val && strncasecmp(accept_type_val, "application/dns-message", strlen("application/dns-message")) == 0)
|
||||
{
|
||||
ctx->type = DOH_TYPE_MESSAGE;
|
||||
return 1;
|
||||
}
|
||||
if (accept_type_val && strncasecmp(accept_type_val, "application/dns-udpwireformat", strlen("application/dns-udpwireformat")) == 0)
|
||||
{
|
||||
ctx->type = DOH_TYPE_UDPWIREFORMAT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void doh_process_req(const struct tfe_stream *stream, const struct tfe_http_session *session, void **pme)
|
||||
{
|
||||
struct doh_ctx *ctx = *(struct doh_ctx **)pme;
|
||||
struct tfe_http_half *response = NULL;
|
||||
struct tfe_http_session *to_write = NULL;
|
||||
|
||||
int rsp_len;
|
||||
int rsp_size;
|
||||
char *rsp_buff = NULL;
|
||||
char cont_len_str[20] = {0};
|
||||
char max_age_str[20] = {0};
|
||||
|
||||
char *req_data = (char *)evbuffer_pullup(ctx->http_req_body, -1);
|
||||
size_t req_len = evbuffer_get_length(ctx->http_req_body);
|
||||
|
||||
if (req_data && req_len)
|
||||
{
|
||||
ctx->doh_req = dns_new();
|
||||
assert(ctx->doh_req);
|
||||
|
||||
if (dns_parser(ctx->doh_req, req_data, req_len) == -1)
|
||||
{
|
||||
// base64_len = (str_len / 3 + 1) * 4
|
||||
int temp_size = (req_len / 3 + 1) * 4;
|
||||
char *temp = (char *)ALLOC(char, temp_size);
|
||||
int len = base64_encode(temp, temp_size - 1, req_data, req_len);
|
||||
TFE_LOG_ERROR(g_doh_conf->local_logger, "%s Doh parser request failed, PASSTHROUGH, data:%s", ctx->addr_string, len > 0 ? temp : "");
|
||||
free(temp);
|
||||
goto end;
|
||||
}
|
||||
TFE_LOG_DEBUG(g_doh_conf->local_logger, "%s qtype %d qname:%s",
|
||||
ctx->addr_string, ctx->doh_req->query_question.qtype, ctx->doh_req->query_question.qname);
|
||||
|
||||
if (ctx->doh_req->query_question.qtype != DNS_TYPE_A && ctx->doh_req->query_question.qtype != DNS_TYPE_AAAA)
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "%s Doh qtype not A/AAAA, PASSTHROUGH", ctx->addr_string);
|
||||
goto end;
|
||||
}
|
||||
if (strlen((char *)ctx->doh_req->query_question.qname) == 0)
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "%s Doh qname is empty, PASSTHROUGH", ctx->addr_string);
|
||||
goto end;
|
||||
}
|
||||
|
||||
doh_maat_scan(stream, session, ctx, (char *)ctx->doh_req->query_question.qname, ctx->doh_req->query_question.qtype);
|
||||
if (!ctx->opts_num)
|
||||
{
|
||||
TFE_LOG_INFO(g_doh_conf->local_logger, "%s Doh no hit answer type, PASSTHROUGH", ctx->addr_string);
|
||||
goto end;
|
||||
}
|
||||
|
||||
rsp_size = sizeof(cheat_pkt_opt_t) * ctx->opts_num * 16;
|
||||
rsp_buff = (char *)ALLOC(char, rsp_size);
|
||||
rsp_len = dns_cheat_response(ctx->doh_req, ctx->opts, ctx->opts_num, rsp_buff, rsp_size - 1);
|
||||
if (rsp_len < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(g_doh_conf->local_logger, "%s Doh cheat response failed: %d, PASSTHROUGH", ctx->addr_string, rsp_len);
|
||||
goto end;
|
||||
}
|
||||
|
||||
to_write = tfe_http_session_allow_write(session);
|
||||
if (to_write == NULL)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
ctx->manipulate = 1;
|
||||
ATOMIC_INC(&(g_doh_conf->stat_val[STAT_ACTION_HIJACK]));
|
||||
|
||||
snprintf(cont_len_str, sizeof(cont_len_str), "%d", rsp_len);
|
||||
response = tfe_http_session_response_create(to_write, 200);
|
||||
tfe_http_std_field_write(response, TFE_HTTP_CONT_LENGTH, cont_len_str);
|
||||
if (ctx->type == DOH_TYPE_MESSAGE)
|
||||
tfe_http_std_field_write(response, TFE_HTTP_CONT_TYPE, "application/dns-message");
|
||||
else
|
||||
tfe_http_std_field_write(response, TFE_HTTP_CONT_TYPE, "application/dns-udpwireformat");
|
||||
|
||||
/* The assigned freshness lifetime of a DoH HTTP response MUST be less
|
||||
* than or equal to the smallest TTL in the Answer section of the DNS
|
||||
* response. */
|
||||
snprintf(max_age_str, sizeof(max_age_str), "max-age=%d", ctx->min_ttl);
|
||||
tfe_http_std_field_write(response, TFE_HTTP_CACHE_CONTROL, max_age_str);
|
||||
tfe_http_half_append_body(response, rsp_buff, rsp_len, 0);
|
||||
tfe_http_half_append_body(response, NULL, 0, 0);
|
||||
|
||||
tfe_http_session_response_set(to_write, response);
|
||||
tfe_http_session_detach(session);
|
||||
end:
|
||||
if (rsp_buff)
|
||||
{
|
||||
free(rsp_buff);
|
||||
rsp_buff = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int doh_on_init(struct tfe_proxy *proxy)
|
||||
{
|
||||
const char *profile = "./conf/doh/doh.conf";
|
||||
|
||||
g_doh_conf = ALLOC(struct doh_conf, 1);
|
||||
assert(g_doh_conf);
|
||||
|
||||
MESA_load_profile_int_def(profile, "doh", "enable", &(g_doh_conf->enable), 1);
|
||||
MESA_load_profile_int_def(profile, "log", "log_level", &(g_doh_conf->local_level), 10);
|
||||
|
||||
if (!g_doh_conf->enable)
|
||||
{
|
||||
TFE_LOG_INFO(NULL, "Doh disabled.");
|
||||
goto success;
|
||||
}
|
||||
|
||||
g_doh_conf->thread_num = tfe_proxy_get_work_thread_count();
|
||||
g_doh_conf->local_logger = MESA_create_runtime_log_handle("./log/doh_pxy.log", g_doh_conf->local_level);
|
||||
|
||||
g_doh_conf->gc_evbase = tfe_proxy_get_gc_evbase();
|
||||
g_doh_conf->fs_handle = tfe_proxy_get_fs_handle();
|
||||
if (doh_field_init() != 0)
|
||||
{
|
||||
TFE_LOG_ERROR(NULL, "Doh init field stat failed.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (doh_kafka_init(profile, g_doh_conf) != 0)
|
||||
{
|
||||
TFE_LOG_ERROR(NULL, "Doh init kafka failed.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (doh_maat_init(profile, "maat") != 0)
|
||||
{
|
||||
TFE_LOG_ERROR(NULL, "Doh init maat failed.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
success:
|
||||
return 0;
|
||||
|
||||
error:
|
||||
TFE_LOG_ERROR(NULL, "Doh init failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void doh_on_begin(const struct tfe_stream *stream, const struct tfe_http_session *session, unsigned int thread_id, void **pme)
|
||||
{
|
||||
struct doh_ctx *ctx = NULL;
|
||||
|
||||
if (!g_doh_conf->enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = *(struct doh_ctx **)pme;
|
||||
assert(ctx == NULL);
|
||||
ctx = doh_ctx_new(thread_id);
|
||||
|
||||
ctx->addr_string = tfe_stream_addr_to_str(stream->addr);
|
||||
|
||||
*pme = ctx;
|
||||
}
|
||||
|
||||
// return : NO_CALL_NEXT_PLUGIN
|
||||
// return : CALL_NEXT_PLUGIN
|
||||
int doh_on_data(const struct tfe_stream *stream, const struct tfe_http_session *session, enum tfe_http_event events, const unsigned char *body_frag, size_t frag_size, unsigned int thread_id, void **pme)
|
||||
{
|
||||
if (!g_doh_conf->enable)
|
||||
{
|
||||
return CALL_NEXT_PLUGIN;
|
||||
}
|
||||
|
||||
struct doh_ctx *ctx = *(struct doh_ctx **)pme;
|
||||
assert(ctx);
|
||||
|
||||
if (!req_session_is_doh(session, ctx))
|
||||
{
|
||||
return CALL_NEXT_PLUGIN;
|
||||
}
|
||||
|
||||
if (!ctx->count)
|
||||
{
|
||||
ctx->count = 1;
|
||||
ATOMIC_INC(&(g_doh_conf->stat_val[STAT_SESSION]));
|
||||
TFE_LOG_DEBUG(g_doh_conf->local_logger, "%s method:%s content-type:%s accept:%s url:%s",
|
||||
ctx->addr_string,
|
||||
http_std_method_to_string(session->req->req_spec.method),
|
||||
tfe_http_std_field_read(session->req, TFE_HTTP_CONT_TYPE),
|
||||
tfe_http_nonstd_field_read(session->req, "Accept"),
|
||||
session->req->req_spec.url);
|
||||
}
|
||||
|
||||
// request get
|
||||
if (REQ_METHOD_IS_GET(session->req->req_spec.method) && (events & EV_HTTP_REQ_HDR))
|
||||
{
|
||||
/* https://tools.ietf.org/html/draft-ietf-doh-dns-over-https-04
|
||||
*
|
||||
* When using the GET method the URI path MUST contain a query parameter
|
||||
* name-value pair [QUERYPARAMETER] with the name of "ct" and a value
|
||||
* indicating the media-format used for the dns parameter. The value
|
||||
* may either be an explicit media type (e.g. ct=application/dns-
|
||||
* udpwireformat&dns=...) or it may be empty. An empty value indicates
|
||||
* the default application/dns-udpwireformat type (e.g. ct&dns=...).
|
||||
*
|
||||
* NOTE: evhttp_parse_query_str()
|
||||
* support "ct=x&dns=xxx"
|
||||
* support "ct=&dns=xxx"
|
||||
* not support "ct&dns=xxx"
|
||||
* So we parser "dns=" by self.
|
||||
*/
|
||||
int len;
|
||||
u_char *temp = NULL;
|
||||
u_char *dns_data = NULL;
|
||||
const char *uri_begin = session->req->req_spec.uri;
|
||||
const char *uri_end = session->req->req_spec.uri + strlen(session->req->req_spec.uri) - 1;
|
||||
char *dns_end = NULL;
|
||||
char *dns_begin = (char *)strstr(uri_begin, "dns=");
|
||||
if (dns_begin == NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((dns_begin == uri_begin || *(dns_begin - 1) == '&' || *(dns_begin - 1) == '?') && dns_begin + 4 < uri_end)
|
||||
{
|
||||
dns_begin = dns_begin + 4;
|
||||
dns_end = strstr(dns_begin, "&");
|
||||
if (dns_end == NULL)
|
||||
{
|
||||
dns_end = (char *)uri_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
dns_end -= 1;
|
||||
}
|
||||
|
||||
if (dns_end <= dns_begin)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
dns_data = (u_char *)calloc(1, dns_end - dns_begin + 1 + 1);
|
||||
memcpy(dns_data, dns_begin, dns_end - dns_begin + 1);
|
||||
}
|
||||
|
||||
temp = (u_char *)ALLOC(u_char, strlen((char *)dns_data) * 2);
|
||||
len = tfe_decode_base64url(temp, dns_data);
|
||||
if (len == 0)
|
||||
{
|
||||
TFE_LOG_ERROR(g_doh_conf->local_logger, "%s Doh base64 decode uri failed:%s, PASSTHROUGH", ctx->addr_string, session->req->req_spec.uri);
|
||||
goto error;
|
||||
}
|
||||
|
||||
assert(ctx->http_req_body == NULL);
|
||||
ctx->http_req_body = evbuffer_new();
|
||||
evbuffer_add(ctx->http_req_body, temp, len);
|
||||
doh_process_req(stream, session, pme);
|
||||
|
||||
error:
|
||||
if (dns_data)
|
||||
{
|
||||
free(dns_data);
|
||||
dns_data = NULL;
|
||||
}
|
||||
|
||||
if (temp)
|
||||
{
|
||||
free(temp);
|
||||
temp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// request post
|
||||
if (REQ_METHOD_IS_POST(session->req->req_spec.method))
|
||||
{
|
||||
if (events & EV_HTTP_REQ_BODY_BEGIN)
|
||||
{
|
||||
assert(ctx->http_req_body == NULL);
|
||||
ctx->http_req_body = evbuffer_new();
|
||||
}
|
||||
|
||||
if (events & EV_HTTP_REQ_BODY_CONT)
|
||||
{
|
||||
evbuffer_add(ctx->http_req_body, body_frag, frag_size);
|
||||
}
|
||||
|
||||
if (events & EV_HTTP_REQ_BODY_END)
|
||||
{
|
||||
doh_process_req(stream, session, pme);
|
||||
}
|
||||
}
|
||||
|
||||
return NO_CALL_NEXT_PLUGIN;
|
||||
}
|
||||
|
||||
void doh_on_end(const struct tfe_stream *stream, const struct tfe_http_session *session, unsigned int thread_id, void **pme)
|
||||
{
|
||||
if (!g_doh_conf->enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct doh_ctx *ctx = *(struct doh_ctx **)pme;
|
||||
if (ctx->manipulate)
|
||||
{
|
||||
int ret = doh_send_log(g_doh_conf, session, stream, ctx);
|
||||
if (ret > 0)
|
||||
{
|
||||
ATOMIC_ADD(&(g_doh_conf->stat_val[STAT_LOG_NUM]), ret);
|
||||
}
|
||||
}
|
||||
|
||||
doh_ctx_free(ctx);
|
||||
*pme = NULL;
|
||||
}
|
||||
|
||||
struct tfe_plugin doh_spec = {
|
||||
.symbol = NULL,
|
||||
.type = TFE_PLUGIN_TYPE_BUSINESS,
|
||||
.on_init = doh_on_init,
|
||||
.on_deinit = NULL,
|
||||
.on_open = NULL,
|
||||
.on_data = NULL,
|
||||
.on_close = NULL,
|
||||
.on_session_begin = doh_on_begin,
|
||||
.on_session_data = doh_on_data,
|
||||
.on_session_end = doh_on_end};
|
||||
TFE_PLUGIN_REGISTER(doh, doh_spec)
|
||||
519
plugin/business/doh/src/logger.cpp
Normal file
519
plugin/business/doh/src/logger.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
#include "logger.h"
|
||||
|
||||
struct json_spec
|
||||
{
|
||||
const char *log_filed_name;
|
||||
enum tfe_http_std_field field_id;
|
||||
};
|
||||
|
||||
enum _log_action //Bigger action number is prior.
|
||||
{
|
||||
LG_ACTION_NONE = 0x00,
|
||||
LG_ACTION_MONIT = 0x01,
|
||||
LG_ACTION_FORWARD = 0x02, /* N/A */
|
||||
LG_ACTION_REJECT = 0x10,
|
||||
LG_ACTION_DROP = 0x20, /* N/A */
|
||||
LG_ACTION_MANIPULATE = 0x30,
|
||||
LG_ACTION_RATELIMIT = 0x40, /* N/A */
|
||||
LG_ACTION_LOOP = 0x60, /* N/A */
|
||||
LG_ACTION_WHITELIST = 0x80,
|
||||
__LG_ACTION_MAX
|
||||
};
|
||||
|
||||
static int get_rr_str2json(cJSON *object, dns_info_t *dns_info, int *dns_sec)
|
||||
{
|
||||
int i = 0;
|
||||
char ip_str[128];
|
||||
dns_rr_t *dns_rr = NULL;
|
||||
cJSON *one_rr_object = NULL;
|
||||
cJSON *dns_rr_array = NULL;
|
||||
|
||||
if (object == NULL || dns_info == NULL || dns_sec == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_rr_array = cJSON_CreateArray();
|
||||
|
||||
for (i = 0; i < dns_info->rr_count; i++)
|
||||
{
|
||||
one_rr_object = cJSON_CreateObject();
|
||||
dns_rr = &(dns_info->rr[i]);
|
||||
|
||||
if (dns_rr->type == DNS_TYPE_OPT)
|
||||
{
|
||||
cJSON_AddStringToObject(one_rr_object, "name", (const char *)(dns_rr->name));
|
||||
cJSON_AddNumberToObject(one_rr_object, "type", dns_rr->type);
|
||||
cJSON_AddNumberToObject(one_rr_object, "udp_payload", dns_rr->rr_class);
|
||||
cJSON_AddNumberToObject(one_rr_object, "rcode", (int)(dns_rr->ttl >> 24));
|
||||
cJSON_AddNumberToObject(one_rr_object, "version", (int)((dns_rr->ttl >> 16) & 0xFF));
|
||||
cJSON_AddNumberToObject(one_rr_object, "Z", (int)(dns_rr->ttl && 0xFFFF));
|
||||
cJSON_AddNumberToObject(one_rr_object, "rdlength", dns_rr->rdlength);
|
||||
}
|
||||
else
|
||||
{
|
||||
cJSON_AddStringToObject(one_rr_object, "name", (const char *)(dns_rr->name));
|
||||
cJSON_AddNumberToObject(one_rr_object, "type", dns_rr->type);
|
||||
cJSON_AddNumberToObject(one_rr_object, "class", dns_rr->rr_class);
|
||||
cJSON_AddNumberToObject(one_rr_object, "ttl", dns_rr->ttl);
|
||||
cJSON_AddNumberToObject(one_rr_object, "rdlength", dns_rr->rdlength);
|
||||
}
|
||||
|
||||
if (dns_rr->rdata.a == NULL)
|
||||
{
|
||||
cJSON_AddItemToArray(dns_rr_array, one_rr_object);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dns_rr->type)
|
||||
{
|
||||
case DNS_TYPE_A:
|
||||
inet_ntop(AF_INET, (void *)(dns_rr->rdata.a), ip_str, sizeof(ip_str));
|
||||
cJSON_AddStringToObject(one_rr_object, "a", ip_str);
|
||||
break;
|
||||
case DNS_TYPE_NS:
|
||||
cJSON_AddStringToObject(one_rr_object, "ns", (const char *)(dns_rr->rdata.ns));
|
||||
break;
|
||||
case DNS_TYPE_MD:
|
||||
cJSON_AddStringToObject(one_rr_object, "md", (const char *)(dns_rr->rdata.md));
|
||||
break;
|
||||
case DNS_TYPE_MF:
|
||||
cJSON_AddStringToObject(one_rr_object, "mf", (const char *)(dns_rr->rdata.mf));
|
||||
break;
|
||||
case DNS_TYPE_CNAME:
|
||||
cJSON_AddStringToObject(one_rr_object, "cname", (const char *)(dns_rr->rdata.cname));
|
||||
break;
|
||||
case DNS_TYPE_SOA:
|
||||
cJSON_AddStringToObject(one_rr_object, "mname", (const char *)(dns_rr->rdata.soa.mname));
|
||||
cJSON_AddStringToObject(one_rr_object, "rname", (const char *)(dns_rr->rdata.soa.rname));
|
||||
cJSON_AddNumberToObject(one_rr_object, "serial", dns_rr->rdata.soa.serial);
|
||||
cJSON_AddNumberToObject(one_rr_object, "refresh", dns_rr->rdata.soa.refresh);
|
||||
cJSON_AddNumberToObject(one_rr_object, "retry", dns_rr->rdata.soa.retry);
|
||||
cJSON_AddNumberToObject(one_rr_object, "cname", dns_rr->rdata.soa.expire);
|
||||
cJSON_AddNumberToObject(one_rr_object, "minimum", dns_rr->rdata.soa.minimum);
|
||||
break;
|
||||
case DNS_TYPE_MB:
|
||||
cJSON_AddStringToObject(one_rr_object, "mb", (const char *)(dns_rr->rdata.mb));
|
||||
break;
|
||||
case DNS_TYPE_MG:
|
||||
cJSON_AddStringToObject(one_rr_object, "mg", (const char *)(dns_rr->rdata.mg));
|
||||
break;
|
||||
case DNS_TYPE_MR:
|
||||
cJSON_AddStringToObject(one_rr_object, "mr", (const char *)(dns_rr->rdata.mr));
|
||||
break;
|
||||
case DNS_TYPE_NULL:
|
||||
cJSON_AddNumberToObject(one_rr_object, "size", dns_rr->rdata.null.size);
|
||||
cJSON_AddStringToObject(one_rr_object, "null", (const char *)(dns_rr->rdata.null.null));
|
||||
break;
|
||||
case DNS_TYPE_WKS:
|
||||
cJSON_AddStringToObject(one_rr_object, "addr", ip_str);
|
||||
cJSON_AddNumberToObject(one_rr_object, "protocol", dns_rr->rdata.wks.protocol);
|
||||
cJSON_AddStringToObject(one_rr_object, "bitmap", (const char *)(dns_rr->rdata.wks.bitmap));
|
||||
cJSON_AddNumberToObject(one_rr_object, "size", dns_rr->rdata.wks.size);
|
||||
break;
|
||||
case DNS_TYPE_PTR:
|
||||
cJSON_AddStringToObject(one_rr_object, "ptr", (const char *)(dns_rr->rdata.ptr));
|
||||
break;
|
||||
case DNS_TYPE_HINFO:
|
||||
cJSON_AddStringToObject(one_rr_object, "cpu", (const char *)(dns_rr->rdata.hinfo.cpu));
|
||||
cJSON_AddStringToObject(one_rr_object, "os", (const char *)(dns_rr->rdata.hinfo.os));
|
||||
break;
|
||||
case DNS_TYPE_MINFO:
|
||||
cJSON_AddStringToObject(one_rr_object, "rmailbx", (const char *)(dns_rr->rdata.minfo.rmailbx));
|
||||
cJSON_AddStringToObject(one_rr_object, "emailbx", (const char *)(dns_rr->rdata.minfo.emailbx));
|
||||
break;
|
||||
case DNS_TYPE_MX:
|
||||
cJSON_AddStringToObject(one_rr_object, "exchange", (const char *)(dns_rr->rdata.mx.exchange));
|
||||
cJSON_AddNumberToObject(one_rr_object, "preference", dns_rr->rdata.mx.preference);
|
||||
break;
|
||||
case DNS_TYPE_TXT:
|
||||
cJSON_AddStringToObject(one_rr_object, "txt", (char *)(dns_rr->rdata.txt.txt));
|
||||
cJSON_AddNumberToObject(one_rr_object, "size", dns_rr->rdata.txt.size);
|
||||
break;
|
||||
case DNS_TYPE_RP:
|
||||
cJSON_AddStringToObject(one_rr_object, "mailbox", (char *)(dns_rr->rdata.rp.mailbox));
|
||||
cJSON_AddStringToObject(one_rr_object, "txt_rr", (char *)(dns_rr->rdata.rp.txt_rr));
|
||||
break;
|
||||
case DNS_TYPE_AAAA:
|
||||
inet_ntop(AF_INET6, dns_rr->rdata.aaaa, ip_str, sizeof(ip_str));
|
||||
cJSON_AddStringToObject(one_rr_object, "aaaa", ip_str);
|
||||
break;
|
||||
case DNS_TYPE_OPT:
|
||||
break;
|
||||
case DNS_TYPE_DS:
|
||||
*dns_sec = 2;
|
||||
cJSON_AddNumberToObject(one_rr_object, "key_tag", dns_rr->rdata.ds.key_tag);
|
||||
cJSON_AddNumberToObject(one_rr_object, "algo", dns_rr->rdata.ds.algo);
|
||||
cJSON_AddNumberToObject(one_rr_object, "digest_type", dns_rr->rdata.ds.digest_type);
|
||||
cJSON_AddStringToObject(one_rr_object, "digest", (char *)(dns_rr->rdata.ds.digest));
|
||||
break;
|
||||
case DNS_TYPE_RRSIG:
|
||||
*dns_sec = 2;
|
||||
cJSON_AddNumberToObject(one_rr_object, "type_covered", dns_rr->rdata.rrsig.type_covered);
|
||||
cJSON_AddNumberToObject(one_rr_object, "algo", dns_rr->rdata.rrsig.algo);
|
||||
cJSON_AddNumberToObject(one_rr_object, "labels", dns_rr->rdata.rrsig.labels);
|
||||
cJSON_AddNumberToObject(one_rr_object, "original_ttl", dns_rr->rdata.rrsig.original_ttl);
|
||||
cJSON_AddNumberToObject(one_rr_object, "sig_expiration", dns_rr->rdata.rrsig.sig_expiration);
|
||||
cJSON_AddNumberToObject(one_rr_object, "sig_inception", dns_rr->rdata.rrsig.sig_inception);
|
||||
cJSON_AddNumberToObject(one_rr_object, "key_tag", dns_rr->rdata.rrsig.key_tag);
|
||||
cJSON_AddStringToObject(one_rr_object, "signer_name", (const char *)(dns_rr->rdata.rrsig.signer_name));
|
||||
cJSON_AddStringToObject(one_rr_object, "signature", (char *)(dns_rr->rdata.rrsig.signature));
|
||||
break;
|
||||
case DNS_TYPE_NSEC:
|
||||
*dns_sec = 2;
|
||||
cJSON_AddStringToObject(one_rr_object, "next_domain", (const char *)(dns_rr->rdata.nsec.next_domain));
|
||||
cJSON_AddStringToObject(one_rr_object, "type_bit_maps", (char *)(dns_rr->rdata.nsec.type_bit_maps));
|
||||
break;
|
||||
case DNS_TYPE_DNSKEY:
|
||||
*dns_sec = 2;
|
||||
cJSON_AddNumberToObject(one_rr_object, "flags", dns_rr->rdata.dnskey.flags);
|
||||
cJSON_AddNumberToObject(one_rr_object, "protocol", dns_rr->rdata.dnskey.protocol);
|
||||
cJSON_AddNumberToObject(one_rr_object, "algo", dns_rr->rdata.dnskey.algo);
|
||||
cJSON_AddStringToObject(one_rr_object, "public_key", (char *)(dns_rr->rdata.dnskey.public_key));
|
||||
break;
|
||||
case DNS_TYPE_NSEC3:
|
||||
*dns_sec = 2;
|
||||
cJSON_AddNumberToObject(one_rr_object, "hash_algo", dns_rr->rdata.nsec3.hash_algo);
|
||||
cJSON_AddNumberToObject(one_rr_object, "flags", dns_rr->rdata.nsec3.flags);
|
||||
cJSON_AddNumberToObject(one_rr_object, "iteration", dns_rr->rdata.nsec3.iteration);
|
||||
cJSON_AddNumberToObject(one_rr_object, "salt_len", dns_rr->rdata.nsec3.salt_len);
|
||||
cJSON_AddNumberToObject(one_rr_object, "hash_len", dns_rr->rdata.nsec3.hash_len);
|
||||
cJSON_AddStringToObject(one_rr_object, "salt_value", (char *)(dns_rr->rdata.nsec3.salt_value));
|
||||
cJSON_AddStringToObject(one_rr_object, "next_hash_owner", (char *)(dns_rr->rdata.nsec3.next_hash_owner));
|
||||
cJSON_AddStringToObject(one_rr_object, "type_bit_maps", (char *)(dns_rr->rdata.nsec3.type_bit_maps));
|
||||
break;
|
||||
case DNS_TYPE_NSEC3PARAM:
|
||||
cJSON_AddNumberToObject(one_rr_object, "hash_algo", dns_rr->rdata.nsec3param.hash_algo);
|
||||
cJSON_AddNumberToObject(one_rr_object, "flags", dns_rr->rdata.nsec3param.flags);
|
||||
cJSON_AddNumberToObject(one_rr_object, "iteration", dns_rr->rdata.nsec3param.iteration);
|
||||
cJSON_AddNumberToObject(one_rr_object, "salt_len", dns_rr->rdata.nsec3param.salt_len);
|
||||
cJSON_AddStringToObject(one_rr_object, "salt_value", (char *)(dns_rr->rdata.nsec3param.salt_value));
|
||||
break;
|
||||
case DNS_QTYPE_AXFR:
|
||||
break;
|
||||
case DNS_QTYPE_MAILB:
|
||||
continue;
|
||||
break;
|
||||
case DNS_QTYPE_MAILA:
|
||||
break;
|
||||
case DNS_QTYPE_ANY:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(dns_rr_array, one_rr_object);
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(object, "rr", dns_rr_array);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_dns_info_to_log(cJSON *common_obj, dns_info_t *dns_info)
|
||||
{
|
||||
int i = 0;
|
||||
dns_rr_t *rr = NULL;
|
||||
int dns_sec = 1;
|
||||
char *cname = NULL, *rr_buf = NULL;
|
||||
|
||||
cJSON_AddNumberToObject(common_obj, "doh_qr", dns_info->hdr_info.qr);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_aa", dns_info->hdr_info.aa);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_message_id", dns_info->hdr_info.id);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_opcode", dns_info->hdr_info.opcode);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_ra", dns_info->hdr_info.ra);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_rcode", dns_info->hdr_info.rcode);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_rd", dns_info->hdr_info.rd);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_tc", dns_info->hdr_info.tc);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_qdcount", dns_info->hdr_info.qdcount);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_ancount", dns_info->hdr_info.ancount);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_nscount", dns_info->hdr_info.aucount);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_arcount", dns_info->hdr_info.adcount);
|
||||
|
||||
if ((strlen((char *)dns_info->query_question.qname)) > 0)
|
||||
{
|
||||
cJSON_AddStringToObject(common_obj, "doh_qname", (char *)dns_info->query_question.qname);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_qtype", dns_info->query_question.qtype);
|
||||
cJSON_AddNumberToObject(common_obj, "doh_qclass", dns_info->query_question.qclass);
|
||||
}
|
||||
|
||||
cJSON *item = NULL;
|
||||
cJSON *cname_array = cJSON_CreateArray();
|
||||
for (i = 0; i < dns_info->rr_count && dns_info->rr != NULL; i++)
|
||||
{
|
||||
rr = &dns_info->rr[i];
|
||||
if (rr != NULL && rr->type == DNS_TYPE_CNAME)
|
||||
{
|
||||
if (rr->rdata.cname != NULL)
|
||||
{
|
||||
item = cJSON_CreateString((const char *)rr->rdata.cname);
|
||||
cJSON_AddItemToArray(cname_array, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cname = cJSON_PrintUnformatted(cname_array);
|
||||
if (cname)
|
||||
{
|
||||
if (strlen(cname) > 0)
|
||||
{
|
||||
cJSON_AddStringToObject(common_obj, "doh_cname", cname);
|
||||
}
|
||||
free(cname);
|
||||
}
|
||||
cJSON_Delete(cname_array);
|
||||
cname_array = NULL;
|
||||
|
||||
cJSON *object = cJSON_CreateObject();
|
||||
get_rr_str2json(object, dns_info, &dns_sec);
|
||||
rr_buf = cJSON_PrintUnformatted(object);
|
||||
cJSON_AddStringToObject(common_obj, "doh_rr", rr_buf);
|
||||
free(rr_buf);
|
||||
rr_buf = NULL;
|
||||
cJSON_Delete(object);
|
||||
object = NULL;
|
||||
|
||||
cJSON_AddNumberToObject(common_obj, "doh_sub", dns_sec);
|
||||
}
|
||||
|
||||
static const char *tfe_device_id_create(const char *profile, const char *section, void *local_logger)
|
||||
{
|
||||
int ret = -1;
|
||||
size_t device_id_size = 0;
|
||||
char *tsg_sn_file = NULL, *device_id;
|
||||
const char *device_def_id = "DFT2201925000001";
|
||||
cJSON *json = NULL, *item = NULL;
|
||||
char device_id_filepath[TFE_STRING_MAX] = {0};
|
||||
|
||||
ret = MESA_load_profile_string_def(profile, section, "device_id_filepath", device_id_filepath, sizeof(device_id_filepath), NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(local_logger, "Doh log init failed, no device_path in profile %s section %s.", profile, section);
|
||||
goto finish;
|
||||
}
|
||||
tsg_sn_file = tfe_read_file(device_id_filepath, &device_id_size);
|
||||
if (tsg_sn_file == NULL)
|
||||
{
|
||||
TFE_LOG_ERROR(local_logger, "Doh log init failed, %s not existed.", tsg_sn_file);
|
||||
goto finish;
|
||||
}
|
||||
json = cJSON_Parse(tsg_sn_file);
|
||||
if (json == NULL)
|
||||
{
|
||||
TFE_LOG_ERROR(local_logger, "invalid device parameter: file = %s", tsg_sn_file);
|
||||
goto finish;
|
||||
}
|
||||
item = cJSON_GetObjectItem(json, "sn");
|
||||
if (unlikely(!item || !cJSON_IsString(item)))
|
||||
{
|
||||
TFE_LOG_ERROR(local_logger, "Invalid device parameter: %s invalid json format", tsg_sn_file);
|
||||
}
|
||||
device_id = tfe_strdup(item->valuestring);
|
||||
|
||||
cJSON_Delete(json);
|
||||
return device_id;
|
||||
finish:
|
||||
return device_def_id;
|
||||
}
|
||||
|
||||
int doh_kafka_init(const char *profile, struct doh_conf *conf)
|
||||
{
|
||||
char nic_name[64] = {0};
|
||||
char brokerlist[TFE_STRING_MAX] = {0};
|
||||
char topic_name[TFE_STRING_MAX] = {0};
|
||||
const char *section = "kafka";
|
||||
|
||||
MESA_load_profile_int_def(profile, section, "ENTRANCE_ID", &(conf->entry_id), 0);
|
||||
MESA_load_profile_int_def(profile, section, "en_sendlog", &conf->en_sendlog, 1);
|
||||
MESA_load_profile_string_def(profile, section, "NIC_NAME", nic_name, sizeof(nic_name), "eth0");
|
||||
MESA_load_profile_string_def(profile, section, "KAFKA_BROKERLIST", brokerlist, sizeof(brokerlist), "");
|
||||
MESA_load_profile_string_def(profile, section, "KAFKA_TOPIC", topic_name, sizeof(topic_name), "POLICY-DOH-LOG");
|
||||
|
||||
TFE_LOG_INFO(conf->local_logger, "Doh sendlog : %s", conf->en_sendlog ? "ENABLE" : "DISABLE");
|
||||
if (!conf->en_sendlog)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
conf->device_id = tfe_device_id_create(profile, section, conf->local_logger);
|
||||
if (!strlen(brokerlist))
|
||||
{
|
||||
TFE_LOG_ERROR(conf->local_logger, "Doh log init failed, no brokerlist in profile %s section %s.", profile, section);
|
||||
return -1;
|
||||
}
|
||||
conf->kafka_logger = tfe_kafka_logger_create(conf->en_sendlog, nic_name, brokerlist, topic_name, conf->local_logger);
|
||||
if (conf->kafka_logger == NULL)
|
||||
{
|
||||
TFE_LOG_ERROR(conf->local_logger, "Doh kafka init failed, error to create kafka logger.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
TFE_LOG_INFO(conf->local_logger, "Doh device id : %s", conf->device_id);
|
||||
TFE_LOG_INFO(conf->local_logger, "Doh kafka topic : %s", topic_name);
|
||||
TFE_LOG_INFO(conf->local_logger, "Doh kafka brokerlist : %s", brokerlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int doh_send_log(struct doh_conf *handle, const struct tfe_http_session *http, const struct tfe_stream *stream, struct doh_ctx *ctx)
|
||||
{
|
||||
Maat_rule_t *result = ctx->result;
|
||||
size_t result_num = ctx->result_num;
|
||||
dns_info_t *dns_info = ctx->doh_req;
|
||||
const struct tfe_stream_addr *addr = stream->addr;
|
||||
const char *tmp_val = NULL;
|
||||
cJSON *common_obj = NULL, *per_hit_obj = NULL;
|
||||
char *log_payload = NULL;
|
||||
int kafka_status = 0;
|
||||
int send_cnt = 0;
|
||||
time_t cur_time;
|
||||
char src_ip_str[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)] = {0};
|
||||
char dst_ip_str[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)] = {0};
|
||||
|
||||
const char *app_proto[] = {"unkonw", "http1", "http2"};
|
||||
struct json_spec req_fields[] = {{"doh_cookie", TFE_HTTP_COOKIE},
|
||||
{"doh_referer", TFE_HTTP_REFERER},
|
||||
{"doh_user_agent", TFE_HTTP_USER_AGENT}};
|
||||
struct json_spec resp_fields[] = {{"doh_content_type", TFE_HTTP_CONT_TYPE},
|
||||
{"doh_content_length", TFE_HTTP_CONT_LENGTH},
|
||||
{"doh_set_cookie", TFE_HTTP_SET_COOKIE}};
|
||||
|
||||
if (!handle->en_sendlog)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
common_obj = cJSON_CreateObject();
|
||||
cur_time = time(NULL);
|
||||
|
||||
cJSON_AddNumberToObject(common_obj, "common_start_time", cur_time);
|
||||
cJSON_AddNumberToObject(common_obj, "common_end_time", cur_time);
|
||||
cJSON_AddStringToObject(common_obj, "doh_version", app_proto[http->major_version]);
|
||||
cJSON_AddStringToObject(common_obj, "common_schema_type", "DOH");
|
||||
|
||||
char opt_val[24];
|
||||
uint16_t opt_out_size;
|
||||
struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(stream);
|
||||
if (cmsg != NULL)
|
||||
{
|
||||
int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_STREAM_TRACE_ID, (unsigned char *)opt_val, sizeof(opt_val), &opt_out_size);
|
||||
if (ret == 0)
|
||||
{
|
||||
cJSON_AddNumberToObject(common_obj, "common_stream_trace_id", atoll(opt_val));
|
||||
}
|
||||
}
|
||||
|
||||
if (http->req)
|
||||
{
|
||||
char *request_line = NULL;
|
||||
struct tfe_http_req_spec req_spec = http->req->req_spec;
|
||||
asprintf(&request_line, "%s %s HTTP/%d.%d", http_std_method_to_string(req_spec.method), req_spec.url, http->major_version, http->minor_version);
|
||||
cJSON_AddStringToObject(common_obj, "doh_request_line", request_line);
|
||||
free(request_line);
|
||||
}
|
||||
|
||||
if (http->resp)
|
||||
{
|
||||
char *response_line = NULL;
|
||||
struct tfe_http_resp_spec resp_spec = http->resp->resp_spec;
|
||||
asprintf(&response_line, "HTTP/%d.%d %d OK", http->major_version, http->minor_version, resp_spec.resp_code);
|
||||
cJSON_AddStringToObject(common_obj, "doh_response_line", response_line);
|
||||
free(response_line);
|
||||
}
|
||||
|
||||
switch (addr->addrtype)
|
||||
{
|
||||
case TFE_ADDR_STREAM_TUPLE4_V4:
|
||||
cJSON_AddNumberToObject(common_obj, "common_address_type", 4);
|
||||
inet_ntop(AF_INET, &addr->tuple4_v4->saddr, src_ip_str, sizeof(src_ip_str));
|
||||
inet_ntop(AF_INET, &addr->tuple4_v4->daddr, dst_ip_str, sizeof(dst_ip_str));
|
||||
cJSON_AddStringToObject(common_obj, "common_client_ip", src_ip_str);
|
||||
cJSON_AddStringToObject(common_obj, "common_server_ip", dst_ip_str);
|
||||
cJSON_AddNumberToObject(common_obj, "common_client_port", ntohs(addr->tuple4_v4->source));
|
||||
cJSON_AddNumberToObject(common_obj, "common_server_port", ntohs(addr->tuple4_v4->dest));
|
||||
cJSON_AddStringToObject(common_obj, "common_l4_protocol", "IPv4_TCP");
|
||||
break;
|
||||
case TFE_ADDR_STREAM_TUPLE4_V6:
|
||||
cJSON_AddNumberToObject(common_obj, "common_address_type", 6);
|
||||
inet_ntop(AF_INET6, &addr->tuple4_v6->saddr, src_ip_str, sizeof(src_ip_str));
|
||||
inet_ntop(AF_INET6, &addr->tuple4_v6->daddr, dst_ip_str, sizeof(dst_ip_str));
|
||||
cJSON_AddStringToObject(common_obj, "common_client_ip", src_ip_str);
|
||||
cJSON_AddStringToObject(common_obj, "common_server_ip", dst_ip_str);
|
||||
cJSON_AddNumberToObject(common_obj, "common_client_port", ntohs(addr->tuple4_v6->source));
|
||||
cJSON_AddNumberToObject(common_obj, "common_server_port", ntohs(addr->tuple4_v6->dest));
|
||||
cJSON_AddStringToObject(common_obj, "common_l4_protocol", "IPv6_TCP");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
size_t c2s_byte_num = 0, s2c_byte_num = 0;
|
||||
tfe_stream_info_get(stream, INFO_FROM_DOWNSTREAM_RX_OFFSET, &c2s_byte_num, sizeof(c2s_byte_num));
|
||||
tfe_stream_info_get(stream, INFO_FROM_UPSTREAM_RX_OFFSET, &s2c_byte_num, sizeof(s2c_byte_num));
|
||||
|
||||
cJSON_AddNumberToObject(common_obj, "common_direction", 0); //0:域内->域外,1:域外->域内,描述的是CLIENT_IP信息
|
||||
cJSON_AddNumberToObject(common_obj, "common_link_id", 0);
|
||||
cJSON_AddNumberToObject(common_obj, "common_stream_dir", 3); //1:c2s, 2:s2c, 3:double
|
||||
cJSON_AddStringToObject(common_obj, "common_sled_ip", handle->kafka_logger->local_ip_str);
|
||||
cJSON_AddNumberToObject(common_obj, "common_entrance_id", handle->entry_id);
|
||||
cJSON_AddStringToObject(common_obj, "common_device_id", handle->device_id);
|
||||
cJSON_AddNumberToObject(common_obj, "common_c2s_byte_num", c2s_byte_num);
|
||||
cJSON_AddNumberToObject(common_obj, "common_s2c_byte_num", s2c_byte_num);
|
||||
cJSON_AddStringToObject(common_obj, "doh_url", http->req->req_spec.url);
|
||||
cJSON_AddStringToObject(common_obj, "doh_host", http->req->req_spec.host);
|
||||
for (size_t i = 0; i < sizeof(req_fields) / sizeof(struct json_spec); i++)
|
||||
{
|
||||
tmp_val = tfe_http_std_field_read(http->req, req_fields[i].field_id);
|
||||
if (tmp_val != NULL)
|
||||
{
|
||||
cJSON_AddStringToObject(common_obj, req_fields[i].log_filed_name, tmp_val);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(resp_fields) / sizeof(struct json_spec) && http->resp != NULL; i++)
|
||||
{
|
||||
tmp_val = tfe_http_std_field_read(http->resp, resp_fields[i].field_id);
|
||||
if (tmp_val != NULL)
|
||||
{
|
||||
cJSON_AddStringToObject(common_obj, resp_fields[i].log_filed_name, tmp_val);
|
||||
}
|
||||
}
|
||||
|
||||
add_dns_info_to_log(common_obj, dns_info);
|
||||
for (size_t i = 0; i < result_num; i++)
|
||||
{
|
||||
|
||||
TFE_LOG_DEBUG(handle->local_logger, "URL: %s, policy_id: %d, service: %d, do_log:%d",
|
||||
http->req->req_spec.url,
|
||||
result[i].config_id,
|
||||
result[i].service_id,
|
||||
result[i].do_log);
|
||||
|
||||
if (result[i].do_log == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
per_hit_obj = cJSON_Duplicate(common_obj, 1);
|
||||
cJSON_AddNumberToObject(per_hit_obj, "common_policy_id", result[i].config_id);
|
||||
cJSON_AddNumberToObject(per_hit_obj, "common_service", result[i].service_id);
|
||||
cJSON_AddNumberToObject(per_hit_obj, "common_action", LG_ACTION_MANIPULATE);
|
||||
cJSON_AddStringToObject(per_hit_obj, "common_sub_action", "redirect");
|
||||
|
||||
log_payload = cJSON_PrintUnformatted(per_hit_obj);
|
||||
|
||||
TFE_LOG_DEBUG(handle->local_logger, "%s", log_payload);
|
||||
|
||||
kafka_status = tfe_kafka_logger_send(handle->kafka_logger, log_payload, strlen(log_payload));
|
||||
free(log_payload);
|
||||
cJSON_Delete(per_hit_obj);
|
||||
if (kafka_status < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(handle->local_logger, "Kafka produce failed: %s", rd_kafka_err2name(rd_kafka_last_error()));
|
||||
}
|
||||
else
|
||||
{
|
||||
send_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(common_obj);
|
||||
return send_cnt;
|
||||
}
|
||||
18
plugin/business/doh/src/logger.h
Normal file
18
plugin/business/doh/src/logger.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _LOGGER_H
|
||||
#define _LOGGER_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "pub.h"
|
||||
|
||||
int doh_kafka_init(const char *profile, struct doh_conf *conf);
|
||||
int doh_send_log(struct doh_conf *handle, const struct tfe_http_session *http, const struct tfe_stream *stream, struct doh_ctx *ctx);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
151
plugin/business/doh/src/pub.cpp
Normal file
151
plugin/business/doh/src/pub.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "pub.h"
|
||||
|
||||
static const char base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static const char index_64[128] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
int base64_encode(char *dst, int dstlen, const char *src, int srclen)
|
||||
{
|
||||
char *to = dst;
|
||||
const unsigned char *from;
|
||||
unsigned char c1, c2;
|
||||
int dst_needed;
|
||||
|
||||
// 参数检测
|
||||
if (dst == NULL || dstlen <= 0 || src == NULL || srclen <= 0)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
/* dst 缓冲区的空间不足。
|
||||
* Base64 编码是每 3 个原始字符编码成 4 个字符,
|
||||
* 如果原始字符串长度不能被 3 整除,使用 0 来补充原始字符串。*/
|
||||
dst_needed = (srclen + 2) / 3;
|
||||
dst_needed *= 4;
|
||||
if (dstlen < dst_needed + 1)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
from = (unsigned char *)src;
|
||||
while (srclen > 0)
|
||||
{
|
||||
c1 = *from++;
|
||||
srclen--;
|
||||
*to++ = base64[c1 >> 2];
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (srclen <= 0)
|
||||
{
|
||||
*to++ = base64[c1];
|
||||
*to++ = '=';
|
||||
*to++ = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *from++;
|
||||
srclen--;
|
||||
c1 |= (c2 >> 4) & 0x0f;
|
||||
*to++ = base64[c1];
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (srclen <= 0)
|
||||
{
|
||||
*to++ = base64[c1];
|
||||
*to++ = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *from++;
|
||||
srclen--;
|
||||
c1 |= (c2 >> 6) & 0x03;
|
||||
*to++ = base64[c1];
|
||||
*to++ = base64[c2 & 0x3f];
|
||||
}
|
||||
*to = '\0';
|
||||
return to - dst;
|
||||
}
|
||||
|
||||
int base64_decode(char *dst, int dstlen, const char *src, int srclen)
|
||||
{
|
||||
const unsigned char *p, *q;
|
||||
unsigned char *t;
|
||||
int c1, c2;
|
||||
|
||||
// 参数检测
|
||||
if (dst == NULL || dstlen <= 0 || src == NULL || srclen <= 0)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
// 移除首尾的空白字符
|
||||
for (p = (const unsigned char *) src; srclen > 0 && isspace(*p); p++, srclen--)
|
||||
{
|
||||
/* void */ ;
|
||||
}
|
||||
for (q = p + srclen - 1; q >= p && isspace(*q); q--, srclen--)
|
||||
{
|
||||
/* void */ ;
|
||||
}
|
||||
|
||||
// 长度必须为 4 的倍数
|
||||
if (srclen % 4 != 0)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
// 目标缓冲区必须足够长
|
||||
if (srclen / 4 * 3 + 1 > dstlen)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
t = (unsigned char *)dst;
|
||||
while (srclen > 0)
|
||||
{
|
||||
srclen -= 4;
|
||||
if (*p >= 128 || (c1 = index_64[*p++]) == -1)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
|
||||
if (*p >= 128 || (c2 = index_64[*p++]) == -1)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
*t++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||
|
||||
if (p[0] == '=' && p[1] == '=')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p >= 128 || (c1 = index_64[*p++]) == -1)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
*t++ = ((c2 & 0x0f) << 4) | ((c1 & 0x3c) >> 2);
|
||||
|
||||
if (p[0] == '=')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p >= 128 || (c2 = index_64[*p++]) == -1)
|
||||
{
|
||||
return MS_ERROR;
|
||||
}
|
||||
*t++ = ((c1 & 0x03) << 6) | c2;
|
||||
}
|
||||
|
||||
return t - (unsigned char *) dst;
|
||||
}
|
||||
100
plugin/business/doh/src/pub.h
Normal file
100
plugin/business/doh/src/pub.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef _PUB_H
|
||||
#define _PUB_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <tfe_resource.h>
|
||||
#include <tfe_proxy.h>
|
||||
#include <tfe_plugin.h>
|
||||
#include <MESA/Maat_rule.h>
|
||||
#include <MESA/MESA_prof_load.h>
|
||||
#include <tfe_kafka_logger.h>
|
||||
|
||||
#include "dns.h"
|
||||
|
||||
#define MS_OK 0
|
||||
#define MS_ERROR -1
|
||||
|
||||
enum pangu_http_stat
|
||||
{
|
||||
STAT_SESSION,
|
||||
STAT_LOG_NUM,
|
||||
STAT_ACTION_HIJACK,
|
||||
DOH_STAT_MAX
|
||||
};
|
||||
|
||||
enum table_type
|
||||
{
|
||||
TYPE_ADDR,
|
||||
TYPE_APPID,
|
||||
TYPE_QNAME,
|
||||
TYPE_HOST,
|
||||
TYPE_MAX
|
||||
};
|
||||
|
||||
enum doh_content_type
|
||||
{
|
||||
DOH_TYPE_MESSAGE,
|
||||
DOH_TYPE_UDPWIREFORMAT,
|
||||
};
|
||||
|
||||
struct maat_table
|
||||
{
|
||||
int id;
|
||||
char name[TFE_STRING_MAX];
|
||||
};
|
||||
|
||||
struct doh_conf
|
||||
{
|
||||
int enable;
|
||||
int thread_num;
|
||||
|
||||
int local_level;
|
||||
void *local_logger;
|
||||
|
||||
int entry_id;
|
||||
int en_sendlog;
|
||||
const char *device_id;
|
||||
tfe_kafka_logger_t *kafka_logger;
|
||||
|
||||
int fs_id[DOH_STAT_MAX];
|
||||
long long stat_val[DOH_STAT_MAX];
|
||||
struct event *gcev;
|
||||
struct event_base *gc_evbase;
|
||||
screen_stat_handle_t fs_handle;
|
||||
|
||||
Maat_feather_t maat;
|
||||
struct maat_table tables[TYPE_MAX];
|
||||
};
|
||||
|
||||
struct doh_ctx
|
||||
{
|
||||
int count;
|
||||
u_int32_t min_ttl;
|
||||
int thread_id;
|
||||
int magic_num;
|
||||
int manipulate;
|
||||
int opts_num;
|
||||
char *addr_string;
|
||||
size_t result_num;
|
||||
Maat_rule_t *result;
|
||||
cheat_pkt_opt_t *opts;
|
||||
scan_status_t scan_mid;
|
||||
enum doh_content_type type;
|
||||
struct evbuffer *http_req_body;
|
||||
dns_info_t *doh_req;
|
||||
};
|
||||
|
||||
int base64_encode(char *dst, int dstlen, const char *src, int srclen);
|
||||
int base64_decode(char *dst, int dstlen, const char *src, int srclen);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
898
plugin/business/doh/test/dns_test.cpp
Normal file
898
plugin/business/doh/test/dns_test.cpp
Normal file
@@ -0,0 +1,898 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../src/pub.h"
|
||||
#include "../src/dns.h"
|
||||
|
||||
#define ERROR(str) \
|
||||
{ \
|
||||
printf(str); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
const char *data;
|
||||
} str_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *desc;
|
||||
str_t req;
|
||||
str_t rsp;
|
||||
} package_t;
|
||||
|
||||
static package_t package_arry[] = {
|
||||
{
|
||||
"dig @127.0.0.1 www.baidu.com a",
|
||||
{56, "TDwBIAABAAAAAAABA3d3dwViYWlkdQNjb20AAAEAAQAAKRAAAAAAAAAA"},
|
||||
{136, "TDyBgAABAAMAAAABA3d3dwViYWlkdQNjb20AAAEAAcAMAAUAAQAAACoADwN3d3cBYQZzaGlmZW7AFsArAAEAAQAAACoABLY9yAfAKwABAAEAAAAqAAS2PcgGAAApEAAAAAAAAAA="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 baidu.com ns",
|
||||
{52, "M00BIAABAAAAAAABBWJhaWR1A2NvbQAAAgABAAApEAAAAAAAAAA="},
|
||||
{172, "M02BgAABAAUAAAABBWJhaWR1A2NvbQAAAgABwAwAAgABAAAcJwAGA25zNMAMwAwAAgABAAAcJwAGA25zMsAMwAwAAgABAAAcJwAGA25zN8AMwAwAAgABAAAcJwAGA2Ruc8AMwAwAAgABAAAcJwAGA25zM8AMAAApEAAAAAAAAAA="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 www.baidu.com cname",
|
||||
{56, "LAMBIAABAAAAAAABA3d3dwViYWlkdQNjb20AAAUAAQAAKRAAAAAAAAAA"},
|
||||
{92, "LAOBgAABAAEAAAABA3d3dwViYWlkdQNjb20AAAUAAcAMAAUAAQAAAGYADwN3d3cBYQZzaGlmZW7AFgAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 www.baidu.com soa",
|
||||
{56, "9D8BIAABAAAAAAABA3d3dwViYWlkdQNjb20AAAYAAQAAKRAAAAAAAAAA"},
|
||||
{168, "9D+BgAABAAEAAQABA3d3dwViYWlkdQNjb20AAAYAAcAMAAUAAQAAAhcADwN3d3cBYQZzaGlmZW7AFsAvAAYAAQAAAmIALQNuczHALxBiYWlkdV9kbnNfbWFzdGVywBB3hAIjAAAABQAAAAUAJ40AAAAOEAAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 -x 192.30.252.153",
|
||||
{76, "G+4BIAABAAAAAAABAzE1MwMyNTICMzADMTkyB2luLWFkZHIEYXJwYQAADAABAAApEAAAAAAAAAA="},
|
||||
{136, "G+6BgAABAAEAAAABAzE1MwMyNTICMzADMTkyB2luLWFkZHIEYXJwYQAADAABwAwADAABAAAOEAAiFWxiLTE5Mi0zMC0yNTItMTUzLWlhZAZnaXRodWIDY29tAAAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 163.com mx",
|
||||
{48, "iRMBIAABAAAAAAABAzE2MwNjb20AAA8AAQAAKRAAAAAAAAAA"},
|
||||
{196, "iROBgAABAAQAAAABAzE2MwNjb20AAA8AAcAMAA8AAQAADnQAGwAKBzE2M214MDEGbXhtYWlsB25ldGVhc2XAEMAMAA8AAQAADnQADAAyBzE2M214MDDAL8AMAA8AAQAADnQADAAKBzE2M214MDPAL8AMAA8AAQAADnQADAAKBzE2M214MDLALwAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 baidu.com txt",
|
||||
{52, "A6kBIAABAAAAAAABBWJhaWR1A2NvbQAAEAABAAApEAAAAAAAAAA="},
|
||||
{296, "A6mBgAABAAIAAAABBWJhaWR1A2NvbQAAEAABwAwAEAABAAAIKgBFRGdvb2dsZS1zaXRlLXZlcmlmaWNhdGlvbj1HSGI5OC02bXNxeXhfcXFqR2w1ZVJhdEQzUVRIeVZCNi14UTNnSkI1VXdNwAwAEAABAAAIKgBaWXY9c3BmMSBpbmNsdWRlOnNwZjEuYmFpZHUuY29tIGluY2x1ZGU6c3BmMi5iYWlkdS5jb20gaW5jbHVkZTpzcGYzLmJhaWR1LmNvbSBhIG14IHB0ciAtYWxsAAApEAAAAAAAAAA="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 www.taobao.com aaaa",
|
||||
{60, "0qQBIAABAAAAAAABA3d3dwZ0YW9iYW8DY29tAAAcAAEAACkQAAAAAAAAAA=="},
|
||||
{640, "0qSBgAABAA8AAAABA3d3dwZ0YW9iYW8DY29tAAAcAAHADAAFAAEAAAG2ACEDd3d3BnRhb2JhbwNjb20HZGFudW95aQd0YmNhY2hlwBfALAAcAAEAAAA8ABAkDgCxmAEEAAADAAAAAAP5wCwAHAABAAAAPAAQJA4AsZgBBAkAAwAAAAAD+cAsABwAAQAAADwAECQOALGYAQQAAAMAAAAAA/rALAAcAAEAAAA8ABAkDglA4AEAAQADAAAAAAP5wCwAHAABAAAAPAAQJA4AsZgBBAgAAwAAAAAD+sAsABwAAQAAADwAECQOCUDgAQABAAMAAAAAA/rALAAcAAEAAAA8ABAkDglA4AEABQADAAAAAAP5wCwAHAABAAAAPAAQJA4AsaggAAAAAwAAAAAD9cAsABwAAQAAADwAECQOALGoIAAAAAMAAAAAA/bALAAcAAEAAAA8ABAkDgCxmAEECQADAAAAAAP6wCwAHAABAAAAPAAQJA4JQOABAAQAAwAAAAAD+cAsABwAAQAAADwAECQOCUDgAQAEAAMAAAAAA/rALAAcAAEAAAA8ABAkDgCxmAEECAADAAAAAAP5wCwAHAABAAAAPAAQJA4JQOABAAUAAwAAAAAD+gAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 com ds",
|
||||
{44, "94UBIAABAAAAAAABA2NvbQAAKwABAAApEAAAAAAAAAA="},
|
||||
{108, "94WBgAABAAEAAAABA2NvbQAAKwABwAwAKwABAAB/zgAkeL0IAuLTyRb23urHMpToJo+1iFBEqDP8VFlYj0qRhM/EGldmAAApEAAAAAAAAAA="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 com rrsig",
|
||||
{44, "ETMBIAABAAAAAAABA2NvbQAALgABAAApEAAAAAAAAAA="},
|
||||
{948, "ETOBgAABAAMAAAABA2NvbQAALgABwAwALgABAAABjgC3AAYIAQAAA4RexfcOXrysJpukA2NvbQAJCiOw6MPHup5mJVrn65fULwvBJoy5mR1IYTJSEzv7PXsT+B/3lp+5Gnfds89MvligsnUWkQvOUiCOkY5ahPwO5fQSB4dDPZJXahG44IR2QtNDHLfFNxcRROwdLmmSe9F+sU5ZL4YtmXu4+trwUycbo34f19o3xRS5D6UBV1clWPp0yK9rQafhMY5UBIZz83txHKumVVjwlnsA2d7w1Qi7wDMALgABAAEBrwETACsIAQABUYBezYNQXrxRwL8HAF4VVK323NSvS//r44sD6QQDSa9aNBCPlimQWZUbjmAh2Z/RkwTAuK0T3ngOw5flW8rHaopbNfIQ4UZSNqzcbzXtJ/F2u2DG4/Xo26LRbF1jHBZOGChGMeug4kVVepPuQvxEoSBUY9FgdGXMZ551kxO/xf3kK6xMhmjQjOQn1xJzZEGtcqV+5pKymT4MNdfPdhpJIDQRnN33bvk8su7wPiaJmGsKGdGHBKlsyMJgLCoJrMvSQIEiQj560Rwy1n1qq3Mlk6CkydQ62mZp2u32d4wBTE3UTs+aDBRfTSQmg6Dofh9x2DJgK5mFISt7rYgvacxpRfqBkD4tDdKUQlrszbjAMwAuAAEAAk6gALcAAggBAAKjAF7AwkJet3dam6QDY29tAJK2SHQgAOJ0UOxt+9f55rJHx5vzvSuuuTsaM06kaK8zhK6Xo0IRqWtu12EHehn3UiPoTGEdUK/KK2ZXmdb8yJ/H+L4BRG9AafN7xaHPAf4GbXr0pV4yOl+HoTEstZmL3JgXHPFMRLl66UYbNGBDFE6B1f1MNZlBvk6c3NjeMSN29DOIZRoajZlDKv3IRhOrRJghwLr5vhlODIwm58lTbI0AACkQAAAAAAAAAA=="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 com dnskey",
|
||||
{44, "FJwBIAABAAAAAAABA2NvbQAAMAABAAApEAAAAAAAAAA="},
|
||||
{648, "FJyBgAABAAIAAAABA2NvbQAAMAABwAwAMAABAAAL5wEGAQEDCAEDw85XTZjL2RV+DXDSdLhJyg4O7Zr/xdzMkEdJaQZlXDXLCLM8TRcbAXyjVvSWAmKqYpPN+uixO1WyHDUc36dofTjvB0Zfh/hNPM2rivJO3r1hJrv+qHftm6IID6IhHxjcrzT2kiOxTiK6A7J8P7WoIMx0V9We0jojoj1jzSMElMljme/VZnENRi5AujZWLxtx8GJsp0L+qBcBr/yhC0sO2Una200NB172W6jFCOwWjLJJr4JtRu6CmdWIhezvYqFTXNPuwEm6pmTe2ffBBlP0IdivwYFHvB7NF1XHTyq7cmJ6EB3dspyj3DDJUxIodv9hwx40TydmssCKSjZ7+KD6P8AMADAAAQAAC+cAqAEAAwgDAQABtsVzV+OQEJLJyG3tqH155FqW2csMraxXKjGSMLrMHOb/lIaB8Mb8fpcS6lPty2AK+ep7FqKdMh9ryecFgI60B5zsZ3W9voT/dJeSCINoxQleZ23wTuhu1VmqMWU3ZA2dOWN8yIQKfXqtleW9ciLbnlPXAWRa2nn4tQKK5+wtN4pz3FtDDvLS5yxH4YrPjIRK1tiL3x+cHmc7PNaFFRyV/QAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 com nsec3param",
|
||||
{44, "s48BIAABAAAAAAABA2NvbQAAMwABAAApEAAAAAAAAAA="},
|
||||
{68, "s4+BgAABAAEAAAABA2NvbQAAMwABwAwAMwABAABFmwAFAQAAAAAAACkQAAAAAAAAAA=="},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 _sip._udp.sip.voice.google.com srv",
|
||||
{80, "9OoBIAABAAAAAAABBF9zaXAEX3VkcANzaXAFdm9pY2UGZ29vZ2xlA2NvbQAAIQABAAApEAAAAAAAAAA="},
|
||||
{212, "9OqBgAABAAIAAAABBF9zaXAEX3VkcANzaXAFdm9pY2UGZ29vZ2xlA2NvbQAAIQABwAwAIQABAAAAxAAmAAoAARPEDXNpcC1hbnljYXN0LTEFdm9pY2UGZ29vZ2xlA2NvbQDADAAhAAEAAADEACYAFAABE8QNc2lwLWFueWNhc3QtMgV2b2ljZQZnb29nbGUDY29tAAAAKRAAAAAAAAAA"},
|
||||
},
|
||||
{
|
||||
"dig @127.0.0.1 . nsec",
|
||||
{40, "3HUBIAABAAAAAAABAAAvAAEAACkQAAAAAAAAAA=="},
|
||||
{72, "3HWBgAABAAEAAAABAAAvAAEAAC8AAQABUSUADgNhYWEAAAciAAAAAAOAAAApEAAAAAAAAAA="},
|
||||
}};
|
||||
|
||||
static int package_arry_size = sizeof(package_arry) / sizeof(package_t);
|
||||
|
||||
static int dns_print(dns_info_t *dns_info, const char *filename)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
int used_len = 0, len = 0;
|
||||
FILE *fp = NULL;
|
||||
char dns_header[256];
|
||||
char question[1024];
|
||||
char rr_buf[4096];
|
||||
char ip_str[128];
|
||||
char tmp_buf[2048];
|
||||
char maps[2048];
|
||||
char salt_value[2048];
|
||||
dns_rr_t *dns_rr = NULL;
|
||||
char *buf = NULL;
|
||||
int buflen = sizeof(rr_buf);
|
||||
buf = rr_buf;
|
||||
cJSON *dns_info_object = cJSON_CreateObject();
|
||||
cJSON *dns_hdr_object = cJSON_CreateObject();
|
||||
cJSON *dns_flags_object = cJSON_CreateObject();
|
||||
cJSON *dns_question_array = cJSON_CreateArray();
|
||||
cJSON *dns_rr_array = cJSON_CreateArray();
|
||||
|
||||
memset(dns_header, 0, sizeof(dns_header));
|
||||
|
||||
fp = fopen(filename, "a+");
|
||||
if (fp == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
used_len = snprintf(dns_header, sizeof(dns_header),
|
||||
"hdr_info: <id=0X%02x, QR=%d, OPCODE=%d, AA=%d, TC=%d, RD=%d, RA=%d,Z=%d, RCODE=%d, qdcount=%d, ancount=%d, aucount=%d, adcount=%d>\n",
|
||||
dns_info->hdr_info.id,
|
||||
dns_info->hdr_info.qr,
|
||||
dns_info->hdr_info.opcode,
|
||||
dns_info->hdr_info.aa,
|
||||
dns_info->hdr_info.tc,
|
||||
dns_info->hdr_info.rd,
|
||||
dns_info->hdr_info.ra,
|
||||
dns_info->hdr_info.z,
|
||||
dns_info->hdr_info.rcode,
|
||||
dns_info->hdr_info.qdcount,
|
||||
dns_info->hdr_info.ancount,
|
||||
dns_info->hdr_info.aucount,
|
||||
dns_info->hdr_info.adcount);
|
||||
|
||||
cJSON_AddNumberToObject(dns_hdr_object, "id", dns_info->hdr_info.id);
|
||||
cJSON_AddNumberToObject(dns_hdr_object, "qdcount", dns_info->hdr_info.qdcount);
|
||||
cJSON_AddNumberToObject(dns_hdr_object, "ancount", dns_info->hdr_info.ancount);
|
||||
cJSON_AddNumberToObject(dns_hdr_object, "aucount", dns_info->hdr_info.aucount);
|
||||
cJSON_AddNumberToObject(dns_hdr_object, "adcount", dns_info->hdr_info.adcount);
|
||||
|
||||
cJSON_AddNumberToObject(dns_flags_object, "qr", dns_info->hdr_info.qr);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "opcode", dns_info->hdr_info.opcode);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "aa", dns_info->hdr_info.aa);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "tc", dns_info->hdr_info.tc);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "rd", dns_info->hdr_info.rd);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "ra", dns_info->hdr_info.ra);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "z", dns_info->hdr_info.z);
|
||||
cJSON_AddNumberToObject(dns_flags_object, "rcode", dns_info->hdr_info.rcode);
|
||||
|
||||
fwrite(dns_header, used_len, 1, fp);
|
||||
|
||||
cJSON_AddItemToObject(dns_info_object, "hdr", dns_hdr_object);
|
||||
cJSON_AddItemToObject(dns_info_object, "flags", dns_flags_object);
|
||||
cJSON_AddItemToObject(dns_info_object, "question", dns_question_array);
|
||||
|
||||
used_len = snprintf(question, sizeof(question), "question: <qtype: %d, qclass: %d, qname: %s>\n",
|
||||
dns_info->query_question.qtype,
|
||||
dns_info->query_question.qclass,
|
||||
dns_info->query_question.qname);
|
||||
|
||||
cJSON *dns_question_object = cJSON_CreateObject();
|
||||
cJSON_AddItemToArray(dns_question_array, dns_question_object);
|
||||
|
||||
cJSON_AddNumberToObject(dns_question_object, "qtype", dns_info->query_question.qtype);
|
||||
cJSON_AddNumberToObject(dns_question_object, "qclass", dns_info->query_question.qclass);
|
||||
cJSON_AddStringToObject(dns_question_object, "qname", (const char *)dns_info->query_question.qname);
|
||||
|
||||
fwrite(question, used_len, 1, fp);
|
||||
|
||||
used_len = snprintf(rr_buf, sizeof(rr_buf), "RRS count: %d\n", dns_info->rr_count);
|
||||
fwrite(rr_buf, used_len, 1, fp);
|
||||
|
||||
cJSON_AddItemToObject(dns_info_object, "rr", dns_rr_array);
|
||||
|
||||
for (i = 0; i < dns_info->rr_count; i++)
|
||||
{
|
||||
cJSON *dns_rr_object = cJSON_CreateObject();
|
||||
cJSON_AddItemToArray(dns_rr_array, dns_rr_object);
|
||||
|
||||
used_len = 0;
|
||||
dns_rr = &(dns_info->rr[i]);
|
||||
memset(rr_buf, 0, sizeof(rr_buf));
|
||||
|
||||
if (dns_rr->type == DNS_TYPE_OPT)
|
||||
{
|
||||
used_len += snprintf(rr_buf, sizeof(rr_buf), "RRS%d OPT <name: %s, type: %d, udp_payload: %d, extended RCODE: %d, version: %d, Z; 0X%x, rdlength: %d>\n",
|
||||
i,
|
||||
dns_rr->name,
|
||||
dns_rr->type,
|
||||
dns_rr->rr_class,
|
||||
dns_rr->ttl >> 24,
|
||||
(dns_rr->ttl >> 16) & 0xFF,
|
||||
dns_rr->ttl && 0xFFFF,
|
||||
dns_rr->rdlength);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "name", (const char *)(dns_rr->name));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "type", dns_rr->type);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "udp_payload", dns_rr->rr_class);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "rcode", (int)(dns_rr->ttl >> 24));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "version", (int)((dns_rr->ttl >> 16) & 0xFF));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "Z", (int)(dns_rr->ttl && 0xFFFF));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "rdlength", dns_rr->rdlength);
|
||||
}
|
||||
else
|
||||
{
|
||||
used_len += snprintf(rr_buf, sizeof(rr_buf), "RRS%d <name: %s, type: %d, rr_class: %d, ttl: %d, rdlength: %d>",
|
||||
i,
|
||||
dns_rr->name,
|
||||
dns_rr->type,
|
||||
dns_rr->rr_class,
|
||||
dns_rr->ttl,
|
||||
dns_rr->rdlength);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "name", (const char *)(dns_rr->name));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "type", dns_rr->type);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "class", dns_rr->rr_class);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "ttl", dns_rr->ttl);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "rdlength", dns_rr->rdlength);
|
||||
}
|
||||
|
||||
switch (dns_rr->type)
|
||||
{
|
||||
case DNS_TYPE_A:
|
||||
inet_ntop(AF_INET, (void *)(dns_rr->rdata.a), ip_str, sizeof(ip_str));
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[A: %s]\n", ip_str);
|
||||
cJSON_AddStringToObject(dns_rr_object, "a", ip_str);
|
||||
break;
|
||||
case DNS_TYPE_NS:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[NS: %s]\n", dns_rr->rdata.ns);
|
||||
cJSON_AddStringToObject(dns_rr_object, "ns", (const char *)(dns_rr->rdata.ns));
|
||||
break;
|
||||
case DNS_TYPE_MD:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MD: %s]\n", dns_rr->rdata.md);
|
||||
cJSON_AddStringToObject(dns_rr_object, "md", (const char *)(dns_rr->rdata.md));
|
||||
break;
|
||||
case DNS_TYPE_MF:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MF: %s]\n", dns_rr->rdata.mf);
|
||||
cJSON_AddStringToObject(dns_rr_object, "mf", (const char *)(dns_rr->rdata.mf));
|
||||
break;
|
||||
case DNS_TYPE_CNAME:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[CNAME: %s]\n", dns_rr->rdata.cname);
|
||||
cJSON_AddStringToObject(dns_rr_object, "cname", (const char *)(dns_rr->rdata.cname));
|
||||
break;
|
||||
case DNS_TYPE_SOA:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len,
|
||||
"[SOA mname: %s, rname: %s, serial: %u, refresh: %u, retry: %u, expire: %u, minimum: %u]\n",
|
||||
dns_rr->rdata.soa.mname,
|
||||
dns_rr->rdata.soa.rname,
|
||||
dns_rr->rdata.soa.serial,
|
||||
dns_rr->rdata.soa.refresh,
|
||||
dns_rr->rdata.soa.retry,
|
||||
dns_rr->rdata.soa.expire,
|
||||
dns_rr->rdata.soa.minimum);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "mname", (const char *)(dns_rr->rdata.soa.mname));
|
||||
cJSON_AddStringToObject(dns_rr_object, "rname", (const char *)(dns_rr->rdata.soa.rname));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "serial", dns_rr->rdata.soa.serial);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "refresh", dns_rr->rdata.soa.refresh);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "retry", dns_rr->rdata.soa.retry);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "cname", dns_rr->rdata.soa.expire);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "minimum", dns_rr->rdata.soa.minimum);
|
||||
break;
|
||||
case DNS_TYPE_MB:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MB: %s]\n", dns_rr->rdata.mb);
|
||||
cJSON_AddStringToObject(dns_rr_object, "mb", (const char *)(dns_rr->rdata.mb));
|
||||
break;
|
||||
case DNS_TYPE_MG:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MG: %s]\n", dns_rr->rdata.mg);
|
||||
cJSON_AddStringToObject(dns_rr_object, "mg", (const char *)(dns_rr->rdata.mg));
|
||||
break;
|
||||
case DNS_TYPE_MR:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MR: %s]\n", dns_rr->rdata.mr);
|
||||
cJSON_AddStringToObject(dns_rr_object, "mr", (const char *)(dns_rr->rdata.mr));
|
||||
break;
|
||||
case DNS_TYPE_NULL:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[null size: %u, null: %s]\n",
|
||||
dns_rr->rdata.null.size, dns_rr->rdata.null.null);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "size", dns_rr->rdata.null.size);
|
||||
cJSON_AddStringToObject(dns_rr_object, "null", (const char *)(dns_rr->rdata.null.null));
|
||||
break;
|
||||
case DNS_TYPE_WKS:
|
||||
inet_ntop(AF_INET, &(dns_rr->rdata.wks.addr), ip_str, sizeof(ip_str));
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[WKS addr: %s, protocol: %u, bitmap: %s, size: %u]\n",
|
||||
ip_str, dns_rr->rdata.wks.protocol, dns_rr->rdata.wks.bitmap, dns_rr->rdata.wks.size);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "addr", ip_str);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "protocol", dns_rr->rdata.wks.protocol);
|
||||
cJSON_AddStringToObject(dns_rr_object, "bitmap", (const char *)(dns_rr->rdata.wks.bitmap));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "size", dns_rr->rdata.wks.size);
|
||||
break;
|
||||
case DNS_TYPE_PTR:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[PTR: %s]\n", dns_rr->rdata.ptr);
|
||||
cJSON_AddStringToObject(dns_rr_object, "ptr", (const char *)(dns_rr->rdata.ptr));
|
||||
break;
|
||||
case DNS_TYPE_HINFO:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[HINFO cpu: %s, os: %s]\n",
|
||||
dns_rr->rdata.hinfo.cpu, dns_rr->rdata.hinfo.os);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "cpu", (const char *)(dns_rr->rdata.hinfo.cpu));
|
||||
cJSON_AddStringToObject(dns_rr_object, "os", (const char *)(dns_rr->rdata.hinfo.os));
|
||||
break;
|
||||
case DNS_TYPE_MINFO:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MINFO rmailbx: %s, emailbx: %s]\n",
|
||||
dns_rr->rdata.minfo.rmailbx, dns_rr->rdata.minfo.emailbx);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "rmailbx", (const char *)(dns_rr->rdata.minfo.rmailbx));
|
||||
cJSON_AddStringToObject(dns_rr_object, "emailbx", (const char *)(dns_rr->rdata.minfo.emailbx));
|
||||
break;
|
||||
case DNS_TYPE_MX:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[MX preference: %u, exchange: %s]\n",
|
||||
dns_rr->rdata.mx.preference, dns_rr->rdata.mx.exchange);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "exchange", (const char *)(dns_rr->rdata.mx.exchange));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "preference", dns_rr->rdata.mx.preference);
|
||||
break;
|
||||
case DNS_TYPE_TXT:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[TXT size: %u, txt: %s]\n",
|
||||
dns_rr->rdata.txt.size, dns_rr->rdata.txt.txt);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "txt", (const char *)(dns_rr->rdata.txt.txt));
|
||||
cJSON_AddNumberToObject(dns_rr_object, "size", dns_rr->rdata.txt.size);
|
||||
break;
|
||||
case DNS_TYPE_RP:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[mailbox: %s, txt_rr: %s]\n",
|
||||
dns_rr->rdata.rp.mailbox, dns_rr->rdata.rp.txt_rr);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "mailbox", (const char *)(dns_rr->rdata.rp.mailbox));
|
||||
cJSON_AddStringToObject(dns_rr_object, "txt_rr", (const char *)(dns_rr->rdata.rp.txt_rr));
|
||||
break;
|
||||
case DNS_TYPE_AAAA:
|
||||
inet_ntop(AF_INET6, dns_rr->rdata.aaaa, ip_str, sizeof(ip_str));
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[AAAA: %s]\n", ip_str);
|
||||
cJSON_AddStringToObject(dns_rr_object, "aaaa", ip_str);
|
||||
break;
|
||||
case DNS_TYPE_OPT:
|
||||
break;
|
||||
case DNS_TYPE_DS:
|
||||
len = 0;
|
||||
assert(dns_rr->rdata.ds.digest_len * 2 < sizeof(tmp_buf));
|
||||
for (j = 0; j < (int)(dns_rr->rdata.ds.digest_len); j++)
|
||||
{
|
||||
len += snprintf(tmp_buf + len, sizeof(tmp_buf) - len, "%02x", dns_rr->rdata.ds.digest[j]);
|
||||
}
|
||||
used_len += snprintf(buf + used_len, buflen - used_len,
|
||||
"[DS key_tag: %u, algo: %u, digest_type: %u, digest: %s]\n",
|
||||
dns_rr->rdata.ds.key_tag, dns_rr->rdata.ds.algo,
|
||||
dns_rr->rdata.ds.digest_type, tmp_buf);
|
||||
|
||||
cJSON_AddNumberToObject(dns_rr_object, "key_tag", dns_rr->rdata.ds.key_tag);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "algo", dns_rr->rdata.ds.algo);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "digest_type", dns_rr->rdata.ds.digest_type);
|
||||
cJSON_AddStringToObject(dns_rr_object, "digest", tmp_buf);
|
||||
break;
|
||||
case DNS_TYPE_RRSIG:
|
||||
len = 0;
|
||||
assert(dns_rr->rdata.rrsig.signature_len * 2 < sizeof(tmp_buf));
|
||||
for (j = 0; j < (int)(dns_rr->rdata.rrsig.signature_len); j++)
|
||||
{
|
||||
len += snprintf(tmp_buf + len, sizeof(tmp_buf) - len, "%02x", dns_rr->rdata.rrsig.signature[j]);
|
||||
}
|
||||
used_len += snprintf(buf + used_len, buflen - used_len,
|
||||
"[RRSIG type_covered: %u, algo: %u, labels: %u, original_ttl: %u, sig_expiration: %u, sig_inception: %u, key_tag: %u, signer_name: %s, signature: %s]\n",
|
||||
dns_rr->rdata.rrsig.type_covered, dns_rr->rdata.rrsig.algo,
|
||||
dns_rr->rdata.rrsig.labels, dns_rr->rdata.rrsig.original_ttl,
|
||||
dns_rr->rdata.rrsig.sig_expiration, dns_rr->rdata.rrsig.sig_inception,
|
||||
dns_rr->rdata.rrsig.key_tag, dns_rr->rdata.rrsig.signer_name, tmp_buf);
|
||||
|
||||
cJSON_AddNumberToObject(dns_rr_object, "type_covered", dns_rr->rdata.rrsig.type_covered);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "algo", dns_rr->rdata.rrsig.algo);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "labels", dns_rr->rdata.rrsig.labels);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "original_ttl", dns_rr->rdata.rrsig.original_ttl);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "sig_expiration", dns_rr->rdata.rrsig.sig_expiration);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "sig_inception", dns_rr->rdata.rrsig.sig_inception);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "key_tag", dns_rr->rdata.rrsig.key_tag);
|
||||
cJSON_AddStringToObject(dns_rr_object, "signer_name", (const char *)(dns_rr->rdata.rrsig.signer_name));
|
||||
cJSON_AddStringToObject(dns_rr_object, "signature", tmp_buf);
|
||||
break;
|
||||
case DNS_TYPE_NSEC:
|
||||
len = 0;
|
||||
for (j = 0; j < (int)(dns_rr->rdata.nsec.maps_len); j++)
|
||||
{
|
||||
len += snprintf(maps + len, sizeof(maps) - len, "%02x", dns_rr->rdata.nsec.type_bit_maps[j]);
|
||||
}
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[NSEC next_domain: %s, type_bit_maps: %s]\n", dns_rr->rdata.nsec.next_domain, maps);
|
||||
|
||||
cJSON_AddStringToObject(dns_rr_object, "next_domain", (const char *)(dns_rr->rdata.nsec.next_domain));
|
||||
cJSON_AddStringToObject(dns_rr_object, "type_bit_maps", maps);
|
||||
break;
|
||||
case DNS_TYPE_DNSKEY:
|
||||
len = 0;
|
||||
assert(dns_rr->rdata.dnskey.public_key_len * 2 < sizeof(tmp_buf));
|
||||
for (j = 0; j < (int)(dns_rr->rdata.dnskey.public_key_len); j++)
|
||||
{
|
||||
len += snprintf(tmp_buf + len, sizeof(tmp_buf) - len, "%02x", dns_rr->rdata.dnskey.public_key[j]);
|
||||
}
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[DNSKEY flags: %u, protocol: %u, algo: %u, public_key: %s]\n",
|
||||
dns_rr->rdata.dnskey.flags, dns_rr->rdata.dnskey.protocol, dns_rr->rdata.dnskey.algo, tmp_buf);
|
||||
|
||||
cJSON_AddNumberToObject(dns_rr_object, "flags", dns_rr->rdata.dnskey.flags);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "protocol", dns_rr->rdata.dnskey.protocol);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "algo", dns_rr->rdata.dnskey.algo);
|
||||
cJSON_AddStringToObject(dns_rr_object, "public_key", tmp_buf);
|
||||
break;
|
||||
case DNS_TYPE_NSEC3:
|
||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||
memset(maps, 0, sizeof(maps));
|
||||
len = 0;
|
||||
assert(dns_rr->rdata.nsec3.hash_len * 2 < sizeof(tmp_buf));
|
||||
for (j = 0; j < (int)(dns_rr->rdata.nsec3.hash_len); j++)
|
||||
{
|
||||
len += snprintf(tmp_buf + len, sizeof(tmp_buf) - len, "%02x", dns_rr->rdata.nsec3.next_hash_owner[j]);
|
||||
}
|
||||
len = 0;
|
||||
for (j = 0; j < (int)(dns_rr->rdata.nsec3.maps_len); j++)
|
||||
{
|
||||
len += snprintf(maps + len, sizeof(maps) - len, "%02x", dns_rr->rdata.nsec3.type_bit_maps[j]);
|
||||
}
|
||||
len = 0;
|
||||
for (j = 0; j < (int)(dns_rr->rdata.nsec3.salt_len); j++)
|
||||
{
|
||||
len += snprintf(salt_value + len, sizeof(salt_value) - len, "%02x", dns_rr->rdata.nsec3.salt_value[j]);
|
||||
}
|
||||
|
||||
used_len += snprintf(buf + used_len, buflen - used_len,
|
||||
"[NSEC3 hash_algo: %u, flags: %u, iteration: %u, salt_len: %u, hash_len: %u, salt_value: %s, next_hash_owner: %s, type_bit_maps: %s]\n",
|
||||
dns_rr->rdata.nsec3.hash_algo, dns_rr->rdata.nsec3.flags,
|
||||
dns_rr->rdata.nsec3.iteration, dns_rr->rdata.nsec3.salt_len,
|
||||
dns_rr->rdata.nsec3.hash_len, salt_value, tmp_buf, maps);
|
||||
|
||||
cJSON_AddNumberToObject(dns_rr_object, "hash_algo", dns_rr->rdata.nsec3.hash_algo);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "flags", dns_rr->rdata.nsec3.flags);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "iteration", dns_rr->rdata.nsec3.iteration);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "salt_len", dns_rr->rdata.nsec3.salt_len);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "hash_len", dns_rr->rdata.nsec3.hash_len);
|
||||
cJSON_AddStringToObject(dns_rr_object, "salt_value", salt_value);
|
||||
cJSON_AddStringToObject(dns_rr_object, "next_hash_owner", tmp_buf);
|
||||
cJSON_AddStringToObject(dns_rr_object, "type_bit_maps", maps);
|
||||
break;
|
||||
case DNS_TYPE_NSEC3PARAM:
|
||||
len = 0;
|
||||
assert(dns_rr->rdata.nsec3param.salt_len * 2 < sizeof(tmp_buf));
|
||||
for (j = 0; j < (int)(dns_rr->rdata.nsec3param.salt_len); j++)
|
||||
{
|
||||
len += snprintf(tmp_buf + len, sizeof(tmp_buf) - len, "%02x", dns_rr->rdata.nsec3param.salt_value[j]);
|
||||
}
|
||||
|
||||
used_len += snprintf(buf + used_len, buflen - used_len,
|
||||
"[NSEC3PARAM hash_algo: %u, flags: %u, iteration: %u, salt_len: %u, salt_value: %s]\n",
|
||||
dns_rr->rdata.nsec3param.hash_algo, dns_rr->rdata.nsec3param.flags,
|
||||
dns_rr->rdata.nsec3param.iteration, dns_rr->rdata.nsec3param.salt_len,
|
||||
tmp_buf);
|
||||
|
||||
cJSON_AddNumberToObject(dns_rr_object, "hash_algo", dns_rr->rdata.nsec3param.hash_algo);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "flags", dns_rr->rdata.nsec3param.flags);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "iteration", dns_rr->rdata.nsec3param.iteration);
|
||||
cJSON_AddNumberToObject(dns_rr_object, "salt_len", dns_rr->rdata.nsec3param.salt_len);
|
||||
cJSON_AddStringToObject(dns_rr_object, "salt_value", tmp_buf);
|
||||
break;
|
||||
case DNS_TYPE_UNKNOWN:
|
||||
used_len += snprintf(buf + used_len, buflen - used_len, "[data: %s]\n", dns_rr->rdata.unknown_data);
|
||||
cJSON_AddStringToObject(dns_rr_object, "data", (const char *)(dns_rr->rdata.unknown_data));
|
||||
break;
|
||||
case DNS_QTYPE_AXFR:
|
||||
continue;
|
||||
break;
|
||||
case DNS_QTYPE_MAILB:
|
||||
continue;
|
||||
break;
|
||||
case DNS_QTYPE_MAILA:
|
||||
continue;
|
||||
break;
|
||||
case DNS_QTYPE_ANY:
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
fwrite(buf, used_len, 1, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
|
||||
//char *question_array=cJSON_Print(dns_info_object);
|
||||
//char *rr_array=cJSON_Print(dns_info_object);
|
||||
|
||||
//cJSON_AddArrayToObject(dns_info_object, question_array);
|
||||
//cJSON_AddArrayToObject(dns_info_object, rr_array);
|
||||
|
||||
char *outout1 = cJSON_PrintUnformatted(dns_info_object);
|
||||
char *outout2 = cJSON_Print(dns_info_object);
|
||||
|
||||
printf("%s\n", outout1);
|
||||
printf("%s\n", outout2);
|
||||
free(outout1);
|
||||
free(outout2);
|
||||
cJSON_Delete(dns_info_object);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void util_dump_dns(const char *data, int len, int is_req)
|
||||
{
|
||||
int en_len;
|
||||
int de_len;
|
||||
int out_len;
|
||||
char en_buff[102400] = {0};
|
||||
char de_buff[102400] = {0};
|
||||
char out_buff[102400 * 2] = {0};
|
||||
|
||||
en_len = base64_encode(en_buff, sizeof(en_buff), data, len);
|
||||
if (en_len == MS_ERROR)
|
||||
{
|
||||
ERROR("base64_encode() failed\n");
|
||||
}
|
||||
|
||||
de_len = base64_decode(de_buff, sizeof(de_buff), en_buff, en_len);
|
||||
if (de_len == MS_ERROR)
|
||||
{
|
||||
ERROR("base64_encode() failed\n");
|
||||
}
|
||||
|
||||
if (de_len != len || strncmp(data, de_buff, de_len) != 0)
|
||||
{
|
||||
ERROR("base64_encode() != base64_decode()\n");
|
||||
}
|
||||
|
||||
FILE *fp = fopen("dns_test_base64.log", "a+");
|
||||
if (fp == NULL)
|
||||
{
|
||||
ERROR("fopen() failed\n");
|
||||
}
|
||||
out_len = snprintf(out_buff, sizeof(out_buff), "dir:%s len:%04d, data:%s\n", is_req ? "req" : "rsp", en_len, en_buff);
|
||||
printf("%s", out_buff);
|
||||
fwrite(out_buff, out_len, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static int util_proxy_dns(char *req_buff, int req_len, char *rsp_buff, int rsp_size)
|
||||
{
|
||||
int ret;
|
||||
int clientfd;
|
||||
struct sockaddr_in saddr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
clientfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (clientfd == -1)
|
||||
{
|
||||
ERROR("socket() failed\n");
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = PF_INET;
|
||||
saddr.sin_port = htons(53);
|
||||
saddr.sin_addr.s_addr = inet_addr("114.114.114.114");
|
||||
|
||||
ret = sendto(clientfd, req_buff, req_len, 0, (struct sockaddr *)&saddr, addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("sendto() failed\n");
|
||||
}
|
||||
|
||||
ret = recvfrom(clientfd, rsp_buff, rsp_size, 0, (struct sockaddr *)&saddr, &addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("recvfrom() failed\n");
|
||||
}
|
||||
|
||||
close(clientfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int util_parser_dns(const char *buff, int len, char *out_buff, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dns_info_t *parser = dns_new();
|
||||
dns_info_t *package = dns_new();
|
||||
assert(parser);
|
||||
assert(package);
|
||||
|
||||
// buff to struct
|
||||
ret = dns_parser(parser, (char *)buff, len);
|
||||
if (ret == -1)
|
||||
{
|
||||
ERROR("dns_parser() failed\n");
|
||||
}
|
||||
|
||||
// struct to buff
|
||||
ret = dns_package(parser, out_buff, size);
|
||||
if (ret == -1)
|
||||
{
|
||||
ERROR("dns_package() failed\n");
|
||||
}
|
||||
|
||||
if (dns_parser(package, out_buff, ret) == -1)
|
||||
{
|
||||
ERROR("dns_parser() failed\n");
|
||||
}
|
||||
|
||||
printf("dns first parser\n");
|
||||
dns_print(parser, "./dns_test_parser1.log");
|
||||
printf("dns second parser\n");
|
||||
dns_print(package, "./dns_test_parser2.log");
|
||||
|
||||
if (len != ret || strncmp(buff, out_buff, len) != 0)
|
||||
{
|
||||
printf("==================================\n"
|
||||
"first parser != second parser\n"
|
||||
"==================================\n");
|
||||
}
|
||||
|
||||
dns_free(parser);
|
||||
dns_free(package);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_as_dns_proxy_not_cheat_respone(void)
|
||||
{
|
||||
int len;
|
||||
int ret;
|
||||
int listenfd = -1;
|
||||
int reuseaddr = 1;
|
||||
char req_buff[10240];
|
||||
char rsp_buff[10240];
|
||||
char req_pacakge[10240];
|
||||
char rsp_package[10240];
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
struct sockaddr_in caddr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (listenfd == -1)
|
||||
{
|
||||
ERROR("socket() failed\n");
|
||||
}
|
||||
|
||||
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1)
|
||||
{
|
||||
ERROR("setsockopt() failed\n");
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = PF_INET;
|
||||
saddr.sin_port = htons(53);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(listenfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
ERROR("bind() failed\n");
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
memset(req_buff, 0, sizeof(req_buff));
|
||||
memset(rsp_buff, 0, sizeof(rsp_buff));
|
||||
ret = recvfrom(listenfd, req_buff, sizeof(req_buff), 0, (struct sockaddr *)&caddr, &addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("recvfrom() failed\n");
|
||||
}
|
||||
|
||||
// DNS 请求包 dump
|
||||
util_dump_dns(req_buff, ret, 1);
|
||||
|
||||
// DNS 请求包 解析/封装 测试
|
||||
printf("============ parser req ============\n");
|
||||
len = util_parser_dns(req_buff, ret, req_pacakge, sizeof(req_pacakge));
|
||||
|
||||
ret = util_proxy_dns(req_buff, ret, rsp_buff, sizeof(rsp_buff));
|
||||
|
||||
// DNS 响应包 dump
|
||||
util_dump_dns(rsp_buff, ret, 0);
|
||||
|
||||
// DNS 响应包 解析/封装 测试
|
||||
printf("============ parser rsp ============\n");
|
||||
len = util_parser_dns(rsp_buff, ret, rsp_package, sizeof(rsp_package));
|
||||
|
||||
ret = sendto(listenfd, rsp_package, len, 0, (struct sockaddr *)&caddr, addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("sendto() failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_as_dns_proxy_but_cheat_respone(void)
|
||||
{
|
||||
int ret;
|
||||
int listenfd = -1;
|
||||
int reuseaddr = 1;
|
||||
char req_buff[10240];
|
||||
char rsp_buff[10240];
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
struct sockaddr_in caddr;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
listenfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (listenfd == -1)
|
||||
{
|
||||
ERROR("socket() failed\n");
|
||||
}
|
||||
|
||||
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1)
|
||||
{
|
||||
ERROR("setsockopt() failed\n");
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = PF_INET;
|
||||
saddr.sin_port = htons(53);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(listenfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
ERROR("bind() failed\n");
|
||||
}
|
||||
|
||||
cheat_pkt_opt_t cheat_opt[32];
|
||||
memset(cheat_opt, 0, sizeof(cheat_opt));
|
||||
|
||||
// DNS_TYPE_A
|
||||
cheat_opt[0].res_type = DNS_TYPE_A;
|
||||
cheat_opt[0].ttl = 30;
|
||||
cheat_opt[0].res_len = 4;
|
||||
inet_pton(AF_INET, "192.168.1.1", cheat_opt[0].res_info);
|
||||
|
||||
// DNS_TYPE_AAAA
|
||||
cheat_opt[1].res_type = DNS_TYPE_AAAA;
|
||||
cheat_opt[1].ttl = 60;
|
||||
cheat_opt[1].res_len = 16;
|
||||
inet_pton(AF_INET6, "fe80::230:64ff:fe57:4a15", cheat_opt[1].res_info);
|
||||
|
||||
// DNS_TYPE_CNAME
|
||||
cheat_opt[2].res_type = DNS_TYPE_CNAME;
|
||||
cheat_opt[2].ttl = 90;
|
||||
cheat_opt[2].res_len = sizeof("www.cname1.com");
|
||||
memcpy(cheat_opt[2].res_info, "www.cname1.com", cheat_opt[2].res_len);
|
||||
|
||||
// DNS_TYPE_NS
|
||||
cheat_opt[3].res_type = DNS_TYPE_NS;
|
||||
cheat_opt[3].ttl = 90;
|
||||
cheat_opt[3].res_len = sizeof("www.ns.com");
|
||||
memcpy(cheat_opt[3].res_info, "www.ns.com", cheat_opt[3].res_len);
|
||||
|
||||
while (1)
|
||||
{
|
||||
memset(req_buff, 0, sizeof(req_buff));
|
||||
memset(rsp_buff, 0, sizeof(rsp_buff));
|
||||
ret = recvfrom(listenfd, req_buff, sizeof(req_buff), 0, (struct sockaddr *)&caddr, &addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("recvfrom() failed\n");
|
||||
}
|
||||
|
||||
// DNS 请求包 dump
|
||||
util_dump_dns(req_buff, ret, 1);
|
||||
|
||||
// 解析 DNS 请求包
|
||||
dns_info_t *parser = dns_new();
|
||||
assert(parser);
|
||||
ret = dns_parser(parser, req_buff, ret);
|
||||
if (ret == -1)
|
||||
{
|
||||
ERROR("dns_parser() failed\n");
|
||||
}
|
||||
|
||||
// 扫描策略
|
||||
|
||||
// 若命中策略,根据策略信息伪造 DNS 响应
|
||||
|
||||
// 伪造 DNS 响应包
|
||||
ret = dns_cheat_response(parser, cheat_opt, 4, rsp_buff, sizeof(rsp_buff));
|
||||
if (ret == -1)
|
||||
{
|
||||
ERROR("dns_cheat_response() failed\n");
|
||||
}
|
||||
dns_free(parser);
|
||||
|
||||
// DNS 响应包 dump
|
||||
util_dump_dns(rsp_buff, ret, 0);
|
||||
|
||||
ret = sendto(listenfd, rsp_buff, ret, 0, (struct sockaddr *)&caddr, addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERROR("sendto() failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_use_offline_package(void)
|
||||
{
|
||||
int i;
|
||||
int req_len;
|
||||
int rsp_len;
|
||||
char req_buff[102400] = {0};
|
||||
char rsp_buff[102400] = {0};
|
||||
char out_buff[102400 * 2] = {0};
|
||||
|
||||
for (i = 0; i < package_arry_size; i++)
|
||||
{
|
||||
printf("test[%d]: %s\n", i, package_arry[i].desc);
|
||||
req_len = base64_decode(req_buff, sizeof(req_buff), package_arry[i].req.data, package_arry[i].req.len);
|
||||
if (req_len == MS_ERROR)
|
||||
{
|
||||
ERROR("base64_encode() failed\n");
|
||||
}
|
||||
printf("============ parser req ============\n");
|
||||
util_parser_dns(req_buff, req_len, out_buff, sizeof(out_buff));
|
||||
|
||||
rsp_len = base64_decode(rsp_buff, sizeof(rsp_buff), package_arry[i].rsp.data, package_arry[i].rsp.len);
|
||||
if (rsp_len == MS_ERROR)
|
||||
{
|
||||
ERROR("base64_encode() failed\n");
|
||||
}
|
||||
printf("============ parser rsp ============\n");
|
||||
util_parser_dns(rsp_buff, rsp_len, out_buff, sizeof(out_buff));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_use_stdin_package(char *package)
|
||||
{
|
||||
int req_len;
|
||||
char req_buff[102400] = {0};
|
||||
char out_buff[102400 * 2] = {0};
|
||||
|
||||
req_len = base64_decode(req_buff, sizeof(req_buff), package, strlen(package));
|
||||
if (req_len == MS_ERROR)
|
||||
{
|
||||
ERROR("base64_encode() failed\n");
|
||||
}
|
||||
util_parser_dns(req_buff, req_len, out_buff, sizeof(out_buff));
|
||||
}
|
||||
|
||||
static void usage(char *name)
|
||||
{
|
||||
printf("Usage: %s [option]\n"
|
||||
" -p : test as dns proxy not cheat respone (dig @127.0.0.1 www.baidu.com a) dump data in base64\n"
|
||||
" -c : test as dns proxy but cheat respone (dig @127.0.0.1 www.baidu.com a) dump data in base64\n"
|
||||
"\n"
|
||||
" -o : test use offline dns package\n"
|
||||
" -b ${base64_pack} : test use stdin dns package\n",
|
||||
name);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2 && argc != 3)
|
||||
{
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
if (argc == 2 && (strncmp(argv[1], "-o", 2) != 0 && strncmp(argv[1], "-p", 2) != 0 && strncmp(argv[1], "-c", 2) != 0))
|
||||
{
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (argc == 3 && strncmp(argv[1], "-b", 2) != 0)
|
||||
{
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
if (strncmp(argv[1], "-p", 2) == 0)
|
||||
{
|
||||
test_as_dns_proxy_not_cheat_respone();
|
||||
}
|
||||
else if (strncmp(argv[1], "-c", 2) == 0)
|
||||
{
|
||||
test_as_dns_proxy_but_cheat_respone();
|
||||
}
|
||||
else if (strncmp(argv[1], "-o", 2) == 0)
|
||||
{
|
||||
test_use_offline_package();
|
||||
}
|
||||
else if (strncmp(argv[1], "-b", 2) == 0)
|
||||
{
|
||||
test_use_stdin_package(argv[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_http.h>
|
||||
#include <tfe_plugin.h>
|
||||
#include <tfe_resource.h>
|
||||
|
||||
#include <MESA/Maat_rule.h>
|
||||
#include <MESA/MESA_handle_logger.h>
|
||||
@@ -182,116 +183,6 @@ struct pangu_rt
|
||||
};
|
||||
struct pangu_rt * g_pangu_rt;
|
||||
|
||||
Maat_feather_t g_business_maat;
|
||||
|
||||
|
||||
#define MAAT_INPUT_JSON 0
|
||||
#define MAAT_INPUT_REDIS 1
|
||||
#define MAAT_INPUT_FILE 2
|
||||
|
||||
static Maat_feather_t create_maat_feather(const char * instance_name, const char * profile, const char * section, int max_thread, void * logger)
|
||||
{
|
||||
Maat_feather_t target;
|
||||
int input_mode = 0, maat_stat_on = 0, maat_perf_on = 0;
|
||||
int ret = 0, scan_detail = 0, effect_interval = 60;
|
||||
char table_info[TFE_STRING_MAX] = {0}, inc_cfg_dir[TFE_STRING_MAX] = {0}, ful_cfg_dir[TFE_STRING_MAX] = {0};
|
||||
char redis_server[TFE_STRING_MAX] = {0};
|
||||
char redis_port_range[TFE_STRING_MAX] = {0};
|
||||
char accept_tags[TFE_STRING_MAX] = {0};
|
||||
int redis_port_begin=0, redis_port_end=0;
|
||||
int redis_port_select=0, deferred_load_on=0;
|
||||
int redis_db_idx = 0;
|
||||
char json_cfg_file[TFE_STRING_MAX] = {0}, maat_stat_file[TFE_STRING_MAX] = {0};
|
||||
MESA_load_profile_int_def(profile, section, "maat_input_mode", &(input_mode), 0);
|
||||
MESA_load_profile_int_def(profile, section, "stat_switch", &(maat_stat_on), 1);
|
||||
MESA_load_profile_int_def(profile, section, "perf_switch", &(maat_perf_on), 1);
|
||||
|
||||
MESA_load_profile_string_def(profile, section, "table_info", table_info, sizeof(table_info), "");
|
||||
MESA_load_profile_string_def(profile, section, "accept_tags", accept_tags, sizeof(accept_tags), "");
|
||||
|
||||
MESA_load_profile_string_def(profile, section, "json_cfg_file", json_cfg_file, sizeof(json_cfg_file), "");
|
||||
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_server", redis_server, sizeof(redis_server), "");
|
||||
MESA_load_profile_string_def(profile, section, "maat_redis_port_range", redis_port_range, sizeof(redis_server), "6379");
|
||||
ret=sscanf(redis_port_range,"%d-%d", &redis_port_begin, &redis_port_end);
|
||||
if(ret==1)
|
||||
{
|
||||
redis_port_select=redis_port_begin;
|
||||
}
|
||||
else if(ret==2)
|
||||
{
|
||||
srand(time(NULL));
|
||||
redis_port_select=redis_port_begin+rand()%(redis_port_end-redis_port_begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "Invalid redis port range %s, MAAT init failed.", redis_port_range);
|
||||
}
|
||||
MESA_load_profile_int_def(profile, section, "maat_redis_db_index", &(redis_db_idx), 0);
|
||||
|
||||
MESA_load_profile_string_def(profile, section, "inc_cfg_dir", inc_cfg_dir, sizeof(inc_cfg_dir), "");
|
||||
MESA_load_profile_string_def(profile, section, "full_cfg_dir", ful_cfg_dir, sizeof(ful_cfg_dir), "");
|
||||
|
||||
MESA_load_profile_string_def(profile, section, "stat_file", maat_stat_file, sizeof(maat_stat_file), "");
|
||||
MESA_load_profile_int_def(profile, section, "effect_interval_s", &(effect_interval), 60);
|
||||
MESA_load_profile_int_def(profile, section, "deferred_load_on", &(deferred_load_on), 0);
|
||||
|
||||
effect_interval *= 1000;//convert s to ms
|
||||
assert(strlen(inc_cfg_dir) != 0 || strlen(ful_cfg_dir) != 0 || strlen(redis_server)!=0 || strlen(json_cfg_file)!=0);
|
||||
|
||||
target = Maat_feather(max_thread, table_info, logger);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INSTANCE_NAME, instance_name, strlen(instance_name) + 1);
|
||||
switch (input_mode)
|
||||
{
|
||||
case MAAT_INPUT_JSON:
|
||||
Maat_set_feather_opt(target, MAAT_OPT_JSON_FILE_PATH, json_cfg_file, strlen(json_cfg_file) + 1);
|
||||
break;
|
||||
case MAAT_INPUT_REDIS:
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_IP, redis_server, strlen(redis_server) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_PORT, &redis_port_select, sizeof(redis_port_select));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_REDIS_INDEX, &redis_db_idx, sizeof(redis_db_idx));
|
||||
break;
|
||||
case MAAT_INPUT_FILE: Maat_set_feather_opt(target, MAAT_OPT_FULL_CFG_DIR, ful_cfg_dir, strlen(ful_cfg_dir) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_INC_CFG_DIR, inc_cfg_dir, strlen(inc_cfg_dir) + 1);
|
||||
break;
|
||||
default: TFE_LOG_ERROR(logger, "Invalid MAAT Input Mode: %d.", input_mode);
|
||||
goto error_out;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_FOREIGN_CONT_DIR, "./pangu_files", strlen("./pangu_files")+1);
|
||||
if (maat_stat_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_FILE_PATH, maat_stat_file, strlen(maat_stat_file) + 1);
|
||||
Maat_set_feather_opt(target, MAAT_OPT_STAT_ON, NULL, 0);
|
||||
if (maat_perf_on)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_PERF_ON, NULL, 0);
|
||||
}
|
||||
}
|
||||
Maat_set_feather_opt(target, MAAT_OPT_DEFERRED_LOAD, &deferred_load_on, sizeof(deferred_load_on));
|
||||
|
||||
Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval));
|
||||
Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail));
|
||||
if(strlen(accept_tags)>0)
|
||||
{
|
||||
Maat_set_feather_opt(target, MAAT_OPT_ACCEPT_TAGS, &accept_tags, sizeof(accept_tags));
|
||||
}
|
||||
|
||||
ret = Maat_initiate_feather(target);
|
||||
if (ret < 0)
|
||||
{
|
||||
TFE_LOG_ERROR(logger, "%s MAAT init failed.", __FUNCTION__);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return target;
|
||||
error_out:
|
||||
Maat_burn_feather(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pangu_http_gc_cb(evutil_socket_t fd, short what, void * arg)
|
||||
{
|
||||
int i=0;
|
||||
@@ -1095,12 +986,7 @@ int maat_ip_table_init(int profile_idx,
|
||||
int pangu_policy_init(const char* profile_path, const char* static_section, const char* dynamic_section)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
g_pangu_rt->maat = create_maat_feather("static", profile_path, static_section, g_pangu_rt->thread_num, g_pangu_rt->local_logger);
|
||||
if (!g_pangu_rt->maat)
|
||||
{
|
||||
goto error_out;
|
||||
}
|
||||
g_pangu_rt->maat = (Maat_feather_t)tfe_bussiness_resouce_get(STATIC_MAAT);
|
||||
|
||||
const char * table_name[__SCAN_TABLE_MAX];
|
||||
table_name[PXY_CTRL_IP] = "TSG_SECURITY_ADDR";
|
||||
@@ -1170,11 +1056,8 @@ int pangu_policy_init(const char* profile_path, const char* static_section, cons
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
g_pangu_rt->dyn_maat = create_maat_feather("dyn", profile_path, dynamic_section, g_pangu_rt->thread_num, g_pangu_rt->local_logger);
|
||||
if (!g_pangu_rt->maat)
|
||||
{
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
g_pangu_rt->dyn_maat = (Maat_feather_t)tfe_bussiness_resouce_get(DYNAMINC_MAAT);
|
||||
g_pangu_rt->subscriber_id_table_id=Maat_table_register(g_pangu_rt->dyn_maat, "TSG_DYN_SUBSCRIBER_IP");
|
||||
ret=Maat_plugin_EX_register(g_pangu_rt->dyn_maat,
|
||||
g_pangu_rt->subscriber_id_table_id,
|
||||
@@ -1304,7 +1187,6 @@ int pangu_http_init(struct tfe_proxy * proxy)
|
||||
TFE_LOG_INFO(NULL, "Tango Cache Enabled.");
|
||||
}
|
||||
TFE_LOG_INFO(NULL, "Pangu HTTP init success.");
|
||||
g_business_maat=g_pangu_rt->maat;
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
@@ -3078,7 +2960,7 @@ void pangu_on_http_end(const struct tfe_stream * stream,
|
||||
return;
|
||||
}
|
||||
|
||||
void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||
int pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, void ** pme)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = *(struct pangu_http_ctx **) pme;
|
||||
@@ -3090,7 +2972,7 @@ void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_
|
||||
{
|
||||
ctx->resumed_cb=NULL;
|
||||
}
|
||||
return;
|
||||
return NO_CALL_NEXT_PLUGIN;
|
||||
}
|
||||
|
||||
enforce_control_policy(stream, session, events, body_frag, frag_size,thread_id, ctx);
|
||||
@@ -3118,7 +3000,7 @@ void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_
|
||||
cache_write(session, events, body_frag, frag_size, thread_id, ctx);
|
||||
}
|
||||
}
|
||||
return;
|
||||
return NO_CALL_NEXT_PLUGIN;
|
||||
}
|
||||
|
||||
struct tfe_plugin pangu_http_spec = {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <cjson/cJSON.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <assert.h>
|
||||
extern Maat_feather_t g_business_maat;
|
||||
#include <tfe_resource.h>
|
||||
|
||||
struct ssl_policy_enforcer
|
||||
{
|
||||
@@ -378,7 +378,7 @@ error_out:
|
||||
struct ssl_policy_enforcer* ssl_policy_enforcer_create(void* logger)
|
||||
{
|
||||
struct ssl_policy_enforcer* enforcer=ALLOC(struct ssl_policy_enforcer, 1);
|
||||
enforcer->maat=g_business_maat;
|
||||
enforcer->maat=(Maat_feather_t)tfe_bussiness_resouce_get(STATIC_MAAT);;
|
||||
enforcer->logger=logger;
|
||||
enforcer->policy_table_id=Maat_table_register(enforcer->maat, "TSG_SECURITY_COMPILE");
|
||||
assert(enforcer->policy_table_id >= 0);
|
||||
|
||||
170
resource/pangu/doh.json
Normal file
170
resource/pangu/doh.json
Normal file
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"compile_table": "PXY_CTRL_COMPILE",
|
||||
"group_table": "GROUP_COMPILE_RELATION",
|
||||
"rules": [
|
||||
{
|
||||
"compile_id": 1021,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region": "{\"protocol\":\"http\",\"method\":\"redirect\",\"code\":302,\"to\":\"https://www.jd.com\"}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_url",
|
||||
"not_flag":0,
|
||||
"regions": [
|
||||
{
|
||||
"table_name": "TSG_OBJ_URL",
|
||||
"table_type": "string",
|
||||
"table_content": {
|
||||
"keywords": "baidu.com",
|
||||
"expr_type": "regex",
|
||||
"match_method": "sub",
|
||||
"format": "uncase plain"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"compile_id": 1022,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region": "{\"protocol\":\"http\",\"method\":\"redirect\",\"code\":302,\"to\":\"https://www.jd.com\"}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_url",
|
||||
"virtual_table":"TSG_FIELD_HTTP_URL",
|
||||
"not_flag":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"compile_id": 1023,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region": "{\"protocol\":\"http\",\"method\":\"replace\",\"rules\":[{\"search_in\":\"http_resp_body\",\"find\":\"邮箱\",\"replace_with\":\"test\"}]}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_fqdn",
|
||||
"not_flag":0,
|
||||
"regions": [
|
||||
{
|
||||
"table_name": "TSG_OBJ_FQDN",
|
||||
"table_type": "string",
|
||||
"table_content": {
|
||||
"keywords": "www.126.com",
|
||||
"expr_type": "regex",
|
||||
"match_method": "sub",
|
||||
"format": "uncase plain"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"compile_id": 1024,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region":"{\"protocol\":\"http\",\"method\":\"replace\",\"rules\":[{\"search_in\":\"http_resp_body\",\"find\":\"大师\",\"replace_with\":\"小小\"}]}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_fqdn",
|
||||
"virtual_table":"TSG_FIELD_HTTP_HOST",
|
||||
"not_flag":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"compile_id": 1025,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region": "{\"protocol\":\"DoH\",\"method\":\"redirect\",\"resolution\":[{\"qtype\":\"A\",\"answer\":[{\"atype\":\"CNAME\",\"value\":\"www.abc.com\",\"ttl\":{\"min\":60,\"max\":300}},{\"atype\":\"A\",\"value\":\"1.1.1.1\",\"ttl\":{\"min\":60,\"max\":300}}]},{\"qtype\":\"AAAA\",\"answer\":[{\"atype\":\"AAAA\",\"value\":\"aaaa:ffff:00\",\"ttl\":{\"min\":60,\"max\":300}},{\"atype\":\"CNAME\",\"value\":\"abc.com.cn\",\"ttl\":{\"min\":60,\"max\":300}}]}]}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_fqdn",
|
||||
"virtual_table":"TSG_FIELD_DOH_QNAME",
|
||||
"not_flag":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"compile_id": 1026,
|
||||
"service": 1,
|
||||
"action": 48,
|
||||
"do_blacklist": 1,
|
||||
"do_log": 1,
|
||||
"effective_range": 0,
|
||||
"user_region": "{\"protocol\":\"DoH\",\"method\":\"redirect\",\"resolution\":[{\"qtype\":\"A\",\"answer\":[{\"atype\":\"CNAME\",\"value\":\"www.a.shifen.com\",\"ttl\":{\"min\":10,\"max\":10}},{\"atype\":\"A\",\"value\":\"182.61.200.6\",\"ttl\":{\"min\":20,\"max\":30}},{\"atype\":\"A\",\"value\":\"182.61.200.7\",\"ttl\":{\"min\":60,\"max\":61}}]},{\"qtype\":\"AAAA\",\"answer\":[{\"atype\":\"CNAME\",\"value\":\"www.taobao.com.danuoyi.tbcache.com\",\"ttl\":{\"min\":100,\"max\":100}},{\"atype\":\"AAAA\",\"value\":\"2408:871a:2800:4:3::3fa\",\"ttl\":{\"min\":200,\"max\":300}},{\"atype\":\"AAAA\",\"value\":\"2408:871a:2800:2:3::3fa\",\"ttl\":{\"min\":600,\"max\":310}}]}]}",
|
||||
"is_valid": "yes",
|
||||
"groups": [
|
||||
{
|
||||
"group_name":"http_fqdn",
|
||||
"virtual_table":"TSG_FIELD_DOH_QNAME",
|
||||
"not_flag":0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"plugin_table": [
|
||||
{
|
||||
"table_name": "TSG_PROFILE_RESPONSE_PAGES",
|
||||
"table_content": [
|
||||
"101\t404\thtml\t./resource/pangu/policy_file/404.html\t1",
|
||||
"102\tHTTP403\ttemplate\t./resource/pangu/HTTP403.html\t1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table_name": "PXY_PROFILE_HIJACK_FILES",
|
||||
"table_content": [
|
||||
"201\tchakanqi\tchakanqi-947KB.exe\tapplication/x-msdos-program\t./resource/pangu/policy_file/chakanqi-947KB.exe\t1",
|
||||
"202\tWPS8648\tWPS8648-132M.exe\tapplication/x-msdos-program\t./resource/pangu/policy_file/WPS8648-132M.exe\t1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table_name": "PXY_PROFILE_INSERT_SCRIPTS",
|
||||
"table_content": [
|
||||
"301\ttime\tjs\t./resource/pangu/policy_file/time.js\tbefore_page_load\t1",
|
||||
"302\tu1\tcss\t./resource/pangu/policy_file/u1.css\tbefore_page_load\t1",
|
||||
"303\tu1\tjs\t./resource/pangu/policy_file/alert.js\tbefore_page_load\t1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table_name": "TSG_PROFILE_DECRYPTION",
|
||||
"table_content": [
|
||||
"0\ttest\t{\"dynamic_bypass\":{\"ev_cert\":0,\"cert_transparency\":0,\"mutual_authentication\":1,\"cert_pinning\":1,\"protocol_errors\":1,\"trusted_root_cert_is_not_installed_on_client\":1},\"protocol_version\":{\"min\":\"ssl3\",\"max\":\"ssl3\",\"mirror_client\":1,\"allow_http2\":1},\"certificate_checks\":{\"approach\":{\"cn\":1,\"issuer\":1,\"self-signed\":1,\"expiration\":0},\"fail_action\":\"pass-through\"}}\t1",
|
||||
"3\ttest\t{\"dynamic_bypass\":{\"ev_cert\":1,\"cert_transparency\":1,\"mutual_authentication\":1,\"cert_pinning\":1,\"protocol_errors\":1,\"trusted_root_cert_is_not_installed_on_client\":0},\"protocol_version\":{\"min\":\"ssl3\",\"max\":\"tls13\",\"mirror_client\":1,\"allow_http2\":1},\"certificate_checks\":{\"approach\":{\"cn\":1,\"issuer\":1,\"self-signed\":1,\"expiration\":1},\"fail_action\":\"fail-close\"}}\t1",
|
||||
"4\ttest\t{\"dynamic_bypass\":{\"ev_cert\":0,\"cert_transparency\":0,\"mutual_authentication\":0,\"cert_pinning\":0,\"protocol_errors\":0,\"trusted_root_cert_is_not_installed_on_client\":0},\"protocol_version\":{\"min\":\"ssl3\",\"max\":\"ssl3\",\"mirror_client\":0,\"allow_http2\":0},\"certificate_checks\":{\"approach\":{\"cn\":0,\"issuer\":0,\"self-signed\":0,\"expiration\":0},\"fail_action\":\"pass-through\"}}\t1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"table_name": "TSG_SECURITY_COMPILE",
|
||||
"table_content": [
|
||||
"0\t0\t2\t1\t1\t{}\t{\"protocol\":\"SSL\",\"keyring\":765,\"decryption\":0},\"decrypt_mirror\":{\"enable\":0}}\t1\t2",
|
||||
"656\t0\t2\t1\t1\t{}\t{\"protocol\":\"SSL\",\"keyring\":1,\"decryption\":0},\"decrypt_mirror\":{\"enable\":0}}\t1\t2",
|
||||
"49\t0\t2\t1\t1\t{}\t{\"protocol\":\"SSL\",\"keyring\":1,\"decryption\":0},\"decrypt_mirror\":{\"enable\":0}}\t1\t2"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -58,4 +58,5 @@
|
||||
38 TSG_OBJ_GEO_LOCATION expr UTF8 UTF8/GBK yes 0
|
||||
39 TSG_SECURITY_SOURCE_LOCATION virtual TSG_OBJ_GEO_LOCATION --
|
||||
40 TSG_SECURITY_DESTINATION_LOCATION virtual TSG_OBJ_GEO_LOCATION --
|
||||
|
||||
41 TSG_FIELD_DOH_QNAME virtual TSG_OBJ_FQDN --
|
||||
42 TSG_FIELD_DOH_HOST virtual TSG_OBJ_FQDN --
|
||||
|
||||
Reference in New Issue
Block a user