This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhuzhenjun-libosfp/src/osfp.c
2023-10-24 16:28:54 +08:00

355 lines
9.1 KiB
C

#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);
}
}