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:
luwenpeng
2020-06-11 17:57:18 +08:00
parent d761b0ea78
commit cd26e3e6c1
27 changed files with 4762 additions and 135 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View 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);

View File

@@ -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);

View File

@@ -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
View 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;
}

View File

@@ -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
View 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

View File

@@ -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()

View 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);

View File

@@ -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
View 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;
}

View File

@@ -1,3 +1,4 @@
add_subdirectory(traffic-mirror)
add_subdirectory(doh)
add_subdirectory(pangu-http)
add_subdirectory(ssl-policy)

View 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)

File diff suppressed because it is too large Load Diff

View 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

View 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)

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View File

@@ -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 = {

View File

@@ -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
View 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"
]
}
]
}

View File

@@ -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 --