diff options
| author | 刘学利 <[email protected]> | 2021-04-27 09:49:15 +0000 |
|---|---|---|
| committer | 刘学利 <[email protected]> | 2021-04-27 09:49:15 +0000 |
| commit | d6393940779a53352c761db9102e817e3b3e444d (patch) | |
| tree | ec7710f49cd24cfb5c2a928d9e8fcf19163039a7 | |
| parent | 1a4d35dec8f7304a2efa677cd5684f581e4d0bf2 (diff) | |
支持同步接收APP的识别结果v4.0.0
支持一个流具有多个APP属性
适配新的APP ID
| -rw-r--r-- | .gitlab-ci.yml | 2 | ||||
| -rw-r--r-- | bin/app_l7_proto_id.conf | 3 | ||||
| -rw-r--r-- | bin/main.conf | 1 | ||||
| -rw-r--r-- | bin/tsg_l7_protocol.conf | 55 | ||||
| -rw-r--r-- | inc/app_label.h | 32 | ||||
| -rw-r--r-- | inc/tsg_send_log.h | 1 | ||||
| -rw-r--r-- | src/tsg_entry.cpp | 1173 | ||||
| -rw-r--r-- | src/tsg_entry.h | 55 | ||||
| -rw-r--r-- | src/tsg_rule.cpp | 263 | ||||
| -rw-r--r-- | src/tsg_send_log.cpp | 740 | ||||
| -rw-r--r-- | src/tsg_send_log_internal.h | 3 | ||||
| -rw-r--r-- | src/uthash.h | 1150 |
12 files changed, 2326 insertions, 1152 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed470f3..36a9342 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ variables: GIT_STRATEGY: "clone" BUILD_PADDING_PREFIX: /tmp/padding_for_CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX/ INSTALL_PREFIX: "/home/mesasoft/sapp_run/" - INSTALL_DEPENDENCY_LIBRARY: libMESA_handle_logger-devel libcjson-devel libMESA_field_stat2-devel sapp sapp-devel framework_env libMESA_prof_load-devel http-devel dns-devel ftp-devel mail-devel ssl-devel librdkafka-devel libmaatframe-devel quic-devel libasan + INSTALL_DEPENDENCY_LIBRARY: libMESA_handle_logger-devel libcjson-devel libMESA_field_stat2-devel sapp sapp-devel framework_env libMESA_prof_load-devel http-devel dns-devel ftp-devel mail-devel ssl-devel librdkafka-devel libmaatframe-devel quic-devel mesa_sip-devel libasan stages: - build diff --git a/bin/app_l7_proto_id.conf b/bin/app_l7_proto_id.conf index 714f943..8c48b31 100644 --- a/bin/app_l7_proto_id.conf +++ b/bin/app_l7_proto_id.conf @@ -49,3 +49,6 @@ STRING BJNP 147 STRING LDAP 148 STRING RTMP 149 STRING RTSP 150 +STRING POP3 116 +STRING SMTP 122 +STRING IMAP 151 diff --git a/bin/main.conf b/bin/main.conf index 5227583..2e9e042 100644 --- a/bin/main.conf +++ b/bin/main.conf @@ -31,4 +31,5 @@ ENTRANCE_ID=18 LOG_LEVEL=10 LOG_PATH=./tsglog/tsg_master POLICY_PRIORITY_LABEL=POLICY_PRIORITY +L7_RPTOCOL_FILE="./tsgconf/tsg_l7_protocol.conf" DEVICE_ID_COMMAND=hostname | awk -F'-' '{print $3}'| awk -F'ADC' '{print $2}'
\ No newline at end of file diff --git a/bin/tsg_l7_protocol.conf b/bin/tsg_l7_protocol.conf new file mode 100644 index 0000000..9c287c1 --- /dev/null +++ b/bin/tsg_l7_protocol.conf @@ -0,0 +1,55 @@ +#TYPE:1:UCHAR,2:USHORT,3:USTRING,4:ULOG,5:USTRING,6:FILE,7:UBASE64,8:PACKET +#TYPE FIELD VALUE +STRING UNCATEGORIZED 15001 +STRING UNCATEGORIZED 15002 +STRING UNKNOWN_OTHER 15003 +STRING DNS 32 +STRING FTP 45 +STRING FTPS 751 +STRING HTTP 67 +STRING HTTPS 68 +STRING ICMP 70 +STRING IKE 15004 +STRING MAIL 15005 +STRING IMAP 75 +STRING IMAPS 76 +STRING IPSEC 85 +STRING XMPP 94 +STRING L2TP 98 +STRING NTP 137 +STRING POP3 147 +STRING POP3S 148 +STRING PPTP 153 +STRING QUIC 2521 +STRING SIP 182 +STRING SMB 185 +STRING SMTP 186 +STRING SMTPS 187 +STRING SPDY 1469 +STRING SSH 198 +STRING SSL 199 +STRING SOCKS 15006 +STRING TELNET 209 +STRING DHCP 29 +STRING RADIUS 158 +STRING OPENVPN 336 +STRING STUN 201 +STRING TEREDO 555 +STRING DTLS 1291 +STRING DoH 15007 +STRING ISAKMP 92 +STRING MDNS 3835 +STRING NETBIOS 129 +STRING NETFLOW 130 +STRING RDP 150 +STRING RTCP 174 +STRING RTP 175 +STRING SLP 15008 +STRING SNMP 190 +STRING SSDP 197 +STRING TFTP 211 +STRING BJNP 2481 +STRING LDAP 100 +STRING RTMP 337 +STRING RTSP 176 +STRING ESNI 15009 diff --git a/inc/app_label.h b/inc/app_label.h index c6b9bd3..4d073ad 100644 --- a/inc/app_label.h +++ b/inc/app_label.h @@ -1,17 +1,39 @@ #ifndef __APP_LABEL_H__ #define __APP_LABEL_H__ +#define MAX_APP_ID_NUM 8 + struct app_id_label { - int surrogate_id; - int app_id; + int app_id_num; + unsigned int app_id[MAX_APP_ID_NUM]; + unsigned int surrogate_id[MAX_APP_ID_NUM]; }; struct basic_proto_label { - unsigned char continue_scan_flag; //0: stop; 1: continue - unsigned char pad; - unsigned short proto_id; + int continue_scan_flag; //0: stop; 1: continue + int protocol_id_num; + unsigned short protocol_id[MAX_APP_ID_NUM]; +}; + + +enum APP_IDENTIFY_ORIGIN +{ + ORIGIN_BASIC_PROTOCOL, + ORIGIN_USER_DEFINE, + ORIGIN_DKPT, + ORIGIN_QM_ENGINE, + ORIGIN_MAX +}; + + +struct app_identify_result +{ + enum APP_IDENTIFY_ORIGIN origin; + int app_id_num; + unsigned int app_id[MAX_APP_ID_NUM]; + unsigned int surrogate_id[MAX_APP_ID_NUM]; }; enum _ATTRIBUTE_TYPE diff --git a/inc/tsg_send_log.h b/inc/tsg_send_log.h index 6c76568..f0c6dc8 100644 --- a/inc/tsg_send_log.h +++ b/inc/tsg_send_log.h @@ -36,6 +36,5 @@ int TLD_cancel(struct TLD_handle_t *handle); int tsg_send_log(struct tsg_log_instance_t *instance, struct TLD_handle_t *handle, tsg_log_t *log_msg, int thread_id); unsigned long long tsg_get_stream_id(struct streaminfo *a_stream); -char *tsg_l7_protocol_id2name(struct tsg_log_instance_t *instance, unsigned short id); #endif diff --git a/src/tsg_entry.cpp b/src/tsg_entry.cpp index e54477f..e788146 100644 --- a/src/tsg_entry.cpp +++ b/src/tsg_entry.cpp @@ -9,7 +9,8 @@ #include <MESA/ftp.h> #include <MESA/ssl.h> #include <MESA/mail.h> -#include "MESA/gquic.h" +#include <MESA/gquic.h> +#include "MESA/mesa_sip.h" #include <MESA/stream.h> #include <MESA/MESA_prof_load.h> #include <MESA/MESA_handle_logger.h> @@ -49,43 +50,43 @@ char TSG_MASTER_VERSION_20200805=0; const char *tsg_conffile="tsgconf/main.conf"; g_tsg_para_t g_tsg_para; -id2field_t g_tsg_fs2_field[TSG_FS2_MAX]={{TLD_TYPE_UNKNOWN, TSG_FS2_TCP_LINKS, "tcp_links"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_UDP_LINKS, "udp_links"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_BYPASS, "bypass"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_HIT_ADDR, "hit_addr"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_HIT_SHARE, "hit_share"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_INTERCEPT, "intercept"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_EXCLUSION, "exclusion"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_SUCCESS_LOG, "success_log"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_FAILED_LOG, "failed_log"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_DROP_LOG, "drop_log"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_ABORT_ALLOW, "abort_allow"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_ABORT_DENY, "abort_deny"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_ABORT_MONITOR, "abort_monitor"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_ABORT_INTERCEPT, "abort_intercept"}, - {TLD_TYPE_UNKNOWN, TSG_FS2_ABORT_UNKNOWN, "abort_unknown"} +id2field_t g_tsg_fs2_field[TSG_FS2_MAX]={{0, TSG_FS2_TCP_LINKS, "tcp_links"}, + {0, TSG_FS2_UDP_LINKS, "udp_links"}, + {0, TSG_FS2_BYPASS, "bypass"}, + {0, TSG_FS2_HIT_ADDR, "hit_addr"}, + {0, TSG_FS2_HIT_SHARE, "hit_share"}, + {0, TSG_FS2_INTERCEPT, "intercept"}, + {0, TSG_FS2_EXCLUSION, "exclusion"}, + {0, TSG_FS2_SUCCESS_LOG, "success_log"}, + {0, TSG_FS2_FAILED_LOG, "failed_log"}, + {0, TSG_FS2_DROP_LOG, "drop_log"}, + {0, TSG_FS2_ABORT_ALLOW, "abort_allow"}, + {0, TSG_FS2_ABORT_DENY, "abort_deny"}, + {0, TSG_FS2_ABORT_MONITOR, "abort_monitor"}, + {0, TSG_FS2_ABORT_INTERCEPT, "abort_intercept"}, + {0, TSG_FS2_ABORT_UNKNOWN, "abort_unknown"} }; -id2field_t g_tsg_proto_name2id[PROTO_MAX]={{TLD_TYPE_UNKNOWN, PROTO_UNKONWN, "unknown"}, - {TLD_TYPE_UNKNOWN, PROTO_IPv4, "IPV4"}, - {TLD_TYPE_UNKNOWN, PROTO_IPv6, "IPV6"}, - {TLD_TYPE_UNKNOWN, PROTO_TCP, "TCP"}, - {TLD_TYPE_UNKNOWN, PROTO_UDP, "UDP"}, - {TLD_TYPE_UNKNOWN, PROTO_HTTP, "HTTP"}, - {TLD_TYPE_UNKNOWN, PROTO_MAIL, "MAIL"}, - {TLD_TYPE_UNKNOWN, PROTO_DNS, "DNS"}, - {TLD_TYPE_UNKNOWN, PROTO_FTP, "FTP"}, - {TLD_TYPE_UNKNOWN, PROTO_SSL, "SSL"}, - {TLD_TYPE_UNKNOWN, PROTO_SIP, "SIP"}, - {TLD_TYPE_UNKNOWN, PROTO_BGP, "BGP"}, - {TLD_TYPE_UNKNOWN, PROTO_STREAMING_MEDIA, "STREAMING_MEDIA"}, - {TLD_TYPE_UNKNOWN, PROTO_QUIC, "QUIC"}, - {TLD_TYPE_UNKNOWN, PROTO_SSH, "SSH"}, - {TLD_TYPE_UNKNOWN, PROTO_SMTP, "SMTP"}, - {TLD_TYPE_UNKNOWN, PROTO_IMAP, "IMAP"}, - {TLD_TYPE_UNKNOWN, PROTO_POP3, "POP3"}, - {TLD_TYPE_UNKNOWN, PROTO_RTP, "RTP"}, - {TLD_TYPE_UNKNOWN, PROTO_APP, "APP"} +id2field_t g_tsg_proto_name2id[PROTO_MAX]={{PROTO_UNKONWN, 0, "unknown"}, + {PROTO_IPv4, 0, "IPV4"}, + {PROTO_IPv6, 0, "IPV6"}, + {PROTO_TCP, 0, "TCP"}, + {PROTO_UDP, 0, "UDP"}, + {PROTO_HTTP, 0, "HTTP"}, + {PROTO_MAIL, 0, "MAIL"}, + {PROTO_DNS, 0, "DNS"}, + {PROTO_FTP, 0, "FTP"}, + {PROTO_SSL, 0, "SSL"}, + {PROTO_SIP, 0, "SIP"}, + {PROTO_BGP, 0, "BGP"}, + {PROTO_STREAMING_MEDIA, 0, "STREAMING_MEDIA"}, + {PROTO_QUIC, 0, "QUIC"}, + {PROTO_SSH, 0, "SSH"}, + {PROTO_SMTP, 0, "SMTP"}, + {PROTO_IMAP, 0, "IMAP"}, + {PROTO_POP3, 0, "POP3"}, + {PROTO_RTP, 0, "RTP"}, + {PROTO_APP, 0,"APP"} }; #define DECCRYPTION_EXCLUSION_ALLOW_POLICY_ID 1 @@ -94,14 +95,11 @@ id2field_t g_tsg_proto_name2id[PROTO_MAX]={{TLD_TYPE_UNKNOWN, PROTO_UNKONWN, "un static int init_context(void **pme, int thread_seq) { struct master_context *context=(struct master_context *)*pme; - + *pme=dictator_malloc(thread_seq, sizeof(struct master_context)); memset(*pme, 0, sizeof(struct master_context)); context=(struct master_context *)*pme; - context->domain_len=0; - memset(context->domain, 0, sizeof(context->domain)); - context->continue_scan_app_id=APP_SCAN_FLAG_CONTINUE; context->continue_scan_proto_id=APP_SCAN_FLAG_CONTINUE; return 0; @@ -155,26 +153,6 @@ static int get_device_id(char *command, int entrance_id) return (entrance_id<<7)+(atoi(buffer)%128); } -static int is_repetitive_protocol_id(unsigned short proto_id) -{ - switch(proto_id) - { - case DNS_PROTO_ID: - case FTP_PROTO_ID: - case HTTP_PROTO_ID: - case MAIL_PROTO_ID: - case QUIC_PROTO_ID: - case SIP_PROTO_ID: - case SSL_PROTO_ID: - case RTP_PROTO_ID: - return 1; - default: - break; - } - - return 0; -} - static int is_only_monitor(struct Maat_rule_t *result, int hit_cnt) { int i=0; @@ -190,84 +168,91 @@ static int is_only_monitor(struct Maat_rule_t *result, int hit_cnt) return 1; } -static int get_default_policy(int compile_id, struct Maat_rule_t *result) +static int set_drop_stream(const struct streaminfo *a_stream) { - struct Maat_rule_t p_result={0}; - struct compile_user_region *user_region=NULL; - - p_result.config_id=compile_id; - user_region=(struct compile_user_region *)Maat_rule_get_ex_data(g_tsg_maat_feather, &p_result, g_tsg_para.table_id[TABLE_SECURITY_COMPILE]); - if(user_region!=NULL) - { - if(user_region->result!=NULL) - { - memcpy(result, user_region->result, sizeof(struct Maat_rule_t)); - if(result->action==TSG_ACTION_BYPASS) - { - result->action=TSG_ACTION_NONE; - } - } - - security_compile_free(g_tsg_para.table_id[TABLE_SECURITY_COMPILE], &p_result, NULL, (MAAT_RULE_EX_DATA *)&user_region, 0, NULL); - return 1; - } + int opt_value=1; + MESA_set_stream_opt(a_stream, MSO_DROP_STREAM, (void *)&opt_value, sizeof(opt_value)); + MESA_set_stream_opt(a_stream, MSO_TIMEOUT, (void *)&g_tsg_para.timeout, sizeof(g_tsg_para.timeout)); return 0; + } -static struct app_id_label *get_app_id_label(struct streaminfo *a_stream, struct master_context *context, int thread_seq) +static int set_struct_project(const struct streaminfo *a_stream, int project_id, void *data) { - struct app_id_label *app_id_label=NULL; + if(a_stream==NULL || project_id<0 || data==NULL) + { + return 0; + } - if(context->continue_scan_app_id==APP_SCAN_FLAG_CONTINUE && g_tsg_para.app_id_project_id>=0) - { - app_id_label=(struct app_id_label *)project_req_get_struct(a_stream, g_tsg_para.app_id_project_id); - if(app_id_label==NULL) - { - return NULL; - } - - if(context->app_id!=app_id_label->app_id) - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "READ_APP_ID_FLAG", - "Get app id label, app_id: %d addr: %s", - app_id_label->app_id, + int ret=project_req_add_struct((struct streaminfo *)a_stream, project_id, data); + if(ret<0) + { + MESA_handle_runtime_log(g_tsg_para.logger, + RLOG_LV_FATAL, + "PROJECT", + "Add project failed, project_id: %d addr: %s", + project_id, PRINTADDR(a_stream, g_tsg_para.level) ); - context->app_id=app_id_label->app_id; - return app_id_label; - } + return 0; + } - + return 1; +} + +static const void *get_struct_project(const struct streaminfo *a_stream, int project_id) +{ + if(a_stream==NULL || project_id<0) + { + return NULL; } - return NULL; + return project_req_get_struct(a_stream, project_id); +} +static int get_table_id(tsg_protocol_t protocol) +{ + switch(protocol) + { + case PROTO_HTTP: + return g_tsg_para.table_id[TABLE_HTTP_HOST]; + case PROTO_SSL: + return g_tsg_para.table_id[TABLE_SSL_SNI]; + case PROTO_QUIC: + return g_tsg_para.table_id[TABLE_QUIC_SNI]; + default: + break; + } + + return -1; } -static int get_basic_proto_id(struct streaminfo *a_stream, struct master_context *context, int thread_seq) +static int get_default_policy(int compile_id, struct Maat_rule_t *result) { - struct basic_proto_label *proto_label=NULL; + struct Maat_rule_t p_result={0}; + struct compile_user_region *user_region=NULL; - if(context->continue_scan_proto_id==APP_SCAN_FLAG_CONTINUE && g_tsg_para.l7_proto_project_id>=0) + p_result.config_id=compile_id; + user_region=(struct compile_user_region *)Maat_rule_get_ex_data(g_tsg_maat_feather, &p_result, g_tsg_para.table_id[TABLE_SECURITY_COMPILE]); + if(user_region!=NULL) { - proto_label=(struct basic_proto_label *)project_req_get_struct(a_stream, g_tsg_para.l7_proto_project_id); - if(proto_label!=NULL) + if(user_region->result!=NULL) { - if(proto_label->continue_scan_flag==APP_SCAN_FLAG_STOP) + memcpy(result, user_region->result, sizeof(struct Maat_rule_t)); + if(result->action==TSG_ACTION_BYPASS) { - context->continue_scan_proto_id=APP_SCAN_FLAG_STOP; + result->action=TSG_ACTION_NONE; } - - return proto_label->proto_id; } + + security_compile_free(g_tsg_para.table_id[TABLE_SECURITY_COMPILE], &p_result, NULL, (MAAT_RULE_EX_DATA *)&user_region, 0, NULL); + return 1; } return 0; } -static int master_send_log(struct streaminfo *a_stream, struct Maat_rule_t *p_result, int result_num, struct identify_info *identify_info, int thread_seq) +static int master_send_log(const struct streaminfo *a_stream, struct Maat_rule_t *p_result, int result_num, char *domain, tsg_protocol_t proto, int thread_seq) { tsg_log_t log_msg; char *domain_field_name=NULL; @@ -275,47 +260,50 @@ static int master_send_log(struct streaminfo *a_stream, struct Maat_rule_t *p_re struct TLD_handle_t *TLD_handle=NULL; TLD_handle=TLD_create(thread_seq); - if(identify_info!=NULL && (identify_info->proto>PROTO_UNKONWN) && (identify_info->proto<PROTO_MAX)) + if(proto>PROTO_UNKONWN && proto<PROTO_MAX) { schema_field_name=log_field_id2name(g_tsg_log_instance, LOG_COMMON_SCHAME_TYPE); - if(identify_info->proto==PROTO_IMAP || identify_info->proto==PROTO_SMTP || identify_info->proto==PROTO_POP3) + if(proto==PROTO_IMAP || proto==PROTO_SMTP || proto==PROTO_POP3) { TLD_append(TLD_handle, schema_field_name, (void *)g_tsg_proto_name2id[PROTO_MAIL].name, TLD_TYPE_STRING); - TLD_append(TLD_handle, (char *)"mail_protocol_type", (void *)g_tsg_proto_name2id[identify_info->proto].name, TLD_TYPE_STRING); + TLD_append(TLD_handle, (char *)"mail_protocol_type", (void *)g_tsg_proto_name2id[proto].name, TLD_TYPE_STRING); } else { - TLD_append(TLD_handle, schema_field_name, (void *)g_tsg_proto_name2id[identify_info->proto].name, TLD_TYPE_STRING); + TLD_append(TLD_handle, schema_field_name, (void *)g_tsg_proto_name2id[proto].name, TLD_TYPE_STRING); } - switch(identify_info->proto) + if(domain!=NULL) { - case PROTO_HTTP: - domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_HTTP_HOST); - TLD_append(TLD_handle, domain_field_name, (void *)identify_info->domain, TLD_TYPE_STRING); - break; - case PROTO_SSL: - domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_SSL_SNI); - TLD_append(TLD_handle, domain_field_name, (void *)identify_info->domain, TLD_TYPE_STRING); - break; - case PROTO_QUIC: - domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_QUIC_SNI); - TLD_append(TLD_handle, domain_field_name, (void *)identify_info->domain, TLD_TYPE_STRING); - break; - default: - break; + switch(proto) + { + case PROTO_HTTP: + domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_HTTP_HOST); + TLD_append(TLD_handle, domain_field_name, (void *)domain, TLD_TYPE_STRING); + break; + case PROTO_SSL: + domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_SSL_SNI); + TLD_append(TLD_handle, domain_field_name, (void *)domain, TLD_TYPE_STRING); + break; + case PROTO_QUIC: + domain_field_name=log_field_id2name(g_tsg_log_instance, LOG_QUIC_SNI); + TLD_append(TLD_handle, domain_field_name, (void *)domain, TLD_TYPE_STRING); + break; + default: + break; + } } } - log_msg.a_stream=a_stream; + log_msg.a_stream=(struct streaminfo *)a_stream; log_msg.result=p_result; log_msg.result_num=result_num; tsg_send_log(g_tsg_log_instance, TLD_handle, &log_msg, thread_seq); if(p_result->config_id!=DECCRYPTION_EXCLUSION_ALLOW_POLICY_ID) { - tsg_set_policy_flow(a_stream, p_result, thread_seq); + tsg_set_policy_flow((struct streaminfo *)a_stream, p_result, thread_seq); } return 1; @@ -340,7 +328,7 @@ static int tsg_proto_name2flag(char *proto_list, int *flag) { if((memcmp(s, g_tsg_proto_name2id[i].name, e-s))==0) { - *flag|=(1<<g_tsg_proto_name2id[i].id); + *flag|=(1<<g_tsg_proto_name2id[i].type); break; } } @@ -351,52 +339,30 @@ static int tsg_proto_name2flag(char *proto_list, int *flag) return 0; } -int get_depolyment_mode(void) +static void free_context_label(int thread_seq, void *project_req_value) { - int ret=0, len=0; - char buff[32]={0}; - - len=sizeof(buff); - ret=sapp_get_platform_opt(SPO_DEPLOYMENT_MODE_STR, buff, &len); - if(ret>=0) - { - if((memcmp(buff, "mirror", strlen(buff)))==0) - { - g_tsg_para.depolyment_mode=0; - } - else - { - g_tsg_para.depolyment_mode=1; - } - } - - return 0; + return ; } -void free_app_id_label(int thread_seq, void *project_req_value) +static void free_policy_label(int thread_seq, void *project_req_value) { if(project_req_value!=NULL) { dictator_free(thread_seq, project_req_value); + project_req_value=NULL; } } -static void free_policy_label(int thread_seq, void *project_req_value) +void free_gather_app_result(int thread_seq, void *project_req_value) { - dictator_free(thread_seq, project_req_value); - project_req_value=NULL; -} - -static void copy_identify_info(struct master_context *context, struct identify_info *identify_info, int thread_seq) -{ - if(identify_info->proto>PROTO_UNKONWN && identify_info->proto<PROTO_MAX && identify_info->domain_len>0 && strlen(identify_info->domain)>0) + if(project_req_value!=NULL) { - memcpy(context->domain, identify_info->domain, identify_info->domain_len); - context->domain_len=identify_info->domain_len; + dictator_free(thread_seq, project_req_value); + project_req_value=NULL; } } -static void copy_monitor_result(struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int result_num, int thread_seq) +static void copy_monitor_result(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int result_num, int thread_seq) { int i=0; @@ -434,21 +400,23 @@ static void copy_monitor_result(struct streaminfo *a_stream, struct master_conte } -static void copy_intercept_result(struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, struct identify_info *identify_info, int thread_seq) +static void copy_intercept_result(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, char *domain, tsg_protocol_t proto, int thread_seq) { int ret=0; policy_priority_label_t *priority_label=NULL; priority_label=(policy_priority_label_t *)dictator_malloc(thread_seq, sizeof(policy_priority_label_t)); - + memset(priority_label, 0, sizeof(policy_priority_label_t)); + + priority_label->proto=proto; + priority_label->domain_len=MIN(sizeof(priority_label->domain)-1 ,strlen(domain)); + memcpy(priority_label->domain, domain, priority_label->domain_len); + priority_label->result_num=1; priority_label->result_type=PULL_KNI_RESULT; - priority_label->proto=identify_info->proto; - priority_label->domain_len=identify_info->domain_len; - memcpy(priority_label->domain, identify_info->domain, identify_info->domain_len); memcpy(priority_label->result, p_result, sizeof(struct Maat_rule_t)); - ret=project_req_add_struct(a_stream, g_tsg_para.priority_project_id, (void *)priority_label); + ret=project_req_add_struct((struct streaminfo *)a_stream, g_tsg_para.priority_project_id, (void *)priority_label); if(ret<0) { free_policy_label(thread_seq, (void *)priority_label); @@ -474,7 +442,7 @@ static void copy_intercept_result(struct streaminfo *a_stream, struct master_con return ; } -static void copy_deny_result(struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int thread_seq) +static void copy_deny_result(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int thread_seq) { if(context->result==NULL) { @@ -502,7 +470,7 @@ static void copy_deny_result(struct streaminfo *a_stream, struct master_context return ; } -static void copy_bypass_result(struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int thread_seq) +static void copy_bypass_result(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *p_result, int thread_seq) { if(context->result==NULL) { @@ -541,25 +509,145 @@ static void copy_bypass_result(struct streaminfo *a_stream, struct master_contex return ; } -int is_intercept_exclusion(struct streaminfo *a_stream, Maat_rule_t *p_result, struct identify_info *identify_info, int thread_seq) +static unsigned char deal_deny_action(const struct streaminfo *a_stream, struct master_context *context, Maat_rule_t *p_result) +{ + int ret=0,opt_value=0; + struct rst_tcp_para rst_paras; + unsigned char state=APP_STATE_GIVEME; + int method_type=TSG_METHOD_TYPE_UNKNOWN; + struct compile_user_region *user_region=NULL; + + user_region=(struct compile_user_region *)Maat_rule_get_ex_data(g_tsg_maat_feather, p_result, g_tsg_para.table_id[TABLE_SECURITY_COMPILE]); + if(user_region!=NULL) + { + method_type=tsg_get_method_id(user_region->method); + switch(method_type) + { + case TSG_METHOD_TYPE_DROP: + set_drop_stream(a_stream); + //copy_deny_result(a_stream, context, p_result, a_stream->threadnum); + state=APP_STATE_DROPPKT|APP_STATE_DROPME; + break; + case TSG_METHOD_TYPE_RESET: + if(a_stream->type==STREAM_TYPE_TCP) + { + rst_paras.rst_pkt_num=1; + rst_paras.signature_seed1=65535; + rst_paras.signature_seed2=13; + rst_paras.th_flags=4; + rst_paras.__pad_no_use=0; + rst_paras.dir=DIR_DOUBLE; + ret=MESA_rst_tcp((struct streaminfo *)a_stream, &rst_paras, sizeof(rst_paras)); + if(ret<0) + { + MESA_handle_runtime_log(g_tsg_para.logger, + RLOG_LV_FATAL, + "RST_TCP", + "Send RST failed policy_id: %d service: %d action: %d addr: %s", + p_result->config_id, + p_result->service_id, + (unsigned char)p_result->action, + PRINTADDR(a_stream, g_tsg_para.level) + ); + } + + opt_value=1; + MESA_set_stream_opt(a_stream, MSO_TCP_RST_REMEDY, (void *)&opt_value, sizeof(opt_value)); + } + + set_drop_stream(a_stream); + //copy_deny_result(a_stream, context, p_result, a_stream->threadnum); + state=APP_STATE_DROPPKT|APP_STATE_DROPME; + break; + case TSG_METHOD_TYPE_BLOCK: + case TSG_METHOD_TYPE_ALERT: + case TSG_METHOD_TYPE_REDIRECTION: + break; + default: + break; + } + + security_compile_free(g_tsg_para.table_id[TABLE_SECURITY_COMPILE], p_result, NULL, (MAAT_RULE_EX_DATA *)&user_region, 0, NULL); + } + + return state; +} + +static int l7_protocol_mapper(const char *filename) +{ + int ret=0; + FILE *fp=NULL; + char line[1024]={0}; + char type_name[32]={0}; + struct l7_protocol *protocol=NULL; + + fp=fopen(filename, "r"); + if(fp==NULL) + { + printf("Open %s failed ...", filename); + return -1; + } + + memset(line, 0, sizeof(line)); + + while((fgets(line, sizeof(line), fp))!=NULL) + { + if(line[0]=='#' || line[0]=='\n' || line[0]=='\r' ||line[0]=='\0') + { + continue; + } + + protocol=(struct l7_protocol *)calloc(1, sizeof(struct l7_protocol)); + ret=sscanf(line, "%s %s %d", type_name, protocol->name, &protocol->id); + assert(ret==3); + + HASH_ADD(hh1, g_tsg_para.name_by_id, id, sizeof(int), protocol); + HASH_ADD(hh2, g_tsg_para.id_by_name, name, strlen(protocol->name), protocol); + + memset(line, 0, sizeof(line)); + } + + fclose(fp); + fp=NULL; + + return 1; +} + +char *tsg_l7_protocol_id2name(unsigned int l7_protocol_id) +{ + struct l7_protocol *l7_proto=NULL; + HASH_FIND(hh1, g_tsg_para.name_by_id, &l7_protocol_id, sizeof(l7_protocol_id), l7_proto); + if(l7_proto!=NULL) + { + return l7_proto->name; + } + + return NULL; +} + +unsigned int tsg_l7_protocol_name2id(const char *l7_protocol_name) +{ + struct l7_protocol *l7_proto=NULL; + + HASH_FIND(hh2, g_tsg_para.id_by_name, l7_protocol_name, strlen(l7_protocol_name), l7_proto); + if(l7_proto!=NULL) + { + return l7_proto->id; + } + + return 0; +} + + +int is_intercept_exclusion(const struct streaminfo *a_stream, Maat_rule_t *p_result, char *domain, int thread_seq) { int ret=0; scan_status_t mid=NULL; Maat_rule_t tmp_result; - if(identify_info!=NULL && identify_info->domain_len>0) + if(domain!=NULL) { - ret=Maat_full_scan_string(g_tsg_maat_feather, - g_tsg_para.table_id[TABLE_EXCLUSION_SSL_SNI], - CHARSET_UTF8, - identify_info->domain, - identify_info->domain_len, - &tmp_result, - NULL, - 1, - &mid, - thread_seq); - + ret=Maat_full_scan_string(g_tsg_maat_feather, g_tsg_para.table_id[TABLE_EXCLUSION_SSL_SNI], CHARSET_UTF8, domain, strlen(domain), &tmp_result, NULL, 1, &mid,thread_seq); if(mid!=NULL) { Maat_clean_status(&mid); @@ -572,7 +660,7 @@ int is_intercept_exclusion(struct streaminfo *a_stream, Maat_rule_t *p_result, s RLOG_LV_DEBUG, "EXCLUSION_SSL_SNI", "Hit %s policy_id: %d service: %d action: %d Decryption Exclusion: [ policy_id: %d service: %d action: %d ] addr: %s", - identify_info->domain, + domain, tmp_result.config_id, tmp_result.service_id, (unsigned char)tmp_result.action, @@ -584,47 +672,49 @@ int is_intercept_exclusion(struct streaminfo *a_stream, Maat_rule_t *p_result, s return 1; } - else - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "EXCLUSION_SSL_SNI", - "Not hit %s stream_dir: %d addr: %s scan ret: %d", - identify_info->domain, - a_stream->dir, - PRINTADDR(a_stream, g_tsg_para.level), - ret - ); - } + + MESA_handle_runtime_log(g_tsg_para.logger, + RLOG_LV_DEBUG, + "EXCLUSION_SSL_SNI", + "Not hit %s stream_dir: %d addr: %s scan ret: %d", + domain, + a_stream->dir, + PRINTADDR(a_stream, g_tsg_para.level), + ret + ); } return 0; } -void close_stream_free_context(struct streaminfo *a_stream, struct master_context *context, int thread_seq) +static int scan_fqdn_category_id(Maat_feather_t maat_feather, const struct streaminfo *a_stream, char *domain, Maat_rule_t *result, int result_num, scan_status_t *mid, int table_id, int thread_seq) { - struct identify_info identify_info; + int scan_ret=0; + struct _session_attribute_label_t *attribute_label=NULL; + + attribute_label=(struct _session_attribute_label_t *)project_req_get_struct(a_stream, g_tsg_para.internal_project_id); + if(attribute_label!=NULL && domain!=NULL && table_id>=0) + { + attribute_label->fqdn_category_id_num=tsg_get_fqdn_category_id(g_tsg_maat_feather, domain, attribute_label->fqdn_category_id, MAX_CATEGORY_ID_NUM, g_tsg_para.logger, thread_seq); + scan_ret=tsg_scan_fqdn_category_id(g_tsg_maat_feather, a_stream, result, result_num, mid, table_id, attribute_label->fqdn_category_id, attribute_label->fqdn_category_id_num, thread_seq); + } + return scan_ret; +} + +void close_stream_free_context(const struct streaminfo *a_stream, struct master_context *context, int thread_seq) +{ if(context!=NULL) { if(context->hit_cnt>0 && context->result!=NULL) { - memset(&identify_info, 0, sizeof(identify_info)); - if(context->proto==PROTO_UNKONWN || context->proto>PROTO_APP) - { - identify_info.proto=PROTO_APP; - } - else - { - identify_info.proto=context->proto; - } + master_send_log(a_stream, context->result, context->hit_cnt, context->domain, context->proto, thread_seq); + } - if(context->domain_len>0) - { - memcpy(identify_info.domain, context->domain, context->domain_len); - identify_info.domain_len=context->domain_len; - } - master_send_log(a_stream, context->result, context->hit_cnt, &identify_info, thread_seq); + if(context->domain!=NULL) + { + dictator_free(thread_seq, (void *)context->domain); + context->domain=NULL; } if(context->result!=NULL) @@ -646,7 +736,7 @@ void close_stream_free_context(struct streaminfo *a_stream, struct master_contex return ; } -void set_session_attribute_label(struct streaminfo *a_stream, enum TSG_ATTRIBUTE_TYPE type, void *value, int thread_seq) +void set_session_attribute_label(const struct streaminfo *a_stream, enum TSG_ATTRIBUTE_TYPE type, void *value, int thread_seq) { struct timespec tv; unsigned long long create_time=0; @@ -660,9 +750,12 @@ void set_session_attribute_label(struct streaminfo *a_stream, enum TSG_ATTRIBUTE attribute_label=(struct _session_attribute_label_t *)dictator_malloc(thread_seq, sizeof(struct _session_attribute_label_t)); memset(attribute_label, 0, sizeof(struct _session_attribute_label_t)); - ret=project_req_add_struct(a_stream, g_tsg_para.internal_project_id, (const void *)attribute_label); + ret=project_req_add_struct((struct streaminfo *)a_stream, g_tsg_para.internal_project_id, (const void *)attribute_label); if(ret<0) { + dictator_free(thread_seq, (void *)attribute_label); + attribute_label=NULL; + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "PROJECT_ADD", @@ -671,6 +764,7 @@ void set_session_attribute_label(struct streaminfo *a_stream, enum TSG_ATTRIBUTE attribute_label->proto, PRINTADDR(a_stream, g_tsg_para.level) ); + return ; } } @@ -688,7 +782,7 @@ void set_session_attribute_label(struct streaminfo *a_stream, enum TSG_ATTRIBUTE attribute_label->proto=(tsg_protocol_t)(*(int *)value); break; case TSG_ATTRIBUTE_TYPE_JA3_HASH: - ja3_info=ssl_get_ja3_fingerprint(a_stream, (unsigned char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, a_stream->threadnum); + ja3_info=ssl_get_ja3_fingerprint((struct streaminfo *)a_stream, (unsigned char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, a_stream->threadnum); if(ja3_info!=NULL) { if(attribute_label!=NULL && ja3_info->fp!=NULL && ja3_info->fp_len>0) @@ -706,64 +800,6 @@ void set_session_attribute_label(struct streaminfo *a_stream, enum TSG_ATTRIBUTE return ; } -char *tsg_schema_index2string(tsg_protocol_t proto) -{ - char *schema_field_value=NULL; - - switch(proto) - { - case PROTO_HTTP: - schema_field_value=(char *)"HTTP"; - break; - case PROTO_SSL: - schema_field_value=(char *)"SSL"; - break; - case PROTO_DNS: - schema_field_value=(char *)"DNS"; - break; - case PROTO_FTP: - schema_field_value=(char *)"FTP"; - break; - case PROTO_BGP: - schema_field_value=(char *)"BGP"; - break; - case PROTO_SIP: - schema_field_value=(char *)"SIP"; - break; - case PROTO_MAIL: - schema_field_value=(char *)"MAIL"; - break; - case PROTO_STREAMING_MEDIA: - schema_field_value=(char *)"STREAMING_MEDIA"; - break; - case PROTO_QUIC: - schema_field_value=(char *)"QUIC"; - break; - case PROTO_SSH: - schema_field_value=(char *)"SSH"; - break; - case PROTO_IMAP: - schema_field_value=(char *)"IMAP"; - break; - case PROTO_POP3: - schema_field_value=(char *)"POP3"; - break; - case PROTO_SMTP: - schema_field_value=(char *)"SMTP"; - break; - case PROTO_RTP: - schema_field_value=(char *)"RTP"; - break; - case PROTO_APP: - schema_field_value=(char *)"APP"; - break; - default: - break; - } - - return schema_field_value; -} - int tsg_set_device_id_to_telegraf(char *device_sn) { char buff[128]={0}; @@ -838,7 +874,7 @@ static void free_session_attribute_label(int thread_seq, void *project_req_value } } -struct Maat_rule_t *tsg_policy_decision_criteria(struct streaminfo *a_stream, Maat_rule_t *result, int result_num, struct identify_info *identify_info, int thread_seq) +struct Maat_rule_t *tsg_policy_decision_criteria(Maat_rule_t *result, int result_num) { int i=0; Maat_rule_t *p_result=NULL; @@ -869,10 +905,11 @@ struct Maat_rule_t *tsg_policy_decision_criteria(struct streaminfo *a_stream, Ma return p_result; } -static int identify_application_protocol(struct streaminfo *a_stream, struct identify_info *identify_info, void *a_packet) +static int identify_application_protocol(const struct streaminfo *a_stream, struct master_context *context, void *a_packet) { - int ret=0; - identify_info->proto = PROTO_UNKONWN; + int ret=0, length=0; + char buff[4096]={0}; + context->proto = PROTO_UNKONWN; switch(a_stream->type) { @@ -880,18 +917,15 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide if(g_tsg_para.proto_flag&(1<<PROTO_HTTP)) //http { char *host=NULL; - ret=http_host_parser((char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, a_stream->curdir, &host); - if(ret>=0) + length=http_host_parser((char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, a_stream->curdir, &host); + if(length>=0) { - identify_info->proto=PROTO_HTTP; - if(ret>0 && host!=NULL) + context->proto=PROTO_HTTP; + if(length>0 && host!=NULL) { - identify_info->domain_len=MIN(ret, (int)sizeof(identify_info->domain) - 1); - strncpy(identify_info->domain, host, identify_info->domain_len); - } - else - { - identify_info->domain_len=0; + context->domain=(char *)dictator_malloc(a_stream->threadnum, length+1); + memset(context->domain, 0, length+1); + memcpy(context->domain, host, length); } return 1; } @@ -905,16 +939,16 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide chello=ssl_chello_parse((unsigned char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, &chello_status); if(chello_status==CHELLO_PARSE_SUCCESS) { - identify_info->proto=PROTO_SSL; - if(chello->sni==NULL) - { - identify_info->domain_len = 0; - } - else + context->proto=PROTO_SSL; + if(chello->sni!=NULL) { - identify_info->domain_len = strnlen(chello->sni, sizeof(identify_info->domain) - 1); - strncpy(identify_info->domain, chello->sni, identify_info->domain_len); + length=strlen(chello->sni); + context->domain=(char *)dictator_malloc(a_stream->threadnum, length+1); + memset(context->domain, 0, length+1); + memcpy(context->domain, chello->sni, length); } + + context->is_esni=(int)chello->is_encrypt_sni; ssl_chello_free(chello); return 1; @@ -925,31 +959,31 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide if(g_tsg_para.proto_flag&(1<<PROTO_FTP)) //ftp { - ret=ftp_control_identify(a_stream); + ret=ftp_control_identify((struct streaminfo *)a_stream); if(ret>0) { - identify_info->proto=PROTO_FTP; + context->proto=PROTO_FTP; return 1; } } if(g_tsg_para.proto_flag&(1<<PROTO_MAIL)) //mail { - ret=mail_protocol_identify_by_first_payload(a_stream,(char *)a_stream->ptcpdetail->pdata, a_stream->ptcpdetail->datalen, a_stream->threadnum); + ret=mail_protocol_identify_by_first_payload((struct streaminfo *)a_stream,(char *)a_stream->ptcpdetail->pdata, a_stream->ptcpdetail->datalen, a_stream->threadnum); if(ret>0) { switch(ret) { case SMTP_PROTOCOL: - identify_info->proto=PROTO_SMTP; + context->proto=PROTO_SMTP; return 1; break; case POP3_PROTOCOL: - identify_info->proto=PROTO_POP3; + context->proto=PROTO_POP3; return 1; break; case IMAP_PROTOCOL: - identify_info->proto=PROTO_IMAP; + context->proto=PROTO_IMAP; return 1; break; default: @@ -971,7 +1005,7 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide tpl4=a_stream->addr.tuple4_v4; if((ntohs(tpl4->source)==53) || (ntohs(tpl4->dest)==53)) { - identify_info->proto=PROTO_DNS; + context->proto=PROTO_DNS; return 1; } break; @@ -979,7 +1013,7 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide tpl6=a_stream->addr.tuple4_v6; if((ntohs(tpl6->source)==53) || (ntohs(tpl6->dest)==53)) { - identify_info->proto=PROTO_DNS; + context->proto=PROTO_DNS; return 1; } break; @@ -993,21 +1027,38 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide ret = ssh_protocol_identify((unsigned char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen,g_tsg_para.logger); if(ret > 0) { - identify_info->proto=PROTO_SSH; + context->proto=PROTO_SSH; return 1; } } if(g_tsg_para.proto_flag&(1<<PROTO_QUIC)) //quic { - ret=quic_protocol_identify(a_stream, a_packet, identify_info->domain, sizeof(identify_info->domain)); - if(ret>=0) + length=quic_protocol_identify((struct streaminfo *)a_stream, a_packet, buff, sizeof(buff)); + if(length>=0) { - identify_info->proto=PROTO_QUIC; - identify_info->domain_len=ret; + context->proto=PROTO_QUIC; + if(length>0 && strlen(buff)>0) + { + context->domain=(char *)dictator_malloc(a_stream->threadnum, length+1); + memset(context->domain, 0, length+1); + memcpy(context->domain, buff, length); + } return 1; } } + + if(g_tsg_para.proto_flag&(1<<PROTO_SIP)) + { + unsigned char sip_ret=0; + char *from=NULL, *to=NULL; + unsigned int from_len=0, to_len=0; + sip_ret=sip_identify_from_to((char *)a_stream->ptcpdetail->pdata, (unsigned int)a_stream->ptcpdetail->datalen, &from, &from_len, &to, &to_len); + if(sip_ret==SIP_TRUE) + { + context->proto=PROTO_SIP; + } + } break; default: break; @@ -1016,17 +1067,16 @@ static int identify_application_protocol(struct streaminfo *a_stream, struct ide return ret; } -int scan_application_id_and_properties(struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *result, int result_num, scan_status_t *mid, int thread_seq) +int scan_application_id_and_properties(const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, struct app_identify_result *identify_result, int thread_seq) { - int hit_num=0; + int i=0,hit_num=0; + char *name=NULL; char app_id_buff[32]={0}; - struct app_id_label *app_id_label=NULL; struct app_id_dict_table *dict=NULL; - app_id_label=get_app_id_label(a_stream, context, thread_seq); - if(app_id_label!=NULL) + for(i=0; i< identify_result->app_id_num; i++) { - snprintf(app_id_buff, sizeof(app_id_buff), "%d", app_id_label->app_id); + snprintf(app_id_buff, sizeof(app_id_buff), "%d", identify_result->app_id[i]); dict=(struct app_id_dict_table *)Maat_plugin_get_EX_data(g_tsg_maat_feather, g_tsg_para.table_id[TABLE_APP_ID_DICT], (const char *)app_id_buff); if(dict!=NULL) { @@ -1035,180 +1085,60 @@ int scan_application_id_and_properties(struct streaminfo *a_stream, struct maste hit_num+=tsg_scan_app_properties_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, dict->technology, (char *)"technology", thread_seq); hit_num+=tsg_scan_app_properties_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, dict->subcategroy, (char *)"subcategroy", thread_seq); hit_num+=tsg_scan_app_properties_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, dict->characteristics, (char *)"characteristics", thread_seq); - - if(dict->continue_scanning==APP_SCAN_FLAG_STOP) - { - context->continue_scan_app_id=APP_SCAN_FLAG_STOP; - } - hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, dict->app_name, app_id_label->app_id, thread_seq); + hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, dict->app_name, identify_result->app_id[i], thread_seq); } else - { - hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, (char *)"", app_id_label->app_id, thread_seq); + { + name=tsg_l7_protocol_id2name(identify_result->app_id[i]); + hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, ((name==NULL) ? (char *)"" : name), identify_result->app_id[i], thread_seq); } } return hit_num; } -extern "C" char TSG_MASTER_TCP_ENTRY(struct streaminfo *a_tcp, void **pme, int thread_seq,void *a_packet) -{ - int opt_value=0; - int proto_id=0; - char *l7_protocol=NULL; - int ret=0,hit_num=0; - int state=APP_STATE_GIVEME; +static unsigned char master_deal_scan_result(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *result, int hit_num, void *a_packet) +{ Maat_rule_t *p_result=NULL; - struct identify_info identify_info; - Maat_rule_t result[MAX_RESULT_NUM]; - struct rst_tcp_para rst_paras; - struct compile_user_region *user_region=NULL; - int method_type=TSG_METHOD_TYPE_UNKNOWN; - struct master_context *context=(struct master_context *)*pme; - - if(*pme==NULL) - { - init_context(pme, thread_seq); - context=(struct master_context *)*pme; - } - - switch(a_tcp->opstate) - { - case OP_STATE_PENDING: - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_TCP_LINKS], 0, FS_OP_ADD, 1); - set_session_attribute_label(a_tcp, TSG_ATTRIBUTE_TYPE_ESTABLISH_LATECY, NULL, thread_seq); - - memset(&identify_info, 0, sizeof(identify_info)); - ret=identify_application_protocol(a_tcp, &identify_info, a_packet); - if(ret==1) - { - copy_identify_info(context, &identify_info, thread_seq); - set_session_attribute_label(a_tcp, TSG_ATTRIBUTE_TYPE_PROTOCOL, (void *)(&identify_info.proto), thread_seq); - - context->proto=identify_info.proto; - - if(identify_info.proto==PROTO_SSL) - { - set_session_attribute_label(a_tcp, TSG_ATTRIBUTE_TYPE_JA3_HASH, NULL, thread_seq); - } - else - { - context->continue_scan_proto_id=APP_SCAN_FLAG_STOP; - } - - hit_num+=tsg_scan_shared_policy(g_tsg_maat_feather, a_tcp, &identify_info, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, thread_seq); - } - - ret=tsg_scan_nesting_addr(g_tsg_maat_feather, a_tcp, identify_info.proto, &context->mid, result+hit_num, MAX_RESULT_NUM-hit_num); - if(ret>0) - { - hit_num+=ret; - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_HIT_ADDR], 0, FS_OP_ADD, 1); - } - if((is_only_monitor(result, hit_num)) && identify_info.proto!=PROTO_UNKONWN) // business deal action of monitor - { - hit_num=0; - } - break; - default: - break; - } + unsigned char state=APP_STATE_GIVEME; - if(context->proto==PROTO_UNKONWN || context->proto==PROTO_SSL || context->proto>PROTO_APP || context->continue_scan_proto_id==APP_SCAN_FLAG_CONTINUE) /* support block/alert(deny), Do action in fw_http_plug */ - { - proto_id=get_basic_proto_id(a_tcp, context, thread_seq); - if(proto_id>0 && proto_id!=context->basic_proto_id) - { - context->proto=((context->proto==PROTO_SSL) ? PROTO_SSL : PROTO_APP); - context->basic_proto_id=proto_id; - l7_protocol=tsg_l7_protocol_id2name(g_tsg_log_instance, proto_id); - if(l7_protocol==NULL && proto_id==g_tsg_para.mail_proto_id) - { - l7_protocol=(char *)"MAIL"; - } - - hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_tcp, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, l7_protocol, proto_id, thread_seq); - } - } - - hit_num+=scan_application_id_and_properties(a_tcp, context, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, thread_seq); - p_result=tsg_policy_decision_criteria(a_tcp, result, hit_num, &identify_info, thread_seq); + p_result=tsg_policy_decision_criteria(result, hit_num); if(g_tsg_para.default_compile_switch==1 && p_result==NULL) { if(get_default_policy(g_tsg_para.default_compile_id, &result[0])) { p_result=&result[0]; - context->is_default_policy=1; } } - + if(p_result!=NULL) - { + { switch((unsigned char)p_result->action) { case TSG_ACTION_DENY: - user_region=(struct compile_user_region *)Maat_rule_get_ex_data(g_tsg_maat_feather, p_result, g_tsg_para.table_id[TABLE_SECURITY_COMPILE]); - if(user_region!=NULL) + state=deal_deny_action(a_stream, context, p_result); + if((state&APP_STATE_DROPPKT)==APP_STATE_DROPPKT) { - method_type=tsg_get_method_id(user_region->method); - switch(method_type) - { - case TSG_METHOD_TYPE_DROP: - opt_value=1; - MESA_set_stream_opt(a_tcp, MSO_DROP_STREAM, (void *)&opt_value, sizeof(opt_value)); - MESA_set_stream_opt(a_tcp, MSO_TIMEOUT, (void *)&g_tsg_para.timeout, sizeof(g_tsg_para.timeout)); - copy_deny_result(a_tcp, context, p_result, thread_seq); - state=APP_STATE_DROPPKT|APP_STATE_DROPME; - break; - case TSG_METHOD_TYPE_RESET: - rst_paras.rst_pkt_num=1; - rst_paras.signature_seed1=65535; - rst_paras.signature_seed2=13; - rst_paras.th_flags=4; - rst_paras.__pad_no_use=0; - rst_paras.dir=DIR_DOUBLE; - ret=MESA_rst_tcp(a_tcp, &rst_paras, sizeof(rst_paras)); - - opt_value=1; - MESA_set_stream_opt(a_tcp, MSO_TCP_RST_REMEDY, (void *)&opt_value, sizeof(opt_value)); - - if(g_tsg_para.depolyment_mode>0) - { - opt_value=1; - MESA_set_stream_opt(a_tcp, MSO_DROP_STREAM, (void *)&opt_value, sizeof(opt_value)); - MESA_set_stream_opt(a_tcp, MSO_TIMEOUT, (void *)&g_tsg_para.timeout, sizeof(g_tsg_para.timeout)); - } - copy_deny_result(a_tcp, context, p_result, thread_seq); - state=APP_STATE_DROPPKT|APP_STATE_DROPME; - break; - case TSG_METHOD_TYPE_BLOCK: - case TSG_METHOD_TYPE_ALERT: - case TSG_METHOD_TYPE_REDIRECTION: - break; - default: - break; - } - - security_compile_free(g_tsg_para.table_id[TABLE_SECURITY_COMPILE], p_result, NULL, (MAAT_RULE_EX_DATA *)&user_region, 0, NULL); + master_send_log(a_stream, p_result, 1, context->domain, context->proto, a_stream->threadnum); } break; case TSG_ACTION_MONITOR: - copy_monitor_result(a_tcp, context, result, hit_num, thread_seq); + copy_monitor_result(a_stream, context, result, hit_num, a_stream->threadnum); break; case TSG_ACTION_BYPASS: - copy_bypass_result(a_tcp, context, p_result, thread_seq); + copy_bypass_result(a_stream, context, p_result, a_stream->threadnum); FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_BYPASS], 0, FS_OP_ADD, 1); state=APP_STATE_GIVEME|APP_STATE_KILL_OTHER; break; case TSG_ACTION_INTERCEPT: - if(is_intercept_exclusion(a_tcp, p_result, &identify_info, thread_seq)) + if(is_intercept_exclusion(a_stream, p_result, context->domain, a_stream->threadnum)) { FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_EXCLUSION], 0, FS_OP_ADD, 1); break; } - copy_intercept_result(a_tcp, context, p_result, &identify_info, thread_seq); + copy_intercept_result(a_stream, context, p_result, context->domain, context->proto, a_stream->threadnum); FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_INTERCEPT], 0, FS_OP_ADD, 1); state=APP_STATE_DROPME|APP_STATE_KILL_OTHER; break; @@ -1217,151 +1147,184 @@ extern "C" char TSG_MASTER_TCP_ENTRY(struct streaminfo *a_tcp, void **pme, int t } } - if((a_tcp->opstate==OP_STATE_CLOSE) || (state&APP_STATE_DROPME)==APP_STATE_DROPME) - { - close_stream_free_context(a_tcp, context, thread_seq); - *pme=NULL; - } - return state; } -extern "C" char TSG_MASTER_UDP_ENTRY(struct streaminfo *a_udp, void **pme, int thread_seq,void *a_packet) +static int app_identify_result_cb(const struct streaminfo *a_stream, int bridge_id, void *data) { - int ret=0,hit_num=0; - int opt_value=0,proto_id=0; - char *l7_protocol=NULL; - int state=APP_STATE_GIVEME; - Maat_rule_t *p_result=NULL; - Maat_rule_t result[MAX_RESULT_NUM]={0}; - struct identify_info identify_info; - struct compile_user_region *user_region=NULL; - int method_type=TSG_METHOD_TYPE_UNKNOWN; - struct master_context *context=(struct master_context *)*pme; + int hit_num=0; + struct master_context *context=NULL; + struct Maat_rule_t scan_result[MAX_RESULT_NUM]; + struct gather_app_result *gather_result=NULL; + struct app_identify_result *identify_result=(struct app_identify_result *)data; - if(*pme==NULL) + if(data==NULL) + { + return 0; + } + + gather_result=(struct gather_app_result *)get_struct_project(a_stream, g_tsg_para.gather_app_project_id); + if(gather_result==NULL) { - init_context(pme, thread_seq); - context=(struct master_context *)*pme; + gather_result=(struct gather_app_result *)dictator_malloc(a_stream->threadnum, sizeof(struct gather_app_result)); + memset(gather_result, 0, sizeof(struct gather_app_result)); + set_struct_project(a_stream, g_tsg_para.gather_app_project_id, (void *)gather_result); } - switch(a_udp->opstate) + + switch(identify_result->origin) { - case OP_STATE_PENDING: - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_UDP_LINKS], 0, FS_OP_ADD, 1); + case ORIGIN_DKPT: + case ORIGIN_QM_ENGINE: + case ORIGIN_USER_DEFINE: + case ORIGIN_BASIC_PROTOCOL: + memcpy(&(gather_result->result[identify_result->origin]), identify_result, sizeof(struct app_identify_result)); + break; + default: + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "APP_BRIDGE_CB", "Unknown type: %d addr: %s", identify_result->origin, PRINTADDR(a_stream, g_tsg_para.level)); + return 0; + } - memset(&identify_info, 0, sizeof(identify_info)); - ret=identify_application_protocol(a_udp, &identify_info, a_packet); - if(ret==1) - { - copy_identify_info(context, &identify_info, thread_seq); - set_session_attribute_label(a_udp, TSG_ATTRIBUTE_TYPE_PROTOCOL, (void *)&(identify_info.proto), thread_seq); + context=(struct master_context *)get_struct_project(a_stream, g_tsg_para.context_project_id); + if(context==NULL) + { + init_context((void **)&context, a_stream->threadnum); + } + + record_time_start(&context->last_scan_time); + + hit_num=scan_application_id_and_properties((struct streaminfo *)a_stream, scan_result, MAX_RESULT_NUM, &context->mid, identify_result, a_stream->threadnum); + master_deal_scan_result(a_stream, context, scan_result, hit_num, NULL); - context->proto=identify_info.proto; - context->continue_scan_proto_id=APP_SCAN_FLAG_STOP; - hit_num+=tsg_scan_shared_policy(g_tsg_maat_feather, a_udp, &identify_info, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, thread_seq); - } + return 0; +} - ret=tsg_scan_nesting_addr(g_tsg_maat_feather, a_udp, identify_info.proto, &context->mid, result, MAX_RESULT_NUM); - if(ret>0) - { - hit_num+=ret; - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_HIT_ADDR], 0, FS_OP_ADD, 1); - } - if((is_only_monitor(result, hit_num)) && identify_info.proto!=PROTO_UNKONWN) // business deal action of deny and monitor - { - hit_num=0; - } +static int master_deal_pending_state(const struct streaminfo *a_stream, struct master_context *context, struct Maat_rule_t *result, int result_num, void *a_packet) +{ + int table_id=0; + int ret=0,hit_num=0; + unsigned int protocol_id=0; + + ret=identify_application_protocol(a_stream, context, a_packet); + if(ret==1) + { + set_session_attribute_label(a_stream, TSG_ATTRIBUTE_TYPE_PROTOCOL, (void *)&(context->proto), a_stream->threadnum); - break; - default: - break; + if(context->proto==PROTO_SSL) + { + set_session_attribute_label(a_stream, TSG_ATTRIBUTE_TYPE_JA3_HASH, NULL, a_stream->threadnum); + } + else + { + context->continue_scan_proto_id=APP_SCAN_FLAG_STOP; + } + + table_id=get_table_id(context->proto); + hit_num+=tsg_scan_shared_policy(g_tsg_maat_feather, a_stream, context->domain, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, table_id, a_stream->threadnum); + hit_num+=scan_fqdn_category_id(g_tsg_maat_feather, a_stream, context->domain, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, table_id, a_stream->threadnum); + if(context->is_esni) + { + protocol_id=tsg_l7_protocol_name2id("ESNI"); + hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_stream, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, (char *)"ESNI", protocol_id, a_stream->threadnum); + } } - if(context->proto==PROTO_UNKONWN || context->proto>PROTO_APP || context->continue_scan_proto_id==APP_SCAN_FLAG_CONTINUE) + ret=tsg_scan_nesting_addr(g_tsg_maat_feather, a_stream, context->proto, &context->mid, result+hit_num, MAX_RESULT_NUM-hit_num); + if(ret>0) { - proto_id=get_basic_proto_id(a_udp, context, thread_seq); - if(proto_id>0 && context->basic_proto_id!=proto_id) - { - if(is_repetitive_protocol_id(proto_id)) - { - context->continue_scan_proto_id=APP_SCAN_FLAG_STOP; - switch(proto_id) - { - case SIP_PROTO_ID: - context->proto=PROTO_SIP; - set_session_attribute_label(a_udp, TSG_ATTRIBUTE_TYPE_PROTOCOL, (void *)&(context->proto), thread_seq); - break; - case RTP_PROTO_ID: - context->proto=PROTO_RTP; - set_session_attribute_label(a_udp, TSG_ATTRIBUTE_TYPE_PROTOCOL, (void *)&(context->proto), thread_seq); - break; - default: - break; - } - } - else - { - context->proto=PROTO_APP; - } - - context->basic_proto_id=proto_id; - l7_protocol=tsg_l7_protocol_id2name(g_tsg_log_instance, proto_id); - hit_num+=tsg_scan_app_id_policy(g_tsg_maat_feather, a_udp, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, l7_protocol, proto_id, thread_seq); - } + hit_num+=ret; + FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_HIT_ADDR], 0, FS_OP_ADD, 1); } - hit_num+=scan_application_id_and_properties(a_udp, context, result+hit_num, MAX_RESULT_NUM-hit_num, &context->mid, thread_seq); - p_result=tsg_policy_decision_criteria(a_udp, result, hit_num, &identify_info, thread_seq); - if(g_tsg_para.default_compile_switch==1 && p_result==NULL) + if((is_only_monitor(result, hit_num)) && context->proto!=PROTO_UNKONWN) // business deal action of monitor { - if(get_default_policy(g_tsg_para.default_compile_id, &result[0])) + hit_num=0; + } + + return hit_num; +} + +extern "C" unsigned char TSG_MASTER_TCP_ENTRY(const struct streaminfo *a_tcp, void **pme, int thread_seq,void *a_packet) +{ + int hit_num=0; + unsigned char state=APP_STATE_GIVEME; + Maat_rule_t result[MAX_RESULT_NUM]; + struct master_context *context=(struct master_context *)*pme; + + if(*pme==NULL) + { + context=(struct master_context *)get_struct_project(a_tcp, g_tsg_para.context_project_id); + if(context==NULL) + { + init_context(pme, thread_seq); + context=(struct master_context *)*pme; + set_struct_project(a_tcp, g_tsg_para.context_project_id, *pme); + } + else { - p_result=&result[0]; - context->is_default_policy=1; + *pme=(void *)context; } + record_time_start(&context->last_scan_time); + } + + if(a_tcp->opstate==OP_STATE_PENDING) + { + FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_TCP_LINKS], 0, FS_OP_ADD, 1); + set_session_attribute_label(a_tcp, TSG_ATTRIBUTE_TYPE_ESTABLISH_LATECY, NULL, thread_seq); + hit_num+=master_deal_pending_state(a_tcp, context, result-hit_num, MAX_RESULT_NUM-hit_num, a_packet); } - if(p_result!=NULL) + if(record_time_elapse_us(&context->last_scan_time)/100000 > g_tsg_para.scan_time_interval) { - switch((unsigned char)p_result->action) + record_time_start(&context->last_scan_time); + } + + state=master_deal_scan_result(a_tcp, context, result, hit_num, a_packet); + if((a_tcp->opstate==OP_STATE_CLOSE) || (state&APP_STATE_DROPME)==APP_STATE_DROPME) + { + close_stream_free_context(a_tcp, context, thread_seq); + *pme=NULL; + } + + return state; +} + +extern "C" unsigned char TSG_MASTER_UDP_ENTRY(const struct streaminfo *a_udp, void **pme, int thread_seq,void *a_packet) +{ + int hit_num=0; + unsigned char state=APP_STATE_GIVEME; + Maat_rule_t result[MAX_RESULT_NUM]={0}; + struct master_context *context=(struct master_context *)*pme; + + if(*pme==NULL) + { + context=(struct master_context *)get_struct_project(a_udp, g_tsg_para.context_project_id); + if(context==NULL) { - case TSG_ACTION_DENY: - user_region=(struct compile_user_region *)Maat_rule_get_ex_data(g_tsg_maat_feather, p_result, g_tsg_para.table_id[TABLE_SECURITY_COMPILE]); - if(user_region!=NULL) - { - method_type=tsg_get_method_id(user_region->method); - switch(method_type) - { - case TSG_METHOD_TYPE_RESET: - case TSG_METHOD_TYPE_DROP: - opt_value=1; - MESA_set_stream_opt(a_udp, MSO_DROP_STREAM, (void *)&opt_value, sizeof(opt_value)); - MESA_set_stream_opt(a_udp, MSO_TIMEOUT, (void *)&g_tsg_para.timeout, sizeof(g_tsg_para.timeout)); - break; - default: - break; - } - security_compile_free(g_tsg_para.table_id[TABLE_SECURITY_COMPILE], p_result, NULL, (MAAT_RULE_EX_DATA *)&user_region, 0, NULL); - } - copy_deny_result(a_udp, context, p_result, thread_seq); - state=APP_STATE_DROPPKT|APP_STATE_DROPME; - break; - case TSG_ACTION_MONITOR: - copy_monitor_result(a_udp, context, result, hit_num, thread_seq); - break; - case TSG_ACTION_BYPASS: - copy_bypass_result(a_udp, context, p_result, thread_seq); - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_BYPASS], 0, FS_OP_ADD, 1); - state=APP_STATE_GIVEME|APP_STATE_KILL_OTHER; - break; - case TSG_ACTION_INTERCEPT: - break; - default: - break; + init_context(pme, thread_seq); + context=(struct master_context *)*pme; + set_struct_project(a_udp, g_tsg_para.context_project_id, *pme); } + else + { + *pme=(void *)context; + } + record_time_start(&context->last_scan_time); + } + + if(a_udp->opstate==OP_STATE_PENDING) + { + FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_UDP_LINKS], 0, FS_OP_ADD, 1); + hit_num+=master_deal_pending_state(a_udp, context, result-hit_num, MAX_RESULT_NUM-hit_num, a_packet); } + if(record_time_elapse_us(&context->last_scan_time)/100000 > g_tsg_para.scan_time_interval) + { + record_time_start(&context->last_scan_time); + } + + state=master_deal_scan_result(a_udp, context, result, hit_num, a_packet); + if((a_udp->opstate==OP_STATE_CLOSE) || (state&APP_STATE_DROPME)==APP_STATE_DROPME) { close_stream_free_context(a_udp, context, thread_seq); @@ -1373,6 +1336,7 @@ extern "C" char TSG_MASTER_UDP_ENTRY(struct streaminfo *a_udp, void **pme, int t extern "C" int TSG_MASTER_INIT() { int i=0,ret=0; + char buff[128]={0}; int value=0,cycle=0; int output_prometheus=0; unsigned short fs_server_port=0; @@ -1384,8 +1348,6 @@ extern "C" int TSG_MASTER_INIT() char identify_proto_name[MAX_STRING_LEN*4]={0}; memset(&g_tsg_para, 0, sizeof(g_tsg_para)); - - get_depolyment_mode(); MESA_load_profile_int_def(tsg_conffile, "SYSTEM","LOG_LEVEL", &g_tsg_para.level, RLOG_LV_FATAL); MESA_load_profile_string_def(tsg_conffile, "SYSTEM","LOG_PATH", g_tsg_para.log_path, sizeof(g_tsg_para.log_path), "tsglog/tsg_master"); @@ -1401,12 +1363,13 @@ extern "C" int TSG_MASTER_INIT() MESA_load_profile_int_def(tsg_conffile, "SYSTEM","DEFAULT_POLICY_ID", &g_tsg_para.default_compile_id, 0); MESA_load_profile_int_def(tsg_conffile, "SYSTEM","DEFAULT_POLICY_SWITCH", &g_tsg_para.default_compile_switch, 0); - MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "IDENTIFY_PROTO_NAME", identify_proto_name, sizeof(identify_proto_name), "HTTP;SSL;DNS;FTP;BGP;SIP;MAIL;STREAMING_MEDIA;QUIC;"); + MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "IDENTIFY_PROTO_NAME", identify_proto_name, sizeof(identify_proto_name), "HTTP;SSL;DNS;FTP;BGP;SIP;MAIL;STREAMING_MEDIA;QUIC;SIP;"); tsg_proto_name2flag(identify_proto_name, &g_tsg_para.proto_flag); MESA_load_profile_int_def(tsg_conffile, "SYSTEM", "ENTRANCE_ID", &g_tsg_para.entrance_id, 0); MESA_load_profile_short_def(tsg_conffile, "SYSTEM", "TIMEOUT", (short *)&g_tsg_para.timeout, 300); MESA_load_profile_int_def(tsg_conffile, "SYSTEM", "MAIL_PROTOCOL_ID",&(g_tsg_para.mail_proto_id), 110); + MESA_load_profile_int_def(tsg_conffile, "SYSTEM", "SCAN_TIME_INTERVAL", &g_tsg_para.scan_time_interval, 10); MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "DEVICE_ID_COMMAND", g_tsg_para.device_id_command, sizeof(g_tsg_para.device_id_command), NULL); g_tsg_para.device_id=get_device_id(g_tsg_para.device_id_command, g_tsg_para.entrance_id); @@ -1428,13 +1391,7 @@ extern "C" int TSG_MASTER_INIT() g_tsg_para.priority_project_id=project_producer_register(label_buff, PROJECT_VAL_TYPE_STRUCT, free_policy_label); if(g_tsg_para.priority_project_id<0) { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_FATAL, - "PROJECT_REGISTER", - "Register %s failed; please check :%s and add <POLICY_PRIORITY struct>", - label_buff, - "etc/project_list.conf" - ); + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "PROJECT_REGISTER", "Register %s failed.", label_buff); return -1; } @@ -1442,37 +1399,35 @@ extern "C" int TSG_MASTER_INIT() g_tsg_para.internal_project_id=project_producer_register(label_buff, PROJECT_VAL_TYPE_STRUCT, free_session_attribute_label); if(g_tsg_para.internal_project_id<0) { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_FATAL, - "PROJECT_REGISTER", - "Register %s failed; please check :%s and add <TSG_MASTER_INTERNAL_LABEL struct>", - label_buff, - "etc/project_list.conf" - ); + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "PROJECT_REGISTER", "Register %s failed.", label_buff); } - MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "APP_ID_LABEL", label_buff, sizeof(label_buff), "APP_ID_LABEL"); - g_tsg_para.app_id_project_id=project_producer_register(label_buff, PROJECT_VAL_TYPE_STRUCT, free_app_id_label); - if(g_tsg_para.app_id_project_id<0) + MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "APP_BRIDGE_NAME", label_buff, sizeof(label_buff), "APP_BRIDGE"); + g_tsg_para.app_bridge_id=stream_bridge_build(label_buff, "w"); + if(g_tsg_para.app_bridge_id<0) { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_FATAL, - "APP_ID_LABEL", - "project_customer_register is error, app_id_label: %s, please check etc/project.conf", - label_buff - ); + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "APP_BRIDGE", "stream_bridge_build is error, app_bridge_name: %s", label_buff); } - MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "L7_PROTO_LABEL", label_buff, sizeof(label_buff), "BASIC_PROTO_LABEL"); - g_tsg_para.l7_proto_project_id=project_customer_register(label_buff, "struct"); - if(g_tsg_para.l7_proto_project_id<0) + ret=stream_bridge_register_data_sync_cb(g_tsg_para.app_bridge_id, app_identify_result_cb); + if(ret<0) + { + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "APP_BRIDGE", "Register callback failed, app_bridge_id: %d", g_tsg_para.app_bridge_id); + return -1; + } + + g_tsg_para.context_project_id=project_producer_register("TSG_MASTER_CONTEXT", PROJECT_VAL_TYPE_STRUCT, free_context_label); + if(g_tsg_para.context_project_id<0) { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_FATAL, - "L7_PROTO_LABEL", - "project_customer_register is error, l7_proto_label: %s, please check etc/project.conf", - label_buff - ); + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "CONTEXT_LABEL", "project_customer_register is error, context label: %s","TSG_MASTER_CONTEXT"); + return -1; + } + + g_tsg_para.gather_app_project_id=project_producer_register("APP_IDENTIFY_RESULT", PROJECT_VAL_TYPE_STRUCT, free_gather_app_result); + if(g_tsg_para.gather_app_project_id<0) + { + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "APP_IDENTIFY_RESULT", "project_customer_register is error, context label: %s","APP_IDENTIFY_RESULT"); + return -1; } ret=tsg_rule_init(tsg_conffile, g_tsg_para.logger); @@ -1525,7 +1480,6 @@ extern "C" int TSG_MASTER_INIT() g_tsg_para.fs2_field_id[i]=FS_register(g_tsg_para.fs2_handle, FS_STYLE_FIELD, FS_CALC_SPEED, g_tsg_fs2_field[i].name); } - char buff[32]={0}; int thread_num=get_thread_count(); for(i=0; i<thread_num && g_tsg_log_instance!=NULL; i++) { @@ -1546,6 +1500,9 @@ extern "C" int TSG_MASTER_INIT() MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_FATAL, "INIT_STATISTIC", "tsg_statistic_init failed ..."); return -1; } + + MESA_load_profile_string_def(tsg_conffile, "SYSTEM", "L7_RPTOCOL_FILE", buff, sizeof(buff), "./tsgconf/tsg_l7_protocol.conf"); + l7_protocol_mapper(buff); return 0; } diff --git a/src/tsg_entry.h b/src/tsg_entry.h index cfe06ce..d0041a7 100644 --- a/src/tsg_entry.h +++ b/src/tsg_entry.h @@ -3,7 +3,10 @@ #include <MESA/Maat_rule.h> #include <MESA/field_stat2.h> + +#include "uthash.h" #include "tsg_rule.h" +#include "app_label.h" #include "tsg_label.h" #include "tsg_statistic.h" @@ -28,15 +31,6 @@ typedef int atomic_t; #define PRINTADDR(a, b) ((b)<RLOG_LV_FATAL ? printaddr(&(a->addr), a->threadnum) : "") #endif -#define DNS_PROTO_ID 103 -#define FTP_PROTO_ID 104 -#define HTTP_PROTO_ID 106 -#define MAIL_PROTO_ID 110 -#define QUIC_PROTO_ID 119 -#define SIP_PROTO_ID 120 -#define SSL_PROTO_ID 126 -#define RTP_PROTO_ID 142 - #define APP_SCAN_FLAG_STOP 0 #define APP_SCAN_FLAG_CONTINUE 1 @@ -101,6 +95,20 @@ struct _str2index char *type; }; +struct gather_app_result +{ + struct app_identify_result result[ORIGIN_MAX]; +}; + +struct l7_protocol +{ + int id; /* first key */ + char name[32]; /* second key */ + UT_hash_handle hh1; /* handle for first hash table */ + UT_hash_handle hh2; /* handle for second hash table */ +}; + + struct _fqdn_category_t { int ref_cnt; @@ -114,14 +122,13 @@ struct master_context tsg_protocol_t proto; int hit_cnt; int app_id; - int is_default_policy; - char continue_scan_app_id; + int is_esni; char continue_scan_proto_id; unsigned short basic_proto_id; - int domain_len; - char domain[MAX_DOAMIN_LEN]; + char *domain; struct Maat_rule_t *result; - scan_status_t mid; + scan_status_t mid; + struct timespec last_scan_time; }; #define _MAX_TABLE_NAME_LEN 64 @@ -130,18 +137,19 @@ typedef struct _tsg_para int level; int mail_proto_id; unsigned short timeout; - unsigned short depolyment_mode; int app_id_table_type; int device_id; int entrance_id; + int scan_time_interval; int default_compile_switch; int default_compile_id; int table_id[TABLE_MAX]; int dyn_subscribe_ip_table_id; //TSG_DYN_SUBSCRIBER_IP int priority_project_id; int internal_project_id; - int l7_proto_project_id; - int app_id_project_id; + int context_project_id; + int gather_app_project_id; + int app_bridge_id; int proto_flag; //tsg_protocol_t int fs2_field_id[TSG_FS2_MAX]; char device_sn[MAX_DOAMIN_LEN/8]; @@ -151,6 +159,8 @@ typedef struct _tsg_para char table_name[TABLE_MAX][_MAX_TABLE_NAME_LEN]; void *logger; screen_stat_handle_t fs2_handle; + struct l7_protocol *name_by_id; + struct l7_protocol *id_by_name; }g_tsg_para_t; extern g_tsg_para_t g_tsg_para; @@ -244,11 +254,14 @@ void location_free_data(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void* void ASN_free_data(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp); void subscribe_id_free_data(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp); void security_compile_free(int idx, const struct Maat_rule_t* rule, const char* srv_def_large, MAAT_RULE_EX_DATA* ad, long argl, void *argp); -char *tsg_schema_index2string(tsg_protocol_t proto); -struct Maat_rule_t *tsg_policy_decision_criteria(struct streaminfo *a_stream, Maat_rule_t *result, int result_num, struct _identify_info *identify_info, int thread_seq); -int tsg_scan_shared_policy(Maat_feather_t maat_feather, struct streaminfo *a_stream, struct identify_info *identify_info, Maat_rule_t *result, int result_num, scan_status_t *mid, int thread_seq); +struct Maat_rule_t *tsg_policy_decision_criteria(struct streaminfo *a_stream, Maat_rule_t *result, int result_num, int thread_seq); +int tsg_scan_shared_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, char *domain, Maat_rule_t *result, int result_num, scan_status_t *mid, int table_id, int thread_seq); int tsg_scan_app_id_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *name, unsigned int id, int thread_seq); -int tsg_scan_app_properties_policy(Maat_feather_t maat_feather, struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *property, char *district, int thread_seq); +int tsg_scan_app_properties_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *property, char *district, int thread_seq); int tsg_scan_subscribe_id_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, struct _subscribe_id_info_t *user_info, int thread_seq); +int tsg_scan_fqdn_category_id(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, int table_id, unsigned int *category_id, int category_id_num, int thread_seq); +unsigned int tsg_l7_protocol_name2id(const char *l7_protocol_name); +char *tsg_l7_protocol_id2name(unsigned int l7_protocol_id); + #endif diff --git a/src/tsg_rule.cpp b/src/tsg_rule.cpp index ceafc0d..b75af05 100644 --- a/src/tsg_rule.cpp +++ b/src/tsg_rule.cpp @@ -12,6 +12,7 @@ #include "Maat_command.h" #include "MESA/http.h" #include "tsg_rule.h" +#include "tsg_label.h" #include "tsg_entry.h" #include "tsg_send_log.h" #include "tsg_send_log_internal.h" @@ -76,35 +77,6 @@ static char* str_unescape(char* s) return s; } -static int proto_str2id(tsg_protocol_t proto) -{ - switch(proto) - { - case PROTO_TCP: return 100; - case PROTO_UDP: return 101; - case PROTO_HTTP: return 106; - case PROTO_MAIL: return 110; - case PROTO_IMAP: return 151; - case PROTO_POP3: return 116;//116 - case PROTO_SMTP: return 122;//122 - case PROTO_DNS: return 103; - case PROTO_FTP: return 104; - case PROTO_SSL: return 126; - case PROTO_SIP: return 120; - case PROTO_QUIC: return 119; - case PROTO_SSH: return 125; - case PROTO_RTP: return 142; - case PROTO_IPv6: - case PROTO_IPv4: - case PROTO_STREAMING_MEDIA: - case PROTO_BGP: - default: - break; - } - - return 0; -} - static int get_data_center(char *accept_tag, char *effective_tag_key, char *data_center, int data_center_len) { int i=0,len; @@ -954,43 +926,34 @@ int tsg_pull_policy_result(struct streaminfo *a_stream, PULL_RESULT_TYPE pull_re { if(label->result_type==pull_result_type) { - num=(label->result_num>result_num) ? result_num : label->result_num; + num=MIN(label->result_num, result_num); memcpy(result, label->result, num*sizeof(Maat_rule_t)); - - memcpy(identify_info->domain, label->domain, label->domain_len); - identify_info->domain_len=label->domain_len; + if(label->domain_len>0) + { + memcpy(identify_info->domain, label->domain, label->domain_len); + identify_info->domain_len=label->domain_len; + } + identify_info->proto = label->proto; return num; } - else - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "PULL_RESULT", - "pull policy failed, hit: %s %s: %s policy_id: %d service: %d action: %d addr: %s", - (label->result_type==PULL_KNI_RESULT) ? "KNI" : "FW", - label->proto==PROTO_HTTP ? "host" : "sni", - label->domain, - label->result->config_id, - label->result->service_id, - label->result->action, - PRINTADDR(a_stream, g_tsg_para.level) - ); - } - } - else - { + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_DEBUG, - "PULL_RESULT", - "pull policy failed, Not hit, label is %s addr: %s", - (label==NULL) ? "NULL" : label->domain, + "PULL_RESULT", + "pull policy failed, hit: %s %s: %s policy_id: %d service: %d action: %d addr: %s", + (label->result_type==PULL_KNI_RESULT) ? "KNI" : "FW", + label->proto==PROTO_HTTP ? "host" : "sni", + label->domain, + label->result->config_id, + label->result->service_id, + label->result->action, PRINTADDR(a_stream, g_tsg_para.level) ); } - + return 0; } @@ -1192,11 +1155,11 @@ int tsg_scan_ip_location(Maat_feather_t maat_feather, const struct streaminfo *a int tsg_scan_nesting_addr(Maat_feather_t maat_feather, const struct streaminfo *a_stream, tsg_protocol_t proto, scan_status_t *mid, Maat_rule_t*result, int result_num) { int ret=0; - struct ipaddr t_addr; unsigned int proto_id=0; + struct ipaddr t_addr; struct ipaddr* p_addr=NULL; int hit_num=0,tans_proto=0; - int is_scan_addr=1, maat_ret=0; + int is_scan_addr=1, maat_ret=0; const struct streaminfo *cur_stream = a_stream; struct _session_attribute_label_t *attribute_label=NULL; @@ -1274,11 +1237,11 @@ int tsg_scan_nesting_addr(Maat_feather_t maat_feather, const struct streaminfo * if(hit_num<result_num && proto>PROTO_UNKONWN && proto<PROTO_MAX) { - proto_id=proto_str2id(proto); + proto_id=tsg_l7_protocol_name2id(g_tsg_proto_name2id[proto].name); hit_num+=tsg_scan_app_id_policy(maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, g_tsg_proto_name2id[proto].name, proto_id, (int)a_stream->threadnum); if(proto==PROTO_SMTP || proto==PROTO_IMAP || proto==PROTO_POP3) { - proto_id=proto_str2id(PROTO_MAIL); + proto_id=tsg_l7_protocol_name2id(g_tsg_proto_name2id[PROTO_MAIL].name); hit_num+=tsg_scan_app_id_policy(maat_feather, a_stream, result+hit_num, result_num-hit_num, mid, g_tsg_proto_name2id[PROTO_MAIL].name, proto_id, (int)a_stream->threadnum); } } @@ -1332,133 +1295,36 @@ int tsg_scan_nesting_addr(Maat_feather_t maat_feather, const struct streaminfo * //return value: -1: failed, 0: not hit, >0: hit count -int tsg_scan_shared_policy(Maat_feather_t maat_feather, struct streaminfo *a_stream, struct identify_info *identify_info, Maat_rule_t *result, int result_num, scan_status_t *mid, int thread_seq) +int tsg_scan_shared_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, char *domain, Maat_rule_t *result, int result_num, scan_status_t *mid, int table_id, int thread_seq) { - char *field_name=NULL; - int i=0,ret=0,idx=0,hit_num=0; - struct _session_attribute_label_t *attribute_label=NULL; + int ret=0; - if(identify_info->proto!=PROTO_UNKONWN && strlen(identify_info->domain)>0 && identify_info->domain_len>0) + if(table_id<0 || domain==NULL) { - switch(identify_info->proto) - { - case PROTO_HTTP: - idx=TABLE_HTTP_HOST; - field_name=(char *)"http_host"; - break; - case PROTO_SSL: - idx=TABLE_SSL_SNI; - field_name=(char *)"ssl_sni"; - break; - case PROTO_QUIC: - idx=TABLE_QUIC_SNI; - field_name=(char *)"quic_sni"; - break; - default: - return 0; - break; - } - - ret=Maat_full_scan_string(g_tsg_maat_feather, - g_tsg_para.table_id[idx], - CHARSET_UTF8, - identify_info->domain, - identify_info->domain_len, - result, - NULL, - result_num, - mid, - thread_seq + return 0; + } + + ret=Maat_full_scan_string(g_tsg_maat_feather, table_id, CHARSET_UTF8, domain, strlen(domain), result, NULL, result_num, mid, thread_seq); + if(ret>0) + { + FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_HIT_SHARE], 0, FS_OP_ADD, 1); + MESA_handle_runtime_log(g_tsg_para.logger, + RLOG_LV_DEBUG, + "SCAN_FQDN", + "Hit %s policy_id: %d service: %d action: %d addr: %s", + domain, + result[0].config_id, + result[0].service_id, + (unsigned char)result[0].action, + PRINTADDR(a_stream, g_tsg_para.level) ); - if(ret>0) - { - FS_operate(g_tsg_para.fs2_handle, g_tsg_para.fs2_field_id[TSG_FS2_HIT_SHARE], 0, FS_OP_ADD, 1); - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "SCAN_FQDN", - "Hit %s: %s policy_id: %d service: %d action: %d addr: %s", - field_name, - identify_info->domain, - result[hit_num].config_id, - result[hit_num].service_id, - (unsigned char)result[hit_num].action, - PRINTADDR(a_stream, g_tsg_para.level) - ); - hit_num+=ret; - } - else - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "SCAN_FQDN", - "Not hit %s: %s ret: %d stream_dir: %d addr: %s", - (ret==-1) ? "NULL" : ((identify_info->proto==PROTO_HTTP) ? "host" : "sni"), - (ret==-1) ? "NULL" : identify_info->domain, - ret, - a_stream->dir, - PRINTADDR(a_stream, g_tsg_para.level) - ); - } - - attribute_label=(struct _session_attribute_label_t *)project_req_get_struct(a_stream, g_tsg_para.internal_project_id); - if(attribute_label!=NULL) - { - attribute_label->fqdn_category_id_num=tsg_get_fqdn_category_id(g_tsg_maat_feather, - identify_info->domain, - attribute_label->fqdn_category_id, - MAX_CATEGORY_ID_NUM, - g_tsg_para.logger, - thread_seq - ); - - - for(i=0; i<attribute_label->fqdn_category_id_num; i++) - { - int idx=identify_info->proto==PROTO_HTTP ? TABLE_HTTP_HOST : TABLE_SSL_SNI; - ret=Maat_scan_intval(g_tsg_maat_feather, - g_tsg_para.table_id[idx], - (unsigned int)attribute_label->fqdn_category_id[i], - result+hit_num, - result_num-hit_num, - mid, - thread_seq - ); - if(ret>0) - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "SCAN_FQDN_CAT", - "Hit %s: %s category_id: %d policy_id: %d service: %d action: %d addr: %s", - (identify_info->proto==PROTO_HTTP) ? "host" : "sni", - identify_info->domain, - attribute_label->fqdn_category_id[i], - result[hit_num].config_id, - result[hit_num].service_id, - (unsigned char)result[hit_num].action, - PRINTADDR(a_stream, g_tsg_para.level) - ); - hit_num+=ret; - } - else - { - MESA_handle_runtime_log(g_tsg_para.logger, - RLOG_LV_DEBUG, - "SCAN_FQDN_CAT", - "Not hit %s: %s category_id: %d ret: %d stream_dir: %d addr: %s", - (ret==-1) ? "NULL" : ((identify_info->proto==PROTO_HTTP) ? "host" : "sni"), - (ret==-1) ? "NULL" : identify_info->domain, - attribute_label->fqdn_category_id[i], - ret, - a_stream->dir, - PRINTADDR(a_stream, g_tsg_para.level) - ); - } - } - } + return ret; } - - return hit_num; + + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_DEBUG, "SCAN_FQDN", "Not hit %s ret: %d stream_dir: %d addr: %s", domain, ret, a_stream->dir, PRINTADDR(a_stream, g_tsg_para.level)); + + return 0; } @@ -1551,6 +1417,41 @@ int tsg_get_fqdn_category_id(Maat_feather_t maat_feather, char *fqdn, unsigned i return 0; } +int tsg_scan_fqdn_category_id(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, int table_id, unsigned int *category_id, int category_id_num, int thread_seq) +{ + int i=0,ret=0,hit_num=0; + + if(table_id<0 || result_num<=0 || category_id==NULL) + { + return 0; + } + + for(i=0; i<category_id_num; i++) + { + ret=Maat_scan_intval(g_tsg_maat_feather, table_id, (unsigned int)category_id[i], result+hit_num, result_num-hit_num, mid, thread_seq); + if(ret>0) + { + MESA_handle_runtime_log(g_tsg_para.logger, + RLOG_LV_DEBUG, + "SCAN_FQDN_CAT", + "Hit category_id: %d policy_id: %d service: %d action: %d addr: %s", + category_id[i], + result[hit_num].config_id, + result[hit_num].service_id, + (unsigned char)result[hit_num].action, + PRINTADDR(a_stream, g_tsg_para.level) + ); + hit_num+=ret; + } + else + { + MESA_handle_runtime_log(g_tsg_para.logger, RLOG_LV_DEBUG, "SCAN_FQDN_CAT", "Not hit category_id: %d ret: %d addr: %s", category_id[i], ret, PRINTADDR(a_stream, g_tsg_para.level)); + } + } + + return hit_num; +} + int tsg_scan_app_id_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *name, unsigned int id, int thread_seq) { @@ -1580,7 +1481,7 @@ int tsg_scan_app_id_policy(Maat_feather_t maat_feather, const struct streaminfo return 0; } -int tsg_scan_app_properties_policy(Maat_feather_t maat_feather, struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *property, char *district, int thread_seq) +int tsg_scan_app_properties_policy(Maat_feather_t maat_feather, const struct streaminfo *a_stream, struct Maat_rule_t *result, int result_num, scan_status_t *mid, char *property, char *district, int thread_seq) { int i=0,ret=0; int ret2=0, hit_num=0; diff --git a/src/tsg_send_log.cpp b/src/tsg_send_log.cpp index 052edd3..d4fd245 100644 --- a/src/tsg_send_log.cpp +++ b/src/tsg_send_log.cpp @@ -73,165 +73,356 @@ static int is_tunnels(struct streaminfo *a_stream) return is_tunnel; } -static int convert_mac_to_string(unsigned char *mac, char *buff) +static int set_isn(struct TLD_handle_t *_handle, struct streaminfo *a_stream, char *field_name, enum MESA_stream_opt type) { - int i=0,len=0; + int ret=0; + unsigned int isn=0; + int size=sizeof(unsigned long long); + + size=sizeof(unsigned int); + ret=MESA_get_stream_opt(a_stream, type, &isn, &size); + if(ret==0) + { + TLD_append(_handle, field_name, (void *)(long)isn, TLD_TYPE_LONG); + } + + return 1; +} + +static int set_tcp_isn(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) +{ + if(a_stream->type==STREAM_TYPE_TCP) + { + switch(a_stream->dir) + { + case DIR_C2S: + set_isn(_handle, a_stream, _instance->id2field[LOG_COMMON_TCP_CLIENT_ISN].name, MSO_TCP_ISN_C2S); + break; + case DIR_S2C: + set_isn(_handle, a_stream, _instance->id2field[LOG_COMMON_TCP_SERVER_ISN].name, MSO_TCP_ISN_S2C); + break; + case DIR_DOUBLE: + set_isn(_handle, a_stream, _instance->id2field[LOG_COMMON_TCP_CLIENT_ISN].name, MSO_TCP_ISN_C2S); + set_isn(_handle, a_stream, _instance->id2field[LOG_COMMON_TCP_SERVER_ISN].name, MSO_TCP_ISN_S2C); + break; + default: + break; + } + } - for(i=0; i<6; i++) + return 1; +} +static int set_direction(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) +{ + int direction=0,i_or_e=0; + + i_or_e=MESA_dir_link_to_human(a_stream->routedir); + switch(a_stream->curdir) { - len+=sprintf(buff+len, "%02x:", mac[i]); + case DIR_C2S: + if(i_or_e=='E' || i_or_e=='e') + { + direction='E'; + } + else + { + direction='I'; + } + break; + case DIR_S2C: + if(i_or_e=='E' || i_or_e=='e') + { + direction='I'; + } + else + { + direction='E'; + } + break; + default: + break; } - buff[len-1]='\0'; + + TLD_append(_handle, _instance->id2field[LOG_COMMON_DIRECTION].name, (void *)(long)direction, TLD_TYPE_LONG); - return 0; + return 1; } -static int action2fs_id(int action) +static int set_address_list(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { - switch(action) + int ret=0; + unsigned short tunnel_type=0; + char nest_addr_buf[1024]; + int tunnel_type_size=sizeof(tunnel_type); + + ret=MESA_get_stream_opt(a_stream, MSO_STREAM_TUNNEL_TYPE, &tunnel_type, &tunnel_type_size); + assert(ret==0); + if(tunnel_type==STREAM_TUNNLE_NON) + { + layer_addr_ntop_r(a_stream,nest_addr_buf, sizeof(nest_addr_buf)); + } + else + { + stream_addr_list_ntop(a_stream,nest_addr_buf, sizeof(nest_addr_buf)); + } + + TLD_append(_handle, _instance->id2field[LOG_COMMON_ADDRESS_LIST].name, (void *)nest_addr_buf, TLD_TYPE_STRING); + + return 1; +} + +static int set_tuple4(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) +{ + int addr_type=0; + unsigned short c_port=0, s_port=0; + struct layer_addr_ipv4 *ipv4=NULL; + struct layer_addr_ipv6 *ipv6=NULL; + char server_ip[MAX_IPV4_LEN*8]={0}; + char client_ip[MAX_IPV4_LEN*8]={0}; + + switch(a_stream->addr.addrtype) { - case TSG_ACTION_DENY: - return TSG_FS2_ABORT_DENY; - break; - case TSG_ACTION_BYPASS: - return TSG_FS2_ABORT_ALLOW; - break; - case TSG_ACTION_MONITOR: - return TSG_FS2_ABORT_MONITOR; + case ADDR_TYPE_IPV4: + case __ADDR_TYPE_IP_PAIR_V4: + ipv4=a_stream->addr.ipv4; + addr_type=4; + c_port=ntohs(ipv4->source); + s_port=ntohs(ipv4->dest); + + inet_ntop(AF_INET, (void *)&ipv4->saddr, client_ip, sizeof(client_ip)); + inet_ntop(AF_INET, (void *)&ipv4->daddr, server_ip, sizeof(server_ip)); break; - case TSG_ACTION_INTERCEPT: - return TSG_FS2_ABORT_INTERCEPT; + case ADDR_TYPE_IPV6: + case __ADDR_TYPE_IP_PAIR_V6: + ipv6=a_stream->addr.ipv6; + addr_type=6; + c_port=ntohs(ipv6->source); + s_port=ntohs(ipv6->dest); + + inet_ntop(AF_INET6, (void *)ipv6->saddr, client_ip, sizeof(client_ip)); + inet_ntop(AF_INET6, (void *)ipv6->daddr, server_ip, sizeof(server_ip)); break; default: - return TSG_FS2_ABORT_UNKNOWN; break; } - return TSG_FS2_ABORT_UNKNOWN; + + TLD_append(_handle, _instance->id2field[LOG_COMMON_SERVER_IP].name, (void *)server_ip, TLD_TYPE_STRING); + TLD_append(_handle, _instance->id2field[LOG_COMMON_CLIENT_IP].name, (void *)client_ip, TLD_TYPE_STRING); + TLD_append(_handle, _instance->id2field[LOG_COMMON_SERVER_PORT].name, (void *)(long)s_port, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_CLIENT_PORT].name, (void *)(long)c_port, TLD_TYPE_LONG); + + TLD_append(_handle, _instance->id2field[LOG_COMMON_STREAM_DIR].name, (void *)(long)a_stream->dir, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_ADDRESS_TYPE].name, (void *)(long)addr_type, TLD_TYPE_LONG); + + return 1; } -int is_multi_hit_same_policy(struct Maat_rule_t *result, int *policy_id, int *policy_id_num) + +static int set_duraction(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { - int j=0; - - for(j=0;j<*policy_id_num;j++) + int ret=0; + struct timespec tv; + long common_con_duration_ms=0; + unsigned long long create_time=0; + int size=sizeof(unsigned long long); + + if(a_stream->ptcpdetail!=NULL) { - if(policy_id[j]==result->config_id) + TLD_append(_handle, _instance->id2field[LOG_COMMON_START_TIME].name, (void *)(a_stream->ptcpdetail->createtime), TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_END_TIME].name, (void *)(a_stream->ptcpdetail->lastmtime), TLD_TYPE_LONG); + + ret=MESA_get_stream_opt(a_stream, MSO_STREAM_CREATE_TIMESTAMP_MS, (void *)&create_time, &size); + if(ret>=0) { - return 1; + clock_gettime(CLOCK_REALTIME, &tv); + common_con_duration_ms=tv.tv_sec*1000+tv.tv_nsec/1000/1000 - create_time; + } + + if(common_con_duration_ms>0) + { + TLD_append(_handle, _instance->id2field[LOG_COMMON_CON_DURATION_MS].name, (void *)(common_con_duration_ms), TLD_TYPE_LONG); } } + else + { + time_t cur_time=time(NULL); + TLD_append(_handle, _instance->id2field[LOG_COMMON_START_TIME].name, (void *)cur_time, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_END_TIME].name, (void *)cur_time, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_CON_DURATION_MS].name, (void *)(common_con_duration_ms), TLD_TYPE_LONG); + } + + return 1; +} - policy_id[(*policy_id_num)++]=result->config_id; - return 0; -} -unsigned long long tsg_get_stream_id(struct streaminfo * a_stream) +static int set_packet_bytes(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { - int ret=0; - int device_id_size=sizeof(unsigned long long); - unsigned long long device_id=(unsigned long long)g_tsg_para.device_id; - - ret=MESA_get_stream_opt(a_stream, MSO_GLOBAL_STREAM_ID, (void *)&device_id, &device_id_size); - if(ret==0) + struct tcp_flow_stat *tflow_project=NULL; + struct udp_flow_stat *uflow_project=NULL; + + switch(a_stream->type) { - return device_id; + case STREAM_TYPE_TCP: + tflow_project=(struct tcp_flow_stat *)project_req_get_struct(a_stream, _instance->tcp_flow_project_id); + if(tflow_project!=NULL) + { + TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_PKT_NUM].name, (void *)(long)tflow_project->S2C_all_pkt, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_BYTE_NUM].name, (void *)(long)tflow_project->S2C_all_byte_raw, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_PKT_NUM].name, (void *)(long)tflow_project->C2S_all_pkt, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_BYTE_NUM].name, (void *)(long)tflow_project->C2S_all_byte_raw, TLD_TYPE_LONG); + } + break; + case STREAM_TYPE_UDP: + uflow_project=(struct udp_flow_stat *)project_req_get_struct(a_stream, _instance->udp_flow_project_id); + if(uflow_project!=NULL) + { + TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_PKT_NUM].name, (void *)(long)uflow_project->S2C_pkt, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_BYTE_NUM].name, (void *)(long)uflow_project->S2C_all_byte_raw, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_PKT_NUM].name, (void *)(long)uflow_project->C2S_pkt, TLD_TYPE_LONG); + TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_BYTE_NUM].name, (void *)(long)uflow_project->C2S_all_byte_raw, TLD_TYPE_LONG); + } + break; + default: + break; } - return -1; + return 1; } -int TLD_cancel(struct TLD_handle_t *handle) +static int get_l7_protocol(struct app_identify_result *result, char *protocol_list, int protocol_list_len, int *flag) { - struct TLD_handle_t *_handle=handle; + int i=0,offset=0; + char *name=NULL; + + if((*flag)==1) + { + return 0; + } - if(_handle!=NULL) + for(i=0; i<result->app_id_num; i++) { - if(_handle->object!=NULL) + (*flag)=1; + name=tsg_l7_protocol_id2name(result->app_id[i]); + if(name!=NULL) { - cJSON_Delete(_handle->object); - _handle->object=NULL; + offset+=snprintf(protocol_list+offset, protocol_list_len-offset, "%s", name); } - - free(handle); - handle=NULL; } - - return 0; + + return 1; } -int TLD_delete(struct TLD_handle_t *handle, char *key) +static int get_app_id_list(struct app_identify_result *result, char *app_list, int app_list_len, char *surrogate_list, int surrogate_list_len, int *flag) { - struct TLD_handle_t *_handle=handle; + int i=0; + int offset1=0,offset2=0; + + if((*flag)==1) + { + return 0; + } - if(_handle!=NULL && key!=NULL) + for(i=0; i<result->app_id_num; i++) { - cJSON_DeleteItemFromObject(_handle->object, key); + (*flag)=1; + offset1+=snprintf(app_list+offset1, app_list_len-offset1, "%d;", result->app_id[i]); + offset2+=snprintf(surrogate_list+offset2, surrogate_list_len-offset2, "%d;", result->surrogate_id[i]); } - return 0; + return 1; } -int TLD_append(struct TLD_handle_t *handle, char *key, void *value, TLD_TYPE type) +static int set_app_id(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { - struct TLD_handle_t *_handle=handle; + int app_id_flag=0; + int l7_protocol_flag=0; + char app_list[256]={0}; + char protocol_list[256]={0}; + char surrogate_list[256]={0}; + struct gather_app_result *label=NULL; - if(_handle==NULL || key==NULL || (value==NULL && type!=TLD_TYPE_LONG)) + label=(struct gather_app_result *)project_req_get_struct(a_stream, g_tsg_para.gather_app_project_id); + if(label!=NULL) + { + get_l7_protocol(&(label->result[ORIGIN_BASIC_PROTOCOL]), protocol_list, sizeof(protocol_list), &l7_protocol_flag); + get_app_id_list(&(label->result[ORIGIN_USER_DEFINE]), app_list, sizeof(app_list), surrogate_list, sizeof(surrogate_list), &app_id_flag); + if(app_id_flag!=1) + { + get_app_id_list(&(label->result[ORIGIN_DKPT]), app_list, sizeof(app_list), surrogate_list, sizeof(surrogate_list), &app_id_flag); + } + + if(app_id_flag!=1) + { + get_app_id_list(&(label->result[ORIGIN_QM_ENGINE]), app_list, sizeof(app_list), surrogate_list, sizeof(surrogate_list), &app_id_flag); + } + + if(app_id_flag==1) + { + TLD_append(_handle, _instance->id2field[LOG_COMMON_APP_ID].name, (void *)app_list, TLD_TYPE_STRING); + TLD_append(_handle, _instance->id2field[LOG_COMMON_APP_SURROGATE_ID].name, (void *)surrogate_list, TLD_TYPE_STRING); + } + + if(l7_protocol_flag==1) + { + TLD_append(_handle, _instance->id2field[LOG_COMMON_L7_PROTOCOL].name, (void *)protocol_list, TLD_TYPE_STRING); + } + } + + return 1; +} + +static int set_vlan(struct tsg_log_instance_t *_instance, struct single_layer_vlan_addr *vlan_addr, int layer_num, cJSON *tunnel_object, tsg_log_field_id_t id) +{ + if(layer_num==0) { - return -1; + return 0; } - switch(type) + int i=0; + cJSON *vlan_array=cJSON_CreateArray(); + for(i=0; i<layer_num; i++) { - case TLD_TYPE_LONG: - cJSON_AddNumberToObject(_handle->object, key, (long)value); - break; - case TLD_TYPE_FILE: - break; - case TLD_TYPE_STRING: - cJSON_AddStringToObject(_handle->object, key, (char *)value); - break; - case TLD_TYPE_CJSON: - cJSON_AddItemToObject(_handle->object, key, (cJSON *)value); - break; - default: - return -1; - break; + cJSON_AddNumberToObject(vlan_array, _instance->id2field[id].name, ntohs(vlan_addr[i].VID)); } - - return 0; + cJSON_AddItemToObject(tunnel_object, _instance->id2field[id].name, vlan_array); + + return 1; } -struct TLD_handle_t *TLD_create(int thread_id) +static int set_mpls(struct tsg_log_instance_t *_instance, struct single_layer_mpls_addr *mpls_addr, int layer_num, cJSON *tunnel_object, tsg_log_field_id_t id) { - //struct _tld_handle *_handle=(struct _tld_handle *)dictator_malloc(thread_id, sizeof(struct _tld_handle)); - - struct TLD_handle_t *_handle=(struct TLD_handle_t *)calloc(1, sizeof(struct TLD_handle_t)); - _handle->thread_id = thread_id; - _handle->object = cJSON_CreateObject(); + if(layer_num==0) + { + return 0; + } + + int i=0; + cJSON *mpls_array=cJSON_CreateArray(); + for(i=0; i<layer_num; i++) + { + cJSON_AddNumberToObject(mpls_array, _instance->id2field[id].name, ntohl(mpls_addr[i].label)); + } - return _handle; + cJSON_AddItemToObject(tunnel_object, _instance->id2field[id].name, mpls_array); + + return 1; } -static int set_l7_protocol(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) -{ - char *l7_protocol=NULL; - struct basic_proto_label *l7_proto_label=NULL; +static int mac_to_string(unsigned char *mac, char *buff) +{ + int i=0,len=0; - l7_proto_label=(struct basic_proto_label *)project_req_get_struct(a_stream, g_tsg_para.l7_proto_project_id); - if(l7_proto_label!=NULL && l7_proto_label->proto_id!=g_tsg_para.mail_proto_id) + for(i=0; i<6; i++) { - l7_protocol=tsg_l7_protocol_id2name(_instance, l7_proto_label->proto_id); - if(l7_protocol!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_L7_PROTOCOL].name, (void *)l7_protocol, TLD_TYPE_STRING); - return 1; - } + len+=sprintf(buff+len, "%02x:", mac[i]); } + buff[len-1]='\0'; + return 0; } @@ -244,10 +435,10 @@ static int set_link_mac(struct tsg_log_instance_t *_instance, struct layer_addr_ if((memcmp(mac->src_addr.h_source, default_mac, 6))) { mac_object=cJSON_CreateObject(); - convert_mac_to_string(mac->src_addr.h_source, buff); + mac_to_string(mac->src_addr.h_source, buff); cJSON_AddStringToObject(mac_object, _instance->id2field[LOG_COMMON_TUNNELS_MAC_SOURCE].name, buff); - convert_mac_to_string(mac->src_addr.h_dest, buff); + mac_to_string(mac->src_addr.h_dest, buff); cJSON_AddStringToObject(mac_object, _instance->id2field[LOG_COMMON_TUNNELS_MAC_DEST].name, buff); cJSON_AddItemToObject(tunnel_object, "c2s_direction_mac", mac_object); @@ -256,10 +447,10 @@ static int set_link_mac(struct tsg_log_instance_t *_instance, struct layer_addr_ if((memcmp(mac->dst_addr.h_source, default_mac, 6))) { mac_object=cJSON_CreateObject(); - convert_mac_to_string(mac->dst_addr.h_source, buff); + mac_to_string(mac->dst_addr.h_source, buff); cJSON_AddStringToObject(mac_object, _instance->id2field[LOG_COMMON_TUNNELS_MAC_SOURCE].name, buff); - convert_mac_to_string(mac->dst_addr.h_dest, buff); + mac_to_string(mac->dst_addr.h_dest, buff); cJSON_AddStringToObject(mac_object, _instance->id2field[LOG_COMMON_TUNNELS_MAC_DEST].name, buff); cJSON_AddItemToObject(tunnel_object, "s2c_direction_mac", mac_object); @@ -268,45 +459,102 @@ static int set_link_mac(struct tsg_log_instance_t *_instance, struct layer_addr_ return 1; } - -static int set_vlan(struct tsg_log_instance_t *_instance, struct single_layer_vlan_addr *vlan_addr, int layer_num, cJSON *tunnel_object, tsg_log_field_id_t id) +static int action2fs_id(int action) { - if(layer_num==0) + switch(action) { - return 0; + case TSG_ACTION_DENY: + return TSG_FS2_ABORT_DENY; + break; + case TSG_ACTION_BYPASS: + return TSG_FS2_ABORT_ALLOW; + break; + case TSG_ACTION_MONITOR: + return TSG_FS2_ABORT_MONITOR; + break; + case TSG_ACTION_INTERCEPT: + return TSG_FS2_ABORT_INTERCEPT; + break; + default: + return TSG_FS2_ABORT_UNKNOWN; + break; } + + return TSG_FS2_ABORT_UNKNOWN; +} + +int TLD_cancel(struct TLD_handle_t *handle) +{ + struct TLD_handle_t *_handle=handle; - int i=0; - cJSON *vlan_array=cJSON_CreateArray(); - for(i=0; i<layer_num; i++) + if(_handle!=NULL) { - cJSON_AddNumberToObject(vlan_array, _instance->id2field[id].name, ntohs(vlan_addr[i].VID)); + if(_handle->object!=NULL) + { + cJSON_Delete(_handle->object); + _handle->object=NULL; + } + + free(handle); + handle=NULL; } - - cJSON_AddItemToObject(tunnel_object, _instance->id2field[id].name, vlan_array); - - return 1; + + return 0; } -static int set_mpls(struct tsg_log_instance_t *_instance, struct single_layer_mpls_addr *mpls_addr, int layer_num, cJSON *tunnel_object, tsg_log_field_id_t id) +int TLD_delete(struct TLD_handle_t *handle, char *key) { - if(layer_num==0) + struct TLD_handle_t *_handle=handle; + + if(_handle!=NULL && key!=NULL) { - return 0; + cJSON_DeleteItemFromObject(_handle->object, key); } - int i=0; - cJSON *mpls_array=cJSON_CreateArray(); - for(i=0; i<layer_num; i++) + return 0; +} + +int TLD_append(struct TLD_handle_t *handle, char *key, void *value, TLD_TYPE type) +{ + struct TLD_handle_t *_handle=handle; + + if(_handle==NULL || key==NULL || (value==NULL && type!=TLD_TYPE_LONG)) { - cJSON_AddNumberToObject(mpls_array, _instance->id2field[id].name, ntohl(mpls_addr[i].label)); + return -1; } - cJSON_AddItemToObject(tunnel_object, _instance->id2field[id].name, mpls_array); + switch(type) + { + case TLD_TYPE_LONG: + cJSON_AddNumberToObject(_handle->object, key, (long)value); + break; + case TLD_TYPE_FILE: + break; + case TLD_TYPE_STRING: + cJSON_AddStringToObject(_handle->object, key, (char *)value); + break; + case TLD_TYPE_CJSON: + cJSON_AddItemToObject(_handle->object, key, (cJSON *)value); + break; + default: + return -1; + break; + } - return 1; + + return 0; } +struct TLD_handle_t *TLD_create(int thread_id) +{ + //struct _tld_handle *_handle=(struct _tld_handle *)dictator_malloc(thread_id, sizeof(struct _tld_handle)); + + struct TLD_handle_t *_handle=(struct TLD_handle_t *)calloc(1, sizeof(struct TLD_handle_t)); + _handle->thread_id = thread_id; + _handle->object = cJSON_CreateObject(); + + return _handle; +} static int get_gtp_ipv4v6_port(struct tsg_log_instance_t *_instance, struct streaminfo *a_stream, cJSON *object) { @@ -345,7 +593,7 @@ static int get_gtp_ipv4v6_port(struct tsg_log_instance_t *_instance, struct stre return 0; } -static int get_common_tunnels(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) +static int set_common_tunnels(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { int ret=0; char ip_buff[64]={0}; @@ -458,16 +706,36 @@ char *log_field_id2name(struct tsg_log_instance_t *instance, tsg_log_field_id_t return NULL; } -char *tsg_l7_protocol_id2name(struct tsg_log_instance_t *instance, unsigned short id) +unsigned long long tsg_get_stream_id(struct streaminfo * a_stream) { - struct tsg_log_instance_t *_instance=instance; + int ret=0; + int device_id_size=sizeof(unsigned long long); + unsigned long long device_id=(unsigned long long)g_tsg_para.device_id; + + ret=MESA_get_stream_opt(a_stream, MSO_GLOBAL_STREAM_ID, (void *)&device_id, &device_id_size); + if(ret==0) + { + return device_id; + } + + return -1; +} + +int is_multi_hit_same_policy(struct Maat_rule_t *result, int *policy_id, int *policy_id_num) +{ + int j=0; - if(_instance!=NULL && id>=MIN_L7_PROTO_ID && id<=MAX_L7_PROTO_ID) + for(j=0;j<*policy_id_num;j++) { - return _instance->l7_proto_id2field[id].name; + if(policy_id[j]==result->config_id) + { + return 1; + } } - return NULL; + policy_id[(*policy_id_num)++]=result->config_id; + + return 0; } static int set_common_sub_action(struct TLD_handle_t *handle, char *field_name, struct Maat_rule_t *p_result) @@ -505,33 +773,15 @@ static int set_common_sub_action(struct TLD_handle_t *handle, char *field_name, return 0; } -int set_common_field_from_label(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) +int set_session_attributes(struct tsg_log_instance_t *_instance, struct TLD_handle_t *_handle, struct streaminfo *a_stream) { char buff[1024]={0}; - int l7_protocol_flag=0; - char *l7_protocol=NULL; - struct app_id_label *app_label=NULL; struct _location_info_t *location=NULL; struct _session_attribute_label_t *attribute_label=NULL; - l7_protocol_flag=set_l7_protocol(_instance, _handle, a_stream); - attribute_label=(struct _session_attribute_label_t *)project_req_get_struct(a_stream, _instance->internal_project_id); if(attribute_label!=NULL) - { - if(l7_protocol_flag==0) - { - l7_protocol=tsg_schema_index2string(attribute_label->proto); - if(l7_protocol!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_L7_PROTOCOL].name, (void *)l7_protocol, TLD_TYPE_STRING); - } - else - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_L7_PROTOCOL].name, (void *)"UNCATEGORIZED", TLD_TYPE_STRING); - } - } - + { TLD_append(_handle, _instance->id2field[LOG_COMMON_ESTABLISH_LATENCY_MS].name, (void *)attribute_label->establish_latency_ms, TLD_TYPE_LONG); if(attribute_label->client_asn!=NULL) @@ -565,159 +815,37 @@ int set_common_field_from_label(struct tsg_log_instance_t *_instance, struct TLD TLD_append(_handle, _instance->id2field[LOG_SSL_JA3_FINGERPRINT].name, (void *)attribute_label->ja3_fingerprint, TLD_TYPE_STRING); } } - else - { - if(l7_protocol_flag==0) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_L7_PROTOCOL].name, (void *)"UNCATEGORIZED", TLD_TYPE_STRING); - } - } - - app_label=(struct app_id_label *)project_req_get_struct(a_stream, g_tsg_para.app_id_project_id); - if(app_label!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_APP_ID].name, (void *)(long)app_label->app_id, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_APP_SURROGATE_ID].name, (void *)(long)app_label->surrogate_id, TLD_TYPE_LONG); - } return 0; } int TLD_append_streaminfo(struct tsg_log_instance_t *instance, struct TLD_handle_t *handle, struct streaminfo *a_stream) { - int i_or_e=0,direction=0; - int ret=0,addr_type=0; - unsigned short tunnel_type=0; - char nest_addr_buf[1024]; char *addr_proto=NULL; - struct timespec tv; - unsigned int client_isn=0,server_isn=0; - int size=sizeof(unsigned long long); - long common_con_duration_ms=0; - unsigned long long create_time=0; unsigned long long stream_id=0; - unsigned short c_port=0, s_port=0; - int tunnel_type_size=sizeof(tunnel_type); - struct layer_addr_ipv4 *ipv4=NULL; - struct layer_addr_ipv6 *ipv6=NULL; - char server_ip[MAX_IPV4_LEN*8]={0}; - char client_ip[MAX_IPV4_LEN*8]={0}; - struct tcp_flow_stat *tflow_project=NULL; - struct udp_flow_stat *uflow_project=NULL; - struct TLD_handle_t *_handle=handle; struct tsg_log_instance_t *_instance=instance; if(_instance==NULL || _handle==NULL || a_stream==NULL) { - MESA_handle_runtime_log(_instance->logger, - RLOG_LV_DEBUG, - "TLD_APPEND_STREAM", - "instance==NULL || TLD_handle==NULL || addr==NULL" - ); + MESA_handle_runtime_log(_instance->logger, RLOG_LV_DEBUG, "TLD_APPEND_STREAM", "instance==NULL || TLD_handle==NULL || addr==NULL"); return -1; } - switch(a_stream->addr.addrtype) - { - case ADDR_TYPE_IPV4: - case __ADDR_TYPE_IP_PAIR_V4: - ipv4=a_stream->addr.ipv4; - addr_type=4; - c_port=ntohs(ipv4->source); - s_port=ntohs(ipv4->dest); - - inet_ntop(AF_INET, (void *)&ipv4->saddr, client_ip, sizeof(client_ip)); - inet_ntop(AF_INET, (void *)&ipv4->daddr, server_ip, sizeof(server_ip)); - break; - case ADDR_TYPE_IPV6: - case __ADDR_TYPE_IP_PAIR_V6: - ipv6=a_stream->addr.ipv6; - addr_type=6; - c_port=ntohs(ipv6->source); - s_port=ntohs(ipv6->dest); - - inet_ntop(AF_INET6, (void *)ipv6->saddr, client_ip, sizeof(client_ip)); - inet_ntop(AF_INET6, (void *)ipv6->daddr, server_ip, sizeof(server_ip)); - break; - default: - break; - } - - - TLD_append(_handle, _instance->id2field[LOG_COMMON_SERVER_IP].name, (void *)server_ip, TLD_TYPE_STRING); - TLD_append(_handle, _instance->id2field[LOG_COMMON_CLIENT_IP].name, (void *)client_ip, TLD_TYPE_STRING); - TLD_append(_handle, _instance->id2field[LOG_COMMON_SERVER_PORT].name, (void *)(long)s_port, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_CLIENT_PORT].name, (void *)(long)c_port, TLD_TYPE_LONG); - - TLD_append(_handle, _instance->id2field[LOG_COMMON_STREAM_DIR].name, (void *)(long)a_stream->dir, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_ADDRESS_TYPE].name, (void *)(long)addr_type, TLD_TYPE_LONG); - - switch(a_stream->type) - { - case STREAM_TYPE_TCP: - tflow_project=(struct tcp_flow_stat *)project_req_get_struct(a_stream, _instance->tcp_flow_project_id); - if(tflow_project!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_PKT_NUM].name, (void *)(long)tflow_project->S2C_all_pkt, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_BYTE_NUM].name, (void *)(long)tflow_project->S2C_all_byte_raw, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_PKT_NUM].name, (void *)(long)tflow_project->C2S_all_pkt, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_BYTE_NUM].name, (void *)(long)tflow_project->C2S_all_byte_raw, TLD_TYPE_LONG); - } - - size=sizeof(unsigned int); - ret=MESA_get_stream_opt(a_stream, MSO_TCP_ISN_C2S, &client_isn, &size); - if(ret==0) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_TCP_CLIENT_ISN].name, (void *)(long)client_isn, TLD_TYPE_LONG); - } - - size=sizeof(unsigned int); - ret=MESA_get_stream_opt(a_stream, MSO_TCP_ISN_S2C, &server_isn, &size); - if(ret==0) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_TCP_SERVER_ISN].name, (void *)(long)server_isn, TLD_TYPE_LONG); - } - break; - case STREAM_TYPE_UDP: - uflow_project=(struct udp_flow_stat *)project_req_get_struct(a_stream, _instance->udp_flow_project_id); - if(uflow_project!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_PKT_NUM].name, (void *)(long)uflow_project->S2C_pkt, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_S2C_BYTE_NUM].name, (void *)(long)uflow_project->S2C_all_byte_raw, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_PKT_NUM].name, (void *)(long)uflow_project->C2S_pkt, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_C2S_BYTE_NUM].name, (void *)(long)uflow_project->C2S_all_byte_raw, TLD_TYPE_LONG); - } - break; - default: - break; - } - - if(a_stream!=NULL && a_stream->ptcpdetail!=NULL) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_START_TIME].name, (void *)(a_stream->ptcpdetail->createtime), TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_END_TIME].name, (void *)(a_stream->ptcpdetail->lastmtime), TLD_TYPE_LONG); + set_app_id(_instance, _handle, a_stream); + set_tcp_isn(_instance, _handle, a_stream); + set_tuple4(_instance, _handle, a_stream); + set_direction(_instance, _handle, a_stream); + set_address_list(_instance, _handle, a_stream); + set_duraction(_instance, _handle, a_stream); + set_packet_bytes(_instance, _handle, a_stream); + set_session_attributes(_instance, _handle, a_stream); - ret=MESA_get_stream_opt(a_stream, MSO_STREAM_CREATE_TIMESTAMP_MS, (void *)&create_time, &size); - if(ret>=0) - { - clock_gettime(CLOCK_REALTIME, &tv); - common_con_duration_ms=tv.tv_sec*1000+tv.tv_nsec/1000/1000 - create_time; - } - - if(common_con_duration_ms>0) - { - TLD_append(_handle, _instance->id2field[LOG_COMMON_CON_DURATION_MS].name, (void *)(common_con_duration_ms), TLD_TYPE_LONG); - } - } - else + if(is_tunnels(a_stream)) { - time_t cur_time=time(NULL); - TLD_append(_handle, _instance->id2field[LOG_COMMON_START_TIME].name, (void *)cur_time, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_END_TIME].name, (void *)cur_time, TLD_TYPE_LONG); - TLD_append(_handle, _instance->id2field[LOG_COMMON_CON_DURATION_MS].name, (void *)(common_con_duration_ms), TLD_TYPE_LONG); + set_common_tunnels(_instance, _handle, a_stream); } - + stream_id=tsg_get_stream_id(a_stream); char stream_id_buff[128]=""; snprintf(stream_id_buff, sizeof(stream_id_buff), "%llu", stream_id); @@ -725,56 +853,6 @@ int TLD_append_streaminfo(struct tsg_log_instance_t *instance, struct TLD_handle addr_proto=(char *)layer_addr_prefix_ntop(a_stream); TLD_append(_handle, _instance->id2field[LOG_COMMON_L4_PROTOCOL].name, (void *)addr_proto, TLD_TYPE_STRING); - - - ret=MESA_get_stream_opt(a_stream, MSO_STREAM_TUNNEL_TYPE, &tunnel_type, &tunnel_type_size); - assert(ret==0); - if(tunnel_type==STREAM_TUNNLE_NON) - { - layer_addr_ntop_r(a_stream,nest_addr_buf, sizeof(nest_addr_buf)); - } - else - { - stream_addr_list_ntop(a_stream,nest_addr_buf, sizeof(nest_addr_buf)); - } - - if(is_tunnels(a_stream)) - { - get_common_tunnels(_instance, _handle, a_stream); - } - - TLD_append(_handle, _instance->id2field[LOG_COMMON_ADDRESS_LIST].name, (void *)nest_addr_buf, TLD_TYPE_STRING); - - set_common_field_from_label(_instance, _handle, a_stream); - - i_or_e=MESA_dir_link_to_human(a_stream->routedir); - switch(a_stream->curdir) - { - case DIR_C2S: - if(i_or_e=='E' || i_or_e=='e') - { - direction='E'; - } - else - { - direction='I'; - } - break; - case DIR_S2C: - if(i_or_e=='E' || i_or_e=='e') - { - direction='I'; - } - else - { - direction='E'; - } - break; - default: - break; - } - - TLD_append(_handle, _instance->id2field[LOG_COMMON_DIRECTION].name, (void *)(long)direction, TLD_TYPE_LONG); return 0; } @@ -874,7 +952,6 @@ int load_log_common_field(const char *filename, id2field_t *id2field, id2field_t struct tsg_log_instance_t *tsg_sendlog_init(const char *conffile) { int i=0,ret=0; - int tmp_value=0; char nic_name[32]={0}; char kafka_errstr[1024]={0}; unsigned int local_ip_nr=0; @@ -952,9 +1029,6 @@ struct tsg_log_instance_t *tsg_sendlog_init(const char *conffile) } inet_ntop(AF_INET,&(local_ip_nr),_instance->local_ip_str,sizeof(_instance->local_ip_str)); - MESA_load_profile_string_def(conffile, "TSG_LOG", "L7_PROTO_ID_FILE", _instance->l7_proto_id_file, sizeof(_instance->l7_proto_id_file), "./tsgconf/app_l7_proto_id.conf"); - load_log_common_field(_instance->l7_proto_id_file, _instance->l7_proto_id2field, NULL, &tmp_value); - rdkafka_conf = rd_kafka_conf_new(); rd_kafka_conf_set(rdkafka_conf, "queue.buffering.max.messages", _instance->send_queue_max_msg, kafka_errstr, sizeof(kafka_errstr)); rd_kafka_conf_set(rdkafka_conf, "topic.metadata.refresh.interval.ms", _instance->refresh_interval_ms, kafka_errstr, sizeof(kafka_errstr)); diff --git a/src/tsg_send_log_internal.h b/src/tsg_send_log_internal.h index 326d2ef..d077abe 100644 --- a/src/tsg_send_log_internal.h +++ b/src/tsg_send_log_internal.h @@ -100,7 +100,7 @@ typedef enum _tsg_log_field_id typedef struct _id2field { - TLD_TYPE type; + int type; int id; char name[MAX_STRING_LEN]; }id2field_t; @@ -137,7 +137,6 @@ struct tsg_log_instance_t id2field_t id2field[LOG_COMMON_MAX]; rd_kafka_topic_t **topic_rkt; id2field_t *service2topic; - id2field_t l7_proto_id2field[MAX_L7_PROTO_ID+1]; void *logger; }; diff --git a/src/uthash.h b/src/uthash.h new file mode 100644 index 0000000..5e5866a --- /dev/null +++ b/src/uthash.h @@ -0,0 +1,1150 @@ +/* +Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.1.0 + +#include <string.h> /* memcmp, memset, strlen */ +#include <stddef.h> /* ptrdiff_t */ +#include <stdlib.h> /* exit */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined(_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include <stdint.h> +#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) +#include <stdint.h> +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#elif defined(__GNUC__) && !defined(__VXWORKS__) +#include <stdint.h> +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifdef uthash_memcmp +/* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */ +#warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead" +#else +#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#endif + +#ifndef HASH_KEYCMP +#define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +#ifndef HASH_NONFATAL_OOM +#define HASH_NONFATAL_OOM 0 +#endif + +#if HASH_NONFATAL_OOM +/* malloc failures can be recovered from */ + +#ifndef uthash_nonfatal_oom +#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define IF_HASH_NONFATAL_OOM(x) x + +#else +/* malloc failures result in lost memory, hash tables are unusable */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define IF_HASH_NONFATAL_OOM(x) + +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ +} while (0) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FCN(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl,oomed) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head,oomed) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } \ + ) \ + } \ + } \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ +do { \ + char *_hs_saved_head = (char*)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ +} while (0) +#endif + +#if HASH_NONFATAL_OOM + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ +} while (0) + +#else + +#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ +do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ +} while (0) + +#endif + + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ +} while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ +do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ +} while (0) +#define HASH_ADD_STR(head,strfield,add) \ +do { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ +} while (0) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ +do { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ +} while (0) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#include <stdio.h> /* fprintf, stderr */ +#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include <unistd.h> to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ + && !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (oomed) { \ + HASH_DEL_IN_BKT(head,addhh); \ + } \ + ) \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ + _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + } \ + ) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM( \ + if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + } \ + ) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ |
