#include "osfp_common.h" #include "osfp.h" #include "osfp_fingerprint.h" #include "osfp_score_db.h" #include "osfp_log.h" #define OSFP_LOWEST_SCORE_LIMIT 20 static struct osfp_result *osfp_result_build(struct osfp_os_class_score *os_class_score, const char *matched) { int i; unsigned int tmp_score; unsigned int likely_score; enum osfp_os_class_id likely_os_class; struct osfp_result *result; result = calloc(1, sizeof(struct osfp_result)); if (result == NULL) { goto exit; } likely_score = 0; likely_os_class = OSFP_OS_CLASS_OTHERS; // likely os score for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { tmp_score = os_class_score->scores[i]; if (likely_score < tmp_score) { likely_score = tmp_score; likely_os_class = i; } result->details[i].score = tmp_score; } if (likely_score == OSFP_PERCENTILE) { // prefiltered ; } else if (likely_score < OSFP_LOWEST_SCORE_LIMIT) { // too low to tell os class likely_os_class = OSFP_OS_CLASS_OTHERS; } else { // when the tied likely scores appear between win/apple-like/unix-like, we throw unknown for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { if (likely_os_class == i) { continue; } if (likely_score == os_class_score->scores[i]) { if (likely_os_class == OSFP_OS_CLASS_LINUX && i == OSFP_OS_CLASS_ANDROID) { continue; } else if (likely_os_class == OSFP_OS_CLASS_MAC_OS && i == OSFP_OS_CLASS_IOS) { continue; } else { likely_os_class = OSFP_OS_CLASS_UNKNOWN; break; } } } } result->likely_os_class = likely_os_class; result->matched = matched; return result; exit: return NULL; } const char *osfp_result_os_name_get(struct osfp_result *result) { enum osfp_os_class_id os_class; if (result == NULL) { return NULL; } os_class = result->likely_os_class; if (os_class < 0 || os_class >= OSFP_OS_CLASS_MAX) { return NULL; } return osfp_os_class_id_to_name(os_class); } char *osfp_result_score_detail_export(struct osfp_result *result) { int i; char *result_str; cJSON *root; cJSON *array; cJSON *os_score; cJSON *matched; osfp_profile_cycle(c1); osfp_profile_cycle(c2); osfp_profile_get_cycle(c1); if (result == NULL) { return NULL; } if (result->json_str != NULL) { return result->json_str; } root = cJSON_CreateObject(); if (root == NULL) { goto exit; } 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->details[result->likely_os_class].score); //cJSON_AddNumberToObject(os_score, "possibility", result->details[result->likely_os_class].possibility); } 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->details[i].score); //cJSON_AddNumberToObject(os_score, "possibility", result->details[i].possibility); cJSON_AddItemToArray(array, os_score); } } } if (result->matched) { matched = cJSON_AddObjectToObject(root, "matched"); if (matched) { cJSON_AddStringToObject(matched, "fingerprint", result->matched); } } result_str = cJSON_Print(root); if (result_str == NULL) { goto exit; } result->json_str = result_str; osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_result_export, c2 - c1); return result_str; exit: if (root) { cJSON_Delete(root); } return NULL; } void osfp_result_free(struct osfp_result *result) { if (result) { if (result->json_str) { free(result->json_str); } free(result); } } struct osfp_result *osfp_ipv4_identify(struct osfp_db *db, struct iphdr* l3_hdr, struct tcphdr *l4_hdr, size_t l4_hdr_len) { int ret; struct osfp_fingerprint fp; struct osfp_os_class_score os_class_score; struct osfp_result *result; const char *matched; osfp_profile_cycle(c1); osfp_profile_cycle(c2); if (db == NULL || l3_hdr == NULL || l4_hdr == NULL || l4_hdr_len == 0) { goto exit; } osfp_profile_get_cycle(c1); ret = osfp_fingerprinting((unsigned char *)l3_hdr, (unsigned char *)l4_hdr, (unsigned int)l4_hdr_len, &fp, 4); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_fingerprinting, c2 - c1); if (ret != 0) { goto exit; } osfp_profile_get_cycle(c1); matched = osfp_score_db_prefilter(db->score_db, &fp, &os_class_score); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_prefilter, c2 - c1); if (matched == NULL) { 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); result = osfp_result_build(&os_class_score, matched); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_result_build, c2 - c1); if (result == NULL) { goto exit; } return result; exit: return NULL; } struct osfp_result *osfp_ipv6_identify(struct osfp_db *db, struct ip6_hdr* l3_hdr, struct tcphdr *l4_hdr, size_t l4_hdr_len) { int ret; struct osfp_fingerprint fp; struct osfp_os_class_score os_class_score; struct osfp_result *result; const char *matched; osfp_profile_cycle(c1); osfp_profile_cycle(c2); if (db == NULL || l3_hdr == NULL || l4_hdr == NULL || l4_hdr_len == 0) { goto exit; } osfp_profile_get_cycle(c1); ret = osfp_fingerprinting((unsigned char *)l3_hdr, (unsigned char *)l4_hdr, (unsigned int)l4_hdr_len, &fp, 6); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_fingerprinting, c2 - c1); if (ret != 0) { goto exit; } osfp_profile_get_cycle(c1); matched = osfp_score_db_prefilter(db->score_db, &fp, &os_class_score); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_prefilter, c2 - c1); if (matched == NULL) { 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); result = osfp_result_build(&os_class_score, matched); osfp_profile_get_cycle(c2); osfp_profile_counter_update(&osfp_profile_result_build, c2 - c1); if (result == NULL) { goto exit; } return result; 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; const char *matched; if (db == NULL || json_str == NULL) { goto exit; } ret = osfp_fingerprint_from_json(&fp, (char *)json_str); if (ret != 0) { goto exit; } matched = osfp_score_db_prefilter(db->score_db, &fp, &os_class_score); if (matched == NULL) { 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, matched); if (result == NULL) { goto exit; } return result; exit: return NULL; } struct osfp_db *osfp_db_new(const char *fp_path) { int ret; struct osfp_db *db; if (fp_path == NULL) { goto exit; } if (0 != access(fp_path, R_OK)) { goto exit; } db = calloc(1, sizeof(struct osfp_db)); if (db == NULL) { goto exit; } db->db_json_path = strdup((const char*)fp_path); if (db->db_json_path == NULL) { goto exit; } db->score_db = (void *)osfp_score_db_create(); if (db->score_db == NULL) { goto exit; } ret = osfp_score_db_load((struct osfp_score_db *)db->score_db, db->db_json_path); if (ret != 0) { goto exit; } return db; exit: if (db) { osfp_db_free(db); } return NULL; } void osfp_db_free(struct osfp_db *db) { if (db) { if (db->db_json_path) { free(db->db_json_path); } if (db->score_db) { osfp_score_db_destroy(db->score_db); } free(db); } }