diff --git a/src/osfp.c b/src/osfp.c index e822436..5b933c5 100644 --- a/src/osfp.c +++ b/src/osfp.c @@ -43,7 +43,9 @@ static struct osfp_result *osfp_result_build(struct osfp_os_class_score *os_clas } } - if (likely_score < OSFP_LOWEST_SCORE_LIMIT) { + if (likely_score == OSFP_PERCENTILE) { + ; + } else if (likely_score < OSFP_LOWEST_SCORE_LIMIT) { likely_os_class = OSFP_OS_CLASS_OTHERS; } else { for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { @@ -183,11 +185,17 @@ struct osfp_result *osfp_ipv4_identify(struct osfp_db *db, struct iphdr* l3_hdr, } osfp_profile_get_cycle(c1); - ret = osfp_score_db_score(db->score_db, 0, &fp, &os_class_score); + ret = osfp_score_db_prefilter(db->score_db, &fp, &os_class_score); osfp_profile_get_cycle(c2); - osfp_profile_counter_update(&osfp_profile_score, c2 - c1); - if (ret != 0) { - goto exit; + osfp_profile_counter_update(&osfp_profile_prefilter, c2 - c1); + if (ret <= 0) { + osfp_profile_get_cycle(c1); + ret = osfp_score_db_score(db->score_db, 0, &fp, &os_class_score); + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&osfp_profile_score, c2 - c1); + if (ret != 0) { + goto exit; + } } osfp_profile_get_cycle(c1); @@ -250,9 +258,12 @@ struct osfp_result *osfp_json_identify(struct osfp_db *db, const char *json_str) goto exit; } - ret = osfp_score_db_score(db->score_db, 0, &fp, &os_class_score); - if (ret != 0) { - goto exit; + ret = osfp_score_db_prefilter(db->score_db, &fp, &os_class_score); + if (ret <= 0) { + 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); diff --git a/src/osfp_common.c b/src/osfp_common.c index bf7680e..914bf1d 100644 --- a/src/osfp_common.c +++ b/src/osfp_common.c @@ -15,6 +15,7 @@ const char *osfp_os_class_name[OSFP_OS_CLASS_MAX] = { }; struct osfp_profile_counter osfp_profile_fingerprinting; +struct osfp_profile_counter osfp_profile_prefilter; struct osfp_profile_counter osfp_profile_score; struct osfp_profile_counter osfp_profile_result_build; struct osfp_profile_counter osfp_profile_result_export; diff --git a/src/osfp_common.h b/src/osfp_common.h index 810e7bc..ac7b404 100644 --- a/src/osfp_common.h +++ b/src/osfp_common.h @@ -59,6 +59,7 @@ struct osfp_profile_counter { }; extern struct osfp_profile_counter osfp_profile_fingerprinting; +extern struct osfp_profile_counter osfp_profile_prefilter; extern struct osfp_profile_counter osfp_profile_score; extern struct osfp_profile_counter osfp_profile_result_build; extern struct osfp_profile_counter osfp_profile_result_export; diff --git a/src/osfp_fingerprint.c b/src/osfp_fingerprint.c index 05dc52e..1d28109 100644 --- a/src/osfp_fingerprint.c +++ b/src/osfp_fingerprint.c @@ -21,6 +21,27 @@ #define OSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME "OSFP_UNKNOWN" +#define OSFP_FP_SET_FIELD(fp, field_id, v, l) do { \ + (fp)->fields[(field_id)].name = osfp_fingerprint_get_field_name(field_id); \ + (fp)->fields[(field_id)].enabled = 1; \ + if ((fp)->value_buffer_used + (l) <= sizeof((fp)->value_buffer)) { \ + memcpy(fp->value_buffer + (fp)->value_buffer_used, (v), (l)); \ + (fp)->fields[(field_id)].value = (fp)->value_buffer + (fp)->value_buffer_used; \ + (fp)->fields[(field_id)].value_len = (l); \ + (fp)->value_buffer_used += (l); \ + } else { \ + (fp)->fields[(field_id)].value = NULL; \ + (fp)->fields[(field_id)].value_len = 0; \ + } \ + } while (0) + +#define OSFP_FP_INIT_FIELD(fp, field_id) do { \ + (fp)->fields[(field_id)].name = osfp_fingerprint_get_field_name((field_id)); \ + (fp)->fields[(field_id)].enabled = 0; \ + (fp)->fields[(field_id)].value = NULL; \ + (fp)->fields[(field_id)].value_len = 0; \ + } while (0) + struct osfp_tcp_opt { unsigned char type; unsigned char len; @@ -44,7 +65,6 @@ struct osfp_fingerprint_field fp_fields[OSFP_FIELD_MAX] = { {OSFP_FINGERPRINT_FIELD_NAME_OS, 0, OSFP_FIELD_TYPE_STRING, 0, NULL, 0}, }; - static char *osfp_fingerprint_tcp_options_to_ordered(char *tcp_options, unsigned int len) { int i; @@ -78,6 +98,168 @@ exit: return NULL; } +int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format) +{ + int rlen = 0, ret, i; + cJSON *root; + + if (fp == NULL || strbuf == NULL || buf_len == 0) { + return 0; + } + + strbuf[0] = 0; + + root = cJSON_CreateObject(); + if (root == NULL) { + return 0; + } + + for (i = 0; i < OSFP_FIELD_MAX; i++) { + if (fp->fields[i].enabled) { + switch (fp_fields[i].type) { + case OSFP_FIELD_TYPE_UINT: + cJSON_AddNumberToObject(root, fp_fields[i].name, *(unsigned int *)fp->fields[i].value); + break; + case OSFP_FIELD_TYPE_STRING: + cJSON_AddStringToObject(root, fp_fields[i].name, (char *)fp->fields[i].value); + break; + default: + break; + } + } else { + cJSON_AddNullToObject(root, fp_fields[i].name); + } + } + + if (!cJSON_PrintPreallocated(root, strbuf, buf_len, format)) { + return 0; + } + + cJSON_Delete(root); + + return strlen(strbuf) + 1; +} + +struct osfp_fingerprint *osfp_fingerprint_from_cjson(cJSON *root) +{ + int i; + cJSON *field; + void *value_ptr; + unsigned int value_len; + struct osfp_fingerprint *fp; + + if (root == NULL) { + goto exit; + } + + fp = calloc(1, sizeof(struct osfp_fingerprint)); + if (fp == NULL) { + goto exit; + } + + for (i = 0; i < OSFP_FIELD_OS; i++) { + field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(i)); + if (field == NULL) { + OSFP_FP_INIT_FIELD(fp, i); + continue; + } + + switch (field->type) { + case cJSON_Number: + value_ptr = (void *)&field->valueint; + value_len = sizeof(field->valueint); + OSFP_FP_SET_FIELD(fp, i, value_ptr, value_len); + break; + case cJSON_String: + value_ptr = (void *)field->valuestring; + value_len = strlen(field->valuestring) + 1; + OSFP_FP_SET_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; + } + } + + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_OS); + + return fp; +exit: + if (fp) { + free(fp); + } + return NULL; +} + +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; + } + + field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS_ORDERED)); + if (field == NULL) { + field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS)); + if (field) { + char *tcp_options_ordered_str = osfp_fingerprint_tcp_options_to_ordered(field->valuestring, strlen(field->valuestring)); + if (tcp_options_ordered_str) { + cJSON_AddItemToObject(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS_ORDERED), + cJSON_CreateString(tcp_options_ordered_str)); + free(tcp_options_ordered_str); + } + } + } + + for (i = 0; i < OSFP_FIELD_OS; i++) { + 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_FP_SET_FIELD(fp, i, value_ptr, value_len); + break; + case cJSON_String: + value_ptr = (void *)field->valuestring; + value_len = strlen(field->valuestring) + 1; + OSFP_FP_SET_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; + } + } + + ret = 0; +exit: + if (root) { + cJSON_Delete(root); + } + return ret; +} + static char option_to_ascii(unsigned char type) { switch (type) { @@ -122,30 +304,6 @@ static unsigned int compute_ip_ttl(unsigned int ip_ttl) return ip_ttl; } -static void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len) -{ - fp->fields[field_id].name = osfp_fingerprint_get_field_name(field_id); - fp->fields[field_id].enabled = 1; - - if (fp->value_buffer_used + len <= sizeof(fp->value_buffer)) { - memcpy(fp->value_buffer + fp->value_buffer_used, value, len); - fp->fields[field_id].value = fp->value_buffer + fp->value_buffer_used; - fp->fields[field_id].value_len = len; - fp->value_buffer_used += len; - } else { - fp->fields[field_id].value = NULL; - fp->fields[field_id].value_len = 0; - } -} - -static void osfp_fingerprint_init_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id) -{ - fp->fields[field_id].name = osfp_fingerprint_get_field_name(field_id); - fp->fields[field_id].enabled = 0; - fp->fields[field_id].value = NULL; - fp->fields[field_id].value_len = 0; -} - static unsigned int decode_tcp_options(struct osfp_tcp_opt *tcp_opts, unsigned int max_opt_cnt, unsigned char *data, unsigned int len) { unsigned int offset = 0; @@ -222,7 +380,7 @@ static int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int break; } tcp_mss = (unsigned int)ntohs(*(unsigned short *)opt->data); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_MSS, &tcp_mss, sizeof(tcp_mss)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_MSS, &tcp_mss, sizeof(tcp_mss)); ret = snprintf(options + offset, sizeof(options), "%u", tcp_mss); if (ret < 0 || offset + ret > maxoffset) { break; @@ -234,7 +392,7 @@ static int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int break; } tcp_ws = (unsigned int)*(unsigned char *)opt->data; - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SCALING, &tcp_ws, sizeof(tcp_ws)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_WINDOW_SCALING, &tcp_ws, sizeof(tcp_ws)); ret = snprintf(options + offset, sizeof(options), "%u", tcp_ws); if (ret < 0 || offset + ret > maxoffset) { break; @@ -246,7 +404,7 @@ static int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int break; } tcp_ter = ntohl(*(unsigned int *)(opt->data + 4)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY, &tcp_ter, sizeof(tcp_ter)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY, &tcp_ter, sizeof(tcp_ter)); ret = snprintf(options + offset, sizeof(options), "%u", tcp_ter); if (ret < 0 || offset + ret > maxoffset) { break; @@ -273,8 +431,8 @@ static int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int options_ordered[ordered_offset] = 0; } - 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); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_OPTIONS, options, strlen(options) + 1); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED, options_ordered, strlen(options_ordered) + 1); return 0; exit: @@ -299,16 +457,16 @@ static int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, s goto exit; } - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OFF, &tcp_off, sizeof(tcp_off)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SIZE, &tcp_window_size, sizeof(tcp_window_size)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_FLAGS, &tcp_flags, sizeof(tcp_flags)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_OFF, &tcp_off, sizeof(tcp_off)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_WINDOW_SIZE, &tcp_window_size, sizeof(tcp_window_size)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_TCP_FLAGS, &tcp_flags, sizeof(tcp_flags)); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_TIMESTAMP); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_WINDOW_SCALING); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_MSS); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_OPTIONS); - osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_TIMESTAMP); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_WINDOW_SCALING); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_MSS); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_OPTIONS); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED); // tcp options if (tcp_off > OSFP_TCP_HEADER_LEN) { @@ -331,10 +489,10 @@ static int osfp_fingerprinting_ipv4(struct iphdr *iph, struct osfp_fingerprint * unsigned int ip_total_length = ntohs(iph->tot_len); unsigned int ip_ttl = compute_ip_ttl(iph->ttl); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_ID, &ip_id, sizeof(ip_id)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOS, &ip_tos, sizeof(ip_tos)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_ID, &ip_id, sizeof(ip_id)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_TOS, &ip_tos, sizeof(ip_tos)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); return 0; exit: @@ -352,130 +510,17 @@ static int osfp_fingerprinting_ipv6(struct ip6_hdr *iph, struct osfp_fingerprint unsigned int ip_total_length = OSFP_IPV6_HEADER_LEN + ntohs(iph->ip6_ctlun.ip6_un1.ip6_un1_plen); unsigned int ip_ttl = compute_ip_ttl(iph->ip6_ctlun.ip6_un1.ip6_un1_hlim); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); + OSFP_FP_SET_FIELD(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); - osfp_fingerprint_init_field(fp, OSFP_FIELD_IP_ID); - osfp_fingerprint_init_field(fp, OSFP_FIELD_IP_TOS); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_IP_ID); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_IP_TOS); return 0; exit: return -1; } -int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format) -{ - int rlen = 0, ret, i; - cJSON *root; - - if (fp == NULL || strbuf == NULL || buf_len == 0) { - return 0; - } - - strbuf[0] = 0; - - root = cJSON_CreateObject(); - if (root == NULL) { - return 0; - } - - for (i = 0; i < OSFP_FIELD_MAX; i++) { - if (fp->fields[i].enabled) { - switch (fp_fields[i].type) { - case OSFP_FIELD_TYPE_UINT: - cJSON_AddNumberToObject(root, fp_fields[i].name, *(unsigned int *)fp->fields[i].value); - break; - case OSFP_FIELD_TYPE_STRING: - cJSON_AddStringToObject(root, fp_fields[i].name, (char *)fp->fields[i].value); - break; - default: - break; - } - } else { - cJSON_AddNullToObject(root, fp_fields[i].name); - } - } - - if (!cJSON_PrintPreallocated(root, strbuf, buf_len, format)) { - return 0; - } - - cJSON_Delete(root); - - 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; - } - - field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS_ORDERED)); - if (field == NULL) { - field = cJSON_GetObjectItem(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS)); - if (field) { - char *tcp_options_ordered_str = osfp_fingerprint_tcp_options_to_ordered(field->valuestring, strlen(field->valuestring)); - if (tcp_options_ordered_str) { - cJSON_AddItemToObject(root, osfp_fingerprint_get_field_name(OSFP_FIELD_TCP_OPTIONS_ORDERED), - cJSON_CreateString(tcp_options_ordered_str)); - free(tcp_options_ordered_str); - } - } - } - - 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; - } - } - - ret = 0; -exit: - if (root) { - cJSON_Delete(root); - } - return ret; -} - int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version) { int ret = OSFP_EINVAL; @@ -507,7 +552,7 @@ int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tc goto exit; } - osfp_fingerprint_setup_field(fp, OSFP_FIELD_OS, OSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME, strlen(OSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME) + 1); + OSFP_FP_INIT_FIELD(fp, OSFP_FIELD_OS); return 0; exit: @@ -531,7 +576,7 @@ int test_osfp_fingerprinting_ipv4(void) }; 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\"}"; + 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\":null}"; struct osfp_fingerprint fp = {0}; ret = osfp_fingerprinting(iph, tcph, 32, &fp, 4); @@ -571,7 +616,7 @@ int test_osfp_fingerprinting_ipv6(void) }; 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\"}"; + 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\":null}"; struct osfp_fingerprint fp = {0}; ret = osfp_fingerprinting(iph, tcph, 32, &fp, 4); diff --git a/src/osfp_fingerprint.h b/src/osfp_fingerprint.h index 00806ae..f31ed16 100644 --- a/src/osfp_fingerprint.h +++ b/src/osfp_fingerprint.h @@ -65,6 +65,7 @@ static inline unsigned int osfp_fingerprint_get_field_type(enum osfp_field_id fi return fp_fields[field_id].type; } +struct osfp_fingerprint *osfp_fingerprint_from_cjson(cJSON *root); int osfp_fingerprint_from_json(struct osfp_fingerprint *fp, char *json_str); int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format); int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version); diff --git a/src/osfp_score_db.c b/src/osfp_score_db.c index 5598537..6267163 100644 --- a/src/osfp_score_db.c +++ b/src/osfp_score_db.c @@ -251,6 +251,27 @@ static int osfp_score_db_load_entry(struct osfp_score_db *score_db, cJSON *entry goto exit; } + // prefileter + struct osfp_prefilter_hash_element *element = NULL; + struct osfp_fingerprint *fp = osfp_fingerprint_from_cjson(entry); + if (fp == NULL) { + goto exit; + } + HASH_FIND(hh, score_db->prefilter_head, fp->value_buffer, fp->value_buffer_used, element); + if (element == NULL) { + element = (struct osfp_prefilter_hash_element *)calloc(1, sizeof(struct osfp_prefilter_hash_element)); + if (element == NULL) { + free(fp); + goto exit; + } + + element->fp_json = cJSON_Print(entry); + element->fp = fp; + element->os_class = os_class; + HASH_ADD_KEYPTR(hh, score_db->prefilter_head, fp->value_buffer, fp->value_buffer_used, element); + } + + // field score db for (i = 0; i < OSFP_FIELD_OS; i++) { db = &score_db->field_score_dbs[i]; if (db == NULL) { @@ -391,6 +412,26 @@ exit: return ret; } +int osfp_score_db_prefilter(struct osfp_score_db *score_db, struct osfp_fingerprint *fp, struct osfp_os_class_score *result_score) +{ + int ret; + struct osfp_prefilter_hash_element *element = NULL; + + if (score_db->prefilter_head == NULL) { + return 0; + } + + HASH_FIND(hh, score_db->prefilter_head, fp->value_buffer, fp->value_buffer_used, element); + if (element == NULL) { + return 0; + } + + memset(result_score, 0, sizeof(struct osfp_os_class_score)); + result_score->scores[element->os_class] = OSFP_PERCENTILE; + + return 1; +} + int osfp_score_db_score(struct osfp_score_db *score_db, unsigned int flags, struct osfp_fingerprint *fp, struct osfp_os_class_score *result_score) { int ret = OSFP_EINVAL, i, j; @@ -410,6 +451,7 @@ int osfp_score_db_score(struct osfp_score_db *score_db, unsigned int flags, stru goto exit; } + // score memset(result_score, 0, sizeof(struct osfp_os_class_score)); perfect_score = score_db->perfect_score; @@ -539,8 +581,27 @@ void osfp_score_db_destroy(struct osfp_score_db *score_db) { int i; struct osfp_field_score_db *db; + struct osfp_prefilter_hash_element *element = NULL; + struct osfp_prefilter_hash_element *tmp = NULL; if (score_db) { + // prefilter + if (score_db->prefilter_head) { + HASH_ITER(hh, score_db->prefilter_head, element, tmp) { + HASH_DELETE(hh, score_db->prefilter_head, element); + if (element) { + if (element->fp) { + free(element->fp); + } + if (element->fp_json) { + free(element->fp_json); + } + free(element); + } + } + } + + // field score db for (i = 0; i < OSFP_FIELD_MAX; i++) { db = &score_db->field_score_dbs[i]; if (db->destroy && db->data) { diff --git a/src/osfp_score_db.h b/src/osfp_score_db.h index 3ee9a84..b73427d 100644 --- a/src/osfp_score_db.h +++ b/src/osfp_score_db.h @@ -22,8 +22,18 @@ struct osfp_field_score_db { struct osfp_os_class_score *(*match)(void *, void *, unsigned int); }; +struct osfp_prefilter_hash_element { + struct osfp_fingerprint *fp; + char *fp_json; + unsigned int os_class; + UT_hash_handle hh; +}; + struct osfp_score_db { unsigned int entry_count; + + struct osfp_prefilter_hash_element *prefilter_head; + unsigned int perfect_score; unsigned int os_class_entry_count[OSFP_OS_CLASS_MAX]; struct osfp_field_score_db field_score_dbs[OSFP_FIELD_MAX]; @@ -33,6 +43,7 @@ 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); +int osfp_score_db_prefilter(struct osfp_score_db *score_db, struct osfp_fingerprint *fp, struct osfp_os_class_score *result_score); int osfp_score_db_score(struct osfp_score_db *score_db, unsigned int flags, struct osfp_fingerprint *fp, struct osfp_os_class_score *result_score); struct osfp_score_db *osfp_score_db_create(void);