summaryrefslogtreecommitdiff
path: root/entry
diff options
context:
space:
mode:
Diffstat (limited to 'entry')
-rw-r--r--entry/CMakeLists.txt15
-rw-r--r--entry/include/base64.h2
-rw-r--r--entry/include/base_utils.h44
-rw-r--r--entry/include/ssl.h230
-rw-r--r--entry/include/ssl_utils.h50
-rw-r--r--entry/src/base64.cpp143
-rw-r--r--entry/src/ssl_utils.cpp468
-rw-r--r--entry/src/sslparse_entry.cpp697
-rw-r--r--entry/src/sslstat_entry.cpp131
-rw-r--r--entry/src/stmstat_entry.cpp530
10 files changed, 2310 insertions, 0 deletions
diff --git a/entry/CMakeLists.txt b/entry/CMakeLists.txt
new file mode 100644
index 0000000..5102350
--- /dev/null
+++ b/entry/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_library(stmstat SHARED src/stmstat_entry.cpp src/ssl_utils.cpp)
+target_include_directories(stmstat PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(stmstat MESA_prof_load MESA_field_stat cjson)
+
+
+add_library(sslstat SHARED src/sslstat_entry.cpp)
+target_include_directories(sslstat PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(sslstat MESA_prof_load MESA_field_stat cjson)
+
+add_library(sslparse SHARED src/sslparse_entry.cpp src/ssl_utils.cpp src/base64.cpp)
+target_include_directories(sslparse PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(sslparse MESA_prof_load MESA_field_stat cjson)
+
+add_executable(test_base64 src/base64.cpp)
+target_include_directories(test_base64 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
diff --git a/entry/include/base64.h b/entry/include/base64.h
new file mode 100644
index 0000000..6f58c5c
--- /dev/null
+++ b/entry/include/base64.h
@@ -0,0 +1,2 @@
+unsigned int b64_encode(const unsigned char* in, unsigned int in_len, unsigned char* out);
+unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out); \ No newline at end of file
diff --git a/entry/include/base_utils.h b/entry/include/base_utils.h
new file mode 100644
index 0000000..311ec78
--- /dev/null
+++ b/entry/include/base_utils.h
@@ -0,0 +1,44 @@
+#pragma once
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <arpa/inet.h>
+#include <netinet/ip6.h>
+#include <net/if.h>
+#include <string.h>
+#include <pthread.h>
+#include "MESA/MESA_handle_logger.h"
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define STRING_MAX 128
+
+#define likely(expr) __builtin_expect((expr), 1)
+#define unlikely(expr) __builtin_expect((expr), 0)
+
+#define ALLOC(type, number) ((type *)calloc(sizeof(type), number))
+#define FREE(p) {free(*p);*p=NULL;}
+
+#define LOG_ERROR(handler, fmt, ...) \
+do { \
+ MESA_handle_runtime_log(handler, RLOG_LV_FATAL, "kni", fmt, ##__VA_ARGS__); } while(0)
+
+#define LOG_INFO(handler, fmt, ...) \
+do { \
+ MESA_handle_runtime_log(handler, RLOG_LV_INFO, "kni", fmt, ##__VA_ARGS__); } while(0)
+
+#define LOG_DEBUG(handler, fmt, ...) \
+do { \
+ MESA_handle_runtime_log(handler, RLOG_LV_DEBUG, "kni", fmt, ##__VA_ARGS__); } while(0)
+
+ \ No newline at end of file
diff --git a/entry/include/ssl.h b/entry/include/ssl.h
new file mode 100644
index 0000000..5981228
--- /dev/null
+++ b/entry/include/ssl.h
@@ -0,0 +1,230 @@
+
+#ifndef H_SSL_H
+#define H_SSL_H
+
+#include <stdio.h>
+#include <string.h>
+
+#define SSH_H_VERSION_20160910_ADD_CERT 0
+
+#define SSL_KEY 3
+#define SSL_TRUE 1
+#define SSL_FLASE 0
+
+
+#define SSL_INTEREST_KEY (1<<SSL_INTEREST_KEY_MASK)
+#define SSL_CERTIFICATE (1<<SSL_CERTIFICATE_MASK)
+#define SSL_CERTIFICATE_DETAIL (1<<SSL_CERTIFICATE_DETAIL_MASK)
+#define SSL_APPLICATION_DATA (1<<SSL_APPLICATION_DATA_MASK)
+#define SSL_CLIENT_HELLO (1<<SSL_CLIENT_HELLO_MASK)
+#define SSL_SERVER_HELLO (1<<SSL_SERVER_HELLO_MASK)
+#define SSL_VERSION (1<<SSL_VERSION_MASK)
+
+typedef enum
+{
+ /*1*/
+ SSL_INTEREST_KEY_MASK = 0,
+ SSL_CERTIFICATE_DETAIL_MASK = 1,
+ SSL_CLIENT_HELLO_MASK = 2,
+ SSL_SERVER_HELLO_MASK= 3,
+ SSL_CERTIFICATE_MASK,
+ SSL_APPLICATION_DATA_MASK,
+ SSL_VERSION_MASK,
+}ssl_interested_region;
+
+typedef struct cdata_buf
+{
+ char* p_data;
+ unsigned int data_size;
+}cdata_buf;
+
+typedef struct _st_random_t
+{
+ unsigned int gmt_time; //4
+ unsigned char random_bytes[28]; //28 byte random_bytes
+}st_random_t;
+
+typedef struct _st_session_t
+{
+ unsigned char session_len; //4
+ unsigned char* session_value;
+}st_session_t;
+
+typedef struct _st_suites_t
+{
+ unsigned short suite_len; //4
+ unsigned char* suite_value;
+}st_suites_t;
+
+typedef struct _st_compress_methods_t
+{
+ unsigned char methlen;
+ unsigned char* methods;//default 0:null
+}st_compress_methods_t;
+
+//#############################################client hello
+#define CLIENT_HELLO_HDRLEN 4
+#define MAX_EXTENSION_NUM 16
+#define MAX_EXT_DATA_LEN 256
+#define SERVER_NAME_EXT_TYPE 0x0000
+#define SERVER_NAME_HOST_TYPE 0x0000
+#define SERVER_NAME_OTHER_TYPE 0x0008
+
+
+typedef struct _st_client_ext_t
+{
+ unsigned short type;
+ unsigned short len;
+ unsigned char data[MAX_EXT_DATA_LEN];//if longer,cut off
+}__attribute__((packed))st_client_ext_t;
+
+typedef struct _st_client_server_name_t
+{
+ short server_name_list_len;
+ unsigned short server_name_type;
+ unsigned char server_name_len;
+ unsigned char* server_name_data;
+}__attribute__((packed))st_client_server_name_t;
+
+
+//client hello info
+typedef struct _st_client_hello_t
+{
+ int totallen; //3
+ unsigned short client_ver;
+ st_random_t random; //32 byte random,not used currently
+ st_session_t session;
+ st_suites_t ciphersuits;
+ st_compress_methods_t com_method; //compress method
+ unsigned short extlen;
+ unsigned short ext_num; //number of extensions
+ st_client_ext_t exts[MAX_EXTENSION_NUM]; //extensions content:1 or more extentions
+ unsigned char server_name[512]; // server_name = host_name+...
+}st_client_hello_t;
+
+//#############################################client hello end
+
+//#############################################server hello
+#define SERVER_HELLO_HDRLEN 4
+
+//client hello info
+typedef struct _st_server_hello_t
+{
+ int totallen; //3
+ unsigned short client_ver;
+ st_random_t random; //32 byte random,not used currently
+ st_session_t session;
+ st_suites_t ciphersuits;
+ st_compress_methods_t com_method; //compress method
+}st_server_hello_t;
+
+//#############################################server hello end
+
+//#############################################certificate
+#define CERTIFICATE_HDRLEN 7
+#define SSL_CERTIFICATE_HDRLEN 3
+//#define SAN_MAXNUM 128
+
+typedef struct _san_t
+{
+ char san[64];
+}san_t;
+
+typedef struct _st_san_t
+{
+ int count;
+ san_t* san_array; //ָ������
+}st_san_t;
+
+typedef struct _st_cert_t
+{
+ int totallen;
+ int certlen;
+ char SSLVersion[10];
+ char SSLSerialNum[128];
+ char SSLAgID [64];
+ char SSLIssuer[512];
+ char SSLSub[512];
+ char SSLFrom[80];
+ char SSLTo[80];
+ char SSLFPAg[32];
+ char SSLIssuerC[64]; //country
+ char SSLIssuerO[64]; //organize
+ char SSLIssuerCN[64];//cname
+ char SSLSubC[64]; //country
+ char SSLSubO[64]; //organize
+ char SSLSubCN[64];//cname
+ st_san_t* SSLSubAltName;
+ uint8_t cert_type;
+}st_cert_t;
+
+//#############################################certificate end
+
+
+typedef struct _business_infor_t
+{
+ void* param;
+ unsigned char return_value;
+}business_infor_t;
+
+typedef struct _ssl_stream_t
+{
+ unsigned long long output_region_flag;
+ unsigned char link_state;
+ unsigned char over_flag;
+ unsigned char ucContType;
+ unsigned char is_ssl_stream;
+ unsigned int uiSslVersion;
+
+ int uiAllMsgLen; //hand shake msg length
+ int uiMsgProcLen;
+ unsigned int uiMsgState;
+ int uiMaxBuffLen;
+
+
+ cdata_buf* p_output_buffer;
+ st_client_hello_t* stClientHello;
+ st_server_hello_t* stServerHello;
+ st_cert_t* stSSLCert;
+
+ business_infor_t* business;
+
+ char* pcSslBuffer;
+ ssl_interested_region output_region_mask;
+ int uiCurBuffLen;
+}ssl_stream;
+
+/*ssl_read_all_cert�еĽṹ��*/
+typedef struct cert_chain_s
+{
+ char* cert;
+ uint32_t cert_len;
+}cert_chain_t;
+
+/*ssl_read_specific_cert��cert_type�IJ���*/
+#define CERT_TYPE_INDIVIDUAL 0 //����֤��
+#define CERT_TYPE_ROOT 1 //��֤��
+#define CERT_TYPE_MIDDLE 2 //�м�֤�飬����֤����ϼ�֤��
+#define CERT_TYPE_CHAIN 3 //����: ��ʽ[len(3bytes)+cert+len(3bytes)+certlen(3bytes)+cert......]
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*return : chain ����, ���մӸ���֤�鵽��֤���˳��洢*/
+int ssl_read_all_cert(const char* conj_cert_buf, uint32_t conj_buflen, cert_chain_t* cert_unit, uint32_t unit_size);
+
+/*return : 1 ���ڣ�0 ������*/
+int ssl_read_specific_cert(const char* conj_cert_buf, uint32_t conj_buflen, uint8_t cert_type, char** cert, uint32_t* cert_len);
+
+const char* ssl_get_suite(st_suites_t* ciphersuits);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
diff --git a/entry/include/ssl_utils.h b/entry/include/ssl_utils.h
new file mode 100644
index 0000000..2ed4faf
--- /dev/null
+++ b/entry/include/ssl_utils.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#define EXTENSION_COUNT_MAX 128
+#define CIPHER_SUITE_COUNT_MAX 256
+
+struct cipher_suite
+{
+ uint16_t value;
+ const char* name;
+};
+
+struct tls_extension{
+ int value;
+ const char* name;
+};
+
+enum chello_parse_result
+{
+ CHELLO_PARSE_SUCCESS = 0,
+ CHELLO_PARSE_INVALID_FORMAT = -1,
+ CHELLO_PARSE_NOT_ENOUGH_BUFF = -2
+};
+
+struct ssl_version
+{
+ uint8_t minor;
+ uint8_t major;
+ uint16_t ossl_format;
+ char str_format[STRING_MAX];
+};
+
+struct ssl_chello
+{
+ struct ssl_version min_version;
+ struct ssl_version max_version;
+ int cipher_suites_count;
+ int extension_count;
+ int cipher_suite_list[CIPHER_SUITE_COUNT_MAX];
+ int extension_list[EXTENSION_COUNT_MAX];
+ char sni[STRING_MAX];
+ char alpn[STRING_MAX];
+};
+
+struct ssl_version_map{
+ int value;
+ const char *name;
+};
+
+void ssl_chello_parse(struct ssl_chello* _chello, const unsigned char* buff, size_t buff_len, enum chello_parse_result* result);
+void ssl_chello_free(struct ssl_chello* chello); \ No newline at end of file
diff --git a/entry/src/base64.cpp b/entry/src/base64.cpp
new file mode 100644
index 0000000..b38e169
--- /dev/null
+++ b/entry/src/base64.cpp
@@ -0,0 +1,143 @@
+
+/*
+ base64.c - by Joe DF ([email protected])
+ Released under the MIT License
+
+ See "base64.h", for more information.
+
+ Thank you for inspiration:
+ http://www.codeproject.com/Tips/813146/Fast-base-functions-for-encode-decode
+*/
+
+#include "base64.h"
+#include <stdio.h>
+#include <algorithm>
+
+//Base64 char table - used internally for encoding
+unsigned char b64_chr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+unsigned int b64_int(unsigned int ch) {
+
+ // ASCII to base64_int
+ // 65-90 Upper Case >> 0-25
+ // 97-122 Lower Case >> 26-51
+ // 48-57 Numbers >> 52-61
+ // 43 Plus (+) >> 62
+ // 47 Slash (/) >> 63
+ // 61 Equal (=) >> 64~
+ if (ch==43)
+ return 62;
+ if (ch==47)
+ return 63;
+ if (ch==61)
+ return 64;
+ if ((ch>47) && (ch<58))
+ return ch + 4;
+ if ((ch>64) && (ch<91))
+ return ch - 'A';
+ if ((ch>96) && (ch<123))
+ return (ch - 'a') + 26;
+ return 0;
+}
+
+/*
+unsigned int b64e_size(unsigned int in_size) {
+
+ // size equals 4*floor((1/3)*(in_size+2));
+ int i, j = 0;
+ for (i=0;i<in_size;i++) {
+ if (i % 3 == 0)
+ j += 1;
+ }
+ return (4*j);
+}
+*/
+
+unsigned int b64d_size(unsigned int in_size) {
+
+ return ((3*in_size)/4);
+}
+
+unsigned int b64_encode(const unsigned char* in, unsigned int in_len, unsigned char* out) {
+
+ unsigned int i=0, j=0, k=0, s[3];
+
+ for (i=0;i<in_len;i++) {
+ s[j++]=*(in+i);
+ if (j==3) {
+ out[k+0] = b64_chr[ (s[0]&255)>>2 ];
+ out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ];
+ out[k+2] = b64_chr[ ((s[1]&0x0F)<<2)+((s[2]&0xC0)>>6) ];
+ out[k+3] = b64_chr[ s[2]&0x3F ];
+ j=0; k+=4;
+ }
+ }
+
+ if (j) {
+ if (j==1)
+ s[1] = 0;
+ out[k+0] = b64_chr[ (s[0]&255)>>2 ];
+ out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ];
+ if (j==2)
+ out[k+2] = b64_chr[ ((s[1]&0x0F)<<2) ];
+ else
+ out[k+2] = '=';
+ out[k+3] = '=';
+ k+=4;
+ }
+
+ out[k] = '\0';
+
+ return k;
+}
+
+unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out) {
+
+ unsigned int i=0, j=0, k=0, s[4];
+
+ for (i=0;i<in_len;i++) {
+ s[j++]=b64_int(*(in+i));
+ if (j==4) {
+ out[k+0] = ((s[0]&255)<<2)+((s[1]&0x30)>>4);
+ if (s[2]!=64) {
+ out[k+1] = ((s[1]&0x0F)<<4)+((s[2]&0x3C)>>2);
+ if ((s[3]!=64)) {
+ out[k+2] = ((s[2]&0x03)<<6)+(s[3]); k+=3;
+ } else {
+ k+=2;
+ }
+ } else {
+ k+=1;
+ }
+ j=0;
+ }
+ }
+ return k;
+}
+
+int test(){
+ unsigned char in_buff[100] = "ab\0d\0fghi";
+ unsigned char out_buff[100];
+ unsigned char *in = in_buff;
+ unsigned char *out = out_buff;
+ int in_len = 10;
+ int out_len = b64_encode(in, in_len, out);
+ printf("encode: out_len = %d\n", out_len);
+ for(int i = 0; i < out_len; i++){
+ printf("%c ", out[i]);
+ }
+ printf("\n");
+ std::swap(in, out);
+ in_len = out_len;
+ out_len = b64_decode(in, in_len, out);
+ printf("decode: out_len = %d\n", out_len);
+ for(int i = 0; i < out_len; i++){
+ printf("%c ", out[i]);
+ }
+ printf("\n");
+ return 0;
+}
+
+int main(){
+ test();
+} \ No newline at end of file
diff --git a/entry/src/ssl_utils.cpp b/entry/src/ssl_utils.cpp
new file mode 100644
index 0000000..34fe599
--- /dev/null
+++ b/entry/src/ssl_utils.cpp
@@ -0,0 +1,468 @@
+#include "base_utils.h"
+#include "ssl_utils.h"
+
+
+struct ssl_version_map g_ssl_veriosn_map_list[] = {
+ {0x0301, "tls1.0"},
+ {0x0302, "tls1.1"},
+ {0x0303, "tls1.2"},
+ {0x0304, "tls1.3"},
+};
+
+struct cipher_suite g_cipher_suite_list[] = {
+ {0xC030, "ECDHE-RSA-AES256-GCM-SHA384"},
+ {0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"},
+ {0xC028, "ECDHE-RSA-AES256-SHA384"},
+ {0xC024, "ECDHE-ECDSA-AES256-SHA384"},
+ {0xC014, "ECDHE-RSA-AES256-SHA"},
+ {0xC00A, "ECDHE-ECDSA-AES256-SHA"},
+ {0x00A5, "DH-DSS-AES256-GCM-SHA384"},
+ {0x00A3, "DHE-DSS-AES256-GCM-SHA384"},
+ {0x00A1, "DH-RSA-AES256-GCM-SHA384"},
+ {0x009F, "DHE-RSA-AES256-GCM-SHA384"},
+ {0x006B, "DHE-RSA-AES256-SHA256"},
+ {0x006A, "DHE-DSS-AES256-SHA256"},
+ {0x0069, "DH-RSA-AES256-SHA256"},
+ {0x0068, "DH-DSS-AES256-SHA256"},
+ {0x0039, "DHE-RSA-AES256-SHA"},
+ {0x0038, "DHE-DSS-AES256-SHA"},
+ {0x0037, "DH-RSA-AES256-SHA"},
+ {0x0036, "DH-DSS-AES256-SHA"},
+ {0x0088, "DHE-RSA-CAMELLIA256-SHA"},
+ {0x0087, "DHE-DSS-CAMELLIA256-SHA"},
+ {0x0086, "DH-RSA-CAMELLIA256-SHA"},
+ {0x0085, "DH-DSS-CAMELLIA256-SHA"},
+ {0xC019, "AECDH-AES256-SHA"},
+ {0x00A7, "ADH-AES256-GCM-SHA384"},
+ {0x006D, "ADH-AES256-SHA256"},
+ {0x003A, "ADH-AES256-SHA"},
+ {0x0089, "ADH-CAMELLIA256-SHA"},
+ {0xC032, "ECDH-RSA-AES256-GCM-SHA384"},
+ {0xC02E, "ECDH-ECDSA-AES256-GCM-SHA384"},
+ {0xC02A, "ECDH-RSA-AES256-SHA384"},
+ {0xC026, "ECDH-ECDSA-AES256-SHA384"},
+ {0xC00F, "ECDH-RSA-AES256-SHA"},
+ {0xC005, "ECDH-ECDSA-AES256-SHA"},
+ {0x009D, "AES256-GCM-SHA384"},
+ {0x003D, "AES256-SHA256"},
+ {0x0035, "AES256-SHA"},
+ {0x0084, "CAMELLIA256-SHA"},
+ {0x008D, "PSK-AES256-CBC-SHA"},
+ {0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"},
+ {0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"},
+ {0xC027, "ECDHE-RSA-AES128-SHA256"},
+ {0xC023, "ECDHE-ECDSA-AES128-SHA256"},
+ {0xC013, "ECDHE-RSA-AES128-SHA"},
+ {0xC009, "ECDHE-ECDSA-AES128-SHA"},
+ {0x00A4, "DH-DSS-AES128-GCM-SHA256"},
+ {0x00A2, "DHE-DSS-AES128-GCM-SHA256"},
+ {0x00A0, "DH-RSA-AES128-GCM-SHA256"},
+ {0x009E, "DHE-RSA-AES128-GCM-SHA256"},
+ {0x0067, "DHE-RSA-AES128-SHA256"},
+ {0x0040, "DHE-DSS-AES128-SHA256"},
+ {0x003F, "DH-RSA-AES128-SHA256"},
+ {0x003E, "DH-DSS-AES128-SHA256"},
+ {0x0033, "DHE-RSA-AES128-SHA"},
+ {0x0032, "DHE-DSS-AES128-SHA"},
+ {0x0031, "DH-RSA-AES128-SHA"},
+ {0x0030, "DH-DSS-AES128-SHA"},
+ {0x009A, "DHE-RSA-SEED-SHA"},
+ {0x0099, "DHE-DSS-SEED-SHA"},
+ {0x0098, "DH-RSA-SEED-SHA"},
+ {0x0097, "DH-DSS-SEED-SHA"},
+ {0x0045, "DHE-RSA-CAMELLIA128-SHA"},
+ {0x0044, "DHE-DSS-CAMELLIA128-SHA"},
+ {0x0043, "DH-RSA-CAMELLIA128-SHA"},
+ {0x0042, "DH-DSS-CAMELLIA128-SHA"},
+ {0xC018, "AECDH-AES128-SHA"},
+ {0x00A6, "ADH-AES128-GCM-SHA256"},
+ {0x006C, "ADH-AES128-SHA256"},
+ {0x0034, "ADH-AES128-SHA"},
+ {0x009B, "ADH-SEED-SHA"},
+ {0x0046, "ADH-CAMELLIA128-SHA"},
+ {0xC031, "ECDH-RSA-AES128-GCM-SHA256"},
+ {0xC02D, "ECDH-ECDSA-AES128-GCM-SHA256"},
+ {0xC029, "ECDH-RSA-AES128-SHA256"},
+ {0xC025, "ECDH-ECDSA-AES128-SHA256"},
+ {0xC00E, "ECDH-RSA-AES128-SHA"},
+ {0xC004, "ECDH-ECDSA-AES128-SHA"},
+ {0x009C, "AES128-GCM-SHA256"},
+ {0x003C, "AES128-SHA256"},
+ {0x002F, "AES128-SHA"},
+ {0x0096, "SEED-SHA"},
+ {0x0041, "CAMELLIA128-SHA"},
+ {0x008C, "PSK-AES128-CBC-SHA"},
+ {0xC012, "ECDHE-RSA-DES-CBC3-SHA"},
+ {0xC008, "ECDHE-ECDSA-DES-CBC3-SHA"},
+ {0x0016, "EDH-RSA-DES-CBC3-SHA"},
+ {0x0013, "EDH-DSS-DES-CBC3-SHA"},
+ {0x0010, "DH-RSA-DES-CBC3-SHA"},
+ {0x000D, "DH-DSS-DES-CBC3-SHA"},
+ {0xC017, "AECDH-DES-CBC3-SHA"},
+ {0x001B, "ADH-DES-CBC3-SHA"},
+ {0xC00D, "ECDH-RSA-DES-CBC3-SHA"},
+ {0xC003, "ECDH-ECDSA-DES-CBC3-SHA"},
+ {0x000A, "DES-CBC3-SHA"},
+ {0x0007, "IDEA-CBC-SHA"},
+ {0x008B, "PSK-3DES-EDE-CBC-SHA"},
+ {0x0021, "KRB5-IDEA-CBC-SHA"},
+ {0x001F, "KRB5-DES-CBC3-SHA"},
+ {0x0025, "KRB5-IDEA-CBC-MD5"},
+ {0x0023, "KRB5-DES-CBC3-MD5"},
+ {0xC011, "ECDHE-RSA-RC4-SHA"},
+ {0xC007, "ECDHE-ECDSA-RC4-SHA"},
+ {0xC016, "AECDH-RC4-SHA"},
+ {0x0018, "ADH-RC4-MD5"},
+ {0xC00C, "ECDH-RSA-RC4-SHA"},
+ {0xC002, "ECDH-ECDSA-RC4-SHA"},
+ {0x0005, "RC4-SHA"},
+ {0x0004, "RC4-MD5"},
+ {0x008A, "PSK-RC4-SHA"},
+ {0x0020, "KRB5-RC4-SHA"},
+ {0x0024, "KRB5-RC4-MD5"},
+ {0xC010, "ECDHE-RSA-NULL-SHA"},
+ {0xC006, "ECDHE-ECDSA-NULL-SHA"},
+ {0xC015, "AECDH-NULL-SHA"},
+ {0xC00B, "ECDH-RSA-NULL-SHA"},
+ {0xC001, "ECDH-ECDSA-NULL-SHA"},
+ {0x003B, "NULL-SHA256"},
+ {0x0002, "NULL-SHA"},
+ {0x0001, "NULL-MD5"},
+ {0x1301, "TLS_AES_128_GCM_SHA256"},
+ {0x1302, "TLS_AES_256_GCM_SHA384"},
+ {0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
+ {0x1304, "TLS_AES_128_CCM_SHA256"},
+ {0x1305, "TLS_AES_128_CCM_8_SHA256"},
+};
+
+struct tls_extension g_tls_extension_list[] = {
+ {0, "server_name"},
+ {1, "max_fragment_length"},
+ {2, "client_certificate_url"},
+ {3, "trusted_ca_keys"},
+ {4, "truncated_hmac"},
+ {5, "status_request"},
+ {6, "user_mapping"},
+ {7, "client_authz"},
+ {8, "server_authz"},
+ {9, "cert_type"},
+ {10, "supported_groups"},
+ {11, "ec_point_formats"},
+ {12, "srp"},
+ {13, "signature_algorithms"},
+ {14, "use_srtp"},
+ {15, "heartbeat"},
+ {16, "application_layer_protocol_negotiation"},
+ {17, "status_request_v2"},
+ {18, "signed_certificate_timestamp"},
+ {19, "client_certificate_type"},
+ {20, "server_certificate_type"},
+ {21, "padding"},
+ {22, "encrypt_then_mac"},
+ {23, "extended_master_secret"},
+ {24, "token_binding"},
+ {25, "cached_info"},
+ {26, "tls_lts"},
+ {27, "compress_certificate"},
+ {28, "record_size_limit"},
+ {29, "pwd_protect"},
+ {30, "pwd_clear"},
+ {31, "password_salt"},
+ {32, "ticket_pinning"},
+ {35, "session_ticket"},
+ {41, "pre_shared_key"},
+ {42, "early_data"},
+ {43, "supported_versions"},
+ {44, "cookie"},
+ {45, "psk_key_exchange_modes"},
+ {47, "certificate_authorities"},
+ {48, "oid_filters"},
+ {49, "post_handshake_auth"},
+ {50, "signature_algorithms_cert"},
+ {51, "key_share"},
+ {52, "transparency_info"},
+ {53, "connection_id"},
+ {55, "external_id_hash"},
+ {56, "external_session_id"},
+ {65281, "renegotiation_info"},
+};
+
+void ssl_chello_free(struct ssl_chello* chello){
+ if(chello==NULL){
+ return;
+ }
+ free(chello);
+}
+
+static void parse_alpn_extension(const unsigned char* buff, size_t buff_len, enum chello_parse_result* result, char *alpn){
+ size_t pos = 0;
+ size_t len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1];
+ if(2 + len != buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ strncpy((char*)alpn, (const char*)buff + 2, len);
+ alpn[len] = '\0';
+ *result = CHELLO_PARSE_SUCCESS;
+ return;
+}
+
+static void parse_server_name_extension(const unsigned char* buff, size_t buff_len, enum chello_parse_result* result, char *sni){
+ size_t pos = 2; /* skip server name list length */
+ size_t len;
+ while (pos + 3 < buff_len){
+ len = ((size_t)buff[pos + 1] << 8) + (size_t)buff[pos + 2];
+ if (pos + 3 + len > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ switch (buff[pos]){
+ case 0x00: /* host_name */
+ strncpy(sni, (const char*)buff + pos + 3, len);
+ sni[len] = '\0';
+ *result = CHELLO_PARSE_SUCCESS;
+ }
+ pos += 3 + len;
+ }
+ if (pos != buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ }
+ return;
+}
+
+int is_extension_existed(int value){
+ int n = sizeof(g_tls_extension_list) / sizeof(tls_extension);
+ for(int i = 0; i < n; i++){
+ if(g_tls_extension_list[i].value == value){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static enum chello_parse_result parse_extensions(const unsigned char* buff, size_t buff_len, struct ssl_chello* chello) {
+ size_t pos = 0;
+ /* Parse each 4 bytes for the extension header */
+ while (pos + 4 <= buff_len){
+ size_t type = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1];
+ size_t len = ((size_t)buff[pos + 2] << 8) + (size_t)buff[pos + 3];
+ int ret = is_extension_existed(type);
+ if(ret == 0){
+ pos += (4 + len);
+ continue;
+ }
+ chello->extension_list[chello->extension_count] = type;
+ chello->extension_count++;
+ /* Check if it's a server name extension */
+ if (buff[pos] == 0x00 && buff[pos + 1] == 0x00){
+ if (pos + 4 + len > buff_len){
+ return CHELLO_PARSE_INVALID_FORMAT;
+ }
+ enum chello_parse_result result = CHELLO_PARSE_SUCCESS;
+ parse_server_name_extension(buff + pos + 4, len, &result, chello->sni);
+ if(result != CHELLO_PARSE_SUCCESS){
+ return result;
+ }
+ }
+ /* Check if it's a alpn extension */
+ if (buff[pos] == 0x00 && buff[pos + 1] == 0x10){
+ if (pos + 4 + len > buff_len){
+ return CHELLO_PARSE_INVALID_FORMAT;
+ }
+ enum chello_parse_result result = CHELLO_PARSE_SUCCESS;
+ parse_alpn_extension(buff + pos + 4, len, &result, chello->alpn);
+ if(result != CHELLO_PARSE_SUCCESS){
+ return result;
+ }
+ }
+ pos += (4 + len);
+ }
+ /* Check we ended where we expected to */
+ if (pos != buff_len){
+ return CHELLO_PARSE_INVALID_FORMAT;
+ }
+ return CHELLO_PARSE_SUCCESS;
+}
+
+static void parse_cipher_suites(struct ssl_chello* chello, const unsigned char* buff, size_t buff_len, enum chello_parse_result* result){
+ int n = sizeof(g_cipher_suite_list) / sizeof(struct cipher_suite);
+ size_t pos = 0;
+ int flag = 0;
+ while(pos < buff_len){
+ int i = 0;
+ for(i = 0;i < n; i++){
+ int val = (buff[pos] << 8) + buff[pos + 1];
+ if(g_cipher_suite_list[i].value == val){
+ chello->cipher_suite_list[chello->cipher_suites_count] = val;
+ chello->cipher_suites_count++;
+ }
+ }
+ pos += 2;
+ if(flag == 1){
+ break;
+ }
+ }
+ if(pos != buff_len && flag == 0){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ *result = CHELLO_PARSE_SUCCESS;
+ return;
+}
+
+void get_ssl_version_str_format(uint16_t value, char *name){
+ int n = sizeof(g_ssl_veriosn_map_list) / sizeof(struct ssl_version_map);
+ for(int i = 0; i < n; i++){
+ if(g_ssl_veriosn_map_list[i].value == value){
+ strcpy(name, g_ssl_veriosn_map_list[i].name);
+ return;
+ }
+ }
+ printf("Failed at get_ssl_version_str_format(), value is %02x\n", value);
+}
+
+void ssl_chello_parse(struct ssl_chello* _chello, const unsigned char* buff, size_t buff_len, enum chello_parse_result* result){
+ if(buff == NULL){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ if(buff_len < 1){
+ *result = CHELLO_PARSE_NOT_ENOUGH_BUFF;
+ return;
+ }
+ if(buff[0] != 0x80 && buff[0] != 0x16){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ /* SSL 2.0 compatible Client Hello
+ * High bit of first byte (length) and content type is Client Hello
+ * See RFC5246 Appendix E.2
+ * if it is SSL 2.0, only parse version
+ */
+ if(buff[0] == 0x80){
+ _chello->min_version.major = 0x02;
+ if(buff_len < 2){
+ *result = CHELLO_PARSE_NOT_ENOUGH_BUFF;
+ return;
+ }
+ size_t len = (size_t)buff[1];
+ if (buff_len < len + 2){
+ *result = CHELLO_PARSE_NOT_ENOUGH_BUFF;
+ return;
+ }
+ buff_len = len + 2;
+ size_t pos = 2;
+ /* Handshark Message Type: Client Hello */
+ if (pos + 1 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ if (buff[pos] != 0x01){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ pos += 1;
+ /* Version */
+ if(pos + 2 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ _chello->max_version.major = buff[pos];
+ _chello->max_version.minor = buff[pos + 1];
+ _chello->max_version.ossl_format=(uint16_t)_chello->max_version.major<<8|_chello->max_version.minor;
+ get_ssl_version_str_format(_chello->max_version.ossl_format, _chello->max_version.str_format);
+ *result = CHELLO_PARSE_SUCCESS;
+ return;
+ }
+ else{
+ if (buff_len < 5){
+ *result = CHELLO_PARSE_NOT_ENOUGH_BUFF;
+ return;
+ }
+ if(buff[1] != 3 || buff[2] > 4 || buff[2] < 0){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ _chello->min_version.major = buff[1];
+ _chello->min_version.minor = buff[2];
+ _chello->min_version.ossl_format=(uint16_t)_chello->min_version.major<<8|_chello->min_version.minor;
+ get_ssl_version_str_format(_chello->min_version.ossl_format, _chello->min_version.str_format);
+ _chello->max_version.major = -1;
+ _chello->max_version.minor = -1;
+ /* TLS record length */
+ size_t len = ((size_t)buff[3] << 8) + (size_t)buff[4] + 5;
+ if (buff_len < len){
+ *result = CHELLO_PARSE_NOT_ENOUGH_BUFF;
+ return;
+ }
+ buff_len = len;
+ size_t pos = 5;
+ if (pos + 1 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ if (buff[pos] != 0x01){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ pos += 4;
+ if(pos + 2 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ _chello->max_version.major = buff[pos];
+ _chello->max_version.minor = buff[pos+1];
+ _chello->max_version.ossl_format=(uint16_t)_chello->max_version.major<<8|_chello->max_version.minor;
+ get_ssl_version_str_format(_chello->max_version.ossl_format, _chello->max_version.str_format);
+ pos += 34;
+ /* Session ID */
+ if (pos + 1 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ len = (size_t)buff[pos];
+ pos += 1 + len;
+ /* Cipher Suites */
+ if (pos + 2 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1];
+ pos += 2;
+ if(pos + len > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ parse_cipher_suites(_chello, buff + pos, len, result);
+ if(*result != CHELLO_PARSE_SUCCESS){
+ return;
+ }
+ pos += len;
+ /* Compression Methods */
+ if (pos >= buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ len = (size_t)buff[pos];
+ pos += 1 + len;
+ /* no extensions */
+ if(pos == buff_len){
+ *result = CHELLO_PARSE_SUCCESS;
+ return;
+ }
+ /* Extensions */
+ if (pos + 2 > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ len = ((size_t)buff[pos] << 8) + (size_t)buff[pos + 1];
+ pos += 2;
+ if (pos + len > buff_len){
+ *result = CHELLO_PARSE_INVALID_FORMAT;
+ return;
+ }
+ enum chello_parse_result ret = parse_extensions(buff + pos, len, _chello);
+ *result = ret;
+ return;
+ }
+}
diff --git a/entry/src/sslparse_entry.cpp b/entry/src/sslparse_entry.cpp
new file mode 100644
index 0000000..b98e44b
--- /dev/null
+++ b/entry/src/sslparse_entry.cpp
@@ -0,0 +1,697 @@
+
+#include "base_utils.h"
+#include "ssl_utils.h"
+#include "MESA/stream_inc/stream_base.h"
+#include "MESA/stream_inc/stream_rawpkt.h"
+#include "cjson/cJSON.h"
+#include "openssl/x509.h"
+#include "base64.h"
+#include <algorithm>
+#define STREAM_PACKET_COUNT_MAX 10000
+#define TLS_MESSAGE_LEN_MAX 20000
+#define SUBJECT_LEN_MAX 1024
+
+int g_stream_total = 0;
+int g_stream_output = 0;
+int g_stream_no_fin = 0;
+int g_stream_error = 0;
+int g_pending = 0, g_close = 0;
+void *g_logger = NULL;
+FILE *g_fp = NULL;
+
+struct tls_message_type{
+ int message_type;
+ int content_type;
+ int handshake_type;
+ const char *name;
+};
+
+struct tls_message_type g_tls_types[] = {
+ {0, 22, 0, "hello_request_RESERVED"},
+ {1, 22, 1, "client_hello"},
+ {2, 22, 2, "server_hello"},
+ {3, 22, 3, "hello_verify_request_RESERVED"},
+ {4, 22, 4, "new_session_ticket"},
+ {5, 22, 5, "end_of_early_data"},
+ {6, 22, 6, "hello_retry_request_RESERVED"},
+ {7, 22, 8, "encrypted_extensions"},
+ {8, 22, 11, "certificate"},
+ {9, 22, 12, "server_key_exchange_RESERVED"},
+ {10, 22, 13, "certificate_request"},
+ {11, 22, 14, "server_hello_done_RESERVED"},
+ {12, 22, 15, "certificate_verify"},
+ {13, 22, 16, "client_key_exchange_RESERVED"},
+ {14, 22, 20, "finished"},
+ {15, 22, 21, "certificate_url_RESERVED"},
+ {16, 22, 22, "certificate_status_RESERVED"},
+ {17, 22, 23, "supplemental_data_RESERVED"},
+ {18, 22, 24, "key_update"},
+ {19, 22, 25, "compressed_certificate"},
+ {20, 22, 254, "message_hash"},
+ {21, 20, 0, "change_cipher_spec"},
+ {22, 21, 0, "alert"},
+ {23, 23, 0, "application_data"},
+ {24, 24, 0, "heartbeat"},
+ {25, 25, 0, "tls12_cid"},
+ {26, 22, -1, "handshake_unknown"},
+};
+
+struct tls_message_detail{
+ int type;
+ int len;
+ unsigned char buff[TLS_MESSAGE_LEN_MAX];
+ int buff_len;
+};
+
+struct tls_filtered_message{
+ unsigned char buff[TLS_MESSAGE_LEN_MAX];
+ int buff_len;
+};
+
+struct pkt_parsed_info{
+ addr_type_t addr_type;
+ union{
+ struct iphdr *v4;
+ struct ip6_hdr *v6;
+ }iphdr;
+ uint16_t iphdr_len;
+ uint16_t ip_totlen;
+ struct tcphdr *tcphdr;
+ uint16_t tcphdr_len;
+ char *data;
+ uint16_t data_len;
+};
+
+struct pme_info{
+ int _errno;
+ char sip[INET_ADDRSTRLEN];
+ int sport;
+ char dip[INET_ADDRSTRLEN];
+ int dport;
+ struct ssl_chello chello;
+ struct tls_message_detail cur_c2s_tls;
+ struct tls_message_detail cur_s2c_tls;
+ struct tls_filtered_message message_client_hello;
+ struct tls_filtered_message message_client_hello_no_extensions;
+ struct tls_filtered_message message_server_hello;
+ struct tls_filtered_message message_server_hello_no_extensions;
+ struct tls_filtered_message message_certificate;
+ struct tls_filtered_message message_certificate_no_serial;
+ struct tls_filtered_message message_raw_client_hello;
+ struct tls_filtered_message message_raw_server_hello;
+ struct tls_filtered_message message_raw_certificate;
+ struct tls_filtered_message message_subject;
+ struct tls_filtered_message message_serial_number;
+ int has_fin_rst;
+};
+
+int ipv4_header_parse(const void *a_packet, struct pkt_parsed_info* pktinfo){
+ if(a_packet == NULL){
+ return -1;
+ }
+ pktinfo->addr_type = ADDR_TYPE_IPV4;
+ pktinfo->iphdr.v4 = (struct iphdr*)a_packet;
+ pktinfo->iphdr_len = pktinfo->iphdr.v4->ihl * 4;
+ pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v4->tot_len);
+ pktinfo->tcphdr = (struct tcphdr*)((char*)pktinfo->iphdr.v4 + pktinfo->iphdr_len);
+ pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
+ pktinfo->data = (char*)pktinfo->tcphdr + pktinfo->tcphdr_len;
+ pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
+ /*
+ struct iphdr *_iphdr = pktinfo->iphdr.v4;
+ int ttl = _iphdr->ttl;
+ int ipid = ntohs(_iphdr->id);
+ printf("ipv4: ipid = %02x, ttl = %d, data_len = %d\n", ipid, ttl, pktinfo->data_len);
+ */
+ return 0;
+}
+
+
+int chello_packet_parse(struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ enum chello_parse_result chello_status = CHELLO_PARSE_INVALID_FORMAT;
+ char *buff = pktinfo->data;
+ int len = pktinfo->data_len;
+ ssl_chello_parse(&(pmeinfo->chello), (const unsigned char*)buff, len, &chello_status);
+ if(chello_status != CHELLO_PARSE_SUCCESS){
+ LOG_ERROR(g_logger, "Error: chello parse failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+int get_tls_message_type(int content_type, int handshake_type){
+ int type_count = sizeof(g_tls_types) / sizeof(struct tls_message_type);
+ for(int i = 0; i < type_count; i++){
+ if(g_tls_types[i].content_type == content_type && g_tls_types[i].handshake_type == handshake_type){
+ return i;
+ }
+ }
+ if(content_type == 22){
+ return type_count - 1;
+ }
+ return -1;
+}
+
+int client_server_hello_get(unsigned char *buff, int len, struct pme_info *pmeinfo, int type){
+ char buff1[TLS_MESSAGE_LEN_MAX];
+ int i = 0, len1 = 0;
+ memcpy(buff1 + len1, buff + i, 6);
+ i += 6;
+ len1 += 6;
+ //random
+ i += 32;
+ //session_id
+ int session_id_len = (uint8_t)buff[i];
+ i += (1 + session_id_len);
+ //cipher suites: type = 1, client hello; type = 2, server hello
+ if(type == 1){
+ int cipher_suites_len = (uint16_t)(buff[i] << 8) + (uint8_t)buff[i + 1];
+ memcpy(buff1 + len1, buff + i, 2 + cipher_suites_len);
+ i += (2 + cipher_suites_len);
+ len1 += (2 + cipher_suites_len);
+ }
+ if(type == 2){
+ memcpy(buff1 + len1, buff + i, 2);
+ i += 2;
+ len1 += 2;
+ }
+ //compression methods
+ int compression_methods_len = (uint8_t)buff[i];
+ memcpy(buff1 + len1, buff + i, 1 + compression_methods_len);
+ i += (1 + compression_methods_len);
+ len1 += (1 + compression_methods_len);
+ int extensions_index = len1;
+ //extensions
+ int extensions_len = (uint16_t)(buff[i] << 8) + (uint8_t)buff[i + 1];
+ memcpy(buff1 + len1, buff + i, 2);
+ i += 2;
+ len1 += 2;
+ int i1 = i;
+ for(; i + 3 < i1 + extensions_len;){
+ int type = (uint16_t)(buff[i] << 8) + (uint8_t)buff[i + 1];
+ int extension_len = (uint16_t)(buff[i + 2] << 8) + (uint8_t)buff[i + 3];
+ if(type == 21){
+ i += (4 + extension_len);
+ continue;
+ }
+ memcpy(buff1 + len1, buff + i, 4 + extension_len);
+ i += (4 + extension_len);
+ len1 += (4 + extension_len);
+ }
+ if(len1 > len){
+ return -1;
+ }
+ if(type == 1){
+ memcpy(pmeinfo->message_client_hello.buff, buff1, len1);
+ pmeinfo->message_client_hello.buff_len = len1;
+ memcpy(pmeinfo->message_client_hello_no_extensions.buff, buff1, extensions_index);
+ pmeinfo->message_client_hello_no_extensions.buff_len = extensions_index;
+ }
+ if(type == 2){
+ memcpy(pmeinfo->message_server_hello.buff, buff1, len1);
+ pmeinfo->message_server_hello.buff_len = len1;
+ memcpy(pmeinfo->message_server_hello_no_extensions.buff, buff1, extensions_index);
+ pmeinfo->message_server_hello_no_extensions.buff_len = extensions_index;
+ }
+ return 0;
+}
+
+int client_hello_get(struct pme_info* pmeinfo, unsigned char *buff, int len){
+ memcpy(pmeinfo->message_raw_client_hello.buff, buff, len);
+ pmeinfo->message_raw_client_hello.buff_len = len;
+ /*
+ int ret = client_server_hello_get(buff, len, pmeinfo, 1);
+ if(ret < 0){
+ LOG_ERROR(g_logger, "Invalid client hello");
+ return -1;
+ }
+ */
+ /*
+ printf("client_hello, buff_len = %d\n", pmeinfo->message_client_hello.buff_len);
+ for(int i = 0; i < pmeinfo->message_client_hello.buff_len; i++){
+ printf("%02x ", (uint8_t)pmeinfo->message_client_hello.buff[i]);
+ }
+ printf("\n");
+ printf("client_hello_no_extensions, buff_len = %d\n", pmeinfo->message_client_hello_no_extensions.buff_len);
+ for(int i = 0; i < pmeinfo->message_client_hello_no_extensions.buff_len; i++){
+ printf("%02x ", (uint8_t)pmeinfo->message_client_hello_no_extensions.buff[i]);
+ }
+ printf("\n");
+ */
+ return 0;
+}
+
+int server_hello_get(struct pme_info* pmeinfo, unsigned char *buff, int len){
+ memcpy(pmeinfo->message_raw_server_hello.buff, buff, len);
+ pmeinfo->message_raw_server_hello.buff_len = len;
+ /*
+ int ret = client_server_hello_get(buff, len, pmeinfo, 2);
+ if(ret < 0){
+ LOG_ERROR(g_logger, "Invalid server hello");
+ return -1;
+ }
+ */
+ /*
+ printf("server_hello, buff_len = %d\n", pmeinfo->message_server_hello.buff_len);
+ for(int i = 0; i < pmeinfo->message_server_hello.buff_len; i++){
+ printf("%02x ", (uint8_t)pmeinfo->message_server_hello.buff[i]);
+ }
+ printf("\n");
+ printf("server_hello_no_extensions, buff_len = %d\n", pmeinfo->message_server_hello_no_extensions.buff_len);
+ for(int i = 0; i < pmeinfo->message_server_hello_no_extensions.buff_len; i++){
+ printf("%02x ", (uint8_t)pmeinfo->message_server_hello_no_extensions.buff[i]);
+ }
+ printf("\n");
+ */
+ return 0;
+}
+
+int get_public_key(X509 *cert, unsigned char *public_key){
+ //printf("call get_public_key\n");
+ int public_key_len = 0;
+ EVP_PKEY *pkey = X509_get_pubkey(cert);
+ if(pkey == NULL){
+ return -1;
+ }
+ unsigned char *p = NULL;
+ public_key_len = i2d_PUBKEY(pkey, &p);
+ public_key_len -= 24;
+ memcpy(public_key, p + 24, public_key_len);
+ /*
+ printf("public_key_len = %d\n", public_key_len);
+ for(int i = 0; i < public_key_len; i++){
+ printf("%02x ", public_key[i]);
+ }
+ printf("\n");
+ */
+ EVP_PKEY_free(pkey);
+ return public_key_len;
+}
+
+int find_sub_block(unsigned char *s1, int len1, unsigned char *s2, int len2){
+ for(int i = 0; i + len2 < len1; i++){
+ int j;
+ for(j = 0; j < len2; j++){
+ if(s1[i + j] != s2[j]){
+ break;
+ }
+ }
+ if(j == len2){
+ return i;
+ }
+ }
+ return -1;
+}
+
+int strip_data_from_buff(unsigned char *input, int input_len, int begin, int end, unsigned char *output){
+ int output_len = 0;
+ memcpy(output + output_len, input, begin);
+ output_len += begin;
+ memcpy(output + output_len, input + end, input_len - end);
+ output_len += (input_len - end);
+ return output_len;
+}
+
+int strip_encrypted_data(unsigned char *input, int input_len, unsigned char *output){
+ int encrypted_data_begin = input_len - 24;
+ int encrypted_data_end = input_len;
+ return strip_data_from_buff(input, input_len, encrypted_data_begin, encrypted_data_end, output);
+}
+
+int strip_public_key(X509 *cert, unsigned char *input, int input_len, unsigned char *output){
+ unsigned char public_key[TLS_MESSAGE_LEN_MAX];
+ int public_key_len = get_public_key(cert, public_key);
+ if(public_key_len < 0){
+ return -1;
+ }
+ int public_key_begin = find_sub_block(input, input_len, public_key, public_key_len);
+ //printf("public key begin = %d\n", public_key_begin);
+ if(public_key_begin < 0){
+ return -1;
+ }
+ int public_key_end = public_key_begin + public_key_len;
+ return strip_data_from_buff(input, input_len, public_key_begin, public_key_end, output);
+}
+
+
+int get_serial_number(X509 *cert, unsigned char *serial_number){
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
+ int len = BN_num_bytes(bn);
+ BN_bn2bin(bn, serial_number);
+ /*
+ printf("serial number len = %d\n", len);
+ for(int i = 0; i < len; i++){
+ printf("%02x ", serial_number[i]);
+ }
+ printf("\n");
+ */
+ return len;
+}
+
+int strip_serial_number(X509 *cert, unsigned char *input, int input_len, unsigned char *output){
+ unsigned char serial_number[TLS_MESSAGE_LEN_MAX];
+ int serial_number_len = get_serial_number(cert, serial_number);
+ if(serial_number_len < 0){
+ return -1;
+ }
+ int serial_number_begin = find_sub_block(input, input_len, serial_number, serial_number_len);
+ //printf("serial number begin = %d\n", serial_number_begin);
+ if(serial_number_begin < 0){
+ return -1;
+ }
+ int serial_number_end = serial_number_begin + serial_number_len;
+ return strip_data_from_buff(input, input_len, serial_number_begin, serial_number_end, output);
+}
+
+int certificate_get(struct pme_info* pmeinfo, unsigned char *buff, int len){
+ //printf("call certificate_get\n");
+ if(10 > len){
+ return -1;
+ }
+ int cert_len = (buff[7] << 16) + (buff[8] << 8) + buff[9];
+ int i = 10;
+ if(i + cert_len > len){
+ return -1;
+ }
+ unsigned char cert_buff[TLS_MESSAGE_LEN_MAX];
+ memcpy(cert_buff, buff + i, cert_len);
+ const unsigned char *p = cert_buff;
+ X509 *cert = d2i_X509(NULL, &p, cert_len);
+ if(cert == NULL){
+ return -1;
+ }
+
+ // 2020.4.19, get serial_number
+ int serail_number_len = get_serial_number(cert, pmeinfo->message_serial_number.buff);
+ pmeinfo->message_serial_number.buff_len = serail_number_len;
+
+
+ /*
+ 2020.3.28, get subject, and raw cert
+ */
+ char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
+ //printf("subject is: %s\n", subj);
+ int subj_len = strnlen(subj, sizeof(pmeinfo->message_subject.buff));
+ memcpy(pmeinfo->message_subject.buff, subj, subj_len);
+ pmeinfo->message_subject.buff_len = subj_len;
+ OPENSSL_free(subj);
+ memcpy(pmeinfo->message_raw_certificate.buff, cert_buff, cert_len);
+ pmeinfo->message_raw_certificate.buff_len = cert_len;
+ //printf("cert_len = %d\n", cert_len);
+
+ /*
+ unsigned char buff1[TLS_MESSAGE_LEN_MAX];
+ unsigned char *input = cert_buff;
+ int input_len = cert_len;
+ unsigned char *output = buff1;
+ int output_len = 0;
+ output_len = strip_public_key(cert, input, input_len, output);
+ std::swap(output, input);
+ input_len = output_len;
+ output_len = strip_encrypted_data(input, input_len, output);
+ if(output_len >= 0){
+ memcpy(pmeinfo->message_certificate.buff, output, output_len);
+ pmeinfo->message_certificate.buff_len = output_len;
+ }
+ std::swap(output, input);
+ input_len = output_len;
+ output_len = strip_serial_number(cert, input, input_len, output);
+ if(output_len >= 0){
+ memcpy(pmeinfo->message_certificate_no_serial.buff, output, output_len);
+ pmeinfo->message_certificate_no_serial.buff_len = output_len;
+ }
+ */
+
+ X509_free(cert);
+ return 0;
+}
+
+int tls_header_parse(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ int i = 0, len = pktinfo->data_len;
+ int curdir = stream->curdir;
+ struct tls_message_detail *cur_tls = NULL;
+ if(curdir == 1){
+ cur_tls = &(pmeinfo->cur_c2s_tls);
+ }
+ if(curdir == 2){
+ cur_tls = &(pmeinfo->cur_s2c_tls);
+ }
+ int cp_len = 0;
+ while(i < len){
+ if(cur_tls->buff_len < 5){
+ cp_len = MIN(5 - cur_tls->buff_len, len - i);
+ memcpy(cur_tls->buff + cur_tls->buff_len, pktinfo->data + i, cp_len);
+ cur_tls->buff_len += cp_len;
+ i += cp_len;
+ if(cur_tls->buff_len < 5){
+ break;
+ }
+ }
+ int content_type = cur_tls->buff[0];
+ if(content_type == 0x16){
+ if(cur_tls->buff_len < 6){
+ cp_len = MIN(1, len - i);
+ memcpy(cur_tls->buff + cur_tls->buff_len, pktinfo->data + i, cp_len);
+ cur_tls->buff_len += cp_len;
+ i += cp_len;
+ if(cur_tls->buff_len < 6){
+ break;
+ }
+ }
+ }
+ int handshake_type = 0;
+ if(content_type == 0x16){
+ handshake_type = cur_tls->buff[5];
+ }
+ int message_type = get_tls_message_type(content_type, handshake_type);
+ cur_tls->type = message_type;
+ cur_tls->len = (uint16_t)(cur_tls->buff[3] << 8) + (uint8_t)cur_tls->buff[4];
+ if(message_type < 0){
+ LOG_ERROR(g_logger, "message_type unknown, content_type = %d, handshake_type = %d", content_type, handshake_type);
+ memset(cur_tls, 0, sizeof(*cur_tls));
+ break;
+ }
+ cp_len = MIN(cur_tls->len + 5 - cur_tls->buff_len, len - i);
+ //client hello, server hello, certificate
+ if(message_type == 1 || message_type == 2 || message_type == 8){
+ memcpy(cur_tls->buff + cur_tls->buff_len, pktinfo->data + i, cp_len);
+ }
+ cur_tls->buff_len += cp_len;
+ i += cp_len;
+ if(cur_tls->len + 5 == cur_tls->buff_len){
+ if(message_type == 1 || message_type == 2 || message_type == 8){
+ switch (message_type){
+ case 1:
+ client_hello_get(pmeinfo, cur_tls->buff + 5, cur_tls->len);
+ break;
+ case 2:
+ server_hello_get(pmeinfo, cur_tls->buff + 5, cur_tls->len);
+ break;
+ case 8:
+ certificate_get(pmeinfo, cur_tls->buff + 5, cur_tls->len);
+ break;
+ default:
+ break;
+ }
+ }
+ memset(cur_tls, 0, sizeof(*cur_tls));
+ }
+ }
+ return 0;
+}
+
+
+
+int packet_need_filter(struct pkt_parsed_info *pktinfo){
+ struct iphdr *_iphdr = pktinfo->iphdr.v4;
+ //int ttl = _iphdr->ttl;
+ // if(ttl == 70 || ttl == 75){
+ // //printf("packet_need_filter: ret = 1, ttl = %d\n", ttl);
+ // return 1;
+ // }
+ int data_len = pktinfo->data_len;
+ if(data_len == 0){
+ //printf("packet_need_filter: ret 1, data_len = %d\n", data_len);
+ return 1;
+ }
+ return 0;
+}
+
+char pending_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ //printf("call pending_opstate\n");
+ g_stream_total++;
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ struct stream_tuple4_v4 *tuple4 = stream->addr.tuple4_v4;
+ inet_ntop(AF_INET, &(tuple4->saddr), pmeinfo->sip, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(tuple4->daddr), pmeinfo->dip, INET_ADDRSTRLEN);
+ pmeinfo->sport = ntohs(tuple4->source);
+ pmeinfo->dport = ntohs(tuple4->dest);
+ if(packet_need_filter(pktinfo) == 1){
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+ }
+ int ret = chello_packet_parse(pmeinfo, pktinfo);
+ if(ret < 0){
+ pmeinfo->_errno = -1;
+ return APP_STATE_FAWPKT | APP_STATE_DROPME;
+ }
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+}
+
+char data_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ if(packet_need_filter(pktinfo) == 0){
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ }
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+}
+
+void time_tostring(struct timeval tv, char *buf, int buflen){
+ char tmbuf[64];
+ time_t nowtime;
+ struct tm *nowtm;
+ nowtime = tv.tv_sec;
+ //printf("nowtime = %lld\n", nowtime);
+ nowtm = localtime(&nowtime);
+ strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm);
+ snprintf(buf, buflen, "%s.%06ld", tmbuf, tv.tv_usec);
+ return;
+}
+
+void print_tls_message(struct tls_filtered_message *message, const char *name){
+ int len = message->buff_len;
+ printf("%s: len = %d, data = \n", name, len);
+ for(int i = 0; i < len; i++){
+ printf("%02x ", message->buff[i]);
+ }
+ printf("\n");
+}
+
+void cjson_add_tls_message(cJSON *log_obj, struct tls_filtered_message *message, const char *tls_message_name){
+ //print_tls_message(message, tls_message_name);
+ unsigned char out_buff[TLS_MESSAGE_LEN_MAX];
+ int out_len = b64_encode((const unsigned char*)message->buff, message->buff_len, out_buff);
+ if(out_len > 0){
+ cJSON *tls_message = cJSON_CreateObject();
+ cJSON_AddNumberToObject(tls_message, "len", out_len);
+ cJSON_AddStringToObject(tls_message, "data", (char*)out_buff);
+ cJSON_AddItemToObject(log_obj, tls_message_name, tls_message);
+ }
+ return;
+}
+
+void output_result(struct pme_info *pmeinfo){
+ if(pmeinfo->has_fin_rst == 0){
+ printf("not have fin or rst\n");
+ g_stream_no_fin++;
+ return;
+ }
+ cJSON *log_obj = cJSON_CreateObject();
+ cJSON_AddStringToObject(log_obj, "sip", pmeinfo->sip);
+ cJSON_AddNumberToObject(log_obj, "sport", pmeinfo->sport);
+ cJSON_AddStringToObject(log_obj, "dip", pmeinfo->dip);
+ cJSON_AddNumberToObject(log_obj, "dport", pmeinfo->dport);
+ cJSON_AddStringToObject(log_obj, "proto", "tcp");
+ // cjson_add_tls_message(log_obj, &(pmeinfo->message_client_hello), "client_hello");
+ // cjson_add_tls_message(log_obj, &(pmeinfo->message_client_hello_no_extensions), "client_hello_no_extensions");
+ // cjson_add_tls_message(log_obj, &(pmeinfo->message_server_hello), "server_hello");
+ // cjson_add_tls_message(log_obj, &(pmeinfo->message_server_hello_no_extensions), "server_hello_no_extensions");
+ //cjson_add_tls_message(log_obj, &(pmeinfo->message_certificate), "certificate");
+ //cjson_add_tls_message(log_obj, &(pmeinfo->message_certificate_no_serial), "certificate_no_serial");
+ cjson_add_tls_message(log_obj, &(pmeinfo->message_serial_number), "serial_number");
+ cjson_add_tls_message(log_obj, &(pmeinfo->message_subject), "subject");
+ cjson_add_tls_message(log_obj, &(pmeinfo->message_raw_client_hello), "raw_client_hello");
+ cjson_add_tls_message(log_obj, &(pmeinfo->message_raw_server_hello), "raw_server_hello");
+ cjson_add_tls_message(log_obj, &(pmeinfo->message_raw_certificate), "raw_certificate");
+
+ char *log_msg = cJSON_PrintUnformatted(log_obj);
+ g_stream_output++;
+ //printf("%s\n\n", log_msg);
+ fputs(log_msg, g_fp);
+ fputs("\n", g_fp);
+ cJSON_Delete(log_obj);
+ cJSON_free(log_msg);
+}
+
+char close_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo, const void *a_packet){
+ if(a_packet != NULL){
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ if(packet_need_filter(pktinfo) == 0){
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ }
+ }
+ return APP_STATE_FAWPKT | APP_STATE_DROPME;
+}
+
+void pme_info_destroy(struct pme_info *pmeinfo){
+ FREE(&pmeinfo);
+ pmeinfo = NULL;
+}
+
+extern "C" char sslparse_entry(struct streaminfo *stream, void** pme, int thread_seq, const void* a_packet){
+ //printf("call sslparse_entry\n");
+ char ret;
+ struct pme_info *pmeinfo = *(struct pme_info **)pme;
+ //printf("pmeinfo = %p, opstate = %d, a_packet = %p\n", pmeinfo, stream->opstate, a_packet);
+ if(a_packet == NULL && stream->opstate != OP_STATE_CLOSE){
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+ }
+ struct pkt_parsed_info pktinfo;
+ memset(&pktinfo, 0, sizeof(pktinfo));
+ ipv4_header_parse(a_packet, &pktinfo);
+ switch(stream->opstate){
+ case OP_STATE_PENDING:
+ //printf("call pending\n");
+ g_pending++;
+ pmeinfo = ALLOC(struct pme_info, 1);
+ *pme = pmeinfo;
+ ret = pending_opstate(stream, pmeinfo, &pktinfo);
+ break;
+ case OP_STATE_DATA:
+ //printf("call data\n");
+ ret = data_opstate(stream, pmeinfo, &pktinfo);
+ break;
+ case OP_STATE_CLOSE:
+ //printf("call close\n");
+ g_close++;
+ ret = close_opstate(stream, pmeinfo, &pktinfo, a_packet);
+ break;
+ default:
+ break;
+ }
+ if((ret & APP_STATE_DROPME)){
+ if(pmeinfo->_errno >= 0){
+ output_result(pmeinfo);
+ }
+ else{
+ g_stream_error++;
+ }
+ pme_info_destroy(pmeinfo);
+ LOG_ERROR(g_logger, "g_pending = %d, g_close = %d, g_stream_total = %d,"
+ "g_stream_output = %d, g_stream_no_fin = %d, g_stream_error = %d\n",
+ g_pending, g_close, g_stream_total, g_stream_output, g_stream_no_fin, g_stream_error);
+ }
+ return ret;
+}
+
+extern "C" int sslparse_init(){
+ char *log_path = (char*)"./ssl_parse_stat.log";
+ int log_level = 10;
+ g_logger = MESA_create_runtime_log_handle(log_path, log_level);
+ g_fp = fopen("./ssl_parse_stat.txt", "a+");
+ return 0;
+}
+
+extern "C" void sslparse_destroy(){
+
+}
diff --git a/entry/src/sslstat_entry.cpp b/entry/src/sslstat_entry.cpp
new file mode 100644
index 0000000..70b4323
--- /dev/null
+++ b/entry/src/sslstat_entry.cpp
@@ -0,0 +1,131 @@
+
+
+
+#include "base_utils.h"
+#include "stream_inc/stream_base.h"
+#include "stream_inc/stream_entry.h"
+#include "ssl.h"
+#include "cjson/cJSON.h"
+
+#define CERT_COUNT_MAX 16
+
+struct ssl_context{
+ char sip[INET_ADDRSTRLEN];
+ int sport;
+ char dip[INET_ADDRSTRLEN];
+ int dport;
+ unsigned char *sni;
+ char *san;
+ int cert_count;
+ cert_chain_t certs[CERT_COUNT_MAX];
+};
+
+FILE *g_fp = NULL;
+
+static char *ssl_assemble_san(st_cert_t *cert){
+ int tmp_buflen = 0, total_buflen = 0;
+ char *san_buf = NULL;
+ for (int i = 0; i < cert->SSLSubAltName->count; i++){
+ tmp_buflen = strlen(cert->SSLSubAltName->san_array[i].san);
+ san_buf = (char *)realloc(san_buf, total_buflen + tmp_buflen + 1);
+ san_buf[total_buflen + tmp_buflen] = ';';
+ memcpy(san_buf + total_buflen, cert->SSLSubAltName->san_array[i].san, tmp_buflen);
+ total_buflen += tmp_buflen + 1;
+ }
+ san_buf[total_buflen - 1] = '\0';
+ return san_buf;
+}
+
+void ssl_ctx_close(struct ssl_context *ctx, struct streaminfo *stream, ssl_stream *a_ssl){
+ if (ctx != NULL){
+ cJSON *log_obj = cJSON_CreateObject();
+ cJSON_AddStringToObject(log_obj, "sip", ctx->sip);
+ cJSON_AddNumberToObject(log_obj, "sport", ctx->sport);
+ cJSON_AddStringToObject(log_obj, "dip", ctx->dip);
+ cJSON_AddNumberToObject(log_obj, "dport", ctx->dport);
+ cJSON_AddStringToObject(log_obj, "proto", "tcp");
+ cJSON_AddStringToObject(log_obj, "sni", (const char*)ctx->sni);
+ cJSON_AddStringToObject(log_obj, "san", ctx->san);
+ //cert
+ cJSON *Cert = cJSON_CreateObject();
+ cJSON_AddNumberToObject(Cert, "cert_count", ctx->cert_count);
+ cJSON *cert_info_list = cJSON_CreateArray();
+ for(int i = 0; i < ctx->cert_count; i++){
+ cJSON *cert_info = cJSON_CreateObject();
+ cJSON_AddNumberToObject(cert_info, "length", ctx->certs[i].cert_len);
+ if(i == 0){
+ cJSON_AddStringToObject(cert_info, "type", "individual");
+ }
+ else{
+ cJSON_AddStringToObject(cert_info, "type", "no-individual");
+ }
+ cJSON_AddItemToArray(cert_info_list, cert_info);
+ }
+ cJSON_AddItemToObject(Cert, "cert_list", cert_info_list);
+ cJSON_AddItemToObject(log_obj, "Cert", Cert);
+ char *log_msg = cJSON_PrintUnformatted(log_obj);
+ fputs(log_msg, g_fp);
+ fputs("\n", g_fp);
+ cJSON_Delete(log_obj);
+ cJSON_free(log_msg);
+ FREE(&(ctx->san))
+ FREE(&ctx);
+ }
+ return;
+}
+
+extern "C" unsigned char sslstat_entry(stSessionInfo *session_info, void **param, int thread_seq, struct streaminfo *stream, void *a_packet){
+ ssl_stream *a_ssl = (ssl_stream *)(session_info->app_info);
+ struct ssl_context *ctx = (ssl_context *)*param;
+ if ((session_info->session_state & SESSION_STATE_PENDING) == SESSION_STATE_PENDING){
+ ctx = ALLOC(struct ssl_context, 1);
+ *param = ctx;
+ struct stream_tuple4_v4 *tuple4 = stream->addr.tuple4_v4;
+ inet_ntop(AF_INET, &(tuple4->saddr), ctx->sip, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(tuple4->daddr), ctx->dip, INET_ADDRSTRLEN);
+ ctx->sport = ntohs(tuple4->source);
+ ctx->dport = ntohs(tuple4->dest);
+ }
+ switch (session_info->prot_flag){
+ case SSL_CLIENT_HELLO:
+ if (a_ssl != NULL && a_ssl->stClientHello != NULL){
+ ctx->sni = a_ssl->stClientHello->server_name;
+ }
+ break;
+ case SSL_CERTIFICATE:
+ ctx->cert_count = ssl_read_all_cert((const char*)session_info->buf, session_info->buflen, ctx->certs, CERT_COUNT_MAX);
+ case SSL_CERTIFICATE_DETAIL:
+ if (a_ssl != NULL && a_ssl->stSSLCert != NULL && stream->curdir == DIR_S2C){
+ st_cert_t *cert = a_ssl->stSSLCert;
+ if (cert->cert_type == CERT_TYPE_INDIVIDUAL){
+ if (cert->SSLSubAltName != NULL && cert->SSLSubAltName->count > 0){
+ char *san_buf = ssl_assemble_san(cert);
+ ctx->san = san_buf;
+ }
+ }
+ }
+ break;
+ case SSL_APPLICATION_DATA:
+ break;
+ default:
+ break;
+ }
+
+ if ((session_info->session_state & SESSION_STATE_CLOSE) == SESSION_STATE_CLOSE){
+
+//close_ssl:
+ ssl_ctx_close(ctx, stream, (ssl_stream *)session_info->app_info);
+ return PROT_STATE_DROPME;
+ }
+ return PROT_STATE_GIVEME;
+}
+
+
+extern "C" int sslstat_init(){
+ g_fp = fopen("./ssl_stat.txt", "a+");
+ return 0;
+}
+
+extern "C" void sslstat_destroy(void){
+ return;
+} \ No newline at end of file
diff --git a/entry/src/stmstat_entry.cpp b/entry/src/stmstat_entry.cpp
new file mode 100644
index 0000000..2708e67
--- /dev/null
+++ b/entry/src/stmstat_entry.cpp
@@ -0,0 +1,530 @@
+
+#include "base_utils.h"
+#include "ssl_utils.h"
+#include "MESA/stream_inc/stream_base.h"
+#include "MESA/stream_inc/stream_rawpkt.h"
+#include "cjson/cJSON.h"
+#define STREAM_PACKET_COUNT_MAX 10000
+
+/*
+{
+ "sip": "0.0.0.0", // IP source address
+ "dip": "255.255.255.255", // IP destination address
+ "proto": 17, // IP protocol number (17 = UDP)
+ "sport": 68, // UDP source port "dp":
+ "dport": 67, // UDP destination port
+ "c2s_bytes": 900, // c to s bytes
+ "c2s__pkts": 3, // packets sent from c to s
+ "s2c_bytes": 900, // s to c bytes
+ "s2c__pkts": 3, // packets sent from s to c
+ "duration": 456, // 456 ms
+ "packets": [
+ {
+ "byte": 300, // bytes in UDP Data field
+ "dir": "c2s", // direction: sa -> da
+ "interval": 0 // inter-packet time: 0 ms since time_start
+ }, ...
+ ],
+ "tls":{
+ "ssl_version": "tls1.3",
+ "cipher_suite": [...],
+ "sni" : "www.baidu.com",
+ "alpn" : "http2",
+ "extensions": [...]
+ }
+}
+*/
+
+void *g_logger = NULL;
+FILE *g_fp = NULL;
+int g_count = 0;
+int g_stream_count = 0;
+int g_stream_succ_count = 0;
+int g_stream_fail_count = 0;
+int g_log_succ_count = 0;
+int g_exceed_max_pkts_count = 0;
+
+struct tls_message_type{
+ int message_type;
+ int content_type;
+ int handshake_type;
+ const char *name;
+};
+
+struct tls_message_type g_tls_types[] = {
+ {0, 22, 0, "hello_request_RESERVED"},
+ {1, 22, 1, "client_hello"},
+ {2, 22, 2, "server_hello"},
+ {3, 22, 3, "hello_verify_request_RESERVED"},
+ {4, 22, 4, "new_session_ticket"},
+ {5, 22, 5, "end_of_early_data"},
+ {6, 22, 6, "hello_retry_request_RESERVED"},
+ {7, 22, 8, "encrypted_extensions"},
+ {8, 22, 11, "certificate"},
+ {9, 22, 12, "server_key_exchange_RESERVED"},
+ {10, 22, 13, "certificate_request"},
+ {11, 22, 14, "server_hello_done_RESERVED"},
+ {12, 22, 15, "certificate_verify"},
+ {13, 22, 16, "client_key_exchange_RESERVED"},
+ {14, 22, 20, "finished"},
+ {15, 22, 21, "certificate_url_RESERVED"},
+ {16, 22, 22, "certificate_status_RESERVED"},
+ {17, 22, 23, "supplemental_data_RESERVED"},
+ {18, 22, 24, "key_update"},
+ {19, 22, 25, "compressed_certificate"},
+ {20, 22, 254, "message_hash"},
+ {21, 20, 0, "change_cipher_spec"},
+ {22, 21, 0, "alert"},
+ {23, 23, 0, "application_data"},
+ {24, 24, 0, "heartbeat"},
+ {25, 25, 0, "tls12_cid"},
+ {26, 22, -1, "handshake_unknown"},
+};
+
+struct pkt_stat_info{
+ struct timeval pkt_time;
+ int bytes;
+ int dir;
+ int interval;
+};
+
+struct pkt_parsed_info{
+ addr_type_t addr_type;
+ union{
+ struct iphdr *v4;
+ struct ip6_hdr *v6;
+ }iphdr;
+ uint16_t iphdr_len;
+ uint16_t ip_totlen;
+ struct tcphdr *tcphdr;
+ uint16_t tcphdr_len;
+ char *data;
+ uint16_t data_len;
+};
+
+struct tls_message_info{
+ int dir;
+ int type;
+ int length;
+};
+
+struct pme_info{
+ int _errno;
+ char sip[INET_ADDRSTRLEN];
+ int sport;
+ char dip[INET_ADDRSTRLEN];
+ int dport;
+ int c2s_bytes;
+ int s2c_bytes;
+ int c2s_pkts;
+ int s2c_pkts;
+ int total_pkts;
+ int duration;
+ struct timeval start_time;
+ struct timeval end_time;
+ int last_c2s_pkt_index;
+ int last_s2c_pkt_index;
+ struct pkt_stat_info pkt_info_list[STREAM_PACKET_COUNT_MAX];
+ struct ssl_chello chello;
+ int tls_message_count;
+ struct tls_message_info tls_info_list[STREAM_PACKET_COUNT_MAX];
+ unsigned char c2s_tls_payload[1500];
+ int c2s_tls_last_segment_len;
+ int c2s_tls_current_segment_offset;
+ unsigned char s2c_tls_payload[1500];
+ int s2c_tls_last_segment_len;
+ int s2c_tls_current_segment_offset;
+ int has_fin_rst;
+};
+
+int ipv4_header_parse(const void *a_packet, struct pkt_parsed_info* pktinfo){
+ if(a_packet == NULL){
+ return -1;
+ }
+ pktinfo->addr_type = ADDR_TYPE_IPV4;
+ pktinfo->iphdr.v4 = (struct iphdr*)a_packet;
+ pktinfo->iphdr_len = pktinfo->iphdr.v4->ihl * 4;
+ pktinfo->ip_totlen = ntohs(pktinfo->iphdr.v4->tot_len);
+ pktinfo->tcphdr = (struct tcphdr*)((char*)pktinfo->iphdr.v4 + pktinfo->iphdr_len);
+ pktinfo->tcphdr_len = pktinfo->tcphdr->doff * 4;
+ pktinfo->data = (char*)pktinfo->tcphdr + pktinfo->tcphdr_len;
+ pktinfo->data_len = pktinfo->ip_totlen - pktinfo->iphdr_len - pktinfo->tcphdr_len;
+ /*
+ struct iphdr *_iphdr = pktinfo->iphdr.v4;
+ int ttl = _iphdr->ttl;
+ int ipid = ntohs(_iphdr->id);
+ printf("ipv4: ipid = %02x, ttl = %d, data_len = %d\n", ipid, ttl, pktinfo->data_len);
+ */
+ return 0;
+}
+
+int packet_stat(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info* pktinfo){
+ if(pmeinfo->total_pkts == STREAM_PACKET_COUNT_MAX){
+ LOG_INFO(g_logger, "packet nums > STREAM_PACKET_COUNT_MAX(%d)\n", STREAM_PACKET_COUNT_MAX);
+ g_exceed_max_pkts_count++;
+ return -1;
+ }
+ pmeinfo->pkt_info_list[pmeinfo->total_pkts].bytes = pktinfo->data_len;
+ pmeinfo->pkt_info_list[pmeinfo->total_pkts].dir = stream->curdir;
+ get_rawpkt_opt_from_streaminfo(stream, RAW_PKT_GET_TIMESTAMP, &(pmeinfo->pkt_info_list[pmeinfo->total_pkts].pkt_time));
+ int last_pkt_index = -1;
+ if(stream->curdir == 1){
+ pmeinfo->c2s_pkts++;
+ pmeinfo->c2s_bytes += pktinfo->data_len;
+ last_pkt_index = pmeinfo->last_c2s_pkt_index;
+ pmeinfo->last_c2s_pkt_index = pmeinfo->total_pkts;
+ }
+ if(stream->curdir == 2){
+ pmeinfo->s2c_pkts++;
+ pmeinfo->s2c_bytes += pktinfo->data_len;
+ last_pkt_index = pmeinfo->last_s2c_pkt_index;
+ pmeinfo->last_s2c_pkt_index = pmeinfo->total_pkts;
+ }
+ if(last_pkt_index >= 0){
+ pmeinfo->pkt_info_list[pmeinfo->total_pkts].interval =
+ (pmeinfo->pkt_info_list[pmeinfo->total_pkts].pkt_time.tv_sec - pmeinfo->pkt_info_list[last_pkt_index].pkt_time.tv_sec) * 1000 +
+ (pmeinfo->pkt_info_list[pmeinfo->total_pkts].pkt_time.tv_usec - pmeinfo->pkt_info_list[last_pkt_index].pkt_time.tv_usec) / 1000;
+ }
+ pmeinfo->total_pkts++;
+ return 0;
+}
+
+int chello_packet_parse(struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ enum chello_parse_result chello_status = CHELLO_PARSE_INVALID_FORMAT;
+ char *buff = pktinfo->data;
+ int len = pktinfo->data_len;
+ ssl_chello_parse(&(pmeinfo->chello), (const unsigned char*)buff, len, &chello_status);
+ if(chello_status != CHELLO_PARSE_SUCCESS){
+ LOG_ERROR(g_logger, "Error: chello parse failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+int get_tls_message_type(int content_type, int handshake_type){
+ int type_count = sizeof(g_tls_types) / sizeof(struct tls_message_type);
+ for(int i = 0; i < type_count; i++){
+ if(g_tls_types[i].content_type == content_type && g_tls_types[i].handshake_type == handshake_type){
+ return i;
+ }
+ }
+ if(content_type == 22){
+ return type_count - 1;
+ }
+ return -1;
+}
+
+int tls_header_parse(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ int curdir = stream->curdir;
+ unsigned char *buff = NULL;
+ int len = 0;
+ if(curdir == 1){
+ if(pmeinfo->c2s_tls_current_segment_offset >= pktinfo->data_len){
+ pmeinfo->c2s_tls_current_segment_offset -= pktinfo->data_len;
+ return 0;
+ }
+ memcpy((char*)pmeinfo->c2s_tls_payload + pmeinfo->c2s_tls_last_segment_len,
+ pktinfo->data + pmeinfo->c2s_tls_current_segment_offset, pktinfo->data_len - pmeinfo->c2s_tls_current_segment_offset);
+ buff = pmeinfo->c2s_tls_payload;
+ len = pktinfo->data_len + pmeinfo->c2s_tls_last_segment_len - pmeinfo->c2s_tls_current_segment_offset;
+ }
+ if(curdir == 2){
+ if(pmeinfo->s2c_tls_current_segment_offset >= pktinfo->data_len){
+ pmeinfo->s2c_tls_current_segment_offset -= pktinfo->data_len;
+ return 0;
+ }
+ memcpy((char*)pmeinfo->s2c_tls_payload + pmeinfo->s2c_tls_last_segment_len,
+ pktinfo->data + pmeinfo->s2c_tls_current_segment_offset, pktinfo->data_len - pmeinfo->s2c_tls_current_segment_offset);
+ buff = pmeinfo->s2c_tls_payload;
+ len = pktinfo->data_len + pmeinfo->s2c_tls_last_segment_len - pmeinfo->s2c_tls_current_segment_offset;
+ }
+ int i = 0;
+ int flag = 0;
+ while(i < len){
+ if(i + 4 >= len){
+ flag = 1;
+ break;
+ }
+ int content_type = buff[i];
+ int handshake_type = 0;
+ if(buff[i] == 0x16){
+ if(i + 5 >= len){
+ flag = 1;
+ break;
+ }
+ handshake_type = buff[i + 5];
+ }
+ int message_type = get_tls_message_type(content_type, handshake_type);
+ if(message_type < 0){
+ LOG_ERROR(g_logger, "message_type unknown, value = %02x %02x %02x %02x %02x\n", buff[i], buff[i + 1], buff[i + 2], buff[i + 3], buff[i + 4]);
+ flag = 2;
+ break;
+ }
+ int version = (uint16_t)(buff[i + 1] << 8) + (uint8_t)buff[i + 2];
+ if(version < 0x0300 || version > 0x0304){
+ LOG_ERROR(g_logger, "version unknown, value = %02x %02x\n", buff[i + 1], buff[i + 2]);
+ flag = 2;
+ break;
+ }
+ int len = (uint16_t)(buff[i + 3] << 8) + (uint8_t)buff[i + 4];
+ pmeinfo->tls_info_list[pmeinfo->tls_message_count].dir = stream->curdir;
+ pmeinfo->tls_info_list[pmeinfo->tls_message_count].type = message_type;
+ pmeinfo->tls_info_list[pmeinfo->tls_message_count].length = len;
+ pmeinfo->tls_message_count++;
+ i += (5 + len);
+ }
+ if(flag == 1){
+ if(curdir == 1){
+ memcpy((char*)pmeinfo->c2s_tls_payload, pktinfo->data, len - i);
+ pmeinfo->c2s_tls_last_segment_len = len - i;
+ pmeinfo->c2s_tls_current_segment_offset = 0;
+ }
+ if(curdir == 2){
+ memcpy((char*)pmeinfo->s2c_tls_payload, pktinfo->data, len - i);
+ pmeinfo->s2c_tls_last_segment_len = len - i;
+ pmeinfo->s2c_tls_current_segment_offset = 0;
+ }
+ return -1;
+ }
+ if(flag == 2){
+ if(curdir == 1){
+ pmeinfo->c2s_tls_last_segment_len = 0;
+ pmeinfo->c2s_tls_current_segment_offset = 0;
+ }
+ if(curdir == 2){
+ pmeinfo->s2c_tls_last_segment_len = 0;
+ pmeinfo->s2c_tls_current_segment_offset = 0;
+ }
+ return -2;
+ }
+ if(curdir == 1){
+ pmeinfo->c2s_tls_last_segment_len = 0;
+ pmeinfo->c2s_tls_current_segment_offset = i - len;
+ }
+ if(curdir == 2){
+ pmeinfo->s2c_tls_last_segment_len = 0;
+ pmeinfo->s2c_tls_current_segment_offset = i - len;
+ }
+ return 0;
+}
+
+int packet_need_filter(struct pkt_parsed_info *pktinfo){
+ struct iphdr *_iphdr = pktinfo->iphdr.v4;
+ int ttl = _iphdr->ttl;
+ if(ttl == 70 || ttl == 75){
+ //printf("packet_need_filter: ret = 1, ttl = %d\n", ttl);
+ return 1;
+ }
+ int data_len = pktinfo->data_len;
+ if(data_len == 0){
+ //printf("packet_need_filter: ret 1, data_len = %d\n", data_len);
+ return 1;
+ }
+ return 0;
+}
+
+char pending_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ pmeinfo->last_c2s_pkt_index = -1;
+ pmeinfo->last_s2c_pkt_index = -1;
+ get_rawpkt_opt_from_streaminfo(stream, RAW_PKT_GET_TIMESTAMP, &(pmeinfo->start_time));
+ get_rawpkt_opt_from_streaminfo(stream, RAW_PKT_GET_TIMESTAMP, &(pmeinfo->end_time));
+ struct stream_tuple4_v4 *tuple4 = stream->addr.tuple4_v4;
+ inet_ntop(AF_INET, &(tuple4->saddr), pmeinfo->sip, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(tuple4->daddr), pmeinfo->dip, INET_ADDRSTRLEN);
+ pmeinfo->sport = ntohs(tuple4->source);
+ pmeinfo->dport = ntohs(tuple4->dest);
+ if(packet_need_filter(pktinfo) == 1){
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+ }
+ int ret = chello_packet_parse(pmeinfo, pktinfo);
+ if(ret < 0){
+ pmeinfo->_errno = -1;
+ return APP_STATE_FAWPKT | APP_STATE_DROPME;
+ }
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ packet_stat(stream, pmeinfo, pktinfo);
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+}
+
+char data_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo){
+ get_rawpkt_opt_from_streaminfo(stream, RAW_PKT_GET_TIMESTAMP, &(pmeinfo->end_time));
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ if(packet_need_filter(pktinfo) == 0){
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ int ret = packet_stat(stream, pmeinfo, pktinfo);
+ if(ret == -1){
+ return APP_STATE_FAWPKT | APP_STATE_DROPME;
+ }
+ }
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+}
+
+void time_tostring(struct timeval tv, char *buf, int buflen){
+ char tmbuf[64];
+ time_t nowtime;
+ struct tm *nowtm;
+ nowtime = tv.tv_sec;
+ //printf("nowtime = %lld\n", nowtime);
+ nowtm = localtime(&nowtime);
+ strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm);
+ snprintf(buf, buflen, "%s.%06ld", tmbuf, tv.tv_usec);
+ return;
+}
+
+void output_result(struct pme_info *pmeinfo){
+ if(pmeinfo->has_fin_rst == 0){
+ return;
+ }
+ cJSON *log_obj = cJSON_CreateObject();
+ cJSON_AddStringToObject(log_obj, "sip", pmeinfo->sip);
+ cJSON_AddNumberToObject(log_obj, "sport", pmeinfo->sport);
+ cJSON_AddStringToObject(log_obj, "dip", pmeinfo->dip);
+ cJSON_AddNumberToObject(log_obj, "dport", pmeinfo->dport);
+ cJSON_AddStringToObject(log_obj, "proto", "tcp");
+ cJSON_AddNumberToObject(log_obj, "c2s_bytes", pmeinfo->c2s_bytes);
+ cJSON_AddNumberToObject(log_obj, "s2c_bytes", pmeinfo->s2c_bytes);
+ cJSON_AddNumberToObject(log_obj, "c2s_pkts", pmeinfo->c2s_pkts);
+ cJSON_AddNumberToObject(log_obj, "s2c_pkts", pmeinfo->s2c_pkts);
+ cJSON_AddNumberToObject(log_obj, "total_pkts", pmeinfo->total_pkts);
+ char time_str[64] = {};
+ time_tostring(pmeinfo->start_time, time_str, sizeof(time_str));
+ cJSON_AddStringToObject(log_obj, "start_time", time_str);
+ time_tostring(pmeinfo->end_time, time_str, sizeof(time_str));
+ cJSON_AddStringToObject(log_obj, "end_time", time_str);
+ pmeinfo->duration = (pmeinfo->end_time.tv_sec - pmeinfo->start_time.tv_sec) * 1000 + (pmeinfo->end_time.tv_usec - pmeinfo->start_time.tv_usec) / 1000;
+ cJSON_AddNumberToObject(log_obj, "duration", pmeinfo->duration);
+ cJSON *pkt_info_list = cJSON_CreateArray();
+ for(int i = 0; i < pmeinfo->total_pkts; i++){
+ cJSON *pkt_info = cJSON_CreateObject();
+ cJSON_AddNumberToObject(pkt_info, "bytes", pmeinfo->pkt_info_list[i].bytes);
+ cJSON_AddNumberToObject(pkt_info, "dir", pmeinfo->pkt_info_list[i].dir);
+ cJSON_AddNumberToObject(pkt_info, "interval", pmeinfo->pkt_info_list[i].interval);
+ time_tostring(pmeinfo->pkt_info_list[i].pkt_time, time_str, sizeof(time_str));
+ cJSON_AddStringToObject(pkt_info, "pkt_time", time_str);
+ cJSON_AddItemToArray(pkt_info_list, pkt_info);
+ }
+ cJSON_AddItemToObject(log_obj, "packets", pkt_info_list);
+ cJSON *tls_info = cJSON_CreateObject();
+ cJSON_AddStringToObject(tls_info, "version", pmeinfo->chello.max_version.str_format);
+ cJSON_AddStringToObject(tls_info, "sni", pmeinfo->chello.sni);
+ cJSON_AddStringToObject(tls_info, "alpn", pmeinfo->chello.alpn);
+ cJSON *cipher_suite_list = cJSON_CreateArray();
+ for(int i = 0; i < pmeinfo->chello.cipher_suites_count; i++){
+ char cipher_suite_str[4] = {0};
+ sprintf(cipher_suite_str, "%04x", pmeinfo->chello.cipher_suite_list[i]);
+ cJSON_AddItemToArray(cipher_suite_list, cJSON_CreateString(cipher_suite_str));
+ }
+ cJSON_AddItemToObject(tls_info, "cipher_suites", cipher_suite_list);
+ cJSON *extensions_list = cJSON_CreateArray();
+ for(int i = 0; i < pmeinfo->chello.extension_count; i++){
+ cJSON_AddItemToArray(extensions_list, cJSON_CreateNumber(pmeinfo->chello.extension_list[i]));
+ }
+ cJSON_AddItemToObject(tls_info, "extensions_list", extensions_list);
+ cJSON_AddItemToObject(log_obj, "tls", tls_info);
+
+ cJSON *tls_message_list = cJSON_CreateArray();
+ cJSON_AddItemToObject(tls_info, "tls_message_list", tls_message_list);
+ for(int i = 0; i < pmeinfo->tls_message_count; i++){
+ cJSON *tls_message = cJSON_CreateObject();
+ cJSON_AddNumberToObject(tls_message, "dir", pmeinfo->tls_info_list[i].dir);
+ cJSON_AddNumberToObject(tls_message, "type", pmeinfo->tls_info_list[i].type);
+ cJSON_AddNumberToObject(tls_message, "length", pmeinfo->tls_info_list[i].length);
+ cJSON_AddItemToArray(tls_message_list, tls_message);
+ }
+
+ char *log_msg = cJSON_PrintUnformatted(log_obj);
+ //printf("%s\n\n", log_msg);
+ LOG_INFO(g_logger, log_msg);
+ fputs(log_msg, g_fp);
+ fputs("\n", g_fp);
+ g_log_succ_count++;
+ cJSON_Delete(log_obj);
+ cJSON_free(log_msg);
+}
+
+char close_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_parsed_info *pktinfo, const void *a_packet){
+ if(a_packet != NULL){
+ get_rawpkt_opt_from_streaminfo(stream, RAW_PKT_GET_TIMESTAMP, &(pmeinfo->end_time));
+ struct tcphdr *_tcphdr = pktinfo->tcphdr;
+ if(_tcphdr->fin || _tcphdr->rst){
+ pmeinfo->has_fin_rst = 1;
+ }
+ if(packet_need_filter(pktinfo) == 0){
+ tls_header_parse(stream, pmeinfo, pktinfo);
+ packet_stat(stream, pmeinfo, pktinfo);
+ }
+ }
+ return APP_STATE_FAWPKT | APP_STATE_DROPME;
+}
+
+void pme_info_destroy(struct pme_info *pmeinfo){
+ FREE(&pmeinfo);
+ pmeinfo = NULL;
+}
+
+extern "C" char stmstat_entry(struct streaminfo *stream, void** pme, int thread_seq, const void* a_packet){
+ if(g_count % 10 == 5){
+ LOG_DEBUG(g_logger, "handle %d packets\n", g_count);
+ LOG_DEBUG(g_logger, "stream_count: %d\nsucc_count: %d\nfail_count: %d\ng_log_succ_count: %d, g_exceed_max_pkts_count: %d\n",
+ g_stream_count, g_stream_succ_count, g_stream_fail_count, g_log_succ_count, g_exceed_max_pkts_count);
+ }
+ g_count++;
+ char ret;
+ struct pme_info *pmeinfo = *(struct pme_info **)pme;
+ //printf("pmeinfo = %p, opstate = %d, a_packet = %p\n", pmeinfo, stream->opstate, a_packet);
+ if(a_packet == NULL && stream->opstate != OP_STATE_CLOSE){
+ return APP_STATE_FAWPKT | APP_STATE_GIVEME;
+ }
+ struct pkt_parsed_info pktinfo;
+ memset(&pktinfo, 0, sizeof(pktinfo));
+ ipv4_header_parse(a_packet, &pktinfo);
+ switch(stream->opstate){
+ case OP_STATE_PENDING:
+ //printf("call pending\n");
+ pmeinfo = ALLOC(struct pme_info, 1);
+ *pme = pmeinfo;
+ g_stream_count++;
+ ret = pending_opstate(stream, pmeinfo, &pktinfo);
+ break;
+ case OP_STATE_DATA:
+ //printf("call data\n");
+ ret = data_opstate(stream, pmeinfo, &pktinfo);
+ break;
+ case OP_STATE_CLOSE:
+ //printf("call close\n");
+ ret = close_opstate(stream, pmeinfo, &pktinfo, a_packet);
+ break;
+ default:
+ break;
+ }
+ if((ret & APP_STATE_DROPME)){
+ if(pmeinfo->_errno >= 0){
+ g_stream_succ_count++;
+ output_result(pmeinfo);
+ }
+ else{
+ g_stream_fail_count++;
+ }
+ pme_info_destroy(pmeinfo);
+ }
+ return ret;
+}
+
+extern "C" int stmstat_init(){
+ char *log_path = (char*)"./stream_stat.log";
+ int log_level = 10;
+ g_logger = MESA_create_runtime_log_handle(log_path, log_level);
+ g_fp = fopen("./stream_stat.txt", "a+");
+ return 0;
+}
+
+extern "C" void stmstat_destroy(){
+ printf("stream_count: %d\nsucc_count: %d\nfail_count: %d\n", g_stream_count, g_stream_succ_count, g_stream_fail_count);
+}