diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..35bfaa1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.5) +project(kni) + +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_C_STANDARD 11) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set (CMAKE_CXX_FLAGS "-Wall") +#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lasan -fsanitize-recover=address -fsanitize=address -fno-omit-frame-pointer") + +add_definitions(-D_GNU_SOURCE) + +if (CMAKE_BUILD_TYPE STREQUAL Debug) + add_definitions(-DDEBUG) +endif() + +add_subdirectory(vendor) +add_subdirectory(entry) + +# cmake -DCMAKE_BUILD_TYPE=Debug/RelWithDebInfo \ No newline at end of file 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include + +#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< +#include + +//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>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>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 +#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); +} diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt new file mode 100644 index 0000000..c9290a8 --- /dev/null +++ b/vendor/CMakeLists.txt @@ -0,0 +1,83 @@ +# CMakeFiles for 3rd vendor library + +include(ExternalProject) + + + +include(ExternalProject) + +### OpenSSL 1.1.1 +ExternalProject_Add(OpenSSL PREFIX openssl + URL ${CMAKE_CURRENT_SOURCE_DIR}/openssl-1.1.1.tar.gz + URL_MD5 d65944e4aa4de6ad9858e02c82d85183 + CONFIGURE_COMMAND ./Configure enable-ssl3 enable-ssl3-method enable-weak-ssl-ciphers linux-x86_64 --prefix= --openssldir=/lib/ssl + enable-ec_nistp_64_gcc_128 no-shared + BUILD_COMMAND ${MAKE_COMMAND} + INSTALL_COMMAND make install_sw + BUILD_IN_SOURCE 1) + +ExternalProject_Get_Property(OpenSSL INSTALL_DIR) +set(OPENSSL_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) +set(OPENSSL_LINK_DIRECTORIES ${INSTALL_DIR}/lib) +set(OPENSSL_PKGCONFIG_PATH ${INSTALL_DIR}/lib/pkgconfig/) +file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + +add_library(openssl-crypto-static STATIC IMPORTED GLOBAL) +add_dependencies(openssl-crypto-static OpenSSL) +set_property(TARGET openssl-crypto-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libcrypto.a) +set_property(TARGET openssl-crypto-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + +add_library(openssl-ssl-static STATIC IMPORTED GLOBAL) +add_dependencies(openssl-ssl-static OpenSSL) +set_property(TARGET openssl-ssl-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libssl.a) +set_property(TARGET openssl-ssl-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + + +### cJSON: 娉ㄦ剰: -DCMAKE_POSITION_INDEPENDENT_CODE=ON +ExternalProject_Add(cJSON PREFIX cJSON + URL ${CMAKE_CURRENT_SOURCE_DIR}/cJSON-1.7.7.tar.gz + URL_MD5 715009c99728bf81d6c97352718650ff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DBUILD_SHARED_AND_STATIC_LIBS=1) + +ExternalProject_Get_Property(cJSON INSTALL_DIR) +file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + +add_library(cjson SHARED IMPORTED GLOBAL) +add_dependencies(cjson cJSON) +set_property(TARGET cjson PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib64/libcjson.a) +set_property(TARGET cjson PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + +### MESA Framework +set(MESA_FRAMEWORK_LIB_DIR /opt/MESA/lib) +set(MESA_FRAMEWORK_INCLUDE_DIR /opt/MESA/include) + +add_library(MESA_handle_logger SHARED IMPORTED GLOBAL) +set_property(TARGET MESA_handle_logger PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_handle_logger.so) +set_property(TARGET MESA_handle_logger PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(MESA_prof_load SHARED IMPORTED GLOBAL) +set_property(TARGET MESA_prof_load PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_prof_load.so) +set_property(TARGET MESA_prof_load PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(wiredcfg SHARED IMPORTED GLOBAL) +set_property(TARGET wiredcfg PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libwiredcfg.so) +set_property(TARGET wiredcfg PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(MESA_htable SHARED IMPORTED GLOBAL) +set_property(TARGET MESA_htable PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_htable.so) +set_property(TARGET MESA_htable PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(maatframe SHARED IMPORTED GLOBAL) +set_property(TARGET maatframe PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libmaatframe.so) +set_property(TARGET maatframe PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(MESA_field_stat SHARED IMPORTED GLOBAL) +set_property(TARGET MESA_field_stat PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_field_stat2.so) +set_property(TARGET MESA_field_stat PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) + +add_library(rdkafka SHARED IMPORTED GLOBAL) +set_property(TARGET rdkafka PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/librdkafka.so) +set_property(TARGET rdkafka PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR}) \ No newline at end of file diff --git a/vendor/cJSON-1.7.7.tar.gz b/vendor/cJSON-1.7.7.tar.gz new file mode 100644 index 0000000..c2350cf Binary files /dev/null and b/vendor/cJSON-1.7.7.tar.gz differ diff --git a/vendor/openssl-1.1.1.tar.gz b/vendor/openssl-1.1.1.tar.gz new file mode 100644 index 0000000..ceeca12 Binary files /dev/null and b/vendor/openssl-1.1.1.tar.gz differ