diff options
| author | zhuzhenjun <[email protected]> | 2023-10-09 15:23:31 +0800 |
|---|---|---|
| committer | zhuzhenjun <[email protected]> | 2023-10-09 15:23:59 +0800 |
| commit | 56e3dec5f0a4980ca5f1f0b311a43f4bb8ae2e81 (patch) | |
| tree | 629aa94f57969e2942688c3ca7f77bd44ed7bdf1 /src | |
| parent | 1a559eba9916e4e39f660cf803ab7196cdd7c342 (diff) | |
v0.0.5
Diffstat (limited to 'src')
| -rw-r--r-- | src/osfp.c | 71 | ||||
| -rw-r--r-- | src/osfp.h | 108 | ||||
| -rw-r--r-- | src/osfp_common.h | 14 | ||||
| -rw-r--r-- | src/osfp_fingerprint.c | 173 | ||||
| -rw-r--r-- | src/osfp_fingerprint.h | 17 | ||||
| -rw-r--r-- | src/osfp_score_db.c | 94 | ||||
| -rw-r--r-- | src/osfp_score_db.h | 5 |
7 files changed, 389 insertions, 93 deletions
@@ -33,24 +33,18 @@ static struct osfp_result *osfp_result_build(struct osfp_os_class_score *os_clas likely_score = tmp_score; likely_os_class = i; } - result->detail.scores[i] = tmp_score; + result->details[i].score = tmp_score; sum_score += tmp_score; } if (sum_score) { for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { - result->detail.possibility[i] = OSFP_PERCENTILE * result->detail.scores[i] / sum_score; + result->details[i].possibility = OSFP_PERCENTILE * result->details[i].score / sum_score; } } - result->likely_score = likely_score; - result->likely_os_class = likely_os_class; - result->likely_possibility = result->detail.possibility[likely_os_class]; - if (likely_score < OSFP_LOWEST_SCORE_LIMIT) { - result->likely_os_class = OSFP_OS_CLASS_OTHERS; - result->likely_score = 0; - result->likely_possibility = 0; + likely_os_class = OSFP_OS_CLASS_OTHERS; } else { for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { if (likely_os_class == i) { @@ -62,15 +56,15 @@ static struct osfp_result *osfp_result_build(struct osfp_os_class_score *os_clas } else if (likely_os_class == OSFP_OS_CLASS_MAC_OS && i == OSFP_OS_CLASS_IOS) { continue; } else { - result->likely_os_class = OSFP_OS_CLASS_UNKNOWN; - result->likely_score = 0; - result->likely_possibility = 0; + likely_os_class = OSFP_OS_CLASS_UNKNOWN; break; } } } } + result->likely_os_class = likely_os_class; + return result; exit: return NULL; @@ -95,6 +89,7 @@ const char *osfp_result_os_name_get(struct osfp_result *result) char *osfp_result_score_detail_export(struct osfp_result *result) { int i; + char *result_str = NULL; cJSON *root = NULL; cJSON *array; cJSON *os_score; @@ -104,6 +99,7 @@ char *osfp_result_score_detail_export(struct osfp_result *result) } if (result->json_str != NULL) { + result_str = result->json_str; goto exit; } @@ -115,37 +111,35 @@ char *osfp_result_score_detail_export(struct osfp_result *result) os_score = cJSON_AddObjectToObject(root, "likely"); if (os_score) { cJSON_AddStringToObject(os_score, "name", osfp_os_class_id_to_name(result->likely_os_class)); - cJSON_AddNumberToObject(os_score, "score", result->likely_score); - //cJSON_AddNumberToObject(os_score, "possibility", result->likely_possibility); + cJSON_AddNumberToObject(os_score, "score", result->details[result->likely_os_class].score); + //cJSON_AddNumberToObject(os_score, "possibility", result->details[result->likely_os_class].possibility); } - array = cJSON_AddArrayToObject(root, "detail"); + array = cJSON_AddArrayToObject(root, "details"); if (array) { for (i = OSFP_OS_CLASS_WINDOWS; i < OSFP_OS_CLASS_OTHERS; i++) { os_score = cJSON_CreateObject(); if (os_score) { cJSON_AddStringToObject(os_score, "name", osfp_os_class_id_to_name(i)); - cJSON_AddNumberToObject(os_score, "score", result->detail.scores[i]); - //cJSON_AddNumberToObject(os_score, "possibility", result->detail.possibility[i]); + cJSON_AddNumberToObject(os_score, "score", result->details[i].score); + //cJSON_AddNumberToObject(os_score, "possibility", result->details[i].possibility); cJSON_AddItemToArray(array, os_score); } } } - result->json_str = malloc(OSFP_DEFAULT_RESULT_BUFLEN_MAX); - if (result->json_str == NULL) { + result_str = cJSON_Print(root); + if (result_str == NULL) { goto exit; } - if (!cJSON_PrintPreallocated(root, result->json_str, OSFP_DEFAULT_RESULT_BUFLEN_MAX, 1)) { - goto exit; - } + result->json_str = result_str; exit: if (root) { cJSON_Delete(root); } - return result->json_str; + return result_str; } void osfp_result_free(struct osfp_result *result) @@ -220,6 +214,37 @@ exit: return NULL; } +struct osfp_result *osfp_json_identify(struct osfp_db *db, const char *json_str) +{ + int ret = OSFP_EINVAL; + struct osfp_fingerprint fp; + struct osfp_os_class_score os_class_score; + struct osfp_result *result; + + if (db == NULL) { + goto exit; + } + + ret = osfp_fingerprint_from_json(&fp, json_str); + if (ret != 0) { + goto exit; + } + + ret = osfp_score_db_score(db->score_db, 0, &fp, &os_class_score); + if (ret != 0) { + goto exit; + } + + result = osfp_result_build(&os_class_score); + if (result == NULL) { + goto exit; + } + + return result; +exit: + return NULL; +} + struct osfp_db *osfp_db_new(const char *db_json_file) { int ret; @@ -8,6 +8,9 @@ #include <linux/ipv6.h> #include <linux/tcp.h> +/** + * @brief 定义操作系统类别的名称常量。 + */ #define OSFP_OS_CLASS_NAME_UNKNOWN "Unknown" #define OSFP_OS_CLASS_NAME_WINDOWS "Windows" #define OSFP_OS_CLASS_NAME_LINUX "Linux" @@ -16,45 +19,112 @@ #define OSFP_OS_CLASS_NAME_ANDROID "Android" #define OSFP_OS_CLASS_NAME_OTHERS "Others" +/** + * @brief 枚举表示不同的操作系统类别。 + */ enum osfp_os_class_id { - OSFP_OS_CLASS_UNKNOWN, - OSFP_OS_CLASS_WINDOWS, - OSFP_OS_CLASS_LINUX, - OSFP_OS_CLASS_MAC_OS, - OSFP_OS_CLASS_IOS, - OSFP_OS_CLASS_ANDROID, - OSFP_OS_CLASS_OTHERS, + OSFP_OS_CLASS_UNKNOWN, // 未知 + OSFP_OS_CLASS_WINDOWS, // Windows + OSFP_OS_CLASS_LINUX, // Linux + OSFP_OS_CLASS_MAC_OS, // Mac OS + OSFP_OS_CLASS_IOS, // iOS + OSFP_OS_CLASS_ANDROID, // Android + OSFP_OS_CLASS_OTHERS, // 其他 OSFP_OS_CLASS_MAX, }; -struct osfp_os_result_detail { - unsigned int scores[OSFP_OS_CLASS_MAX]; - unsigned int possibility[OSFP_OS_CLASS_MAX]; +/** + * @brief 结构体用于 osfp_result 中的详细结果。 + */ +struct osfp_result_detail { + unsigned int score; // 得分 + unsigned int possibility; // 可能性 }; +/** + * @brief 结构体用于表示操作系统识别结果。 + */ struct osfp_result { - char *json_str; - - enum osfp_os_class_id likely_os_class; - unsigned int likely_score; - unsigned int likely_possibility; - - struct osfp_os_result_detail detail; + char *json_str; // JSON 字符串 + enum osfp_os_class_id likely_os_class; // 最可能的操作系统类别 + struct osfp_result_detail details[OSFP_OS_CLASS_MAX]; // 详细结果数组 }; +/** + * @brief 结构体用于表示操作系统指纹库。 + */ struct osfp_db { - char *db_json_path; - void *score_db; + char *db_json_path; // 操作系统指纹库 JSON 文件路径 + void *score_db; // 分数数据库指针 }; +/** + * @brief 创建一个新的操作系统指纹库。 + * + * @param db_json_path 操作系统指纹库 JSON 文件的路径。 + * @return 指向新创建的操作系统指纹库的指针。 + */ struct osfp_db *osfp_db_new(const char *db_json_path); + +/** + * @brief 释放操作系统指纹库占用的内存。 + * + * @param db 指向要释放的操作系统指纹库的指针。 + */ void osfp_db_free(struct osfp_db *db); +/** + * @brief 通过 IPv4 头部和 TCP 头部识别操作系统。 + * + * @param db 操作系统指纹库。 + * @param l3_hdr 指向 IPv4 头部的指针。 + * @param l4_hdr 指向 TCP 头部的指针。 + * @param l4_hdr_len TCP 头部的长度(注意:包含TCP选项部分)。 + * @return 指向操作系统识别结果的指针。 + */ struct osfp_result *osfp_ipv4_identify(struct osfp_db *db, struct iphdr* l3_hdr, struct tcphdr *l4_hdr, size_t l4_hdr_len); + +/** + * @brief 通过 IPv6 头部和 TCP 头部识别操作系统。 + * + * @param db 操作系统指纹库。 + * @param l3_hdr 指向 IPv6 头部的指针。 + * @param l4_hdr 指向 TCP 头部的指针。 + * @param l4_hdr_len TCP 头部的长度(注意:包含TCP选项部分)。 + * @return 指向操作系统识别结果的指针(注意:内存需要使用者释放)。 + */ struct osfp_result *osfp_ipv6_identify(struct osfp_db *db, struct ipv6hdr* l3_hdr, struct tcphdr *l4_hdr, size_t l4_hdr_len); +/** + * @brief 通过 json 格式的指纹识别操作系统。 + * + * @param db 操作系统指纹库。 + * @param json_str 指纹字符串。 + * @return 指向操作系统识别结果的指针(注意:内存需要使用者释放)。 + */ +struct osfp_result *osfp_json_identify(struct osfp_db *db, const char *json_str); + +/** + * @brief 获取操作系统识别结果的操作系统名称。 + * + * @param result 操作系统识别结果。 + * @return 指向操作系统名称的常量字符指针(注意:这块内存将由osfp_result_free释放)。 + */ const char *osfp_result_os_name_get(struct osfp_result *result); + +/** + * @brief 导出操作系统识别结果的得分详情。 + * + * @param result 操作系统识别结果。 + * @return 指向得分详情字符串的指针(注意:内存需要使用者释放)。 + */ char *osfp_result_score_detail_export(struct osfp_result *result); + +/** + * @brief 释放操作系统识别结果占用的内存。 + * + * @param result 操作系统识别结果。 + */ void osfp_result_free(struct osfp_result *result); #endif diff --git a/src/osfp_common.h b/src/osfp_common.h index 5d1d7bf..12d84a1 100644 --- a/src/osfp_common.h +++ b/src/osfp_common.h @@ -84,20 +84,6 @@ #define OSFP_TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */ #define OSFP_TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */ - -#define OSFP_WRITE_STRING_TO_BUF(ret, buf, size, off, ...) do { \ - ret = snprintf((char *)buf + off, \ - size - off, \ - __VA_ARGS__); \ - if (ret >= 0) { \ - if ( (off + ret) >= size) { \ - off = size - 1; \ - } else { \ - off += ret; \ - } \ - } \ - } while (0) - static inline unsigned long long osfp_rdtsc(void) { union { diff --git a/src/osfp_fingerprint.c b/src/osfp_fingerprint.c index 8efb6ae..a4551d9 100644 --- a/src/osfp_fingerprint.c +++ b/src/osfp_fingerprint.c @@ -40,7 +40,7 @@ struct osfp_fingerprint_field fp_fields[OSFP_FIELD_MAX] = { {OSFP_FINGERPRINT_FIELD_NAME_TCP_FLAGS, 1, OSFP_FIELD_TYPE_UINT, 25, NULL, 0}, {OSFP_FINGERPRINT_FIELD_NAME_TCP_MSS, 1, OSFP_FIELD_TYPE_UINT, 150, NULL, 0}, {OSFP_FINGERPRINT_FIELD_NAME_TCP_OPTIONS, 1, OSFP_FIELD_TYPE_STRING, 400, NULL, 0}, - {OSFP_FINGERPRINT_FIELD_NAME_TCP_OPTIONS_ORDERED, 1, OSFP_FIELD_TYPE_STRING, 250, NULL, 0}, + {OSFP_FINGERPRINT_FIELD_NAME_TCP_OPTIONS_ORDERED, 0, OSFP_FIELD_TYPE_STRING, 250, NULL, 0}, {OSFP_FINGERPRINT_FIELD_NAME_OS, 0, OSFP_FIELD_TYPE_STRING, 0, NULL, 0}, }; @@ -134,6 +134,8 @@ int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsi return 0; } + strbuf[0] = 0; + root = cJSON_CreateObject(); if (root == NULL) { return 0; @@ -165,6 +167,61 @@ int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsi return strlen(strbuf) + 1; } +int osfp_fingerprint_from_json(struct osfp_fingerprint *fp, char *json_str) +{ + int ret, i; + cJSON *root; + cJSON *field; + + void *value_ptr; + unsigned int value_len; + + if (fp == NULL || json_str == NULL) { + goto exit; + } + + memset(fp, 0, sizeof(struct osfp_fingerprint)); + + root = cJSON_Parse(json_str); + if (root == NULL) { + osfp_log_error("parse json: '%s'\n", json_str); + goto exit; + } + + for (i = 0; i < OSFP_FIELD_OS; i++) { + if (!fp_fields[i].enabled) { + continue; + } + + field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(i)); + if (field == NULL) { + goto exit; + } + + switch (field->type) { + case cJSON_Number: + value_ptr = (void *)&field->valueint; + value_len = sizeof(field->valueint); + osfp_fingerprint_setup_field(fp, i, value_ptr, value_len); + break; + case cJSON_String: + value_ptr = (void *)field->valuestring; + value_len = strlen(field->valuestring) + 1; + osfp_fingerprint_setup_field(fp, i, value_ptr, value_len); + break; + case cJSON_NULL: + //printf("fingerprint parse error: %s\n%s\n", field->string, cJSON_Print(root)); + break; + default: + goto exit; + } + } + + return 0; +exit: + return ret; +} + unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id) { return fp_fields[field_id].enabled; @@ -175,7 +232,7 @@ unsigned int osfp_fingerprint_get_field_importance(enum osfp_field_id field_id) return fp_fields[field_id].importance; } -char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id) +const char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id) { return fp_fields[field_id].name; } @@ -201,7 +258,7 @@ void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_i } } -void osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_len, struct osfp_fingerprint *fp) +int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_len, struct osfp_fingerprint *fp) { int ret,i; @@ -218,6 +275,10 @@ void osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_le unsigned int ordered_offset = 0; unsigned int ordered_maxoffset = sizeof(options_ordered) - 1; + if (opt_data == NULL || opt_len == 0 || fp == NULL) { + goto exit; + } + tcp_opt_cnt = decode_tcp_options(tcp_opts, OSFP_TCP_OPTMAX, opt_data, opt_len); for (i = 0; i < tcp_opt_cnt && offset < maxoffset && ordered_offset < ordered_maxoffset; i++) { @@ -290,7 +351,9 @@ void osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_le osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS, options, strlen(options) + 1); osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED, options_ordered, strlen(options_ordered) + 1); - return; + return 0; +exit: + return -1; } int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp) @@ -406,27 +469,27 @@ exit: } #ifdef UNITTEST -int test_osfp_fingerprinting(void) +int test_osfp_fingerprinting_ipv4(void) { int ret; char iph[] = { - 0x45, 0x00, 0x00, 0x34, 0x51, 0xc4, 0x40, 0x00, - 0x80, 0x06, 0xe7, 0x27, 0xc0, 0xa8, 0x73, 0x08, - 0x6a, 0xb9, 0x23, 0x6e + 0x45, 0x00, 0x00, 0x34, 0x51, 0xc4, 0x40, 0x00, + 0x80, 0x06, 0xe7, 0x27, 0xc0, 0xa8, 0x73, 0x08, + 0x6a, 0xb9, 0x23, 0x6e }; char tcph[] = { - 0xc1, 0xbd, 0x00, 0x50, 0x3d, 0x58, 0x51, 0x60, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 0x00, - 0x3d, 0x3a, 0x00, 0x00, 0x02, 0x04, 0x04, 0xec, - 0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02 + 0xc1, 0xbd, 0x00, 0x50, 0x3d, 0x58, 0x51, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 0x00, + 0x3d, 0x3a, 0x00, 0x00, 0x02, 0x04, 0x04, 0xec, + 0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02 }; char str_buf[2048] = ""; - const char *target_buf = "{\"ip_id\":1,\"ip_tos\":0,\"ip_total_length\":52,\"ip_ttl\":128,\"tcp_off\":32,\"tcp_timestamp\":null,\"tcp_timestamp_echo_reply\":null,\"tcp_window_scaling\":8,\"tcp_window_size\":8192,\"tcp_flags\":2,\"tcp_mss\":1260,\"tcp_options\":\"M1260,N,W8,N,N,S,\",\"tcp_options_ordered\":\"MNWNNS\",\"os\":\"OSFP_UNKNOWN\"}"; + const char *target = "{\"ip_id\":1,\"ip_tos\":0,\"ip_total_length\":52,\"ip_ttl\":128,\"tcp_off\":32,\"tcp_timestamp\":null,\"tcp_timestamp_echo_reply\":null,\"tcp_window_scaling\":8,\"tcp_window_size\":8192,\"tcp_flags\":2,\"tcp_mss\":1260,\"tcp_options\":\"M1260,N,W8,N,N,S,\",\"tcp_options_ordered\":\"MNWNNS\",\"os\":\"OSFP_UNKNOWN\"}"; struct osfp_fingerprint fp = {0}; - ret = osfp_fingerprinting(iph, tcph, &fp); + ret = osfp_fingerprinting(iph, tcph, 32, &fp, 4); if (ret != 0) { goto exit; } @@ -436,7 +499,87 @@ int test_osfp_fingerprinting(void) goto exit; } - if (0 != memcmp(str_buf, target_buf, strlen(target_buf))) { + if (0 != memcmp(str_buf, target, strlen(target))) { + goto exit; + } + + return 0; +exit: + return ret; +} + +int test_osfp_fingerprinting_ipv6(void) +{ + int ret; + char iph[] = { + 0x45, 0x00, 0x00, 0x34, 0x51, 0xc4, 0x40, 0x00, + 0x80, 0x06, 0xe7, 0x27, 0xc0, 0xa8, 0x73, 0x08, + 0x6a, 0xb9, 0x23, 0x6e + }; + + char tcph[] = { + 0xc1, 0xbd, 0x00, 0x50, 0x3d, 0x58, 0x51, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 0x00, + 0x3d, 0x3a, 0x00, 0x00, 0x02, 0x04, 0x04, 0xec, + 0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02 + }; + + char str_buf[2048] = ""; + const char *target = "{\"ip_id\":1,\"ip_tos\":0,\"ip_total_length\":52,\"ip_ttl\":128,\"tcp_off\":32,\"tcp_timestamp\":null,\"tcp_timestamp_echo_reply\":null,\"tcp_window_scaling\":8,\"tcp_window_size\":8192,\"tcp_flags\":2,\"tcp_mss\":1260,\"tcp_options\":\"M1260,N,W8,N,N,S,\",\"tcp_options_ordered\":\"MNWNNS\",\"os\":\"OSFP_UNKNOWN\"}"; + struct osfp_fingerprint fp = {0}; + + ret = osfp_fingerprinting(iph, tcph, 32, &fp, 4); + if (ret != 0) { + goto exit; + } + + ret = osfp_fingerprint_to_json_buf(&fp, str_buf, 2048, 0); + if (ret <= 0) { + goto exit; + } + + if (0 != memcmp(str_buf, target, strlen(target))) { + goto exit; + } + + return 0; +exit: + return ret; +} + +int test_osfp_fingerprinting_tcp_option(void) +{ + int ret; + char tcp_opt[] = { + 0x02, 0x04, 0x04, 0xec,0x01, 0x03, 0x03, 0x08, + 0x01, 0x01, 0x04, 0x02 + }; + + char str_buf[2048] = ""; + const char *target_options = "M1260,N,W8,N,N,S,"; + const char *target_options_ordered = "MNWNNS"; + + struct osfp_fingerprint fp = {0}; + + ret = osfp_fingerprinting_tcp_option((unsigned char *)tcp_opt, 12, &fp); + if (ret != 0) { + goto exit; + } + + if (fp.fields[OSFP_FIELD_TCP_OPTIONS].value_len != strlen(target_options) + 1) + { + goto exit; + } + + if (0 != memcmp(fp.fields[OSFP_FIELD_TCP_OPTIONS].value, target_options, strlen(target_options) + 1)) { + goto exit; + } + + if (fp.fields[OSFP_FIELD_TCP_OPTIONS_ORDERED].value_len != strlen(target_options_ordered) + 1) { + goto exit; + } + + if (0 != memcmp(fp.fields[OSFP_FIELD_TCP_OPTIONS_ORDERED].value, target_options_ordered, strlen(target_options_ordered) + 1)) { goto exit; } diff --git a/src/osfp_fingerprint.h b/src/osfp_fingerprint.h index b8838c0..d7c39c8 100644 --- a/src/osfp_fingerprint.h +++ b/src/osfp_fingerprint.h @@ -29,7 +29,7 @@ enum osfp_field_type { }; struct osfp_fingerprint_field { - char *name; + const char *name; unsigned int enabled; unsigned int type; unsigned int importance; @@ -43,21 +43,24 @@ struct osfp_fingerprint { unsigned int value_buffer_used; }; -char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id); +int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format); + +void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len); + +const char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id); unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id); unsigned int osfp_fingerprint_get_field_importance(enum osfp_field_id field_id); unsigned int osfp_fingerprint_get_field_type(enum osfp_field_id field_id); -int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format); -void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len); - -void osfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, struct osfp_fingerprint *fp); +int osfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, struct osfp_fingerprint *fp); int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp); int osfp_fingerprinting_ipv4(struct iphdr *iph, struct osfp_fingerprint *fp); int osfp_fingerprinting_ipv6(struct ipv6hdr *iph, struct osfp_fingerprint *fp); int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version); #ifdef UNITTEST -int test_osfp_fingerprinting(void); +int test_osfp_fingerprinting_ipv4(void); +int test_osfp_fingerprinting_ipv6(void); +int test_osfp_fingerprinting_tcp_option(void); #endif #endif diff --git a/src/osfp_score_db.c b/src/osfp_score_db.c index c5f5d1f..2e38cde 100644 --- a/src/osfp_score_db.c +++ b/src/osfp_score_db.c @@ -192,15 +192,6 @@ void osfp_score_db_hash_destroy(void *data) { } } -struct osfp_os_class_score *osfp_score_db_filed_match(struct osfp_field_score_db *db, void *value, unsigned int len) -{ - if (db == NULL || value == NULL || len == 0) { - return NULL; - } - - return db->match(db->data, value, len); -} - char *osfp_score_db_read_file(char *fp_file) { int ret = -1; @@ -343,7 +334,7 @@ exit: int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file) { - int ret = OSFP_EINVAL, i; + int ret = OSFP_EINVAL, i, count; char *file_buffer; cJSON *root = NULL; cJSON *entry; @@ -367,9 +358,9 @@ int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file) goto exit; } - score_db->entry_count = cJSON_GetArraySize(root); + count = cJSON_GetArraySize(root); - for (i = 0; i < score_db->entry_count; i++) { + for (i = 0; i < count; i++) { entry = cJSON_GetArrayItem(root, i); if (entry) { ret = osfp_score_db_load_entry(score_db, entry); @@ -377,7 +368,7 @@ int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file) osfp_log_debug("json entry load failed.\n%s\n", cJSON_Print(entry)); continue; } - } + } } for (i = 0; i < OSFP_FIELD_MAX; i++) { @@ -437,7 +428,7 @@ int osfp_score_db_score(struct osfp_score_db *score_db, unsigned int flags, stru continue; } - os_class_score_matched = osfp_score_db_filed_match(field_score_db, field->value, field->value_len); + os_class_score_matched = field_score_db->match(field_score_db->data, field->value, field->value_len); if (os_class_score_matched == NULL) { continue; } @@ -482,7 +473,6 @@ void osfp_score_db_debug_print(struct osfp_score_db *score_db) printf("field %s enabled: %u\n", osfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].enabled); printf("field %s type: %u\n", osfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].type); printf("field %s entry_count: %u\n", osfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].entry_count); - printf("field %s enabled: %u\n", osfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].data); } } @@ -556,3 +546,77 @@ void osfp_score_db_destroy(struct osfp_score_db *score_db) free(score_db); } } + +#ifdef UNITTEST +int test_osfp_score_db(void) +{ + int ret, i; + struct osfp_score_db *db; + const char *test_file_path = "./.fp.json"; + const char *fingerprint_file_content = "[" + " {" + " \"tcp_options\": \"M1432,S,T,N,W9,\"," + " \"tcp_options_ordered\": \"MSTNW\"," + " \"ip_total_length\": 60," + " \"tcp_off\": 10," + " \"tcp_window_scaling\": 9," + " \"tcp_window_size\": 65535," + " \"ip_ttl\": 64," + " \"ip_id\": 1," + " \"tcp_timestamp\": 1," + " \"tcp_timestamp_echo_reply\": 0," + " \"tcp_mss\": 1432," + " \"tcp_flags\": 2," + " \"ip_tos\": 0," + " \"os\": \"Android\"" + " }" + "]"; + + db = (void *)osfp_score_db_create(); + if (db == NULL) { + goto exit; + } + + FILE *fingerprint_file_ptr = fopen(test_file_path, "w"); + if (fingerprint_file_ptr == NULL) { + goto exit; + } + + fprintf(fingerprint_file_ptr, "%s", fingerprint_file_content); + fflush(fingerprint_file_ptr); + fclose(fingerprint_file_ptr); + + ret = osfp_score_db_load(db, (char *)test_file_path); + remove(test_file_path); + if (ret != 0) { + goto exit; + } + + if (db->entry_count != 1) { + goto exit; + } + + if (db->os_class_entry_count[OSFP_OS_CLASS_ANDROID] != 1) { + goto exit; + } + + for (i = 0; i < OSFP_FIELD_MAX; i++) { + if (db->field_score_dbs[i].enabled != osfp_fingerprint_get_field_enabled(i)) { + goto exit; + } + if (db->field_score_dbs[i].enabled && db->field_score_dbs[i].type != osfp_fingerprint_get_field_type(i)) { + goto exit; + } + if (db->field_score_dbs[i].enabled && db->field_score_dbs[i].entry_count != 1) { + goto exit; + } + } + + osfp_score_db_destroy(db); + + return 0; +exit: + return -1; +} + +#endif diff --git a/src/osfp_score_db.h b/src/osfp_score_db.h index cd72467..71b4704 100644 --- a/src/osfp_score_db.h +++ b/src/osfp_score_db.h @@ -28,6 +28,7 @@ struct osfp_score_db { struct osfp_field_score_db field_score_dbs[OSFP_FIELD_MAX]; }; +char *osfp_score_db_read_file(char *fp_file); void osfp_score_db_debug_print(struct osfp_score_db *score_db); int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file); @@ -36,4 +37,8 @@ int osfp_score_db_score(struct osfp_score_db *score_db, unsigned int flags, stru struct osfp_score_db *osfp_score_db_create(void); void osfp_score_db_destroy(struct osfp_score_db *score_db); +#ifdef UNITTEST +int test_osfp_score_db(void); +#endif + #endif |
