diff --git a/common/include/kni_cmsg.h b/common/include/kni_cmsg.h index 3bb9d5e..aec6e3a 100644 --- a/common/include/kni_cmsg.h +++ b/common/include/kni_cmsg.h @@ -74,6 +74,8 @@ enum tfe_cmsg_tlv_type TFE_CMSG_DST_IP_LOCATION_PROVINE, // string max size 256 TFE_CMSG_SRC_IP_LOCATION_CITY, // string max size 256 TFE_CMSG_DST_IP_LOCATION_CITY, // string max size 256 + //ja3 fingerprint + TFE_CMSG_SSL_CLIENT_JA3_FINGERPRINT, //cmsg tlv max KNI_CMSG_TLV_NR_MAX, }; diff --git a/conf/kni/kni.conf b/conf/kni/kni.conf index 991b597..101a9f1 100644 --- a/conf/kni/kni.conf +++ b/conf/kni/kni.conf @@ -75,7 +75,11 @@ print_mode = 1 #self test Shunt rules security policy id [tsg_diagnose] enabled = 1 -security_policy_id = 3 +security_policy_id = 3,10 + + +[ssl_dynamic_bypass] +enabled = 1 #kni dynamic bypass [traceid2sslinfo_htable] diff --git a/entry/CMakeLists.txt b/entry/CMakeLists.txt index 34d3877..c43d5b4 100644 --- a/entry/CMakeLists.txt +++ b/entry/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(kni SHARED src/kni_entry.cpp src/tfe_mgr.cpp src/ssl_utils.cpp src/kni_tun.cpp src/kni_pxy_tcp_option.cpp) +add_library(kni SHARED src/kni_entry.cpp src/tfe_mgr.cpp src/kni_tun.cpp src/kni_pxy_tcp_option.cpp src/kni_dynamic_bypass.cpp) target_include_directories(kni PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(kni common MESA_prof_load MESA_htable MESA_field_stat maatframe mrzcpd dabloom) \ No newline at end of file diff --git a/entry/include/kni_dynamic_bypass.h b/entry/include/kni_dynamic_bypass.h new file mode 100644 index 0000000..c75bc0c --- /dev/null +++ b/entry/include/kni_dynamic_bypass.h @@ -0,0 +1,12 @@ +#pragma once +#ifndef __KNI_DYNAMIC_BYPASS_H__ +#define __KNI_DYNAMIC_BYPASS_H__ + +#include "kni_entry.h" + +int first_data_ssl_dynamic_bypass(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_info *pktinfo, int thread_seq); +void next_data_ssl_dynamic_bypass(struct pkt_info *pktinfo); +int ssl_dynamic_bypass_htable_add(struct pme_info *pmeinfo); +int ssl_dynamic_bypass_htable_init(const char *profile,void * local_logger); + +#endif diff --git a/entry/include/kni_entry.h b/entry/include/kni_entry.h index 7c47c0a..26a25fb 100644 --- a/entry/include/kni_entry.h +++ b/entry/include/kni_entry.h @@ -12,7 +12,6 @@ #define CALLER_SAPP 0 #define CALLER_TFE 1 -#define SSL_INFO_LEN 2048 #define _MAX_MAAT_TABLE_NAME_LEN 64 #define MAX_STRING_LEN 32 @@ -216,7 +215,8 @@ struct kni_handle{ char dst_mac_addr[6]; int tsg_diagnose_enable; int *arr_last_tfe_dispatch_index; - struct security_policy_shunt_tsg_diagnose secpolicyid_shunt_tsg_diagnose; + struct security_policy_shunt_tsg_diagnose secpolicyid_shunt_tsg_diagnose; + int ssl_dynamic_bypass_enable; MESA_htable_handle sslinfo2bypass_htable; int pxy_tcp_option_enable; //for proxy tcp option enable int pxy_tcp_option_enable_override; @@ -231,10 +231,7 @@ struct traceid2pme_search_cb_args{ void *logger; }; -struct dynamic_bypass_ssl_feature{ - char value[SSL_INFO_LEN]; - size_t vlen; -}; + #endif diff --git a/entry/include/ssl_utils.h b/entry/include/ssl_utils.h deleted file mode 100644 index 9f5592d..0000000 --- a/entry/include/ssl_utils.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -enum chello_parse_result -{ - CHELLO_PARSE_SUCCESS = 0, - CHELLO_PARSE_INVALID_FORMAT = -1, - CHELLO_PARSE_NOT_ENOUGH_BUFF = -2 -}; - -struct ssl_version -{ - uint8_t minor; - uint8_t major; - uint16_t ossl_format; -}; - -struct ssl_chello -{ - struct ssl_version min_version; - struct ssl_version max_version; - - char *sni; - char *alpn; - char *sign_algos; - uint16_t sign_algos_len; - char *supported_groups; - uint16_t supported_groups_len; - char *cipher_suites; - uint16_t cipher_suites_len; -}; -struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, enum chello_parse_result* result); - -void ssl_chello_free(struct ssl_chello* chello); - -void ssl_cipher_suites_to_name(const char *source, int source_len, char *result_common, size_t sz_common, char *result_tls13, size_t sz_tls13); - diff --git a/entry/src/kni_dynamic_bypass.cpp b/entry/src/kni_dynamic_bypass.cpp new file mode 100644 index 0000000..d98076a --- /dev/null +++ b/entry/src/kni_dynamic_bypass.cpp @@ -0,0 +1,368 @@ +#include "kni_dynamic_bypass.h" + +#define SSL_INFO_LEN 512 + +struct dynamic_bypass_ssl_feature{ + size_t vlen; + char value[SSL_INFO_LEN]; +}; + +extern struct kni_handle *g_kni_handle; +extern struct kni_field_stat_handle *g_kni_fs_handle; + +char * stream_addr_to_str(struct pme_info *pmeinfo,struct pkt_info *pktinfo) +{ + char * __str_ret = NULL; + if(pmeinfo==NULL || pktinfo == NULL) return NULL; + if (pmeinfo->addr_type == ADDR_TYPE_IPV4) + { + char __src_addr[INET_ADDRSTRLEN]; + char __dst_addr[INET_ADDRSTRLEN]; + uint16_t __src_port; + uint16_t __dst_port; + if(pktinfo->iphdr.v4->saddr < pktinfo->iphdr.v4->daddr){ + __src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source); + __dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest); + inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __src_addr, sizeof(__src_addr)); + inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __dst_addr, sizeof(__dst_addr)); + } + else + { + __src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest); + __dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source); + inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __src_addr, sizeof(__src_addr)); + inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __dst_addr, sizeof(__dst_addr)); + } + asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port); + } + + if (pmeinfo->addr_type == ADDR_TYPE_IPV6) + { + char __src_addr[INET6_ADDRSTRLEN]; + char __dst_addr[INET6_ADDRSTRLEN]; + uint16_t __src_port; + uint16_t __dst_port; + if(memcmp((void*)&(pktinfo->iphdr.v6->ip6_src), (void*)&(pktinfo->iphdr.v6->ip6_dst), IPV6_ADDR_LEN) < 0){ + __src_port = ntohs((uint16_t) pktinfo->tcphdr->source); + __dst_port = ntohs((uint16_t) pktinfo->tcphdr->dest); + memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__src_addr)); + memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__dst_addr)); + } + else + { + __src_port = ntohs((uint16_t) pktinfo->tcphdr->dest); + __dst_port = ntohs((uint16_t) pktinfo->tcphdr->source); + memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__src_addr)); + memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__dst_addr)); + } + asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port); + } + + return __str_ret; +} + +int stream_addr_str_split(char* addr_str, const char** sip, const char** sport, const char** dip, const char** dport) +{ + const char* seps=" "; + char* saveptr=NULL, *subtoken=NULL, *str=NULL; + int i=0; + for (str = addr_str, i=0; ; str = NULL, i++) + { + subtoken = strtok_r(str, seps, &saveptr); + if (subtoken == NULL) + break; + switch(i) + { + case 0: + if(sip!=NULL) *sip=subtoken; + break; + case 1: + if(sport!=NULL) *sport=subtoken; + break; + case 2: + if(dip!=NULL) *dip=subtoken; + break; + case 3: + if(dport!=NULL) *dport=subtoken; + break; + default: + return -1; + break; + } + } + return 0; + +} + +static long sslinfo2bypass_htable_search_cb(void *data, const uchar *key, uint size, void *user_args){ + if(data != NULL) + return 0; + else + return -1; +} + +static int sslinfo2bypass_htable_search(MESA_htable_handle htable,char *key, int klen, struct pme_info *pmeinfo) +{ + void *logger = g_kni_handle->local_logger; + long cb_ret = -1; + void *value; + value = MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, sslinfo2bypass_htable_search_cb, NULL, &cb_ret); + if(cb_ret == 0) + { + pmeinfo->ssl_pinningst = *((uint64_t *)value); + KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret); + } + else + { + KNI_LOG_DEBUG(logger, "MESA_htable:Search result value is null, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret); + } + return cb_ret; +} + +static int traceid2sslinfo_htable_add(char *key, uint klen, void * value,int thread_seq) +{ + void *logger = g_kni_handle->local_logger; + int ret; + MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[thread_seq].traceid2sslinfo_htable; + ret = MESA_htable_add(traceid2sslinfo_htable, (const unsigned char *)key, klen, (const void*)value); + if(ret >= 0) + { + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_ADD_SUCC], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, 1); + KNI_LOG_DEBUG(logger, "MESA_htable:Success to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq); + } + else + { + KNI_LOG_ERROR(logger, "MESA_htable:Fail to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq); + } + return ret; +} + + +static int sslinfo2bypass_htable_add(char *key, uint klen, void * value, void *logger) +{ + int ret = -1; + MESA_htable_handle sslinfo2bypass_htable = g_kni_handle->sslinfo2bypass_htable; + ret = MESA_htable_add(sslinfo2bypass_htable, (const unsigned char *)key, klen, (const void*)value); + if(ret < 0) + { + KNI_LOG_ERROR(logger, "MESA_htable: Failed at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret); + } + else + { + KNI_LOG_DEBUG(logger, "MESA_htable: Success at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_ADD_SUCC], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, 1); + + } + return ret; +} + +static long traceid2sslinfo_htable_search_cb(void *data, const uchar *key, uint size, void *user_args) +{ + struct dynamic_bypass_ssl_feature * ssl_feature = (struct dynamic_bypass_ssl_feature *)data; + void *logger = g_kni_handle->local_logger; + uint64_t * p_ssl_pinningst = (uint64_t *)user_args; + uint64_t *value = NULL; + long cb_ret = -1; + + if(ssl_feature != NULL) + { + value = ALLOC(uint64_t, 1); + *value = *p_ssl_pinningst; + if(sslinfo2bypass_htable_add(ssl_feature->value, ssl_feature->vlen, (void *)value, logger) < 0) + { + KNI_LOG_ERROR(logger, "Dynamic bypass, fail add to table = sslinfo2bypass_htable, key = %s, key_size = %d", + ssl_feature->value, ssl_feature->vlen); + } + cb_ret = 0; + } + return cb_ret; +} + + +static int traceid2sslinfo_htable_search(MESA_htable_handle htable,char *key, int klen, int thread_seq,uint64_t ssl_pinningst) +{ + long cb_ret = -1; + void *logger = g_kni_handle->local_logger; + MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, traceid2sslinfo_htable_search_cb, &ssl_pinningst, &cb_ret); + if(cb_ret >= 0) + { + KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", + thread_seq, key, klen,cb_ret); + } + else + { + KNI_LOG_ERROR(logger, "MESA_htable: Fail to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", + thread_seq, key, klen,cb_ret); + } + + return cb_ret; +} + +static void traceid2sslinfo_htable_data_free_cb(void *data){ + FREE(&data); +} + +static void sslinfo2bypass_htable_data_free_cb(void *data){ + FREE(&data); +} + +static int traceid2sslinfo_htable_expire_notify_cb(void *data, int eliminate_type) +{ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1); + return 1; +} + +static int sslinfo2bypass_htable_expire_notify_cb(void *data, int eliminate_type) +{ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_DEL_SUCC], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, -1); + return 1; +} + + + +static int get_ssl_conn_info(struct pme_info *pmeinfo,struct pkt_info *pktinfo, struct dynamic_bypass_ssl_feature *ssl_feature) +{ + void *logger = g_kni_handle->local_logger; + + const char *sip=NULL, *sport=NULL, *dip=NULL, *dport=NULL; + char *addr_str = NULL; + + if(pmeinfo->session_attribute_label->ja3_fingerprint == NULL) + { + KNI_LOG_DEBUG(logger, "Dynamic bypass:get stream label ja3_fingerprint is null, stream traceid = %s", pmeinfo->stream_traceid); + return 1; + } + + addr_str = stream_addr_to_str(pmeinfo,pktinfo); + stream_addr_str_split(addr_str, &sip, &sport, &dip, &dport); + + + ssl_feature->vlen = snprintf(ssl_feature->value, SSL_INFO_LEN, "%s:%s:%s", + pmeinfo->session_attribute_label->ja3_fingerprint,sip, + pmeinfo->domain_len > 0 ? (char*)&(pmeinfo->domain): dip); + + FREE(&addr_str); + return 0; +} + + +int first_data_ssl_dynamic_bypass(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_info *pktinfo, int thread_seq) +{ + struct dynamic_bypass_ssl_feature *ssl_feature = NULL; + void *logger = g_kni_handle->local_logger; + + int ret = -1; + if(pmeinfo->protocol != PROTO_SSL){ + KNI_LOG_DEBUG(logger, "Dynamic bypass: stream protocol is not ssl: stream traceid = %s, protocol = %d", pmeinfo->stream_traceid,pmeinfo->protocol); + return ret; + } + + ssl_feature = ALLOC(struct dynamic_bypass_ssl_feature,1); + if(get_ssl_conn_info(pmeinfo,pktinfo, ssl_feature) == 1){ + FREE(&ssl_feature); + return ret; + } + + KNI_LOG_DEBUG(logger, "Dynamic bypass: ssl_info: %s, ssl_info len:%d, stream traceid = %s", ssl_feature->value, ssl_feature->vlen, pmeinfo->stream_traceid); + + if(sslinfo2bypass_htable_search(g_kni_handle->sslinfo2bypass_htable,ssl_feature->value, ssl_feature->vlen,pmeinfo) == 0) + { + KNI_LOG_DEBUG(logger, "Dynamic bypass: passthrough ok, stream traceid = %s,ssl_pinningst = %d", pmeinfo->stream_traceid, pmeinfo->ssl_pinningst); + FREE(&ssl_feature); + ret = 0; + } + else + { + KNI_LOG_DEBUG(logger, "Dynamic bypass: not passthrough, stream traceid = %s", pmeinfo->stream_traceid); + if(traceid2sslinfo_htable_add(pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid),ssl_feature,thread_seq) >=0) + { + ret = 1; + } + else + { + FREE(&ssl_feature); + } + } + + return ret; +} + + +void next_data_ssl_dynamic_bypass(struct pkt_info *pktinfo) +{ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen); + +} + + +int ssl_dynamic_bypass_htable_add(struct pme_info *pmeinfo) +{ + void *logger = g_kni_handle->local_logger; + long cb_ret; + int ret = -1; + MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[pmeinfo->thread_seq].traceid2sslinfo_htable; + if(pmeinfo->ssl_intercept_state == 0) + { + cb_ret = traceid2sslinfo_htable_search(traceid2sslinfo_htable,pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), pmeinfo->thread_seq, pmeinfo->ssl_pinningst); + if(cb_ret >= 0) + { + cb_ret = MESA_htable_del(traceid2sslinfo_htable, (const unsigned char *)pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), NULL); + if(cb_ret < 0) + { + KNI_LOG_ERROR(logger, "Delete traceid2sslinfo_htable fail,key=%s",pmeinfo->stream_traceid); + } + else + { + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1); + } + ret = 0; + } + } + return ret; +} + + +int ssl_dynamic_bypass_htable_init(const char *profile,void *local_logger) +{ + struct kni_htable_opt opt; + MESA_htable_handle sslinfo2bypass_htable = NULL; + int ret = 0; + int ssl_dynamic_bypass_enable = 1; + + MESA_load_profile_int_def(profile, "ssl_dynamic_bypass", "enabled", &ssl_dynamic_bypass_enable, 1); + KNI_LOG_ERROR(local_logger, "Dynamic bypass: MESA_prof_load, [%s]:\n enabled: %d", "ssl_dynamic_bypass",ssl_dynamic_bypass_enable); + g_kni_handle->ssl_dynamic_bypass_enable = ssl_dynamic_bypass_enable; + + if(ssl_dynamic_bypass_enable == 1){ + //init traceid2sslinfo_htable + memset(&opt, 0, sizeof(opt)); + kni_get_htable_opt(&opt, profile, "traceid2sslinfo_htable", (void*)traceid2sslinfo_htable_data_free_cb, (void *)traceid2sslinfo_htable_expire_notify_cb, local_logger); + for(int i = 0; i < g_kni_handle->thread_count; i++){ + MESA_htable_handle traceid2sslinfo_htable = kni_create_htable((char*)"traceid2sslinfo_htable", &opt, local_logger); + if(traceid2sslinfo_htable == NULL){ + KNI_LOG_ERROR(local_logger, "Failed at kni_create_htable, table = traceid2sslinfo_htable"); + ret = -1; + return ret; + } + g_kni_handle->threads_handle[i].traceid2sslinfo_htable = traceid2sslinfo_htable; + } + + //init sslinfo2bypass_htable + memset(&opt, 0, sizeof(opt)); + kni_get_htable_opt(&opt, profile, "sslinfo2bypass_htable", (void*)sslinfo2bypass_htable_data_free_cb, (void *)sslinfo2bypass_htable_expire_notify_cb, local_logger); + sslinfo2bypass_htable = kni_create_htable((char*)"sslinfo2bypass_htable", &opt, local_logger); + if(sslinfo2bypass_htable == NULL){ + KNI_LOG_ERROR(local_logger, "Failed at create sslinfo2bypass_htable"); + ret = -2; + return ret; + } + g_kni_handle->sslinfo2bypass_htable = sslinfo2bypass_htable; + } + return ret; + +} diff --git a/entry/src/kni_entry.cpp b/entry/src/kni_entry.cpp index 0e3e1ba..d9184df 100644 --- a/entry/src/kni_entry.cpp +++ b/entry/src/kni_entry.cpp @@ -19,7 +19,6 @@ bypass: drome: pme_new_fail: destroy_pme #include "tfe_mgr.h" #include #include -#include "ssl_utils.h" #ifdef __cplusplus extern "C" { @@ -33,6 +32,7 @@ extern "C" { #include #include "kni_entry.h" #include "kni_pxy_tcp_option.h" +#include "kni_dynamic_bypass.h" struct kni_handle *g_kni_handle = NULL; struct kni_field_stat_handle *g_kni_fs_handle = NULL; @@ -351,6 +351,10 @@ static int session_attribute_cmsg_set(struct kni_cmsg *cmsg, struct pme_info *pm ret = wrapped_kni_cmsg_set(cmsg,TFE_CMSG_DST_IP_LOCATION_CITY, (const unsigned char*)session_attribute_label->server_location->city_full, strlen(session_attribute_label->server_location->city_full), pmeinfo); if(ret < 0) break; } + if(session_attribute_label->ja3_fingerprint == NULL) + ret = wrapped_kni_cmsg_set(cmsg,TFE_CMSG_SSL_CLIENT_JA3_FINGERPRINT, (const unsigned char*)empty_arr, strlen(empty_arr), pmeinfo); + else + ret = wrapped_kni_cmsg_set(cmsg,TFE_CMSG_SSL_CLIENT_JA3_FINGERPRINT, (const unsigned char*)session_attribute_label->ja3_fingerprint, strlen(session_attribute_label->ja3_fingerprint), pmeinfo); }while(0); return ret; } @@ -905,279 +909,9 @@ static int dabloom_add(struct pkt_info *pktinfo, int thread_seq){ return ret; } -int stream_addr_str_split(char* addr_str, const char** sip, const char** sport, const char** dip, const char** dport) -{ - const char* seps=" "; - char* saveptr=NULL, *subtoken=NULL, *str=NULL; - int i=0; - for (str = addr_str, i=0; ; str = NULL, i++) - { - subtoken = strtok_r(str, seps, &saveptr); - if (subtoken == NULL) - break; - switch(i) - { - case 0: - if(sip!=NULL) *sip=subtoken; - break; - case 1: - if(sport!=NULL) *sport=subtoken; - break; - case 2: - if(dip!=NULL) *dip=subtoken; - break; - case 3: - if(dport!=NULL) *dport=subtoken; - break; - default: - return -1; - break; - } - } - return 0; - -} -char * stream_addr_to_str(struct pme_info *pmeinfo,struct pkt_info *pktinfo) -{ - char * __str_ret = NULL; - if(pmeinfo==NULL || pktinfo == NULL) return NULL; - if (pmeinfo->addr_type == ADDR_TYPE_IPV4) - { - char __src_addr[INET_ADDRSTRLEN]; - char __dst_addr[INET_ADDRSTRLEN]; - uint16_t __src_port; - uint16_t __dst_port; - if(pktinfo->iphdr.v4->saddr < pktinfo->iphdr.v4->daddr){ - __src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source); - __dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest); - inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __src_addr, sizeof(__src_addr)); - inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __dst_addr, sizeof(__dst_addr)); - } - else - { - __src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest); - __dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source); - inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __src_addr, sizeof(__src_addr)); - inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __dst_addr, sizeof(__dst_addr)); - } - asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port); - } - - if (pmeinfo->addr_type == ADDR_TYPE_IPV6) - { - char __src_addr[INET6_ADDRSTRLEN]; - char __dst_addr[INET6_ADDRSTRLEN]; - uint16_t __src_port; - uint16_t __dst_port; - if(memcmp((void*)&(pktinfo->iphdr.v6->ip6_src), (void*)&(pktinfo->iphdr.v6->ip6_dst), IPV6_ADDR_LEN) < 0){ - __src_port = ntohs((uint16_t) pktinfo->tcphdr->source); - __dst_port = ntohs((uint16_t) pktinfo->tcphdr->dest); - memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__src_addr)); - memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__dst_addr)); - } - else - { - __src_port = ntohs((uint16_t) pktinfo->tcphdr->dest); - __dst_port = ntohs((uint16_t) pktinfo->tcphdr->source); - memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__src_addr)); - memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__dst_addr)); - } - asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port); - } - - return __str_ret; -} - - -static size_t ssl_svc_app_st_mk_key(struct ssl_chello* chello, struct pkt_info *pktinfo, struct pme_info *pmeinfo, char* key_buff, size_t sz) -{ - size_t key_len=0; - const char* sip=NULL, *sport=NULL, *dip=NULL, *dport=NULL; - char * addr_str= stream_addr_to_str(pmeinfo,pktinfo); - stream_addr_str_split(addr_str, &sip, &sport, &dip, &dport); - - key_len=snprintf(key_buff, sz, "%d:%d:%s:%s", chello->min_version.ossl_format, - chello->max_version.ossl_format, - chello->sni?chello->sni: dip , - chello->alpn?chello->alpn:"null"); - if(chello->cipher_suites && sz-key_len>chello->cipher_suites_len) - { - memcpy(key_buff+key_len, chello->cipher_suites, chello->cipher_suites_len); - key_len+=chello->cipher_suites_len; - } - if(chello->sign_algos && sz-key_len > chello->sign_algos_len) - { - memcpy(key_buff+key_len, chello->sign_algos, chello->sign_algos_len); - key_len+=chello->sign_algos_len; - } - if(chello->supported_groups && sz-key_len > chello->supported_groups_len) - { - memcpy(key_buff+key_len, chello->supported_groups, chello->supported_groups_len); - key_len+=chello->supported_groups_len; - } - free(addr_str); - return key_len; -} - - -static size_t ssl_svc_client_st_mk_key(struct ssl_chello* chello,struct pme_info *pmeinfo, struct pkt_info *pktinfo,char* key_buff, size_t sz) -{ - size_t key_len=0; - const char *sip=NULL, *sport=NULL, *dip=NULL, *dport=NULL; - char *addr_str = stream_addr_to_str(pmeinfo,pktinfo); - stream_addr_str_split(addr_str, &sip, &sport, &dip, &dport); - char chello_id_buff[sz]; - size_t chello_id_len=0; - - key_len=snprintf(key_buff, sz, "%s:", sip); - chello_id_len=ssl_svc_app_st_mk_key(chello, pktinfo,pmeinfo, chello_id_buff, sizeof(chello_id_buff)); - memcpy(key_buff+key_len, chello_id_buff, MIN(chello_id_len, sz-key_len)); - key_len += MIN(chello_id_len, sz-key_len); - - FREE(&addr_str); - return key_len; -} - -static struct ssl_chello * ssl_get_chello_info(struct streaminfo *stream) -{ - enum chello_parse_result chello_status = CHELLO_PARSE_INVALID_FORMAT; - struct ssl_chello *chello = NULL; - chello = ssl_chello_parse((unsigned char *)stream->ptcpdetail->pdata, (unsigned int)stream->ptcpdetail->datalen, &chello_status); - if(chello_status == CHELLO_PARSE_SUCCESS) - { - return chello; - } - else - { - if(chello) - ssl_chello_free(chello); - return NULL; - } -} - - -static long sslinfo2bypass_htable_search_cb(void *data, const uchar *key, uint size, void *user_args){ - if(data != NULL) - return 0; - else - return -1; -} - - -static int sslinfo2bypass_htable_search(MESA_htable_handle htable,char *key, int klen, struct pme_info *pmeinfo) -{ - void *logger = g_kni_handle->local_logger; - long cb_ret = -1; - void *value; - value = MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, sslinfo2bypass_htable_search_cb, NULL, &cb_ret); - if(cb_ret == 0) - { - pmeinfo->ssl_pinningst = *((uint64_t *)value); - KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret); - } - else - { - KNI_LOG_DEBUG(logger, "MESA_htable:Search result value is null, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret); - } - return cb_ret; -} - -static int traceid2sslinfo_htable_add(char *key, uint klen, void * value,int thread_seq) -{ - void *logger = g_kni_handle->local_logger; - int ret; - MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[thread_seq].traceid2sslinfo_htable; - ret = MESA_htable_add(traceid2sslinfo_htable, (const unsigned char *)key, klen, (const void*)value); - if(ret >= 0) - { - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_ADD_SUCC], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, 1); - KNI_LOG_DEBUG(logger, "MESA_htable:Success to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq); - } - else - { - KNI_LOG_ERROR(logger, "MESA_htable:Fail to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq); - } - return ret; -} - -static int first_data_ssl_dynamic_bypass(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_info *pktinfo, int thread_seq) -{ - struct dynamic_bypass_ssl_feature *ssl_feature = NULL; - struct ssl_chello *chello = NULL; - void *logger = g_kni_handle->local_logger; - - int ret = -1; - if(pmeinfo->protocol != PROTO_SSL) - { - KNI_LOG_DEBUG(logger, "Dynamic bypass: stream protocol is not ssl: stream traceid = %s, protocol = %d", pmeinfo->stream_traceid,pmeinfo->protocol); - return ret; - } - chello = ssl_get_chello_info(stream); - if(!chello) - { - KNI_LOG_ERROR(logger, "Dynamic bypass: fail to get ssl stream client hello info, stream traceid = %s", pmeinfo->stream_traceid); - return ret; - } - - - ssl_feature = ALLOC(struct dynamic_bypass_ssl_feature,1); - ssl_feature->vlen = ssl_svc_client_st_mk_key(chello, pmeinfo, pktinfo,ssl_feature->value,SSL_INFO_LEN); - - KNI_LOG_DEBUG(logger, "Dynamic bypass: chello info=%s, info len = %d", ssl_feature->value, ssl_feature->vlen); - ssl_chello_free(chello); - if(sslinfo2bypass_htable_search(g_kni_handle->sslinfo2bypass_htable,ssl_feature->value, ssl_feature->vlen,pmeinfo) == 0) - { - KNI_LOG_DEBUG(logger, "Dynamic bypass: passthrough ok, stream traceid = %s,ssl_pinningst = %d", pmeinfo->stream_traceid, pmeinfo->ssl_pinningst); - ret = 0; - } - else - { - KNI_LOG_DEBUG(logger, "Dynamic bypass: not passthrough, stream traceid = %s", pmeinfo->stream_traceid); - if(traceid2sslinfo_htable_add(pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid),ssl_feature,thread_seq) >=0) - { - ret = 1; - } - else - { - FREE(&ssl_feature); - } - } - if(ret == 0) - { - //dynamic bypass fs stat - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_STM], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen); - //dynamic bypass ipv4 or ipv6 - if(stream->addr.addrtype == ADDR_TYPE_IPV6){ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_IPV6_STM], 0, FS_OP_ADD, 1); - } - else{ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_IPV4_STM], 0, FS_OP_ADD, 1); - } - - if(pmeinfo->has_dup_traffic == 1){ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DUP_TFC_STM], 0, FS_OP_ADD, 1); - KNI_LOG_DEBUG(logger, "stream has dup traffic, traceid = %s", pmeinfo->stream_traceid); - } - - pmeinfo->ssl_intercept_state = 0; - pmeinfo->is_dynamic_bypass = 1; - if(g_kni_handle->dup_traffic_switch == 1){ - if(pmeinfo->has_dup_traffic == 1){ - ret = dabloom_add(pktinfo, thread_seq); - if(ret < 0){ - return -1; - } - } - } - } - return ret; -} - static struct _session_attribute_label_t * kni_pull_session_attribute_results(struct streaminfo *a_stream,struct pme_info *pmeinfo) { @@ -1231,7 +965,10 @@ static struct _session_attribute_label_t * kni_pull_session_attribute_results(st KNI_LOG_DEBUG(logger, "share-session-attribute: destination ip location province is: %s,stream traceid = %s",session_attribute_label->server_location->province_full,pmeinfo->stream_traceid); KNI_LOG_DEBUG(logger, "share-session-attribute: destination ip location city is: %s,stream traceid = %s",session_attribute_label->server_location->city_full,pmeinfo->stream_traceid); } - + if(session_attribute_label->ja3_fingerprint == NULL) + KNI_LOG_DEBUG(logger, "share-session-attribute: ja3_fingerprint is NULL,stream traceid = %s",pmeinfo->stream_traceid); + else + KNI_LOG_DEBUG(logger, "share-session-attribute: ja3_fingerprint is %s,stream traceid = %s",session_attribute_label->ja3_fingerprint,pmeinfo->stream_traceid); } else { @@ -1361,9 +1098,37 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei } //dynamic bypass - if(first_data_ssl_dynamic_bypass(stream, pmeinfo, pktinfo, thread_seq) == 0) - { - return APP_STATE_FAWPKT | APP_STATE_KILL_OTHER | APP_STATE_GIVEME; + if(g_kni_handle->ssl_dynamic_bypass_enable == 1){ + if(first_data_ssl_dynamic_bypass(stream, pmeinfo, pktinfo, thread_seq) == 0) + { + //dynamic bypass fs stat + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_STM], 0, FS_OP_ADD, 1); + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen); + //dynamic bypass ipv4 or ipv6 + if(stream->addr.addrtype == ADDR_TYPE_IPV6){ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_IPV6_STM], 0, FS_OP_ADD, 1); + } + else{ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DY_PASS_IPV4_STM], 0, FS_OP_ADD, 1); + } + + if(pmeinfo->has_dup_traffic == 1){ + FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_DUP_TFC_STM], 0, FS_OP_ADD, 1); + KNI_LOG_DEBUG(logger, "stream has dup traffic, traceid = %s", pmeinfo->stream_traceid); + } + + pmeinfo->ssl_intercept_state = 0; + pmeinfo->is_dynamic_bypass = 1; + if(g_kni_handle->dup_traffic_switch == 1){ + if(pmeinfo->has_dup_traffic == 1){ + ret = dabloom_add(pktinfo, thread_seq); + if(ret < 0){ + KNI_LOG_DEBUG(logger, "stream add dabloom fail, ret=%d, traceid = %s",ret, pmeinfo->stream_traceid); + } + } + } + return APP_STATE_FAWPKT | APP_STATE_KILL_OTHER | APP_STATE_GIVEME; + } } //add cmsg @@ -1482,12 +1247,6 @@ char* kni_maat_action_trans(enum kni_action action){ -static void next_data_ssl_dynamic_bypass(struct pkt_info *pktinfo) -{ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen); - -} - char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct pkt_info *pktinfo, int thread_seq){ FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_READY_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen); int ret, len; @@ -1527,10 +1286,11 @@ char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct pmeinfo->stream_traceid, pmeinfo->stream_addr); return APP_STATE_DROPPKT | APP_STATE_KILL_OTHER | APP_STATE_GIVEME; } - if(pmeinfo->is_dynamic_bypass) - { - next_data_ssl_dynamic_bypass(pktinfo); - return APP_STATE_FAWPKT | APP_STATE_KILL_OTHER | APP_STATE_GIVEME; + if(g_kni_handle->ssl_dynamic_bypass_enable == 1){ + if(pmeinfo->is_dynamic_bypass){ + next_data_ssl_dynamic_bypass(pktinfo); + return APP_STATE_FAWPKT | APP_STATE_KILL_OTHER | APP_STATE_GIVEME; + } } ret = send_to_tfe((char*)a_packet, len, thread_seq, pmeinfo->tfe_id, pmeinfo->addr_type); @@ -1987,93 +1747,6 @@ static int wrapped_kni_cmsg_get(struct pme_info *pmeinfo, struct kni_cmsg *cmsg, } -static int sslinfo2bypass_htable_add(char *key, uint klen, void * value, void *logger) -{ - int ret = -1; - MESA_htable_handle sslinfo2bypass_htable = g_kni_handle->sslinfo2bypass_htable; - ret = MESA_htable_add(sslinfo2bypass_htable, (const unsigned char *)key, klen, (const void*)value); - if(ret < 0) - { - KNI_LOG_ERROR(logger, "MESA_htable: Failed at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret); - } - else - { - KNI_LOG_DEBUG(logger, "MESA_htable: Success at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_ADD_SUCC], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, 1); - - } - return ret; -} - -static long traceid2sslinfo_htable_search_cb(void *data, const uchar *key, uint size, void *user_args) -{ - struct dynamic_bypass_ssl_feature * ssl_feature = (struct dynamic_bypass_ssl_feature *)data; - void *logger = g_kni_handle->local_logger; - uint64_t * p_ssl_pinningst = (uint64_t *)user_args; - uint64_t *value = NULL; - long cb_ret = -1; - - if(ssl_feature != NULL) - { - value = ALLOC(uint64_t, 1); - *value = *p_ssl_pinningst; - if(sslinfo2bypass_htable_add(ssl_feature->value, ssl_feature->vlen, (void *)value, logger) < 0) - { - KNI_LOG_ERROR(logger, "Dynamic bypass, fail add to table = sslinfo2bypass_htable, key = %s, key_size = %d", - ssl_feature->value, ssl_feature->vlen); - } - cb_ret = 0; - } - return cb_ret; -} - - -static int traceid2sslinfo_htable_search(MESA_htable_handle htable,char *key, int klen, int thread_seq,uint64_t ssl_pinningst) -{ - long cb_ret = -1; - void *logger = g_kni_handle->local_logger; - MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, traceid2sslinfo_htable_search_cb, &ssl_pinningst, &cb_ret); - if(cb_ret >= 0) - { - KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", - thread_seq, key, klen,cb_ret); - } - else - { - KNI_LOG_ERROR(logger, "MESA_htable: Fail to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", - thread_seq, key, klen,cb_ret); - } - - return cb_ret; -} - -static int ssl_dynamic_bypass_htable_add(struct pme_info *pmeinfo) -{ - void *logger = g_kni_handle->local_logger; - long cb_ret; - int ret = -1; - MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[pmeinfo->thread_seq].traceid2sslinfo_htable; - if(pmeinfo->ssl_intercept_state == 0) - { - cb_ret = traceid2sslinfo_htable_search(traceid2sslinfo_htable,pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), pmeinfo->thread_seq, pmeinfo->ssl_pinningst); - if(cb_ret >= 0) - { - cb_ret = MESA_htable_del(traceid2sslinfo_htable, (const unsigned char *)pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), NULL); - if(cb_ret < 0) - { - KNI_LOG_ERROR(logger, "Delete traceid2sslinfo_htable fail,key=%s",pmeinfo->stream_traceid); - } - else - { - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1); - } - ret = 0; - } - } - return ret; -} static long traceid2pme_htable_search_cb(void *data, const uchar *key, uint size, void *user_args){ struct traceid2pme_search_cb_args *args = (struct traceid2pme_search_cb_args*)user_args; @@ -2093,7 +1766,9 @@ static long traceid2pme_htable_search_cb(void *data, const uchar *key, uint size KNI_LOG_DEBUG(logger, "recv cmsg from tfe, stream traceid = %s, stream addr = %s, stream ssl intercept state = %d ,pinning state = %d", pmeinfo->stream_traceid, pmeinfo->stream_addr,pmeinfo->ssl_intercept_state,pmeinfo->ssl_pinningst); - ssl_dynamic_bypass_htable_add(pmeinfo); + if(g_kni_handle->ssl_dynamic_bypass_enable == 1){ + ssl_dynamic_bypass_htable_add(pmeinfo); + } can_destroy = judge_stream_can_destroy(pmeinfo, CALLER_TFE); if(can_destroy == 1){ @@ -2462,27 +2137,6 @@ static void tuple2stream_htable_data_free_cb(void *data){ FREE(&data); } -static void traceid2sslinfo_htable_data_free_cb(void *data){ - FREE(&data); -} - -static void sslinfo2bypass_htable_data_free_cb(void *data){ - FREE(&data); -} - -static int traceid2sslinfo_htable_expire_notify_cb(void *data, int eliminate_type) -{ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1); - return 1; -} - -static int sslinfo2bypass_htable_expire_notify_cb(void *data, int eliminate_type) -{ - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_DEL_SUCC], 0, FS_OP_ADD, 1); - FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, -1); - return 1; -} int dup_traffic_dabloom_init(const char *profile, void *logger){ @@ -2546,7 +2200,6 @@ extern "C" int kni_init(){ pthread_t thread_id = -1; struct thread_tfe_cmsg_receiver_args *cmsg_receiver_args; MESA_htable_handle traceid2pme_htable = NULL; - MESA_htable_handle sslinfo2bypass_htable = NULL; struct tfe_mgr *_tfe_mgr = NULL; char label_buff[MAX_STRING_LEN*4]={0}; tfe_cmsg_enum_to_string(); @@ -2696,27 +2349,12 @@ extern "C" int kni_init(){ } g_kni_handle->threads_handle[i].tuple2stream_htable = tuple2stream_htable; } - //init traceid2sslinfo_htable - memset(&opt, 0, sizeof(opt)); - kni_get_htable_opt(&opt, profile, "traceid2sslinfo_htable", (void*)traceid2sslinfo_htable_data_free_cb, (void *)traceid2sslinfo_htable_expire_notify_cb, local_logger); - for(int i = 0; i < g_kni_handle->thread_count; i++){ - MESA_htable_handle traceid2sslinfo_htable = kni_create_htable((char*)"traceid2sslinfo_htable", &opt, local_logger); - if(traceid2sslinfo_htable == NULL){ - KNI_LOG_ERROR(local_logger, "Failed at kni_create_htable, table = traceid2sslinfo_htable"); - goto error_out; - } - g_kni_handle->threads_handle[i].traceid2sslinfo_htable = traceid2sslinfo_htable; - } - - //init sslinfo2bypass_htable - memset(&opt, 0, sizeof(opt)); - kni_get_htable_opt(&opt, profile, "sslinfo2bypass_htable", (void*)sslinfo2bypass_htable_data_free_cb, (void *)sslinfo2bypass_htable_expire_notify_cb, local_logger); - sslinfo2bypass_htable = kni_create_htable((char*)"sslinfo2bypass_htable", &opt, local_logger); - if(sslinfo2bypass_htable == NULL){ - KNI_LOG_ERROR(local_logger, "Failed at create sslinfo2bypass_htable"); + //init ssl dynamic bypass htable + ret = ssl_dynamic_bypass_htable_init(profile, local_logger); + if(ret < 0){ goto error_out; } - g_kni_handle->sslinfo2bypass_htable = sslinfo2bypass_htable; + //init dabloom_handle ret = dup_traffic_dabloom_init(profile, local_logger); if(ret < 0){ diff --git a/entry/src/ssl_utils.cpp b/entry/src/ssl_utils.cpp deleted file mode 100644 index 6248722..0000000 --- a/entry/src/ssl_utils.cpp +++ /dev/null @@ -1,638 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define ALLOC(type, number) ((type *)calloc(sizeof(type), number)) -#define FREE(p) {free(*p);*p=NULL;} -#define TFE_SYMBOL_MAX 64 - -void ssl_chello_free(struct ssl_chello* chello) -{ - if(chello == NULL) - { - return; - } - FREE(&(chello->sni)); - chello->sni = NULL; - FREE(&(chello->alpn)); - chello->alpn = NULL; - FREE(&(chello->sign_algos)); - chello->sign_algos = NULL; - FREE(&(chello->supported_groups)); - chello->supported_groups = NULL; - FREE(&(chello->cipher_suites)); - chello->cipher_suites = NULL; - FREE(&chello); -} -static int cipher_is_grease(uint16_t cipher) -{ - uint16_t a=cipher>>8; - uint16_t b=cipher&0x00ff; - //https://tools.ietf.org/html/draft-davidben-tls-grease-01#section-5 - if(a==b && (a&0x0f)==0x0a) - { - return 1; - } - else - { - return 0; - } -} - -static int parse_server_name_extension(const unsigned char *buff, uint16_t buff_len, struct ssl_chello* chello) -{ - size_t pos = 2; /* skip server name list length */ - uint16_t len; - char *sni = NULL; - while (pos + 3 < buff_len) - { - len = (buff[pos + 1] << 8) | buff[pos + 2]; - if (pos + 3 + len > buff_len) - { - chello->sni = sni; - return CHELLO_PARSE_INVALID_FORMAT; - } - switch (buff[pos]) - { - case 0x00: /* host_name */ - sni = ALLOC(char, len + 1); - strncpy(sni, (const char*)buff + pos + 3, len); - sni[len] = '\0'; - chello->sni = sni; - return CHELLO_PARSE_SUCCESS; - } - pos += 3 + len; - } - chello->sni = sni; - if (pos != buff_len) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - return CHELLO_PARSE_SUCCESS; -} - -static int parse_alpn_extension(const unsigned char* buff, uint16_t buff_len, struct ssl_chello* chello) -{ - int pos = 0; - uint16_t len = (buff[pos] << 8) | buff[pos + 1]; - char *alpn = NULL; - if(2 + len != buff_len) - { - chello->alpn = alpn; - return CHELLO_PARSE_INVALID_FORMAT; - } - alpn = ALLOC(char, len + 1); - strncpy((char*)alpn, (const char*)buff + 2, len); - alpn[len] = '\0'; - chello->alpn = alpn; - return CHELLO_PARSE_SUCCESS; -} - -static int parse_supported_versions_extension(const unsigned char* buff, uint16_t buff_len, struct ssl_chello* chello) -{ - if(buff_len < 1) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - uint8_t len = buff[0]; - if(len + 1 > buff_len || len % 2 != 0) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - uint16_t max_version = 0x0000, min_version = 0xffff; - for(int i = 1; i < len; i+=2) - { - uint16_t version = (buff[i] << 8) | buff[i + 1]; - //unknown version - if(version < 0x0300 || version > 0x0304) - { - continue; - } - if(version > max_version) - { - max_version = version; - } - if(version < min_version) - { - min_version = version; - } - } - if(max_version != 0x0000) - { - chello->max_version.ossl_format = max_version; - chello->max_version.major = (max_version >> 8); - chello->max_version.minor = max_version & 0x00ff; - chello->min_version.ossl_format = min_version; - chello->min_version.major = (min_version >> 8); - chello->min_version.minor = min_version & 0x00ff; - } - return CHELLO_PARSE_SUCCESS; -} - -static int parse_sign_algos_extension(const unsigned char* buff, uint16_t buff_len, struct ssl_chello* chello) -{ - if(buff_len < 2) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - uint16_t len = (buff[0] << 8) | buff[1]; - if(len + 2 > buff_len) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - char *sign_algos = ALLOC(char, len); - memcpy(sign_algos, (void*)(buff + 2), len); - chello->sign_algos = sign_algos; - chello->sign_algos_len = len; - return CHELLO_PARSE_SUCCESS; -} - -static int parse_supported_groups_extension(const unsigned char* buff, uint16_t buff_len, struct ssl_chello* chello) -{ - if(buff_len < 2) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - uint16_t len = (buff[0] << 8) | buff[1]; - if(len + 2 > buff_len) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - chello->supported_groups = ALLOC(char, len); - uint16_t* known_groups = (uint16_t*) chello->supported_groups; - uint16_t* raw_groups= (uint16_t*) (buff + 2); - size_t i=0, j=0; - for(i=0; isupported_groups_len = j*2; - return CHELLO_PARSE_SUCCESS; -} - -static int parse_extensions(const unsigned char *buff, uint16_t buff_len, struct ssl_chello *chello) { - uint16_t pos = 0; - /* Parse each 4 bytes for the extension header */ - while (pos + 4 <= buff_len) - { - uint16_t len = (buff[pos + 2] << 8) | buff[pos + 3]; - if (pos + 4 + len > buff_len) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - uint16_t extension_type = (buff[pos] << 8) | buff[pos + 1]; - int result = CHELLO_PARSE_SUCCESS; - switch(extension_type){ - //server name extension - case 0x0000: - result = parse_server_name_extension(buff + pos + 4, len, chello); - break; - //alpn extension - case 0x0010: - result = parse_alpn_extension(buff + pos + 4, len, chello); - break; - //supported versions extension - case 0x002b: - result = parse_supported_versions_extension(buff + pos + 4, len, chello); - break; - //signature algorithms extension - case 0x000d: - result = parse_sign_algos_extension(buff + pos + 4, len, chello); - break; - //supported groups extensions - case 0x000a: - result = parse_supported_groups_extension(buff + pos + 4, len, chello); - break; - default: - break; - } - if(result != CHELLO_PARSE_SUCCESS) - { - return result; - } - pos += (4 + len); - } - /* Check we ended where we expected to */ - if (pos != buff_len) - { - return CHELLO_PARSE_INVALID_FORMAT; - } - return CHELLO_PARSE_SUCCESS; -} - - -struct cipher_suite -{ - uint16_t value; - const char* name; -}; - -static struct cipher_suite cipher_suite_list[] = -{ - {0xC030, "ECDHE-RSA-AES256-GCM-SHA384"}, - {0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"}, - {0xC028, "ECDHE-RSA-AES256-SHA384"}, - {0xC024, "ECDHE-ECDSA-AES256-SHA384"}, - {0xC014, "ECDHE-RSA-AES256-SHA"}, - {0xC00A, "ECDHE-ECDSA-AES256-SHA"}, - {0x00A5, "DH-DSS-AES256-GCM-SHA384"}, - {0x00A3, "DHE-DSS-AES256-GCM-SHA384"}, - {0x00A1, "DH-RSA-AES256-GCM-SHA384"}, - {0x009F, "DHE-RSA-AES256-GCM-SHA384"}, - {0x006B, "DHE-RSA-AES256-SHA256"}, - {0x006A, "DHE-DSS-AES256-SHA256"}, - {0x0069, "DH-RSA-AES256-SHA256"}, - {0x0068, "DH-DSS-AES256-SHA256"}, - {0x0039, "DHE-RSA-AES256-SHA"}, - {0x0038, "DHE-DSS-AES256-SHA"}, - {0x0037, "DH-RSA-AES256-SHA"}, - {0x0036, "DH-DSS-AES256-SHA"}, - {0x0088, "DHE-RSA-CAMELLIA256-SHA"}, - {0x0087, "DHE-DSS-CAMELLIA256-SHA"}, - {0x0086, "DH-RSA-CAMELLIA256-SHA"}, - {0x0085, "DH-DSS-CAMELLIA256-SHA"}, - {0xC019, "AECDH-AES256-SHA"}, - {0x00A7, "ADH-AES256-GCM-SHA384"}, - {0x006D, "ADH-AES256-SHA256"}, - {0x003A, "ADH-AES256-SHA"}, - {0x0089, "ADH-CAMELLIA256-SHA"}, - {0xC032, "ECDH-RSA-AES256-GCM-SHA384"}, - {0xC02E, "ECDH-ECDSA-AES256-GCM-SHA384"}, - {0xC02A, "ECDH-RSA-AES256-SHA384"}, - {0xC026, "ECDH-ECDSA-AES256-SHA384"}, - {0xC00F, "ECDH-RSA-AES256-SHA"}, - {0xC005, "ECDH-ECDSA-AES256-SHA"}, - {0x009D, "AES256-GCM-SHA384"}, - {0x003D, "AES256-SHA256"}, - {0x0035, "AES256-SHA"}, - {0x0084, "CAMELLIA256-SHA"}, - {0x008D, "PSK-AES256-CBC-SHA"}, - {0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"}, - {0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"}, - {0xC027, "ECDHE-RSA-AES128-SHA256"}, - {0xC023, "ECDHE-ECDSA-AES128-SHA256"}, - {0xC013, "ECDHE-RSA-AES128-SHA"}, - {0xC009, "ECDHE-ECDSA-AES128-SHA"}, - {0x00A4, "DH-DSS-AES128-GCM-SHA256"}, - {0x00A2, "DHE-DSS-AES128-GCM-SHA256"}, - {0x00A0, "DH-RSA-AES128-GCM-SHA256"}, - {0x009E, "DHE-RSA-AES128-GCM-SHA256"}, - {0x0067, "DHE-RSA-AES128-SHA256"}, - {0x0040, "DHE-DSS-AES128-SHA256"}, - {0x003F, "DH-RSA-AES128-SHA256"}, - {0x003E, "DH-DSS-AES128-SHA256"}, - {0x0033, "DHE-RSA-AES128-SHA"}, - {0x0032, "DHE-DSS-AES128-SHA"}, - {0x0031, "DH-RSA-AES128-SHA"}, - {0x0030, "DH-DSS-AES128-SHA"}, - {0x009A, "DHE-RSA-SEED-SHA"}, - {0x0099, "DHE-DSS-SEED-SHA"}, - {0x0098, "DH-RSA-SEED-SHA"}, - {0x0097, "DH-DSS-SEED-SHA"}, - {0x0045, "DHE-RSA-CAMELLIA128-SHA"}, - {0x0044, "DHE-DSS-CAMELLIA128-SHA"}, - {0x0043, "DH-RSA-CAMELLIA128-SHA"}, - {0x0042, "DH-DSS-CAMELLIA128-SHA"}, - {0xC018, "AECDH-AES128-SHA"}, - {0x00A6, "ADH-AES128-GCM-SHA256"}, - {0x006C, "ADH-AES128-SHA256"}, - {0x0034, "ADH-AES128-SHA"}, - {0x009B, "ADH-SEED-SHA"}, - {0x0046, "ADH-CAMELLIA128-SHA"}, - {0xC031, "ECDH-RSA-AES128-GCM-SHA256"}, - {0xC02D, "ECDH-ECDSA-AES128-GCM-SHA256"}, - {0xC029, "ECDH-RSA-AES128-SHA256"}, - {0xC025, "ECDH-ECDSA-AES128-SHA256"}, - {0xC00E, "ECDH-RSA-AES128-SHA"}, - {0xC004, "ECDH-ECDSA-AES128-SHA"}, - {0x009C, "AES128-GCM-SHA256"}, - {0x003C, "AES128-SHA256"}, - {0x002F, "AES128-SHA"}, - {0x0096, "SEED-SHA"}, - {0x0041, "CAMELLIA128-SHA"}, - {0x008C, "PSK-AES128-CBC-SHA"}, - {0xC012, "ECDHE-RSA-DES-CBC3-SHA"}, - {0xC008, "ECDHE-ECDSA-DES-CBC3-SHA"}, - {0x0016, "EDH-RSA-DES-CBC3-SHA"}, - {0x0013, "EDH-DSS-DES-CBC3-SHA"}, - {0x0010, "DH-RSA-DES-CBC3-SHA"}, - {0x000D, "DH-DSS-DES-CBC3-SHA"}, - {0xC017, "AECDH-DES-CBC3-SHA"}, - {0x001B, "ADH-DES-CBC3-SHA"}, - {0xC00D, "ECDH-RSA-DES-CBC3-SHA"}, - {0xC003, "ECDH-ECDSA-DES-CBC3-SHA"}, - {0x000A, "DES-CBC3-SHA"}, - {0x0007, "IDEA-CBC-SHA"}, - {0x008B, "PSK-3DES-EDE-CBC-SHA"}, - {0x0021, "KRB5-IDEA-CBC-SHA"}, - {0x001F, "KRB5-DES-CBC3-SHA"}, - {0x0025, "KRB5-IDEA-CBC-MD5"}, - {0x0023, "KRB5-DES-CBC3-MD5"}, - {0xC011, "ECDHE-RSA-RC4-SHA"}, - {0xC007, "ECDHE-ECDSA-RC4-SHA"}, - {0xC016, "AECDH-RC4-SHA"}, - {0x0018, "ADH-RC4-MD5"}, - {0xC00C, "ECDH-RSA-RC4-SHA"}, - {0xC002, "ECDH-ECDSA-RC4-SHA"}, - {0x0005, "RC4-SHA"}, - {0x0004, "RC4-MD5"}, - {0x008A, "PSK-RC4-SHA"}, - {0x0020, "KRB5-RC4-SHA"}, - {0x0024, "KRB5-RC4-MD5"}, - {0xC010, "ECDHE-RSA-NULL-SHA"}, - {0xC006, "ECDHE-ECDSA-NULL-SHA"}, - {0xC015, "AECDH-NULL-SHA"}, - {0xC00B, "ECDH-RSA-NULL-SHA"}, - {0xC001, "ECDH-ECDSA-NULL-SHA"}, - {0x003B, "NULL-SHA256"}, - {0x0002, "NULL-SHA"}, - {0x0001, "NULL-MD5"} -}; - -static struct cipher_suite cipher_suite_list_tls13[] = -{ - {0x1301, "TLS_AES_128_GCM_SHA256"}, - {0x1302, "TLS_AES_256_GCM_SHA384"}, - {0x1303, "TLS_CHACHA20_POLY1305_SHA256"}, - {0x1304, "TLS_AES_128_CCM_SHA256"}, - {0x1305, "TLS_AES_128_CCM_8_SHA256"} -}; - -static int cipher_suites_convert_helper(uint16_t value, char *name, size_t name_sz) -{ - int n1 = sizeof(cipher_suite_list) / sizeof(struct cipher_suite); - int n2 = sizeof(cipher_suite_list_tls13) / sizeof(struct cipher_suite); - for(int i = 0; i < n1; i++) - { - if(value == cipher_suite_list[i].value) - { - if(name) memcpy(name, cipher_suite_list[i].name, strnlen(cipher_suite_list[i].name, name_sz)); - return 1; - } - } - for(int i = 0; i < n2; i++) - { - if(value == cipher_suite_list_tls13[i].value) - { - if(name) memcpy(name, cipher_suite_list_tls13[i].name, strnlen(cipher_suite_list_tls13[i].name, name_sz)); - return 2; - } - } - return 0; -} - -void ssl_cipher_suites_to_name(const char *source, int source_len, char *result_common, size_t sz_common, char *result_tls13, size_t sz_tls13) -{ - int target_common_reach_max = 0; - int target_tls13_reach_max = 0; - char name[TFE_SYMBOL_MAX] = ""; - for(int i = 0; i < source_len - 1;) - { - uint16_t val = (source[i] << 8) | source[i + 1]; - memset(name, 0, sizeof(name)); - int ret = cipher_suites_convert_helper(val, name, sizeof(name)); - //target common - if(ret == 1 && target_common_reach_max == 0) - { - if(strnlen(name, sizeof(name)) + strnlen(result_common, sz_common) + 1 > sz_common) - { - target_common_reach_max = 1; - } - else - { - strncat(result_common, name, sz_common); - strncat(result_common, ":", sz_common); - } - } - //result_tls13 - if(ret == 2 && target_tls13_reach_max == 0) - { - if(strnlen(name, sizeof(name)) + strnlen(result_tls13, sz_tls13) + 1 > sz_tls13) - { - target_tls13_reach_max = 1; - } - else - { - strncat(result_tls13, name, sz_tls13); - strncat(result_tls13, ":", sz_tls13); - } - } - i += 2; - } - int len1 = strnlen(result_common, sz_common); - if(len1 > 0) - { - result_common[len1 - 1] = '\0'; - } - int len2 = strnlen(result_tls13, sz_tls13); - if(len2 > 0) - { - result_tls13[len2 - 1] = '\0'; - } - return; -} - -struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, enum chello_parse_result* result) -{ - if(buff == NULL) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return NULL; - } - if(buff_len < 1) - { - *result = CHELLO_PARSE_NOT_ENOUGH_BUFF; - return NULL; - } - if(buff[0] != 0x80 && buff[0] != 0x16) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return NULL; - } - /* SSL 2.0 compatible Client Hello - * High bit of first byte (length) and content type is Client Hello - * See RFC5246 Appendix E.2 - * if it is SSL 2.0, only parse version - */ - if(buff[0] == 0x80) - { - struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); - _chello->min_version.major = 0x02; - if(buff_len < 2) - { - *result = CHELLO_PARSE_NOT_ENOUGH_BUFF; - return _chello; - } - size_t len = (size_t)buff[1]; - if (buff_len < len + 2) - { - *result = CHELLO_PARSE_NOT_ENOUGH_BUFF; - return _chello; - } - buff_len = len + 2; - size_t pos = 2; - /* Handshark Message Type: Client Hello */ - if (pos + 1 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - if (buff[pos] != 0x01) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - pos += 1; - /* Version */ - if(pos + 2 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - _chello->max_version.major = buff[pos]; - _chello->max_version.minor = buff[pos + 1]; - _chello->max_version.ossl_format=(uint16_t)_chello->max_version.major<<8|_chello->max_version.minor; - *result = CHELLO_PARSE_SUCCESS; - return _chello; - } - else - { - if (buff_len < 5) - { - *result = CHELLO_PARSE_NOT_ENOUGH_BUFF; - return NULL; - } - if(buff[1] != 3 || buff[2] > 4 || buff[2] < 0) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return NULL; - } - - struct ssl_chello* _chello = (struct ssl_chello*)ALLOC(struct ssl_chello, 1); - _chello->min_version.major = buff[1]; - _chello->min_version.minor = buff[2]; - _chello->min_version.ossl_format=(uint16_t)_chello->min_version.major<<8|_chello->min_version.minor; - _chello->max_version.major = -1; - _chello->max_version.minor = -1; - _chello->sni = NULL; - _chello->alpn = NULL; - _chello->cipher_suites = NULL; - _chello->cipher_suites_len = 0; - _chello->sign_algos = NULL; - _chello->sign_algos_len = 0; - _chello->supported_groups = NULL; - _chello->supported_groups_len = 0; - - /* TLS record length */ - size_t len = ((size_t)buff[3] << 8) + (size_t)buff[4] + 5; - if (buff_len < len) - { - *result = CHELLO_PARSE_NOT_ENOUGH_BUFF; - return _chello; - } - buff_len = len; - size_t pos = 5; - if (pos + 1 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - if (buff[pos] != 0x01) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - pos += 4; - if(pos + 2 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - _chello->max_version.major = buff[pos]; - _chello->max_version.minor = buff[pos+1]; - _chello->max_version.ossl_format=(uint16_t)_chello->max_version.major<<8|_chello->max_version.minor; - - pos += 34; - /* Session ID */ - if (pos + 1 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - len = (size_t)buff[pos]; - pos += 1 + len; - /* Cipher Suites */ - if (pos + 2 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; - pos += 2; - if(pos + len > buff_len || len % 2 != 0) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - size_t i=0, j=0; - _chello->cipher_suites = ALLOC(char, len); - uint16_t* known_cipher=(uint16_t*)_chello->cipher_suites; - uint16_t* raw_cipher=(uint16_t*)(buff + pos); - for(i=0, j=0; icipher_suites_len = j*2; - - pos += len; - - /* Compression Methods */ - if (pos >= buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - len = (size_t)buff[pos]; - pos += 1 + len; - - /* No extension */ - if(pos == buff_len) - { - *result = CHELLO_PARSE_SUCCESS; - return _chello; - } - - /* Extensions */ - if (pos + 2 > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1]; - pos += 2; - if (pos + len > buff_len) - { - *result = CHELLO_PARSE_INVALID_FORMAT; - return _chello; - } - int ret = parse_extensions(buff + pos, len, _chello); - *result = (enum chello_parse_result)ret; - return _chello; - } -} -