diff --git a/CMakeLists.txt b/CMakeLists.txt index e6067c3..7c0d8a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ 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) +option(ENABLE_PLUGIN_TCP_POLICY "Enable TCP policy support" TRUE) if(ENABLE_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE 1) diff --git a/common/include/raw_socket.h b/common/include/raw_socket.h index 7e924e8..337197b 100644 --- a/common/include/raw_socket.h +++ b/common/include/raw_socket.h @@ -14,7 +14,7 @@ extern "C" struct raw_socket { int sockfd; - char interface[64]; + char interface[16]; struct ether_addr mac_addr; struct sockaddr_ll sockaddr; }; diff --git a/common/include/ssl_stream.h b/common/include/ssl_stream.h index 3fc9957..1781e20 100644 --- a/common/include/ssl_stream.h +++ b/common/include/ssl_stream.h @@ -13,7 +13,6 @@ typedef enum ssl_stream_action ssl_stream_new_hook(struct ssl_stream *upstream, enum SSL_STREAM_OPT { - SSL_STREAM_OPT_INTERCEPT_POLICY_ID, SSL_STREAM_OPT_IS_EV_CERT, //0:FALSE, 1:TRUE. SSL_STREAM_OPT_IS_CT_CERT, //0:FALSE, 1:TRUE. SSL_STREAM_OPT_IS_MUTUAL_AUTH, //0:FALSE, 1:TRUE. @@ -47,6 +46,7 @@ int ssl_stream_get_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT int ssl_stream_get_string_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT opt_type, char* in_buff, size_t sz); void ssl_stream_set_cmsg_string(struct ssl_stream *stream, enum tfe_cmsg_tlv_type type, const char *value_str); +uint64_t ssl_stream_get_policy_id(struct ssl_stream *upstream); unsigned int is_ssl_debug(); diff --git a/common/include/tfe_cmsg.h b/common/include/tfe_cmsg.h index 5d60191..26273a7 100644 --- a/common/include/tfe_cmsg.h +++ b/common/include/tfe_cmsg.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct tfe_cmsg; struct tfe_cmsg_serialize_header; @@ -33,7 +34,7 @@ enum tfe_cmsg_tlv_type TFE_CMSG_TCP_RESTORE_TS_CLIENT_VAL = 0xe, TFE_CMSG_TCP_RESTORE_TS_SERVER_VAL = 0xf, - TFE_CMSG_POLICY_ID = 0x10, + TFE_CMSG_POLICY_ID = 0x10, // size uint64_t TFE_CMSG_STREAM_TRACE_ID = 0x11, TFE_CMSG_SSL_INTERCEPT_STATE, //size uint64_t, 0-passthrough, 1-intercept, 2-shutdown, referer from enum ssl_stream_action @@ -50,6 +51,8 @@ enum tfe_cmsg_tlv_type TFE_CMSG_DST_MAC, /* TCP option information */ + TFE_CMSG_DOWNSTREAM_TCP_MSS_ENABLE, + TFE_CMSG_DOWNSTREAM_TCP_MSS_VALUE, TFE_CMSG_DOWNSTREAM_TCP_NODELAY, TFE_CMSG_DOWNSTREAM_TCP_TTL, TFE_CMSG_DOWNSTREAM_TCP_KEEPALIVE, @@ -58,6 +61,8 @@ enum tfe_cmsg_tlv_type TFE_CMSG_DOWNSTREAM_TCP_KEEPINTVL, TFE_CMSG_DOWNSTREAM_TCP_USER_TIMEOUT, + TFE_CMSG_UPSTREAM_TCP_MSS_ENABLE, + TFE_CMSG_UPSTREAM_TCP_MSS_VALUE, TFE_CMSG_UPSTREAM_TCP_NODELAY, TFE_CMSG_UPSTREAM_TCP_TTL, TFE_CMSG_UPSTREAM_TCP_KEEPALIVE, diff --git a/common/src/tfe_scan.cpp b/common/src/tfe_scan.cpp index 6cfde1a..4d2e585 100644 --- a/common/src/tfe_scan.cpp +++ b/common/src/tfe_scan.cpp @@ -128,7 +128,7 @@ int tfe_scan_ip_location(const struct tfe_stream *stream, long long *result, str int hit_cnt_ip = 0; size_t n_hit_result = 0; uint16_t opt_out_size; - char buff[TFE_STRING_MAX] = {0}; + char buff[TFE_STRING_MAX * 5] = {0}; char src_city[TFE_STRING_MAX] = {0}; char dst_city[TFE_STRING_MAX] = {0}; char src_provine[TFE_STRING_MAX] = {0}; @@ -255,7 +255,7 @@ int tfe_scan_ip_asn(const struct tfe_stream *stream, long long *result, struct m int hit_cnt_ip = 0; size_t n_hit_result = 0; uint16_t opt_out_size; - char buff[TFE_STRING_MAX] = {0}; + char buff[TFE_STRING_MAX * 5] = {0}; char src_asn[TFE_STRING_MAX] = {0}; char dst_asn[TFE_STRING_MAX] = {0}; char src_org[TFE_STRING_MAX] = {0}; diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index a065039..6622586 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -48,6 +48,10 @@ if(ENABLE_PLUGIN_SSL_POLICY) target_link_libraries(tfe -Wl,--whole-archive ssl-policy -Wl,--no-whole-archive) endif() +if(ENABLE_PLUGIN_TCP_POLICY) + target_link_libraries(tfe -Wl,--whole-archive tcp-policy -Wl,--no-whole-archive) +endif() + if(ENABLE_PLUGIN_TRAFFIC_MIRROR) target_link_libraries(tfe -Wl,--whole-archive traffic-mirror -Wl,--no-whole-archive) endif() diff --git a/platform/include/internal/proxy.h b/platform/include/internal/proxy.h index 12203b0..f45ba11 100644 --- a/platform/include/internal/proxy.h +++ b/platform/include/internal/proxy.h @@ -130,7 +130,8 @@ struct tfe_proxy struct tfe_plugin * modules; struct ssl_mgr * ssl_mgr_handler; - struct ssl_policy_enforcer* ssl_ply_enforcer; + struct tcp_policy_enforcer *tcp_ply_enforcer; + struct ssl_policy_enforcer *ssl_ply_enforcer; struct key_keeper * key_keeper_handler; unsigned int en_kni_v1_acceptor; diff --git a/platform/src/acceptor_kni_v3.cpp b/platform/src/acceptor_kni_v3.cpp index 61aa39c..004c2e8 100644 --- a/platform/src/acceptor_kni_v3.cpp +++ b/platform/src/acceptor_kni_v3.cpp @@ -18,6 +18,8 @@ #define TCP_RESTORE_TCPOPT_KIND 88 +extern void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id); + struct acceptor_kni_v3 { struct tfe_proxy *proxy; @@ -529,6 +531,51 @@ static int fake_tcp_handshake(struct tfe_proxy *proxy, struct tcp_restore_info * return 0; } +static int overwrite_tcp_mss(struct tfe_cmsg *cmsg, struct tcp_restore_info *restore) +{ + int ret = 0; + uint16_t size = 0; + int server_side_mss_enable = 0; + int server_side_mss_value = 0; + int client_side_mss_enable = 0; + int client_side_mss_value = 0; + + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_ENABLE, (unsigned char *)&client_side_mss_enable, sizeof(client_side_mss_enable), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at fetch client side tcp mss from cmsg: %s", strerror(-ret)); + return -1; + } + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_VALUE, (unsigned char *)&client_side_mss_value, sizeof(client_side_mss_value), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at fetch client side tcp mss value from cmsg: %s", strerror(-ret)); + return -1; + } + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_ENABLE, (unsigned char *)&server_side_mss_enable, sizeof(server_side_mss_enable), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at fetch server side tcp mss from cmsg: %s", strerror(-ret)); + return -1; + } + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_VALUE, (unsigned char *)&server_side_mss_value, sizeof(server_side_mss_value), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at fetch server side tcp mss value from cmsg: %s", strerror(-ret)); + return -1; + } + if (client_side_mss_enable) + { + restore->client.mss = client_side_mss_value; + } + if (server_side_mss_enable) + { + restore->server.mss = server_side_mss_value; + } + + return 0; +} + /* * nfmsg : message objetc that contains the packet * nfad : Netlink packet data handle @@ -555,6 +602,7 @@ static int payload_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, s struct tcp_restore_info restore_info; uint8_t stream_protocol_in_char = 0; uint16_t size = 0; + uint64_t rule_id = 0; struct acceptor_kni_v3 *__ctx = (struct acceptor_kni_v3 *)data; clock_gettime(CLOCK_MONOTONIC, &(__ctx->start)); memset(&pktinfo, 0, sizeof(pktinfo)); @@ -659,6 +707,25 @@ static int payload_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, s pktinfo.tcphdr->check = tfe_pkt_checksum_tcp_v6((void*)pktinfo.tcphdr, pktinfo.ip_totlen - pktinfo.iphdr_len, pktinfo.iphdr.v6->ip6_src, pktinfo.iphdr.v6->ip6_dst); } + if (tfe_cmsg_deserialize((const unsigned char *)restore_info.cmsg, restore_info.cmsg_len, &cmsg) < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at tfe_cmsg_deserialize()"); + goto end; + } + + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *)&rule_id, sizeof(rule_id), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at fetch rule_id from cmsg: %s", strerror(-ret)); + goto end; + } + tcp_policy_enforce(__ctx->proxy->tcp_ply_enforcer, cmsg, rule_id); + + if (overwrite_tcp_mss(cmsg, &restore_info)) + { + goto end; + } + tfe_tcp_restore_info_dump(&restore_info); // tcp repair C2S @@ -677,12 +744,6 @@ static int payload_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, s goto end; } - if (tfe_cmsg_deserialize((const unsigned char *)restore_info.cmsg, restore_info.cmsg_len, &cmsg) < 0) - { - TFE_LOG_ERROR(g_default_logger, "Failed at tfe_cmsg_deserialize()"); - goto end; - } - tfe_cmsg_get_value(cmsg, TFE_CMSG_TCP_RESTORE_PROTOCOL, (unsigned char *)&stream_protocol_in_char, sizeof(stream_protocol_in_char), &size); if (steering_device_is_available() && ( (STREAM_PROTO_PLAIN == (enum tfe_stream_proto)stream_protocol_in_char && __ctx->proxy->traffic_steering_options.enable_steering_http) || diff --git a/platform/src/proxy.cpp b/platform/src/proxy.cpp index 869a0bb..575bbbb 100644 --- a/platform/src/proxy.cpp +++ b/platform/src/proxy.cpp @@ -61,6 +61,7 @@ extern struct ssl_policy_enforcer* ssl_policy_enforcer_create(void* logger); extern enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_para); +extern struct tcp_policy_enforcer *tcp_policy_enforcer_create(void *logger); static int signals[] = {SIGHUP, SIGPIPE, SIGUSR1, SIGUSR2}; /* Global Resource */ @@ -165,17 +166,16 @@ int tfe_proxy_fds_accept(struct tfe_proxy *ctx, int fd_downstream, int fd_upstre uint8_t stream_protocol_in_char = 0; int tcp_passthrough = -1; uint16_t size = 0; + int result = 0; - int result = tfe_cmsg_get_value(cmsg, TFE_CMSG_TCP_RESTORE_PROTOCOL, (unsigned char *)&stream_protocol_in_char, - sizeof(stream_protocol_in_char), &size); - + result = tfe_cmsg_get_value(cmsg, TFE_CMSG_TCP_RESTORE_PROTOCOL, (unsigned char *)&stream_protocol_in_char, sizeof(stream_protocol_in_char), &size); if (unlikely(result < 0)) - { - TFE_LOG_ERROR(ctx->logger, "failed at fetch connection's protocol from cmsg: %s", strerror(-result)); - goto __errout; - } + { + TFE_LOG_ERROR(ctx->logger, "failed at fetch connection's protocol from cmsg: %s", strerror(-result)); + goto __errout; + } - stream_protocol = (enum tfe_stream_proto)stream_protocol_in_char; + stream_protocol = (enum tfe_stream_proto)stream_protocol_in_char; tfe_stream_option_set(stream, TFE_STREAM_OPT_SESSION_TYPE, &stream_protocol, sizeof(stream_protocol)); tfe_stream_cmsg_setup(stream, cmsg); @@ -697,7 +697,12 @@ int main(int argc, char * argv[]) TFE_LOG_INFO(g_default_logger, "Plugin %s initialized. ", plugin_iter->symbol); } - g_default_proxy->ssl_ply_enforcer=ssl_policy_enforcer_create(g_default_logger); + g_default_proxy->tcp_ply_enforcer = tcp_policy_enforcer_create(g_default_logger); + CHECK_OR_EXIT(g_default_proxy->tcp_ply_enforcer == NULL, "Failed at creating tcp policy enforcer. Exit."); + + g_default_proxy->ssl_ply_enforcer = ssl_policy_enforcer_create(g_default_logger); + CHECK_OR_EXIT(g_default_proxy->ssl_ply_enforcer == NULL, "Failed at creating ssl policy enforcer. Exit."); + 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); CHECK_OR_EXIT(ret == 0, "Failed at creating thread. Exit."); diff --git a/platform/src/ssl_stream.cpp b/platform/src/ssl_stream.cpp index f54f585..52c8e6d 100644 --- a/platform/src/ssl_stream.cpp +++ b/platform/src/ssl_stream.cpp @@ -2180,9 +2180,7 @@ int ssl_stream_set_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT int ssl_stream_get_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT opt_type, int *opt_val) { struct ssl_service_status* svc=&upstream->up_parts.svc_status; - struct tfe_cmsg *cmsg=NULL; UNUSED int ret=0; - uint16_t out_size=0; switch(opt_type) { case SSL_STREAM_OPT_IS_EV_CERT: @@ -2203,18 +2201,24 @@ int ssl_stream_get_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT case SSL_STREAM_OPT_HAS_PROTOCOL_ERRORS: *opt_val=svc->has_protocol_errors; break; - case SSL_STREAM_OPT_INTERCEPT_POLICY_ID: - cmsg=tfe_stream_get0_cmsg(upstream->tcp_stream); - ret=tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char*)opt_val, sizeof(*opt_val), &out_size); - assert(ret==0); - assert(out_size==sizeof(*opt_val)); - break; default: return -1; } return 0; } + +uint64_t ssl_stream_get_policy_id(struct ssl_stream *upstream) +{ + uint16_t out_size; + uint64_t policy_id = 0; + struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(upstream->tcp_stream); + int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *)policy_id, sizeof(policy_id), &out_size); + assert(ret == 0); + + return policy_id; +} + int ssl_stream_get_string_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT opt_type, char* in_buff, size_t sz) { const char* sni=upstream->up_parts.client_hello->sni?upstream->up_parts.client_hello->sni:"null"; diff --git a/plugin/business/CMakeLists.txt b/plugin/business/CMakeLists.txt index 5832980..4e67d00 100644 --- a/plugin/business/CMakeLists.txt +++ b/plugin/business/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(traffic-mirror) add_subdirectory(doh) add_subdirectory(tsg-http) add_subdirectory(ssl-policy) +add_subdirectory(tcp-policy) diff --git a/plugin/business/ssl-policy/src/ssl_policy.cpp b/plugin/business/ssl-policy/src/ssl_policy.cpp index e4299a2..140eebb 100644 --- a/plugin/business/ssl-policy/src/ssl_policy.cpp +++ b/plugin/business/ssl-policy/src/ssl_policy.cpp @@ -16,7 +16,7 @@ struct ssl_policy_enforcer }; struct intercept_param { - int policy_id; + uint64_t policy_id; int ref_cnt; int keyring_for_trusted; int keyring_for_untrusted; @@ -94,7 +94,7 @@ void intercept_param_new_cb(const char *table_name, int table_id, const char* ke } param=ALLOC(struct intercept_param, 1); - param->policy_id=atoi(key); + param->policy_id=atoll(key); param->ref_cnt=1; /* param->bypass_mutual_auth=1; @@ -118,7 +118,7 @@ void intercept_param_new_cb(const char *table_name, int table_id, const char* ke } else { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %d invalid keyring_for_trusted format", param->policy_id); + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_trusted format", param->policy_id); } } @@ -135,7 +135,7 @@ void intercept_param_new_cb(const char *table_name, int table_id, const char* ke } else { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %d invalid keyring_for_untrusted format", param->policy_id); + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_untrusted format", param->policy_id); } } @@ -152,11 +152,11 @@ void intercept_param_new_cb(const char *table_name, int table_id, const char* ke } else { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter:%d invalid decryption format", param->policy_id); + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid decryption format", param->policy_id); } } *ad=param; - TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %d", param->policy_id); + TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %lu", param->policy_id); error_out: cJSON_Delete(json); free(json_str); @@ -173,7 +173,7 @@ void intercept_param_free_cb(int table_id, void **ad, long argl, void* argp) if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) { - TFE_LOG_INFO(enforcer->logger, "Del intercept policy %d", param->policy_id);\ + TFE_LOG_INFO(enforcer->logger, "Del intercept policy %lu", param->policy_id); free(param); *ad=NULL; } @@ -351,17 +351,16 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p struct decryption_param *profile_param=NULL; enum ssl_stream_action action=SSL_ACTION_PASSTHROUGH; UNUSED int ret=0; - int policy_id=0; + uint64_t policy_id=0; char policy_id_str[16]={0}; char profile_id_str[16]={0}; char sni[512], addr_string[512]; - ret=ssl_stream_get_integer_opt(upstream, SSL_STREAM_OPT_INTERCEPT_POLICY_ID, &policy_id); - assert(ret==0); - snprintf(policy_id_str, sizeof(policy_id_str), "%d", policy_id); + policy_id = ssl_stream_get_policy_id(upstream); + snprintf(policy_id_str, sizeof(policy_id_str), "%lu", policy_id); policy_param=(struct intercept_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->policy_table_id, policy_id_str); if(policy_param==NULL) { - TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %d.", policy_id); + TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %lu.", policy_id); ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Invalid Intercept Param"); return SSL_ACTION_PASSTHROUGH; } @@ -369,7 +368,7 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p { ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_SNI, sni, sizeof(sni)); ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_ADDR, addr_string, sizeof(addr_string)); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy %d", addr_string, sni, policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy %lu", addr_string, sni, policy_id); } snprintf(profile_id_str, sizeof(profile_id_str), "%u", policy_param->decryption_profile_id); @@ -416,37 +415,37 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Not Installed"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to Certificate Not Installed", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Not Installed", addr_string, sni, policy_param->policy_id); } else if ((pinning_staus == 1 || ja3_pinning_status == JA3_PINNING_STATUS_IS_PINNING) && ja3_pinning_status != JA3_PINNING_STATUS_NOT_PINNING && profile_param->bypass_pinning) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Pinning"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to Certificate Pinning", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Pinning", addr_string, sni, policy_param->policy_id); } else if (is_mauth && profile_param->bypass_mutual_auth) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Mutual Authentication"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to Mutual Authentication", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Mutual Authentication", addr_string, sni, policy_param->policy_id); } else if (is_ev && profile_param->bypass_ev_cert) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "EV Certificate"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to EV Certificate", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to EV Certificate", addr_string, sni, policy_param->policy_id); } else if (is_ct && profile_param->bypass_ct_cert) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Transparency"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to Certificate Transparency", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Transparency", addr_string, sni, policy_param->policy_id); } else if (has_error && profile_param->bypass_protocol_errors) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Protocol Errors"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %d, action PASSTHROUGH due to Protocol Errors", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Protocol Errors", addr_string, sni, policy_param->policy_id); } else { diff --git a/plugin/business/tcp-policy/CMakeLists.txt b/plugin/business/tcp-policy/CMakeLists.txt new file mode 100644 index 0000000..ffd2578 --- /dev/null +++ b/plugin/business/tcp-policy/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(tcp-policy src/tcp_policy.cpp) +target_link_libraries(tcp-policy PUBLIC common) +target_link_libraries(tcp-policy PUBLIC cjson) +target_link_libraries(tcp-policy PUBLIC maatframe) \ No newline at end of file diff --git a/plugin/business/tcp-policy/src/tcp_policy.cpp b/plugin/business/tcp-policy/src/tcp_policy.cpp new file mode 100644 index 0000000..4152d5d --- /dev/null +++ b/plugin/business/tcp-policy/src/tcp_policy.cpp @@ -0,0 +1,400 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tcp_policy.h" + +struct tcp_policy_enforcer +{ + struct maat *maat; + int policy_table_id; + int profile_table_id; + void *logger; +}; + +struct side_conn_param +{ + int maxseg_enable; + int maxseg_vaule; + int nodelay; + int keepalive; + int keepcnt; + int keepidle; + int keepintvl; + int ttl; + int user_timeout; +}; + +struct tcp_profile_param +{ + int ref_cnt; + int tcp_passthrough; + int bypass_duplicated_packet; // TODO no use, need delete from CM + + struct side_conn_param client_side; + struct side_conn_param server_side; +}; + +struct intercept_param +{ + uint64_t rule_id; + int ref_cnt; + int tcp_option_profile; +}; + +static void intercept_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp) +{ + size_t offset = 0; + size_t len = 0; + char *json_str = NULL; + cJSON *json = NULL; + cJSON *item = NULL; + struct intercept_param *policy_param = NULL; + struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; + + if (maat_helper_read_column(table_line, 7, &offset, &len) < 0) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept user region: %s", table_line); + goto error_out; + } + + json_str = ALLOC(char, len + 1); + memcpy(json_str, table_line + offset, len); + json = cJSON_Parse(json_str); + if (json == NULL) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: id = %s", key); + goto error_out; + } + + item = cJSON_GetObjectItem(json, "tcp_option_profile"); + if (item == NULL || item->type != cJSON_Number) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %s invalid tcp_option_profile format", key); + goto error_out; + } + + policy_param = ALLOC(struct intercept_param, 1); + policy_param->rule_id = atoll(key); + policy_param->ref_cnt = 1; + policy_param->tcp_option_profile = item->valueint; + + *ad = policy_param; + TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %lu", policy_param->rule_id); + +error_out: + if (json) + { + cJSON_Delete(json); + } + if (json_str) + { + free(json_str); + } +} + +static void intercept_param_free_cb(int table_id, void **ad, long argl, void *argp) +{ + struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; + struct intercept_param *policy_param = (struct intercept_param *)*ad; + if (policy_param == NULL) + { + return; + } + + if ((__sync_sub_and_fetch(&policy_param->ref_cnt, 1) == 0)) + { + TFE_LOG_INFO(enforcer->logger, "Del intercept policy %lu", policy_param->rule_id); + free(policy_param); + *ad = NULL; + } +} + +static void intercept_param_free(struct intercept_param *policy_param) +{ + intercept_param_free_cb(0, (void **)&policy_param, 0, NULL); +} + +static void intercept_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) +{ + struct intercept_param *policy_param = (struct intercept_param *)*from; + if (policy_param) + { + __sync_add_and_fetch(&(policy_param->ref_cnt), 1); + *to = policy_param; + } + else + { + *to = NULL; + } +} + +static int parser_side_conn_param(const char *json_str, struct side_conn_param *out_val, void *logger) +{ + cJSON *json = NULL; + cJSON *object = NULL; + cJSON *item = NULL; + + json = cJSON_Parse(json_str); + if (json == NULL) + { + TFE_LOG_ERROR(logger, "Invalid tcp option param %s", json_str); + return -1; + } + + object = cJSON_GetObjectItem(json, "tcp_maxseg"); + if (object) + { + item = cJSON_GetObjectItem(object, "enable"); + if (item && item->type == cJSON_Number) + { + out_val->maxseg_enable = item->valueint; + } + item = cJSON_GetObjectItem(object, "maxseg"); + if (item && item->type == cJSON_Number) + { + out_val->maxseg_vaule = item->valueint; + } + } + + item = cJSON_GetObjectItem(json, "nodelay"); + if (item && item->type == cJSON_Number) + { + out_val->nodelay = item->valueint; + } + + object = cJSON_GetObjectItem(json, "keep_alive"); + if (object) + { + item = cJSON_GetObjectItem(object, "enable"); + if (item && item->type == cJSON_Number) + { + out_val->keepalive = item->valueint; + } + item = cJSON_GetObjectItem(object, "tcp_keepcnt"); + if (item && item->type == cJSON_Number) + { + out_val->keepcnt = item->valueint; + } + item = cJSON_GetObjectItem(object, "tcp_keepidle"); + if (item && item->type == cJSON_Number) + { + out_val->keepidle = item->valueint; + } + item = cJSON_GetObjectItem(object, "tcp_keepintvl"); + if (item && item->type == cJSON_Number) + { + out_val->keepintvl = item->valueint; + } + } + + item = cJSON_GetObjectItem(json, "ttl"); + if (item && item->type == cJSON_Number) + { + out_val->ttl = item->valueint; + } + + item = cJSON_GetObjectItem(json, "user_timeout"); + if (item && item->type == cJSON_Number) + { + out_val->user_timeout = item->valueint; + } + cJSON_Delete(json); + + return 0; +} + +static void profile_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp) +{ + int ret = 0; + int profile_id = 0; + int tcp_passthrough = 0; + int bypass_duplicated_packet = 0; + char client_side_conn_param[512] = {0}; + char server_side_conn_param[512] = {0}; + int is_valid = 0; + struct tcp_profile_param *profile_param = NULL; + struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; + + ret = sscanf(table_line, "%d\t%d\t%d\t%s\t%s\t%d", &profile_id, &tcp_passthrough, &bypass_duplicated_packet, client_side_conn_param, server_side_conn_param, &is_valid); + if (ret != 6) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid tcp option profile: %s", table_line); + goto error_out; + } + + profile_param = ALLOC(struct tcp_profile_param, 1); + profile_param->ref_cnt = 1; + profile_param->tcp_passthrough = tcp_passthrough; + profile_param->bypass_duplicated_packet = bypass_duplicated_packet; + + if (parser_side_conn_param(client_side_conn_param, &profile_param->client_side, enforcer->logger) == -1) + { + goto error_out; + } + + if (parser_side_conn_param(server_side_conn_param, &profile_param->server_side, enforcer->logger) == -1) + { + goto error_out; + } + + *ad = profile_param; + TFE_LOG_INFO(enforcer->logger, "Add tcp option profile: %s", key); + return; + +error_out: + if (profile_param) + { + free(profile_param); + } + return; +} + +static void profile_param_free_cb(int table_id, void **ad, long argl, void *argp) +{ + struct tcp_profile_param *profile_param = (struct tcp_profile_param *)*ad; + if (profile_param == NULL) + { + return; + } + + if ((__sync_sub_and_fetch(&profile_param->ref_cnt, 1) == 0)) + { + free(profile_param); + *ad = NULL; + } +} + +static void profile_param_free(struct tcp_profile_param *profile_param) +{ + profile_param_free_cb(0, (void **)&profile_param, 0, NULL); +} + +static void profile_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) +{ + struct tcp_profile_param *profile_param = (struct tcp_profile_param *)*from; + if (profile_param) + { + __sync_add_and_fetch(&(profile_param->ref_cnt), 1); + *to = profile_param; + } + else + { + *to = NULL; + } +} + +struct tcp_policy_enforcer *tcp_policy_enforcer_create(void *logger) +{ + int ret = 0; + struct tcp_policy_enforcer *enforcer = ALLOC(struct tcp_policy_enforcer, 1); + enforcer->maat = (struct maat *)tfe_bussiness_resouce_get(STATIC_MAAT); + enforcer->logger = logger; + enforcer->policy_table_id = maat_get_table_id(enforcer->maat, "TSG_SECURITY_COMPILE"); + if (enforcer->policy_table_id < 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register table of TSG_SECURITY_COMPILE, ret = %d", enforcer->policy_table_id); + goto error_out; + } + enforcer->profile_table_id = maat_get_table_id(enforcer->maat, "PXY_PROFILE_TCP_OPTION"); + if (enforcer->profile_table_id < 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register table of PXY_PROFILE_TCP_OPTION, ret = %d", enforcer->profile_table_id); + goto error_out; + } + + ret = maat_plugin_table_ex_schema_register(enforcer->maat, "TSG_SECURITY_COMPILE", + intercept_param_new_cb, + intercept_param_free_cb, + intercept_param_dup_cb, + 0, enforcer); + if (ret < 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register callback of TSG_SECURITY_COMPILE, ret = %d", ret); + goto error_out; + } + ret = maat_plugin_table_ex_schema_register(enforcer->maat, "PXY_PROFILE_TCP_OPTION", + profile_param_new_cb, + profile_param_free_cb, + profile_param_dup_cb, + 0, enforcer); + if (ret < 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register callback of PXY_PROFILE_TCP_OPTION, ret = %d", ret); + goto error_out; + } + return enforcer; + +error_out: + tcp_policy_enforcer_destory(enforcer); + return NULL; +} + +void tcp_policy_enforcer_destory(struct tcp_policy_enforcer *enforcer) +{ + if (enforcer) + { + free(enforcer); + enforcer = NULL; + } +} + +void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id) +{ + char rule_id_str[16] = {0}; + char profile_id_str[16] = {0}; + + snprintf(rule_id_str, sizeof(rule_id_str), "%lu", rule_id); + struct intercept_param *policy_param = (struct intercept_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->policy_table_id, rule_id_str); + if (policy_param == NULL) + { + TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %lu.", rule_id); + return; + } + + snprintf(profile_id_str, sizeof(profile_id_str), "%d", policy_param->tcp_option_profile); + struct tcp_profile_param *profile_param = (struct tcp_profile_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->profile_table_id, profile_id_str); + if (profile_param == NULL) + { + TFE_LOG_INFO(enforcer->logger, "Failed to get tcp option parameter of profile %lu.", rule_id); + intercept_param_free(policy_param); + return; + } + + tfe_cmsg_set(cmsg, TFE_CMSG_TCP_PASSTHROUGH, (unsigned char *)&profile_param->tcp_passthrough, sizeof(profile_param->tcp_passthrough)); + + struct side_conn_param *client_side = &profile_param->client_side; + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_ENABLE, (unsigned char *)&client_side->maxseg_enable, sizeof(client_side->maxseg_enable)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_VALUE, (unsigned char *)&client_side->maxseg_vaule, sizeof(client_side->maxseg_vaule)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_NODELAY, (unsigned char *)&client_side->nodelay, sizeof(client_side->nodelay)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_TTL, (unsigned char *)&client_side->ttl, sizeof(client_side->ttl)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_KEEPALIVE, (unsigned char *)&client_side->keepalive, sizeof(client_side->keepalive)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_KEEPCNT, (unsigned char *)&client_side->keepcnt, sizeof(client_side->keepcnt)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_KEEPIDLE, (unsigned char *)&client_side->keepidle, sizeof(client_side->keepidle)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_KEEPINTVL, (unsigned char *)&client_side->keepidle, sizeof(client_side->keepintvl)); + tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_USER_TIMEOUT, (unsigned char *)&client_side->user_timeout, sizeof(client_side->user_timeout)); + + struct side_conn_param *server_side = &profile_param->server_side; + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_ENABLE, (unsigned char *)&server_side->maxseg_enable, sizeof(server_side->maxseg_enable)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_VALUE, (unsigned char *)&server_side->maxseg_vaule, sizeof(server_side->maxseg_vaule)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_NODELAY, (unsigned char *)&server_side->nodelay, sizeof(server_side->nodelay)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_TTL, (unsigned char *)&server_side->ttl, sizeof(server_side->ttl)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_KEEPALIVE, (unsigned char *)&server_side->keepalive, sizeof(server_side->keepalive)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_KEEPCNT, (unsigned char *)&server_side->keepcnt, sizeof(server_side->keepcnt)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_KEEPIDLE, (unsigned char *)&server_side->keepidle, sizeof(server_side->keepidle)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_KEEPINTVL, (unsigned char *)&server_side->keepintvl, sizeof(server_side->keepintvl)); + tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_USER_TIMEOUT, (unsigned char *)&server_side->user_timeout, sizeof(server_side->user_timeout)); + + TFE_LOG_INFO(enforcer->logger, "hit rule_id %lu tcp_option_profile %d tcp_passthrough %d " + "client_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} " + "server_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} ", + rule_id, policy_param->tcp_option_profile, profile_param->tcp_passthrough, + client_side->maxseg_enable, client_side->maxseg_vaule, client_side->nodelay, client_side->ttl, client_side->keepalive, client_side->keepcnt, client_side->keepidle, client_side->keepidle, client_side->user_timeout, + server_side->maxseg_enable, server_side->maxseg_vaule, server_side->nodelay, server_side->ttl, server_side->keepalive, server_side->keepcnt, server_side->keepidle, server_side->keepidle, server_side->user_timeout); + profile_param_free(profile_param); + intercept_param_free(policy_param); +} \ No newline at end of file diff --git a/plugin/business/tcp-policy/src/tcp_policy.h b/plugin/business/tcp-policy/src/tcp_policy.h new file mode 100644 index 0000000..5b34a5f --- /dev/null +++ b/plugin/business/tcp-policy/src/tcp_policy.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include + +struct tcp_policy_enforcer; +struct tcp_policy_enforcer *tcp_policy_enforcer_create(void *logger); +void tcp_policy_enforcer_destory(struct tcp_policy_enforcer *enforcer); +void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id); \ No newline at end of file diff --git a/plugin/business/traffic-mirror/src/entry.cpp b/plugin/business/traffic-mirror/src/entry.cpp index 6d08632..de81065 100644 --- a/plugin/business/traffic-mirror/src/entry.cpp +++ b/plugin/business/traffic-mirror/src/entry.cpp @@ -540,7 +540,7 @@ int traffic_mirror_on_open_cb(const struct tfe_stream * stream, unsigned int thr char str_policy_id[TFE_SYMBOL_MAX] = {0}; char str_profile_id[TFE_SYMBOL_MAX] = {0}; - unsigned int opt_val; + uint64_t rule_id; uint16_t opt_out_size; struct policy_table_ex_data * policy_ex_data = NULL; @@ -549,14 +549,14 @@ int traffic_mirror_on_open_cb(const struct tfe_stream * stream, unsigned int thr struct ether_addr c_ether_addr = {}; struct ether_addr s_ether_addr = {}; - int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *) &opt_val, sizeof(opt_val), &opt_out_size); + int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *)&rule_id, sizeof(rule_id), &opt_out_size); if (ret < 0) { TFE_LOG_ERROR(instance->logger, "failed at getting policy id from cmsg, detach the stream."); goto detach; } - snprintf(str_policy_id, sizeof(str_policy_id), "%u", opt_val); + snprintf(str_policy_id, sizeof(str_policy_id), "%lu", rule_id); policy_ex_data = (struct policy_table_ex_data *)maat_plugin_table_get_ex_data(instance->maat_feather, instance->policy_table_id, str_policy_id); if (!policy_ex_data || !policy_ex_data->enable) { diff --git a/resource/pangu/table_info.conf b/resource/pangu/table_info.conf index 58d2e98..65b34d4 100644 --- a/resource/pangu/table_info.conf +++ b/resource/pangu/table_info.conf @@ -444,5 +444,15 @@ "key_type":"pointer", "foreign": [2] } + }, + { + "table_id":43, + "table_name":"PXY_PROFILE_TCP_OPTION", + "table_type":"plugin", + "valid_column":6, + "custom": { + "key":1, + "key_type":"pointer" + } } ] \ No newline at end of file