summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzhuzhenjun <[email protected]>2023-10-09 15:23:31 +0800
committerzhuzhenjun <[email protected]>2023-10-09 15:23:59 +0800
commit56e3dec5f0a4980ca5f1f0b311a43f4bb8ae2e81 (patch)
tree629aa94f57969e2942688c3ca7f77bd44ed7bdf1 /src
parent1a559eba9916e4e39f660cf803ab7196cdd7c342 (diff)
v0.0.5
Diffstat (limited to 'src')
-rw-r--r--src/osfp.c71
-rw-r--r--src/osfp.h108
-rw-r--r--src/osfp_common.h14
-rw-r--r--src/osfp_fingerprint.c173
-rw-r--r--src/osfp_fingerprint.h17
-rw-r--r--src/osfp_score_db.c94
-rw-r--r--src/osfp_score_db.h5
7 files changed, 389 insertions, 93 deletions
diff --git a/src/osfp.c b/src/osfp.c
index 87685ba..c629d57 100644
--- a/src/osfp.c
+++ b/src/osfp.c
@@ -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;
diff --git a/src/osfp.h b/src/osfp.h
index 0a4c7e6..660a687 100644
--- a/src/osfp.h
+++ b/src/osfp.h
@@ -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