v0.0.5
This commit is contained in:
22
CMakeLists.txt.in
Normal file
22
CMakeLists.txt.in
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(libosfp)
|
||||||
|
|
||||||
|
# 添加其他CMake配置
|
||||||
|
|
||||||
|
# 生成RPM包
|
||||||
|
set(CPACK_GENERATOR "RPM")
|
||||||
|
set(CPACK_PACKAGE_NAME "libosfp")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "Geedge")
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Libosfp is a C library for OS fingerprinting.")
|
||||||
|
set(CPACK_PACKAGE_VERSION "1.0.0")
|
||||||
|
set(CPACK_PACKAGE_RELEASE 1)
|
||||||
|
set(CPACK_PACKAGE_CONTACT "zhuzhenjun@geedgenetworks.com")
|
||||||
|
|
||||||
|
set(CPACK_RPM_PACKAGE_AUTOREQPROV "no")
|
||||||
|
|
||||||
|
install(DIRECTORY @prefix@/include DESTINATION . USE_SOURCE_PERMISSIONS)
|
||||||
|
install(DIRECTORY @prefix@/lib DESTINATION /usr/lib64 USE_SOURCE_PERMISSIONS)
|
||||||
|
install(DIRECTORY @prefix@/bin DESTINATION . USE_SOURCE_PERMISSIONS)
|
||||||
|
install(FILES fp.json DESTINATION var/lib/libosfp)
|
||||||
|
|
||||||
|
include(CPack)
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
SUBDIRS = src example
|
SUBDIRS = src example test
|
||||||
ACLOCAL_AMFLAGS=-I m4
|
ACLOCAL_AMFLAGS=-I m4
|
||||||
|
|||||||
77
README.md
77
README.md
@@ -1,83 +1,20 @@
|
|||||||
# libosfp
|
# libosfp
|
||||||
|
|
||||||
Libosfp is a C libaray for OS fingerprinting.
|
Libosfp is a C library for OS fingerprinting.
|
||||||
|
|
||||||
## install
|
## install
|
||||||
|
|
||||||
```
|
```
|
||||||
# osfp_example depends on libpcap
|
# osfp_example depends on libpcap
|
||||||
yum install -y libpcap-devel
|
yum install -y libpcap-devel
|
||||||
# build and install to ./target
|
# build and install
|
||||||
./autogen.sh; ./configure --prefix="$(pwd)/target"; make clean; make install
|
./package.sh
|
||||||
|
yum install package/*.rpm
|
||||||
```
|
```
|
||||||
|
|
||||||
## run example
|
## run example
|
||||||
```
|
|
||||||
# load the fingerprint file ./fp.json and capture on eth0, filter tcp port 8888
|
|
||||||
./target/bin/osfp_example -f ./fp.json -i eth0 "tcp port 8888"
|
|
||||||
# outputs like this
|
|
||||||
# --------------------------- SYN
|
|
||||||
# Example ipv4 header detect: --------------------------
|
|
||||||
# Connection info: 114.64.231.114:57570 -> 172.21.0.10:8888
|
|
||||||
# Most likely os class: Windows
|
|
||||||
# Details:
|
|
||||||
# {
|
|
||||||
# "likely": {
|
|
||||||
# "name": "Windows",
|
|
||||||
# "score": 20
|
|
||||||
# },
|
|
||||||
# "detail": [{
|
|
||||||
# "name": "Windows",
|
|
||||||
# "score": 20
|
|
||||||
# }, {
|
|
||||||
# "name": "Linux",
|
|
||||||
# "score": 10
|
|
||||||
# }, {
|
|
||||||
# "name": "Mac OS",
|
|
||||||
# "score": 1
|
|
||||||
# }, {
|
|
||||||
# "name": "iOS",
|
|
||||||
# "score": 0
|
|
||||||
# }, {
|
|
||||||
# "name": "Android",
|
|
||||||
# "score": 7
|
|
||||||
# }]
|
|
||||||
# }
|
|
||||||
```
|
|
||||||
|
|
||||||
## sample
|
|
||||||
```
|
```
|
||||||
#include "stdio.h"
|
# load the fingerprint file and capture on eth0, filter tcp port 8888
|
||||||
#include "osfp.h"
|
osfp_example -f /usr/var/lib/libosfp/fp.json -i eth0 "tcp port 8888"
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
const char *json_file_path = "./fp.json";
|
|
||||||
|
|
||||||
struct iphdr *l3_hdr = (struct iphdr *)iph;
|
|
||||||
struct tcphdr *l4_hdr = (struct tcphdr *)tcph;
|
|
||||||
size_t l4_hdr_len = sizeof(tcph);
|
|
||||||
|
|
||||||
struct osfp_db *db = osfp_db_new(json_file_path);
|
|
||||||
if (db) {
|
|
||||||
struct osfp_result *result = osfp_ipv4_identify(db, l3_hdr, l4_hdr, l4_hdr_len);
|
|
||||||
if (result) {
|
|
||||||
printf("likely os: %s\n", osfp_result_os_name_get(result));
|
|
||||||
printf("details: \n%s\n", osfp_result_score_detail_export(result));
|
|
||||||
osfp_db_free(db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|||||||
6
build.sh
Executable file
6
build.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./autogen.sh;
|
||||||
|
./configure --prefix=$(pwd)/target;
|
||||||
|
make -j
|
||||||
|
make install
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([libosfp],[0.0.4],[zhuzhenjun@geedgenetworks.com])
|
AC_INIT([libosfp],[0.0.5],[zhuzhenjun@geedgenetworks.com])
|
||||||
AM_INIT_AUTOMAKE([foreign])
|
AM_INIT_AUTOMAKE([foreign])
|
||||||
|
|
||||||
#m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes])
|
#m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes])
|
||||||
@@ -10,6 +10,10 @@ AS_IF([test "x$enable_debug" = xyes],
|
|||||||
[CFLAGS="-DDEBUGLOG -ggdb3 -O0 -fsanitize=address -fno-omit-frame-pointer"],
|
[CFLAGS="-DDEBUGLOG -ggdb3 -O0 -fsanitize=address -fno-omit-frame-pointer"],
|
||||||
[CFLAGS="-g -O2"])
|
[CFLAGS="-g -O2"])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([test], [AS_HELP_STRING([--enable-test], [enable test])], [enable_test=$enableval], [enable_test=yes])
|
||||||
|
AS_IF([test "x$enable_test" = xyes],
|
||||||
|
[CFLAGS="${CFLAGS} -DUNITTEST"])
|
||||||
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CPP
|
AC_PROG_CPP
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
@@ -18,5 +22,5 @@ AC_PROG_MAKE_SET
|
|||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([libosfp-config Makefile src/Makefile example/Makefile])
|
AC_CONFIG_FILES([CMakeLists.txt libosfp-config Makefile src/Makefile example/Makefile test/Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -442,21 +442,27 @@ void example_detect(struct osfp_db *osfp_db, Packet *p)
|
|||||||
int ret;
|
int ret;
|
||||||
char str_buf[1024];
|
char str_buf[1024];
|
||||||
//unsigned char *iph = (unsigned char *)(p->iph != NULL ? (void *)p->iph : (void *)p->ip6h);
|
//unsigned char *iph = (unsigned char *)(p->iph != NULL ? (void *)p->iph : (void *)p->ip6h);
|
||||||
|
struct iphdr *iph;
|
||||||
|
struct ipv6hdr *ip6h;
|
||||||
struct tcphdr *tcph;
|
struct tcphdr *tcph;
|
||||||
unsigned int tcph_len;
|
unsigned int tcph_len;
|
||||||
struct osfp_result *result;
|
struct osfp_result *result = NULL;
|
||||||
unsigned int os_class_flags = OSFP_OS_CLASS_FLAG_WINDOWS | OSFP_OS_CLASS_FLAG_LINUX | OSFP_OS_CLASS_FLAG_MAC_OS;
|
|
||||||
|
|
||||||
printf("Example ipv4 header detect: --------------------------\n");
|
printf("Example ipv4 header detect: --------------------------\n");
|
||||||
|
|
||||||
if (p->iph == NULL) {
|
iph = (struct iphdr *)p->iph;
|
||||||
goto exit;
|
ip6h = (struct ipv6hdr *)p->ip6h;
|
||||||
}
|
|
||||||
|
|
||||||
tcph = (struct tcphdr *)p->tcph;
|
tcph = (struct tcphdr *)p->tcph;
|
||||||
tcph_len = tcph->doff << 2;
|
tcph_len = tcph->doff << 2;
|
||||||
|
|
||||||
result = osfp_ipv4_identify(osfp_db, p->iph, tcph, tcph_len);
|
if (iph) {
|
||||||
|
result = osfp_ipv4_identify(osfp_db, iph, tcph, tcph_len);
|
||||||
|
} else if (ip6h) {
|
||||||
|
result = osfp_ipv6_identify(osfp_db, ip6h, tcph, tcph_len);
|
||||||
|
} else {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
printf("osfp header match failed, erro: %s\n", "?");
|
printf("osfp header match failed, erro: %s\n", "?");
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -468,9 +474,10 @@ void example_detect(struct osfp_db *osfp_db, Packet *p)
|
|||||||
printf("Details:\n");
|
printf("Details:\n");
|
||||||
printf("%s\n", osfp_result_score_detail_export(result));
|
printf("%s\n", osfp_result_score_detail_export(result));
|
||||||
|
|
||||||
osfp_result_free(result);
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
if (result) {
|
||||||
|
osfp_result_free(result);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ int main(int argc, char **argv)
|
|||||||
if (result) {
|
if (result) {
|
||||||
printf("likely os: %s\n", osfp_result_os_name_get(result));
|
printf("likely os: %s\n", osfp_result_os_name_get(result));
|
||||||
printf("details: \n%s\n", osfp_result_score_detail_export(result));
|
printf("details: \n%s\n", osfp_result_score_detail_export(result));
|
||||||
|
osfp_result_free(result);
|
||||||
osfp_db_free(db);
|
osfp_db_free(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
package.sh
Executable file
12
package.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./autogen.sh;
|
||||||
|
./configure --prefix=$(pwd)/target;
|
||||||
|
make install;
|
||||||
|
|
||||||
|
rm -rf package
|
||||||
|
mkdir package
|
||||||
|
cd package
|
||||||
|
cmake ..
|
||||||
|
cpack
|
||||||
|
cd -
|
||||||
BIN
pcap/linux_ipv4_syn.pcap
Normal file
BIN
pcap/linux_ipv4_syn.pcap
Normal file
Binary file not shown.
BIN
pcap/linux_ipv4_syn_ack.pcap
Normal file
BIN
pcap/linux_ipv4_syn_ack.pcap
Normal file
Binary file not shown.
BIN
pcap/unknown_ipv6_syn.pcap
Normal file
BIN
pcap/unknown_ipv6_syn.pcap
Normal file
Binary file not shown.
BIN
pcap/unknown_ipv6_syn_ack.pcap
Normal file
BIN
pcap/unknown_ipv6_syn_ack.pcap
Normal file
Binary file not shown.
BIN
pcap/windows_ipv4_syn.pcap
Normal file
BIN
pcap/windows_ipv4_syn.pcap
Normal file
Binary file not shown.
BIN
pcap/windows_ipv6_malformed.pcap
Normal file
BIN
pcap/windows_ipv6_malformed.pcap
Normal file
Binary file not shown.
BIN
pcap/windows_ipv6_syn_ack.pcap
Normal file
BIN
pcap/windows_ipv6_syn_ack.pcap
Normal file
Binary file not shown.
71
src/osfp.c
71
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_score = tmp_score;
|
||||||
likely_os_class = i;
|
likely_os_class = i;
|
||||||
}
|
}
|
||||||
result->detail.scores[i] = tmp_score;
|
result->details[i].score = tmp_score;
|
||||||
sum_score += tmp_score;
|
sum_score += tmp_score;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sum_score) {
|
if (sum_score) {
|
||||||
for (i = 0; i < OSFP_OS_CLASS_MAX; i++) {
|
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) {
|
if (likely_score < OSFP_LOWEST_SCORE_LIMIT) {
|
||||||
result->likely_os_class = OSFP_OS_CLASS_OTHERS;
|
likely_os_class = OSFP_OS_CLASS_OTHERS;
|
||||||
result->likely_score = 0;
|
|
||||||
result->likely_possibility = 0;
|
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < OSFP_OS_CLASS_MAX; i++) {
|
for (i = 0; i < OSFP_OS_CLASS_MAX; i++) {
|
||||||
if (likely_os_class == 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) {
|
} else if (likely_os_class == OSFP_OS_CLASS_MAC_OS && i == OSFP_OS_CLASS_IOS) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
result->likely_os_class = OSFP_OS_CLASS_UNKNOWN;
|
likely_os_class = OSFP_OS_CLASS_UNKNOWN;
|
||||||
result->likely_score = 0;
|
|
||||||
result->likely_possibility = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result->likely_os_class = likely_os_class;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
exit:
|
exit:
|
||||||
return NULL;
|
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)
|
char *osfp_result_score_detail_export(struct osfp_result *result)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
char *result_str = NULL;
|
||||||
cJSON *root = NULL;
|
cJSON *root = NULL;
|
||||||
cJSON *array;
|
cJSON *array;
|
||||||
cJSON *os_score;
|
cJSON *os_score;
|
||||||
@@ -104,6 +99,7 @@ char *osfp_result_score_detail_export(struct osfp_result *result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result->json_str != NULL) {
|
if (result->json_str != NULL) {
|
||||||
|
result_str = result->json_str;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,37 +111,35 @@ char *osfp_result_score_detail_export(struct osfp_result *result)
|
|||||||
os_score = cJSON_AddObjectToObject(root, "likely");
|
os_score = cJSON_AddObjectToObject(root, "likely");
|
||||||
if (os_score) {
|
if (os_score) {
|
||||||
cJSON_AddStringToObject(os_score, "name", osfp_os_class_id_to_name(result->likely_os_class));
|
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, "score", result->details[result->likely_os_class].score);
|
||||||
//cJSON_AddNumberToObject(os_score, "possibility", result->likely_possibility);
|
//cJSON_AddNumberToObject(os_score, "possibility", result->details[result->likely_os_class].possibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
array = cJSON_AddArrayToObject(root, "detail");
|
array = cJSON_AddArrayToObject(root, "details");
|
||||||
if (array) {
|
if (array) {
|
||||||
for (i = OSFP_OS_CLASS_WINDOWS; i < OSFP_OS_CLASS_OTHERS; i++) {
|
for (i = OSFP_OS_CLASS_WINDOWS; i < OSFP_OS_CLASS_OTHERS; i++) {
|
||||||
os_score = cJSON_CreateObject();
|
os_score = cJSON_CreateObject();
|
||||||
if (os_score) {
|
if (os_score) {
|
||||||
cJSON_AddStringToObject(os_score, "name", osfp_os_class_id_to_name(i));
|
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, "score", result->details[i].score);
|
||||||
//cJSON_AddNumberToObject(os_score, "possibility", result->detail.possibility[i]);
|
//cJSON_AddNumberToObject(os_score, "possibility", result->details[i].possibility);
|
||||||
cJSON_AddItemToArray(array, os_score);
|
cJSON_AddItemToArray(array, os_score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result->json_str = malloc(OSFP_DEFAULT_RESULT_BUFLEN_MAX);
|
result_str = cJSON_Print(root);
|
||||||
if (result->json_str == NULL) {
|
if (result_str == NULL) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cJSON_PrintPreallocated(root, result->json_str, OSFP_DEFAULT_RESULT_BUFLEN_MAX, 1)) {
|
result->json_str = result_str;
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (root) {
|
if (root) {
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
}
|
}
|
||||||
return result->json_str;
|
return result_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void osfp_result_free(struct osfp_result *result)
|
void osfp_result_free(struct osfp_result *result)
|
||||||
@@ -220,6 +214,37 @@ exit:
|
|||||||
return NULL;
|
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)
|
struct osfp_db *osfp_db_new(const char *db_json_file)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|||||||
108
src/osfp.h
108
src/osfp.h
@@ -8,6 +8,9 @@
|
|||||||
#include <linux/ipv6.h>
|
#include <linux/ipv6.h>
|
||||||
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 定义操作系统类别的名称常量。
|
||||||
|
*/
|
||||||
#define OSFP_OS_CLASS_NAME_UNKNOWN "Unknown"
|
#define OSFP_OS_CLASS_NAME_UNKNOWN "Unknown"
|
||||||
#define OSFP_OS_CLASS_NAME_WINDOWS "Windows"
|
#define OSFP_OS_CLASS_NAME_WINDOWS "Windows"
|
||||||
#define OSFP_OS_CLASS_NAME_LINUX "Linux"
|
#define OSFP_OS_CLASS_NAME_LINUX "Linux"
|
||||||
@@ -16,45 +19,112 @@
|
|||||||
#define OSFP_OS_CLASS_NAME_ANDROID "Android"
|
#define OSFP_OS_CLASS_NAME_ANDROID "Android"
|
||||||
#define OSFP_OS_CLASS_NAME_OTHERS "Others"
|
#define OSFP_OS_CLASS_NAME_OTHERS "Others"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 枚举表示不同的操作系统类别。
|
||||||
|
*/
|
||||||
enum osfp_os_class_id {
|
enum osfp_os_class_id {
|
||||||
OSFP_OS_CLASS_UNKNOWN,
|
OSFP_OS_CLASS_UNKNOWN, // 未知
|
||||||
OSFP_OS_CLASS_WINDOWS,
|
OSFP_OS_CLASS_WINDOWS, // Windows
|
||||||
OSFP_OS_CLASS_LINUX,
|
OSFP_OS_CLASS_LINUX, // Linux
|
||||||
OSFP_OS_CLASS_MAC_OS,
|
OSFP_OS_CLASS_MAC_OS, // Mac OS
|
||||||
OSFP_OS_CLASS_IOS,
|
OSFP_OS_CLASS_IOS, // iOS
|
||||||
OSFP_OS_CLASS_ANDROID,
|
OSFP_OS_CLASS_ANDROID, // Android
|
||||||
OSFP_OS_CLASS_OTHERS,
|
OSFP_OS_CLASS_OTHERS, // 其他
|
||||||
OSFP_OS_CLASS_MAX,
|
OSFP_OS_CLASS_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osfp_os_result_detail {
|
/**
|
||||||
unsigned int scores[OSFP_OS_CLASS_MAX];
|
* @brief 结构体用于 osfp_result 中的详细结果。
|
||||||
unsigned int possibility[OSFP_OS_CLASS_MAX];
|
*/
|
||||||
|
struct osfp_result_detail {
|
||||||
|
unsigned int score; // 得分
|
||||||
|
unsigned int possibility; // 可能性
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结构体用于表示操作系统识别结果。
|
||||||
|
*/
|
||||||
struct osfp_result {
|
struct osfp_result {
|
||||||
char *json_str;
|
char *json_str; // JSON 字符串
|
||||||
|
enum osfp_os_class_id likely_os_class; // 最可能的操作系统类别
|
||||||
enum osfp_os_class_id likely_os_class;
|
struct osfp_result_detail details[OSFP_OS_CLASS_MAX]; // 详细结果数组
|
||||||
unsigned int likely_score;
|
|
||||||
unsigned int likely_possibility;
|
|
||||||
|
|
||||||
struct osfp_os_result_detail detail;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结构体用于表示操作系统指纹库。
|
||||||
|
*/
|
||||||
struct osfp_db {
|
struct osfp_db {
|
||||||
char *db_json_path;
|
char *db_json_path; // 操作系统指纹库 JSON 文件路径
|
||||||
void *score_db;
|
void *score_db; // 分数数据库指针
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建一个新的操作系统指纹库。
|
||||||
|
*
|
||||||
|
* @param db_json_path 操作系统指纹库 JSON 文件的路径。
|
||||||
|
* @return 指向新创建的操作系统指纹库的指针。
|
||||||
|
*/
|
||||||
struct osfp_db *osfp_db_new(const char *db_json_path);
|
struct osfp_db *osfp_db_new(const char *db_json_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 释放操作系统指纹库占用的内存。
|
||||||
|
*
|
||||||
|
* @param db 指向要释放的操作系统指纹库的指针。
|
||||||
|
*/
|
||||||
void osfp_db_free(struct osfp_db *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);
|
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);
|
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);
|
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);
|
char *osfp_result_score_detail_export(struct osfp_result *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 释放操作系统识别结果占用的内存。
|
||||||
|
*
|
||||||
|
* @param result 操作系统识别结果。
|
||||||
|
*/
|
||||||
void osfp_result_free(struct osfp_result *result);
|
void osfp_result_free(struct osfp_result *result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -84,20 +84,6 @@
|
|||||||
#define OSFP_TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */
|
#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_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)
|
static inline unsigned long long osfp_rdtsc(void)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
|
|||||||
@@ -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_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_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, 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},
|
{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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strbuf[0] = 0;
|
||||||
|
|
||||||
root = cJSON_CreateObject();
|
root = cJSON_CreateObject();
|
||||||
if (root == NULL) {
|
if (root == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -165,6 +167,61 @@ int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsi
|
|||||||
return strlen(strbuf) + 1;
|
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)
|
unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id)
|
||||||
{
|
{
|
||||||
return fp_fields[field_id].enabled;
|
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;
|
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;
|
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;
|
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_offset = 0;
|
||||||
unsigned int ordered_maxoffset = sizeof(options_ordered) - 1;
|
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);
|
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++) {
|
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, options, strlen(options) + 1);
|
||||||
osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED, options_ordered, strlen(options_ordered) + 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)
|
int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp)
|
||||||
@@ -406,27 +469,27 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNITTEST
|
#ifdef UNITTEST
|
||||||
int test_osfp_fingerprinting(void)
|
int test_osfp_fingerprinting_ipv4(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char iph[] = {
|
char iph[] = {
|
||||||
0x45, 0x00, 0x00, 0x34, 0x51, 0xc4, 0x40, 0x00,
|
0x45, 0x00, 0x00, 0x34, 0x51, 0xc4, 0x40, 0x00,
|
||||||
0x80, 0x06, 0xe7, 0x27, 0xc0, 0xa8, 0x73, 0x08,
|
0x80, 0x06, 0xe7, 0x27, 0xc0, 0xa8, 0x73, 0x08,
|
||||||
0x6a, 0xb9, 0x23, 0x6e
|
0x6a, 0xb9, 0x23, 0x6e
|
||||||
};
|
};
|
||||||
|
|
||||||
char tcph[] = {
|
char tcph[] = {
|
||||||
0xc1, 0xbd, 0x00, 0x50, 0x3d, 0x58, 0x51, 0x60,
|
0xc1, 0xbd, 0x00, 0x50, 0x3d, 0x58, 0x51, 0x60,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, 0x00,
|
||||||
0x3d, 0x3a, 0x00, 0x00, 0x02, 0x04, 0x04, 0xec,
|
0x3d, 0x3a, 0x00, 0x00, 0x02, 0x04, 0x04, 0xec,
|
||||||
0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02
|
0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
char str_buf[2048] = "";
|
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};
|
struct osfp_fingerprint fp = {0};
|
||||||
|
|
||||||
ret = osfp_fingerprinting(iph, tcph, &fp);
|
ret = osfp_fingerprinting(iph, tcph, 32, &fp, 4);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -436,7 +499,87 @@ int test_osfp_fingerprinting(void)
|
|||||||
goto exit;
|
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;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ enum osfp_field_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct osfp_fingerprint_field {
|
struct osfp_fingerprint_field {
|
||||||
char *name;
|
const char *name;
|
||||||
unsigned int enabled;
|
unsigned int enabled;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int importance;
|
unsigned int importance;
|
||||||
@@ -43,21 +43,24 @@ struct osfp_fingerprint {
|
|||||||
unsigned int value_buffer_used;
|
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_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_importance(enum osfp_field_id field_id);
|
||||||
unsigned int osfp_fingerprint_get_field_type(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);
|
int osfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, struct osfp_fingerprint *fp);
|
||||||
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(struct tcphdr *tcph, unsigned int tcph_len, 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_ipv4(struct iphdr *iph, struct osfp_fingerprint *fp);
|
||||||
int osfp_fingerprinting_ipv6(struct ipv6hdr *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);
|
int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version);
|
||||||
|
|
||||||
#ifdef UNITTEST
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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)
|
char *osfp_score_db_read_file(char *fp_file)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@@ -343,7 +334,7 @@ exit:
|
|||||||
|
|
||||||
int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file)
|
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;
|
char *file_buffer;
|
||||||
cJSON *root = NULL;
|
cJSON *root = NULL;
|
||||||
cJSON *entry;
|
cJSON *entry;
|
||||||
@@ -367,9 +358,9 @@ int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file)
|
|||||||
goto exit;
|
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);
|
entry = cJSON_GetArrayItem(root, i);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
ret = osfp_score_db_load_entry(score_db, 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));
|
osfp_log_debug("json entry load failed.\n%s\n", cJSON_Print(entry));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < OSFP_FIELD_MAX; i++) {
|
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;
|
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) {
|
if (os_class_score_matched == NULL) {
|
||||||
continue;
|
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 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 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 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);
|
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
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ struct osfp_score_db {
|
|||||||
struct osfp_field_score_db field_score_dbs[OSFP_FIELD_MAX];
|
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);
|
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_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);
|
struct osfp_score_db *osfp_score_db_create(void);
|
||||||
void osfp_score_db_destroy(struct osfp_score_db *score_db);
|
void osfp_score_db_destroy(struct osfp_score_db *score_db);
|
||||||
|
|
||||||
|
#ifdef UNITTEST
|
||||||
|
int test_osfp_score_db(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
11
test/Makefile.am
Normal file
11
test/Makefile.am
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
bin_PROGRAMS = osfp_test
|
||||||
|
|
||||||
|
osfp_test_SOURCES = \
|
||||||
|
test.c
|
||||||
|
|
||||||
|
osfp_test_LDADD = \
|
||||||
|
../src/.libs/libosfp.la
|
||||||
|
|
||||||
|
osfp_test_CFLAGS = \
|
||||||
|
-I../src
|
||||||
|
|
||||||
11
test/README.md
Normal file
11
test/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# test
|
||||||
|
```
|
||||||
|
./.libs/osfp_test -f ../fp.json -t ../data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
# output
|
||||||
|
```
|
||||||
|
total 12505, failed 0, pass 9582, wrong 2923, other 107, unknown 37
|
||||||
|
miss rate: 24%
|
||||||
|
details in: ./osfp_test.log
|
||||||
|
```
|
||||||
228
test/osfp_test
Executable file
228
test/osfp_test
Executable file
@@ -0,0 +1,228 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# osfp_test - temporary wrapper script for .libs/osfp_test
|
||||||
|
# Generated by libtool (GNU libtool) 2.4.2
|
||||||
|
#
|
||||||
|
# The osfp_test program cannot be directly executed until all the libtool
|
||||||
|
# libraries that it depends on are installed.
|
||||||
|
#
|
||||||
|
# This wrapper script should never be moved out of the build directory.
|
||||||
|
# If it is, it will not operate correctly.
|
||||||
|
|
||||||
|
# Sed substitution that helps us do robust quoting. It backslashifies
|
||||||
|
# metacharacters that are still active within double-quoted strings.
|
||||||
|
sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
|
||||||
|
|
||||||
|
# Be Bourne compatible
|
||||||
|
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
|
||||||
|
emulate sh
|
||||||
|
NULLCMD=:
|
||||||
|
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
|
||||||
|
# is contrary to our usage. Disable this feature.
|
||||||
|
alias -g '${1+"$@"}'='"$@"'
|
||||||
|
setopt NO_GLOB_SUBST
|
||||||
|
else
|
||||||
|
case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
|
||||||
|
fi
|
||||||
|
BIN_SH=xpg4; export BIN_SH # for Tru64
|
||||||
|
DUALCASE=1; export DUALCASE # for MKS sh
|
||||||
|
|
||||||
|
# The HP-UX ksh and POSIX shell print the target directory to stdout
|
||||||
|
# if CDPATH is set.
|
||||||
|
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||||
|
|
||||||
|
relink_command="(cd /root/geedge/libosfp/test; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/root/.cargo/bin:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin; export PATH; gcc -I../src -g -O2 -DUNITTEST -o \$progdir/\$file osfp_test-test.o ../src/.libs/libosfp.so -Wl,-rpath -Wl,/root/geedge/libosfp/src/.libs -Wl,-rpath -Wl,/root/geedge/libosfp/target/lib)"
|
||||||
|
|
||||||
|
# This environment variable determines our operation mode.
|
||||||
|
if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
|
||||||
|
# install mode needs the following variables:
|
||||||
|
generated_by_libtool_version='2.4.2'
|
||||||
|
notinst_deplibs=' ../src/.libs/libosfp.la'
|
||||||
|
else
|
||||||
|
# When we are sourced in execute mode, $file and $ECHO are already set.
|
||||||
|
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
|
||||||
|
file="$0"
|
||||||
|
|
||||||
|
# A function that is used when there is no print builtin or printf.
|
||||||
|
func_fallback_echo ()
|
||||||
|
{
|
||||||
|
eval 'cat <<_LTECHO_EOF
|
||||||
|
$1
|
||||||
|
_LTECHO_EOF'
|
||||||
|
}
|
||||||
|
ECHO="printf %s\\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Very basic option parsing. These options are (a) specific to
|
||||||
|
# the libtool wrapper, (b) are identical between the wrapper
|
||||||
|
# /script/ and the wrapper /executable/ which is used only on
|
||||||
|
# windows platforms, and (c) all begin with the string --lt-
|
||||||
|
# (application programs are unlikely to have options which match
|
||||||
|
# this pattern).
|
||||||
|
#
|
||||||
|
# There are only two supported options: --lt-debug and
|
||||||
|
# --lt-dump-script. There is, deliberately, no --lt-help.
|
||||||
|
#
|
||||||
|
# The first argument to this parsing function should be the
|
||||||
|
# script's ../libtool value, followed by no.
|
||||||
|
lt_option_debug=
|
||||||
|
func_parse_lt_options ()
|
||||||
|
{
|
||||||
|
lt_script_arg0=$0
|
||||||
|
shift
|
||||||
|
for lt_opt
|
||||||
|
do
|
||||||
|
case "$lt_opt" in
|
||||||
|
--lt-debug) lt_option_debug=1 ;;
|
||||||
|
--lt-dump-script)
|
||||||
|
lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
|
||||||
|
test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
|
||||||
|
lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
|
||||||
|
cat "$lt_dump_D/$lt_dump_F"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--lt-*)
|
||||||
|
$ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Print the debug banner immediately:
|
||||||
|
if test -n "$lt_option_debug"; then
|
||||||
|
echo "osfp_test:osfp_test:${LINENO}: libtool wrapper (GNU libtool) 2.4.2" 1>&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Used when --lt-debug. Prints its arguments to stdout
|
||||||
|
# (redirection is the responsibility of the caller)
|
||||||
|
func_lt_dump_args ()
|
||||||
|
{
|
||||||
|
lt_dump_args_N=1;
|
||||||
|
for lt_arg
|
||||||
|
do
|
||||||
|
$ECHO "osfp_test:osfp_test:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg"
|
||||||
|
lt_dump_args_N=`expr $lt_dump_args_N + 1`
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Core function for launching the target application
|
||||||
|
func_exec_program_core ()
|
||||||
|
{
|
||||||
|
|
||||||
|
if test -n "$lt_option_debug"; then
|
||||||
|
$ECHO "osfp_test:osfp_test:${LINENO}: newargv[0]: $progdir/$program" 1>&2
|
||||||
|
func_lt_dump_args ${1+"$@"} 1>&2
|
||||||
|
fi
|
||||||
|
exec "$progdir/$program" ${1+"$@"}
|
||||||
|
|
||||||
|
$ECHO "$0: cannot exec $program $*" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# A function to encapsulate launching the target application
|
||||||
|
# Strips options in the --lt-* namespace from $@ and
|
||||||
|
# launches target application with the remaining arguments.
|
||||||
|
func_exec_program ()
|
||||||
|
{
|
||||||
|
case " $* " in
|
||||||
|
*\ --lt-*)
|
||||||
|
for lt_wr_arg
|
||||||
|
do
|
||||||
|
case $lt_wr_arg in
|
||||||
|
--lt-*) ;;
|
||||||
|
*) set x "$@" "$lt_wr_arg"; shift;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done ;;
|
||||||
|
esac
|
||||||
|
func_exec_program_core ${1+"$@"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse options
|
||||||
|
func_parse_lt_options "$0" ${1+"$@"}
|
||||||
|
|
||||||
|
# Find the directory that this script lives in.
|
||||||
|
thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
|
||||||
|
test "x$thisdir" = "x$file" && thisdir=.
|
||||||
|
|
||||||
|
# Follow symbolic links until we get to the real thisdir.
|
||||||
|
file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
|
||||||
|
while test -n "$file"; do
|
||||||
|
destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
|
||||||
|
|
||||||
|
# If there was a directory component, then change thisdir.
|
||||||
|
if test "x$destdir" != "x$file"; then
|
||||||
|
case "$destdir" in
|
||||||
|
[\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
|
||||||
|
*) thisdir="$thisdir/$destdir" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
|
||||||
|
file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
|
||||||
|
done
|
||||||
|
|
||||||
|
# Usually 'no', except on cygwin/mingw when embedded into
|
||||||
|
# the cwrapper.
|
||||||
|
WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
|
||||||
|
if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
|
||||||
|
# special case for '.'
|
||||||
|
if test "$thisdir" = "."; then
|
||||||
|
thisdir=`pwd`
|
||||||
|
fi
|
||||||
|
# remove .libs from thisdir
|
||||||
|
case "$thisdir" in
|
||||||
|
*[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
|
||||||
|
.libs ) thisdir=. ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try to get the absolute directory name.
|
||||||
|
absdir=`cd "$thisdir" && pwd`
|
||||||
|
test -n "$absdir" && thisdir="$absdir"
|
||||||
|
|
||||||
|
program=lt-'osfp_test'
|
||||||
|
progdir="$thisdir/.libs"
|
||||||
|
|
||||||
|
if test ! -f "$progdir/$program" ||
|
||||||
|
{ file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /usr/bin/sed 1q`; \
|
||||||
|
test "X$file" != "X$progdir/$program"; }; then
|
||||||
|
|
||||||
|
file="$$-$program"
|
||||||
|
|
||||||
|
if test ! -d "$progdir"; then
|
||||||
|
mkdir "$progdir"
|
||||||
|
else
|
||||||
|
rm -f "$progdir/$file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# relink executable if necessary
|
||||||
|
if test -n "$relink_command"; then
|
||||||
|
if relink_command_output=`eval $relink_command 2>&1`; then :
|
||||||
|
else
|
||||||
|
printf %s\n "$relink_command_output" >&2
|
||||||
|
rm -f "$progdir/$file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
|
||||||
|
{ rm -f "$progdir/$program";
|
||||||
|
mv -f "$progdir/$file" "$progdir/$program"; }
|
||||||
|
rm -f "$progdir/$file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "$progdir/$program"; then
|
||||||
|
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
|
||||||
|
# Run the actual program with our arguments.
|
||||||
|
func_exec_program ${1+"$@"}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# The program doesn't exist.
|
||||||
|
$ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
|
||||||
|
$ECHO "This script is just a wrapper for $program." 1>&2
|
||||||
|
$ECHO "See the libtool documentation for more information." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
67229
test/osfp_test.log
Normal file
67229
test/osfp_test.log
Normal file
File diff suppressed because it is too large
Load Diff
198
test/test.c
198
test/test.c
@@ -4,16 +4,196 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <linux/in.h>
|
#include "cJSON.h"
|
||||||
#include <linux/if_ether.h>
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/ipv6.h>
|
|
||||||
#include <linux/tcp.h>
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include <pcap.h>
|
|
||||||
|
|
||||||
#include "osfp.h"
|
#include "osfp.h"
|
||||||
#include "osfp_fingerprint.h"
|
#include "osfp_fingerprint.h"
|
||||||
#include "osfp_score_db.h"
|
#include "osfp_score_db.h"
|
||||||
|
#include "osfp_log.h"
|
||||||
|
#include "osfp_common.h"
|
||||||
|
|
||||||
|
#define DATA_FILE_PATH "./data.json"
|
||||||
|
#define DB_FILE_PATH "./db.json"
|
||||||
|
#define TEST_FILE_PATH "./test.json"
|
||||||
|
#define LOG_FILE_PATH "./osfp_test.log"
|
||||||
|
|
||||||
|
unsigned char *data_file_path = DATA_FILE_PATH;
|
||||||
|
unsigned char *db_file_path;
|
||||||
|
unsigned char *test_file_path;
|
||||||
|
|
||||||
|
FILE *data_file_ptr;
|
||||||
|
FILE *db_file_ptr;
|
||||||
|
FILE *test_file_ptr;
|
||||||
|
FILE *log_file_ptr;
|
||||||
|
|
||||||
|
unsigned int debug_enable;
|
||||||
|
|
||||||
|
void test_data_prepare()
|
||||||
|
{
|
||||||
|
char *file_buffer;
|
||||||
|
|
||||||
|
if (test_file_path == NULL) {
|
||||||
|
file_buffer = osfp_score_db_read_file(data_file_path);
|
||||||
|
if (file_buffer == NULL) {
|
||||||
|
osfp_log_error("read file: '%s'\n", data_file_path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *data;
|
||||||
|
data = cJSON_Parse(file_buffer);
|
||||||
|
if (data == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *test;
|
||||||
|
test = cJSON_CreateArray();
|
||||||
|
|
||||||
|
unsigned int data_count = cJSON_GetArraySize(data);
|
||||||
|
unsigned int db_count = data_count * 8 / 10;
|
||||||
|
unsigned int test_count = data_count - db_count;
|
||||||
|
srand(time(0));
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < test_count; i++) {
|
||||||
|
cJSON_AddItemToArray(test, cJSON_DetachItemFromArray(data, rand() % data_count));
|
||||||
|
data_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
db_file_ptr = fopen(DB_FILE_PATH, "w");
|
||||||
|
test_file_ptr = fopen(TEST_FILE_PATH, "w");
|
||||||
|
|
||||||
|
fprintf(db_file_ptr, "%s", cJSON_Print(data));
|
||||||
|
fprintf(test_file_ptr, "%s", cJSON_Print(test));
|
||||||
|
|
||||||
|
fflush(db_file_ptr);
|
||||||
|
fflush(test_file_ptr);
|
||||||
|
|
||||||
|
db_file_path = DB_FILE_PATH;
|
||||||
|
test_file_path = TEST_FILE_PATH;
|
||||||
|
}else{
|
||||||
|
db_file_path = data_file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_miss_rate()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int other_count = 0;
|
||||||
|
unsigned int unknown_count = 0;
|
||||||
|
unsigned int identify_failed_count = 0;
|
||||||
|
unsigned int wrong_count = 0;
|
||||||
|
unsigned int verified_count = 0;
|
||||||
|
unsigned int fingerprint_count = 0;
|
||||||
|
char *file_buffer;
|
||||||
|
|
||||||
|
file_buffer = osfp_score_db_read_file(test_file_path);
|
||||||
|
if (file_buffer == NULL) {
|
||||||
|
osfp_log_error("read file: '%s'\n", test_file_path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *root = cJSON_Parse(file_buffer);
|
||||||
|
if (root == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fingerprint_count = cJSON_GetArraySize(root);
|
||||||
|
|
||||||
|
if (debug_enable) {
|
||||||
|
osfp_log_level_set(OSFP_LOG_LEVEL_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct osfp_db *osfp_db = osfp_db_new(db_file_path);
|
||||||
|
if (osfp_db == NULL) {
|
||||||
|
printf("could not create osfp context. fingerprints file: %s\n", db_file_path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//osfp_score_db_debug_print(osfp_db->score_db);
|
||||||
|
|
||||||
|
FILE *log_file_ptr = fopen(LOG_FILE_PATH, "w");
|
||||||
|
|
||||||
|
for (i = 0; i < fingerprint_count; i++) {
|
||||||
|
cJSON *entry = cJSON_GetArrayItem(root, i);
|
||||||
|
if (entry) {
|
||||||
|
cJSON *os_class_json = cJSON_GetObjectItem(entry, "os");
|
||||||
|
int os_class = osfp_os_class_name_to_id(os_class_json->valuestring);
|
||||||
|
|
||||||
|
const char *fp_str = cJSON_PrintUnformatted(entry);
|
||||||
|
|
||||||
|
struct osfp_result *result = osfp_json_identify(osfp_db, fp_str);
|
||||||
|
if (result == NULL) {
|
||||||
|
identify_failed_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os_class == result->likely_os_class) {
|
||||||
|
verified_count++;
|
||||||
|
osfp_result_free(result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrong_count++;
|
||||||
|
|
||||||
|
if (result->likely_os_class == OSFP_OS_CLASS_OTHERS) {
|
||||||
|
other_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->likely_os_class == OSFP_OS_CLASS_UNKNOWN) {
|
||||||
|
unknown_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(log_file_ptr, "expect: %s, result: %s\n", os_class_json->valuestring, osfp_result_os_name_get(result));
|
||||||
|
|
||||||
|
char *result_json = osfp_result_score_detail_export(result);
|
||||||
|
if (result_json) {
|
||||||
|
fprintf(log_file_ptr, "%s\n", result_json);
|
||||||
|
} else {
|
||||||
|
fprintf(log_file_ptr, "result detail error:%p\n", result);
|
||||||
|
}
|
||||||
|
fflush(log_file_ptr);
|
||||||
|
osfp_result_free(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("total %u, failed %u, pass %u, wrong %u, other %u, unknown %u\n",
|
||||||
|
fingerprint_count, identify_failed_count, verified_count, wrong_count, other_count, unknown_count);
|
||||||
|
|
||||||
|
printf("miss rate: %d%%\n", 100 - (verified_count * 100 / fingerprint_count));
|
||||||
|
|
||||||
|
printf("details in: %s\n", LOG_FILE_PATH);
|
||||||
|
|
||||||
|
osfp_db_free(osfp_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
while ((r = getopt(argc, argv, "+f:t:o:d")) != -1) {
|
||||||
|
switch(r) {
|
||||||
|
case 'f':
|
||||||
|
data_file_path = (unsigned char*)optarg;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
test_file_path = (unsigned char*)optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
debug_enable = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0 == test_osfp_fingerprinting_ipv4());
|
||||||
|
assert(0 == test_osfp_fingerprinting_ipv6());
|
||||||
|
assert(0 == test_osfp_fingerprinting_tcp_option());
|
||||||
|
assert(0 == test_osfp_score_db());
|
||||||
|
|
||||||
|
test_data_prepare();
|
||||||
|
test_miss_rate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user