v0.0.1
This commit is contained in:
@@ -15,9 +15,9 @@
|
||||
#include <pcap.h>
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_fingerprint.h"
|
||||
#include "libosfp_score_db.h"
|
||||
|
||||
#define DEFAULT_FP_FILE "./fp.json"
|
||||
#define DEFAULT_FP_FILE_PATH "./fp.json"
|
||||
|
||||
#define ETHERNET_HEADER_LEN 14
|
||||
#define VLAN_HEADER_LEN 4
|
||||
@@ -131,6 +131,9 @@ typedef struct Packet_ {
|
||||
struct ipv6hdr *ip6h;
|
||||
struct tcphdr *tcph;
|
||||
|
||||
char srcip[46];
|
||||
char dstip[46];
|
||||
|
||||
Address src;
|
||||
Address dst;
|
||||
union {
|
||||
@@ -154,7 +157,10 @@ typedef struct Packet_ {
|
||||
} Packet;
|
||||
|
||||
|
||||
unsigned char *fp_file;
|
||||
unsigned char *fp_file_path;
|
||||
unsigned char *fp_output_file_path;
|
||||
FILE *fingerprinting_output_fp;
|
||||
|
||||
unsigned char *if_name;
|
||||
unsigned char *pcap_file_name;
|
||||
unsigned char *bpf_string;
|
||||
@@ -172,7 +178,7 @@ void usage(void) {
|
||||
" -i iface - listen on the specified network interface\n"
|
||||
" -r file - read offline pcap data from a given file\n"
|
||||
" -f file - read fingerprint database from 'file' (%s)\n",
|
||||
DEFAULT_FP_FILE);
|
||||
DEFAULT_FP_FILE_PATH);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -427,50 +433,39 @@ const char *PrintInet(int af, const void *src, char *dst, socklen_t size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void example_header_match(libosfp_context_t *libosfp_context, Packet *p)
|
||||
void example_detect(libosfp_context_t *libosfp_context, Packet *p)
|
||||
{
|
||||
// tcp/ip header match
|
||||
int ret;
|
||||
char str_buf[1024];
|
||||
|
||||
unsigned char *iph = (unsigned char *)(p->iph != NULL ? (void *)p->iph : (void *)p->ip6h);
|
||||
unsigned char *tcph = (unsigned char *)p->tcph;
|
||||
libosfp_result_t result;
|
||||
unsigned int os_class_flags = LIBOSFP_OS_CLASS_FLAG_WINDOWS | LIBOSFP_OS_CLASS_FLAG_LINUX | LIBOSFP_OS_CLASS_FLAG_MAC_OS;
|
||||
|
||||
printf("Example header match: --------------------------\n");
|
||||
printf("Example header detect: --------------------------\n");
|
||||
|
||||
ret = libosfp_header_match(libosfp_context, iph, tcph, &result);
|
||||
ret = libosfp_detect(libosfp_context, os_class_flags, iph, tcph, &result);
|
||||
if (ret != 0) {
|
||||
printf("libosfp header match failed, erro: %s\n", "?");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
char srcip[46] = {0}, dstip[46] = {0};
|
||||
Port sp, dp;
|
||||
if (p->iph) {
|
||||
PrintInet(AF_INET, (const void *)&(p->src.addr_data32[0]), srcip, sizeof(srcip));
|
||||
PrintInet(AF_INET, (const void *)&(p->dst.addr_data32[0]), dstip, sizeof(dstip));
|
||||
} else if (p->ip6h) {
|
||||
PrintInet(AF_INET6, (const void *)&(p->src.address), srcip, sizeof(srcip));
|
||||
PrintInet(AF_INET6, (const void *)&(p->dst.address), dstip, sizeof(dstip));
|
||||
}
|
||||
sp = p->sp;
|
||||
dp = p->dp;
|
||||
|
||||
printf("Connection info: %s:%d -> %s:%d\n", srcip, sp, dstip, dp);
|
||||
printf("Connection info: %s:%d -> %s:%d\n", p->srcip, p->sp, p->dstip, p->dp);
|
||||
printf("Most likely os class: %s\n", libosfp_result_likely_os_class_name_get(&result));
|
||||
printf("Likely score: %u/100\n", libosfp_result_likely_os_class_score_get(&result));
|
||||
printf("Likely score: %u/100\n", result.score.likely_score);
|
||||
|
||||
libosfp_result_to_buf(&result, str_buf, sizeof(str_buf));
|
||||
fprintf(stdout, "%s\n", str_buf);
|
||||
printf("Details:\n");
|
||||
if (libosfp_result_to_buf(&result, str_buf, sizeof(str_buf))) {
|
||||
printf("%s", str_buf);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void example_fingerprint_match(libosfp_context_t *libosfp_context, Packet *p)
|
||||
void example_detect_fingerprint(libosfp_context_t *libosfp_context, Packet *p)
|
||||
{
|
||||
// fingerprint match
|
||||
int ret;
|
||||
char str_buf[1024];
|
||||
|
||||
@@ -479,8 +474,9 @@ void example_fingerprint_match(libosfp_context_t *libosfp_context, Packet *p)
|
||||
libosfp_result_t result;
|
||||
libosfp_fingerprint_t fp;
|
||||
|
||||
printf("Example fingerprint match: --------------------------\n");
|
||||
|
||||
// fingerprinting
|
||||
printf("Example fingerprint detect: --------------------------\n");
|
||||
memset(&fp, 0, sizeof(libosfp_fingerprint_t));
|
||||
ret = libosfp_fingerprinting(iph, tcph, &fp);
|
||||
if (ret != 0) {
|
||||
printf("libosfp fingerprinting failed\n");
|
||||
@@ -488,20 +484,31 @@ void example_fingerprint_match(libosfp_context_t *libosfp_context, Packet *p)
|
||||
}
|
||||
|
||||
libosfp_fingerprint_to_json_buf(&fp, str_buf, sizeof(str_buf));
|
||||
fprintf(stdout, "%s\n", str_buf);
|
||||
printf("%s\n", str_buf);
|
||||
|
||||
ret = libosfp_score_db_score(libosfp_context, &fp, &result);
|
||||
// output fingerprint with connection info line
|
||||
if (fingerprinting_output_fp) {
|
||||
fprintf(fingerprinting_output_fp, "Connection info: %s:%d -> %s:%d\n", p->srcip, p->sp, p->dstip, p->dp);
|
||||
fprintf(fingerprinting_output_fp, "%s\n", str_buf);
|
||||
fflush(fingerprinting_output_fp);
|
||||
}
|
||||
|
||||
// score
|
||||
memset(&result, 0, sizeof(libosfp_result_t));
|
||||
ret = libosfp_score_db_score(libosfp_context->score_db, 0, &fp, &result.score);
|
||||
if (ret != 0) {
|
||||
printf("libosfp fingerprint score failed, error: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf("Connection info: %s\n", "");
|
||||
printf("Connection info: %s:%d -> %s:%d\n", p->srcip, p->sp, p->dstip, p->dp);
|
||||
printf("Most likely os class: %s\n", libosfp_result_likely_os_class_name_get(&result));
|
||||
printf("Likely score: %u/100\n", libosfp_result_likely_os_class_score_get(&result));
|
||||
printf("Likely score: %u/100\n", result.score.likely_score);
|
||||
|
||||
libosfp_result_to_buf(&result, str_buf, sizeof(str_buf));
|
||||
fprintf(stdout, "%s\n", str_buf);
|
||||
printf("Details:\n");
|
||||
if (libosfp_result_to_buf(&result, str_buf, sizeof(str_buf))) {
|
||||
printf("%s", str_buf);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -524,9 +531,19 @@ void process_packet(char *user, struct pcap_pkthdr *h, u_char *pkt)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
example_header_match(libosfp_context, p);
|
||||
if (p->iph) {
|
||||
PrintInet(AF_INET, (const void *)&(p->src.addr_data32[0]), p->srcip, sizeof(p->srcip));
|
||||
PrintInet(AF_INET, (const void *)&(p->dst.addr_data32[0]), p->dstip, sizeof(p->dstip));
|
||||
} else if (p->ip6h) {
|
||||
PrintInet(AF_INET6, (const void *)&(p->src.address), p->srcip, sizeof(p->srcip));
|
||||
PrintInet(AF_INET6, (const void *)&(p->dst.address), p->dstip, sizeof(p->dstip));
|
||||
}
|
||||
|
||||
example_fingerprint_match(libosfp_context, p);
|
||||
// fingerprint detect example for libosfp developer
|
||||
example_detect_fingerprint(libosfp_context, p);
|
||||
|
||||
// tcp/ip header detect example for user
|
||||
example_detect(libosfp_context, p);
|
||||
|
||||
printf("--------------------------- processed packet count %d\n", ++processed_packet);
|
||||
|
||||
@@ -538,14 +555,14 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
|
||||
while ((r = getopt(argc, argv, "+f:i:r:")) != -1) {
|
||||
while ((r = getopt(argc, argv, "+f:i:r:o:")) != -1) {
|
||||
switch(r) {
|
||||
case 'f':
|
||||
if (fp_file) {
|
||||
if (fp_file_path) {
|
||||
printf("Multiple -f options not supported.\n");
|
||||
exit(1);
|
||||
}
|
||||
fp_file = (unsigned char*)optarg;
|
||||
fp_file_path = (unsigned char*)optarg;
|
||||
break;
|
||||
case 'i':
|
||||
if (if_name) {
|
||||
@@ -561,6 +578,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
pcap_file_name = (unsigned char*)optarg;
|
||||
break;
|
||||
case 'o':
|
||||
if (fp_output_file_path) {
|
||||
printf("Multiple -o options not supported.\n");
|
||||
exit(1);
|
||||
}
|
||||
fp_output_file_path = (unsigned char*)optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
@@ -576,6 +600,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// fingerprinting out file create
|
||||
if (fp_output_file_path) {
|
||||
fingerprinting_output_fp = fopen(fp_output_file_path, "a+");
|
||||
if (!fingerprinting_output_fp) {
|
||||
printf("No such file: %s\n", fp_output_file_path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare pcap handle
|
||||
|
||||
char pcap_err[PCAP_ERRBUF_SIZE];
|
||||
@@ -621,13 +654,14 @@ int main(int argc, char *argv[])
|
||||
link_type = pcap_datalink(pcap_handle);
|
||||
|
||||
// create libosfp context
|
||||
if (fp_file == NULL) {
|
||||
fp_file = DEFAULT_FP_FILE;
|
||||
if (fp_file_path == NULL) {
|
||||
fp_file_path = DEFAULT_FP_FILE_PATH;
|
||||
}
|
||||
|
||||
libosfp_context_t *libosfp_context = libosfp_context_create(fp_file);
|
||||
//libosfp_context_t *libosfp_context = libosfp_context_create(fp_file_path);
|
||||
libosfp_context_t *libosfp_context = libosfp_context_create(NULL);
|
||||
if (libosfp_context == NULL) {
|
||||
printf("could not create libosfp context. fingerprints file: %s\n", fp_file);
|
||||
printf("could not create libosfp context. fingerprints file: %s\n", fp_file_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -635,9 +669,12 @@ int main(int argc, char *argv[])
|
||||
r = libosfp_context_setup(libosfp_context);
|
||||
if (r != LIBOSFP_NOERR) {
|
||||
printf("could not setup libosfp context. error: %d\n", LIBOSFP_NOERR);
|
||||
libosfp_context_destroy(libosfp_context);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
libosfp_score_db_debug_print(libosfp_context->score_db);
|
||||
|
||||
// loop
|
||||
while (1) {
|
||||
int r = pcap_dispatch(pcap_handle, 0, (pcap_handler)process_packet, (void*)libosfp_context);
|
||||
@@ -647,7 +684,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// create libosfp context
|
||||
// destroy libosfp context
|
||||
libosfp_context_destroy(libosfp_context);
|
||||
|
||||
return 0;
|
||||
|
||||
38
gen_c.sh
Executable file
38
gen_c.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
which jq >& /dev/null || (echo "error: ${0} require system command \"jq\"." && exit)
|
||||
|
||||
DEFAULT_FINGERPRINTS=$1
|
||||
if [[ ${DEFAULT_FINGERPRINTS} == "" ]]; then
|
||||
DEFAULT_FINGERPRINTS="./fp.json"
|
||||
fi
|
||||
|
||||
C_FILE_PATH=$2
|
||||
if [[ ${DEFAULT_FILE_PATH} == "" ]]; then
|
||||
C_FILE_PATH=src
|
||||
fi
|
||||
|
||||
C_INCLUDE_FILE="${C_FILE_PATH}/libosfp_default_fingerprints.h"
|
||||
C_SOURCE_FILE="${C_FILE_PATH}/libosfp_default_fingerprints.c"
|
||||
|
||||
|
||||
|
||||
cat > ${C_INCLUDE_FILE} <<EOF
|
||||
// File generated by gen_c.sh
|
||||
#ifndef _LIBOSFP_DEFAULT_FINGERPRINTS_H__
|
||||
#define _LIBOSFP_DEFAULT_FINGERPRINTS_H__
|
||||
extern const char *g_default_fingerprints;
|
||||
#endif
|
||||
EOF
|
||||
|
||||
|
||||
cat > ${C_SOURCE_FILE} <<EOF
|
||||
// File generated by gen_c.sh
|
||||
const char *g_default_fingerprints =
|
||||
EOF
|
||||
|
||||
jq -c . ${DEFAULT_FINGERPRINTS} | jq -R >> ${C_SOURCE_FILE}
|
||||
|
||||
cat >> ${C_SOURCE_FILE} <<EOF
|
||||
;
|
||||
EOF
|
||||
@@ -9,10 +9,16 @@ libosfp_la_SOURCES = \
|
||||
utstring.h \
|
||||
cJSON.h \
|
||||
cJSON.c \
|
||||
libosfp_common.h \
|
||||
libosfp_common.c \
|
||||
libosfp_default_fingerprints.h \
|
||||
libosfp_default_fingerprints.c \
|
||||
libosfp.h \
|
||||
libosfp.c \
|
||||
libosfp_fingerprint.h \
|
||||
libosfp_fingerprint.c \
|
||||
libosfp_log.h \
|
||||
libosfp_log.c \
|
||||
libosfp_score_db.h \
|
||||
libosfp_score_db.c
|
||||
|
||||
|
||||
120
src/libosfp.c
120
src/libosfp.c
@@ -1,77 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_fingerprint.h"
|
||||
#include "libosfp_score_db.h"
|
||||
#include "libosfp_log.h"
|
||||
|
||||
#define LIBOSFP_OS_CLASS_NAME_WINDOWS "Windows"
|
||||
#define LIBOSFP_OS_CLASS_NAME_LINUX "Linux"
|
||||
#define LIBOSFP_OS_CLASS_NAME_MAC_OS "Mac OS"
|
||||
#define LIBOSFP_OS_CLASS_NAME_IOS "iOS"
|
||||
#define LIBOSFP_OS_CLASS_NAME_ANDROID "Android"
|
||||
|
||||
#define LIBOSFP_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)
|
||||
|
||||
|
||||
const char *os_class_name[LIBOSFP_OS_CLASS_MAX] = {
|
||||
LIBOSFP_OS_CLASS_NAME_WINDOWS,
|
||||
LIBOSFP_OS_CLASS_NAME_LINUX,
|
||||
LIBOSFP_OS_CLASS_NAME_MAC_OS,
|
||||
LIBOSFP_OS_CLASS_NAME_IOS,
|
||||
LIBOSFP_OS_CLASS_NAME_ANDROID
|
||||
};
|
||||
|
||||
libosfp_os_class_id_t libosfp_os_class_name_to_id(char *name)
|
||||
{
|
||||
libosfp_os_class_id_t os_class;
|
||||
|
||||
if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_WINDOWS, strlen(LIBOSFP_OS_CLASS_NAME_WINDOWS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_WINDOWS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_LINUX, strlen(LIBOSFP_OS_CLASS_NAME_LINUX))) {
|
||||
os_class = LIBOSFP_OS_CLASS_Linux;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_MAC_OS, strlen(LIBOSFP_OS_CLASS_NAME_MAC_OS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_MAC_OS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_IOS, strlen(LIBOSFP_OS_CLASS_NAME_IOS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_IOS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_ANDROID, strlen(LIBOSFP_OS_CLASS_NAME_ANDROID))) {
|
||||
os_class = LIBOSFP_OS_CLASS_ANDROID;
|
||||
} else {
|
||||
os_class = LIBOSFP_OS_CLASS_MAX;
|
||||
}
|
||||
|
||||
return os_class;
|
||||
}
|
||||
|
||||
const char *libosfp_os_class_id_to_name(libosfp_os_class_id_t os_class)
|
||||
{
|
||||
if (os_class < 0 || os_class >= LIBOSFP_OS_CLASS_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return os_class_name[os_class];
|
||||
}
|
||||
|
||||
const char *libosfp_result_likely_os_class_name_get(libosfp_result_t *result)
|
||||
{
|
||||
libosfp_os_class_id_t os_class;
|
||||
@@ -80,50 +11,45 @@ const char *libosfp_result_likely_os_class_name_get(libosfp_result_t *result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_class = result->likely_os_class;
|
||||
os_class = result->score.likely_os_class;
|
||||
if (os_class < 0 || os_class >= LIBOSFP_OS_CLASS_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return os_class_name[os_class];
|
||||
}
|
||||
|
||||
unsigned int libosfp_result_likely_os_class_score_get(libosfp_result_t *result)
|
||||
{
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result->likely_score;
|
||||
return libosfp_os_class_id_to_name(os_class);
|
||||
}
|
||||
|
||||
int libosfp_result_to_buf(libosfp_result_t *result, char *strbuf, unsigned int buf_len)
|
||||
{
|
||||
int ret, offset = 0, i;
|
||||
libosfp_os_class_id_t likely_os_class;
|
||||
|
||||
if (result == NULL || strbuf == NULL || buf_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
likely_os_class = result->score.likely_os_class;
|
||||
if (likely_os_class < 0 || likely_os_class >= LIBOSFP_OS_CLASS_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBOSFP_WRITE_STRING_TO_BUF(ret, strbuf, buf_len, offset,
|
||||
"Most likely os class: %s\nLikely score: %u/100\n",
|
||||
os_class_name[result->likely_os_class], result->likely_score);
|
||||
|
||||
LIBOSFP_WRITE_STRING_TO_BUF(ret, strbuf, buf_len, offset,"Details:\n");
|
||||
libosfp_os_class_id_to_name(likely_os_class), result->score.likely_score);
|
||||
|
||||
for (i = 0; i < LIBOSFP_OS_CLASS_MAX; i++) {
|
||||
LIBOSFP_WRITE_STRING_TO_BUF(ret, strbuf, buf_len, offset,"%s score: %u\n",
|
||||
os_class_name[i], result->score.os_class_score[i]);
|
||||
libosfp_os_class_id_to_name(i), result->score.os_class_score[i]);
|
||||
}
|
||||
|
||||
exit:
|
||||
return offset;
|
||||
}
|
||||
|
||||
libosfp_error_code_t libosfp_header_match(libosfp_context_t *libosfp_context, unsigned char *ip_hdr, unsigned char *tcp_hdr, libosfp_result_t *result)
|
||||
libosfp_error_code_t libosfp_detect(libosfp_context_t *libosfp_context, unsigned int flags, unsigned char *ip_hdr, unsigned char *tcp_hdr, libosfp_result_t *result)
|
||||
{
|
||||
int ret = LIBOSFP_EINVAL;
|
||||
libosfp_fingerprint_t fp = {0};
|
||||
libosfp_fingerprint_t fp;
|
||||
|
||||
if (libosfp_context == NULL || ip_hdr == NULL || tcp_hdr == NULL || result == NULL) {
|
||||
goto exit;
|
||||
@@ -134,7 +60,7 @@ libosfp_error_code_t libosfp_header_match(libosfp_context_t *libosfp_context, un
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = libosfp_score_db_score(libosfp_context, &fp, result);
|
||||
ret = libosfp_score_db_score(libosfp_context->score_db, flags, &fp, &result->score);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -164,20 +90,22 @@ exit:
|
||||
|
||||
libosfp_context_t *libosfp_context_create(char *fp_file)
|
||||
{
|
||||
libosfp_context_t *libosfp_context = NULL;
|
||||
libosfp_context_t *libosfp_context;
|
||||
|
||||
if (fp_file == NULL || 0 != access(fp_file, R_OK)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
libosfp_context = malloc(sizeof(libosfp_context_t));
|
||||
libosfp_context = calloc(1, sizeof(libosfp_context_t));
|
||||
if (libosfp_context == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
libosfp_context->fp_file = strdup((const char*)fp_file);
|
||||
if (libosfp_context->fp_file == NULL) {
|
||||
goto exit;
|
||||
if (fp_file != NULL) {
|
||||
if (0 != access(fp_file, R_OK)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
libosfp_context->fp_file = strdup((const char*)fp_file);
|
||||
if (libosfp_context->fp_file == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
libosfp_context->score_db = (void *)libosfp_score_db_create();
|
||||
|
||||
@@ -1,32 +1,10 @@
|
||||
#ifndef __LIBOSFP_H__
|
||||
#define __LIBOSFP_H__
|
||||
|
||||
typedef enum libosfp_error_code {
|
||||
LIBOSFP_NOERR,
|
||||
LIBOSFP_EINVAL,
|
||||
LIBOSFP_ERR_READ_FILE,
|
||||
LIBOSFP_ERR_PARSE_FILE,
|
||||
} libosfp_error_code_t;
|
||||
|
||||
typedef enum libosfp_os_class_id {
|
||||
LIBOSFP_OS_CLASS_WINDOWS,
|
||||
LIBOSFP_OS_CLASS_Linux,
|
||||
LIBOSFP_OS_CLASS_MAC_OS,
|
||||
LIBOSFP_OS_CLASS_IOS,
|
||||
LIBOSFP_OS_CLASS_ANDROID,
|
||||
LIBOSFP_OS_CLASS_MAX,
|
||||
} libosfp_os_class_id_t;
|
||||
|
||||
typedef struct libosfp_score {
|
||||
unsigned int os_class_score[LIBOSFP_OS_CLASS_MAX];
|
||||
} libosfp_score_t;
|
||||
#include "libosfp_common.h"
|
||||
|
||||
typedef struct libosfp_result {
|
||||
enum libosfp_error_code err;
|
||||
enum libosfp_os_class_id likely_os_class; // top rated os class
|
||||
unsigned int likely_score;
|
||||
unsigned int perfect_score;
|
||||
libosfp_score_t score;
|
||||
libosfp_score_t score;
|
||||
} libosfp_result_t;
|
||||
|
||||
typedef struct libosfp_context {
|
||||
@@ -34,15 +12,10 @@ typedef struct libosfp_context {
|
||||
void *score_db;
|
||||
} libosfp_context_t;
|
||||
|
||||
|
||||
libosfp_os_class_id_t libosfp_os_class_name_to_id(char *name);
|
||||
const char *libosfp_os_class_id_to_name(libosfp_os_class_id_t os_class);
|
||||
|
||||
int libosfp_result_to_buf(libosfp_result_t *result, char *strbuf, unsigned int buf_len);
|
||||
unsigned int libosfp_result_likely_os_class_score_get(libosfp_result_t *result);
|
||||
const char *libosfp_result_likely_os_class_name_get(libosfp_result_t *result);
|
||||
|
||||
libosfp_error_code_t libosfp_header_match(libosfp_context_t *libosfp_context, unsigned char *ip_hdr, unsigned char *tcp_hdr, libosfp_result_t *result);
|
||||
libosfp_error_code_t libosfp_detect(libosfp_context_t *libosfp_context, unsigned int flags, unsigned char *ip_hdr, unsigned char *tcp_hdr, libosfp_result_t *result);
|
||||
libosfp_error_code_t libosfp_context_setup(libosfp_context_t *libosfp_context);
|
||||
libosfp_context_t *libosfp_context_create(char *fp_file);
|
||||
void libosfp_context_destroy(libosfp_context_t *libosfp_context);
|
||||
|
||||
36
src/libosfp_common.c
Normal file
36
src/libosfp_common.c
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "libosfp_common.h"
|
||||
|
||||
const char *os_class_name[LIBOSFP_OS_CLASS_MAX] = {
|
||||
LIBOSFP_OS_CLASS_NAME_WINDOWS,
|
||||
LIBOSFP_OS_CLASS_NAME_LINUX,
|
||||
LIBOSFP_OS_CLASS_NAME_MAC_OS,
|
||||
LIBOSFP_OS_CLASS_NAME_IOS,
|
||||
LIBOSFP_OS_CLASS_NAME_ANDROID
|
||||
};
|
||||
|
||||
libosfp_os_class_id_t libosfp_os_class_name_to_id(char *name)
|
||||
{
|
||||
libosfp_os_class_id_t os_class;
|
||||
|
||||
if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_WINDOWS, strlen(LIBOSFP_OS_CLASS_NAME_WINDOWS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_WINDOWS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_LINUX, strlen(LIBOSFP_OS_CLASS_NAME_LINUX))) {
|
||||
os_class = LIBOSFP_OS_CLASS_LINUX;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_MAC_OS, strlen(LIBOSFP_OS_CLASS_NAME_MAC_OS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_MAC_OS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_IOS, strlen(LIBOSFP_OS_CLASS_NAME_IOS))) {
|
||||
os_class = LIBOSFP_OS_CLASS_IOS;
|
||||
} else if (0 == strncmp(name, LIBOSFP_OS_CLASS_NAME_ANDROID, strlen(LIBOSFP_OS_CLASS_NAME_ANDROID))) {
|
||||
os_class = LIBOSFP_OS_CLASS_ANDROID;
|
||||
} else {
|
||||
os_class = LIBOSFP_OS_CLASS_MAX;
|
||||
}
|
||||
|
||||
return os_class;
|
||||
}
|
||||
|
||||
const char *libosfp_os_class_id_to_name(libosfp_os_class_id_t os_class)
|
||||
{
|
||||
return os_class_name[os_class];
|
||||
}
|
||||
|
||||
142
src/libosfp_common.h
Normal file
142
src/libosfp_common.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef __LIBOSFP_COMMON_H__
|
||||
#define __LIBOSFP_COMMON_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "utarray.h"
|
||||
#include "uthash.h"
|
||||
#include "utlist.h"
|
||||
#include "utringbuffer.h"
|
||||
#include "utstack.h"
|
||||
#include "utstring.h"
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#define LIBOSFP_OS_CLASS_NAME_WINDOWS "Windows"
|
||||
#define LIBOSFP_OS_CLASS_NAME_LINUX "Linux"
|
||||
#define LIBOSFP_OS_CLASS_NAME_MAC_OS "Mac OS"
|
||||
#define LIBOSFP_OS_CLASS_NAME_IOS "iOS"
|
||||
#define LIBOSFP_OS_CLASS_NAME_ANDROID "Android"
|
||||
|
||||
#define LIBOSFP_TCP_OPTLENMAX 64
|
||||
#define LIBOSFP_TCP_OPTMAX 20
|
||||
|
||||
#define LIBOSFP_ETHERNET_HEADER_LEN 14
|
||||
#define LIBOSFP_VLAN_HEADER_LEN 4
|
||||
#define LIBOSFP_IPV4_HEADER_LEN 20
|
||||
#define LIBOSFP_IPV6_HEADER_LEN 40
|
||||
#define LIBOSFP_TCP_HEADER_LEN 20
|
||||
|
||||
|
||||
//# TCP Options (opt_type) - http://www.iana.org/assignments/tcp-parameters
|
||||
#define LIBOSFP_TCP_OPT_EOL 0 //# end of option list
|
||||
#define LIBOSFP_TCP_OPT_NOP 1 //# no operation
|
||||
#define LIBOSFP_TCP_OPT_MSS 2 //# maximum segment size
|
||||
#define LIBOSFP_TCP_OPT_WSCALE 3 //# window scale factor, RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_SACKOK 4 //# SACK permitted, RFC 2018
|
||||
#define LIBOSFP_TCP_OPT_SACK 5 //# SACK, RFC 2018
|
||||
#define LIBOSFP_TCP_OPT_ECHO 6 //# echo (obsolete), RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_ECHOREPLY 7 //# echo reply (obsolete), RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_TIMESTAMP 8 //# timestamps, RFC 1323
|
||||
#define LIBOSFP_TCP_OPT_POCONN 9 //# partial order conn, RFC 1693
|
||||
#define LIBOSFP_TCP_OPT_POSVC 10 //# partial order service, RFC 1693
|
||||
#define LIBOSFP_TCP_OPT_CC 11 //# connection count, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_CCNEW 12 //# CC.NEW, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_CCECHO 13 //# CC.ECHO, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_ALTSUM 14 //# alt checksum request, RFC 1146
|
||||
#define LIBOSFP_TCP_OPT_ALTSUMDATA 15 //# alt checksum data, RFC 1146
|
||||
#define LIBOSFP_TCP_OPT_SKEETER 16 //# Skeeter
|
||||
#define LIBOSFP_TCP_OPT_BUBBA 17 //# Bubba
|
||||
#define LIBOSFP_TCP_OPT_TRAILSUM 18 //# trailer checksum
|
||||
#define LIBOSFP_TCP_OPT_MD5 19 //# MD5 signature, RFC 2385
|
||||
#define LIBOSFP_TCP_OPT_SCPS 20 //# SCPS capabilities
|
||||
#define LIBOSFP_TCP_OPT_SNACK 21 //# selective negative acks
|
||||
#define LIBOSFP_TCP_OPT_REC 22 //# record boundaries
|
||||
#define LIBOSFP_TCP_OPT_CORRUPT 23 //# corruption experienced
|
||||
#define LIBOSFP_TCP_OPT_SNAP 24 //# SNAP
|
||||
#define LIBOSFP_TCP_OPT_TCPCOMP 26 //# TCP compression filter
|
||||
#define LIBOSFP_TCP_OPT_MAX 27 //# Quick-Start Response
|
||||
#define LIBOSFP_TCP_OPT_USRTO 28 //# User Timeout Option (also, other known unauthorized use) [***][1] [RFC5482]
|
||||
#define LIBOSFP_TCP_OPT_AUTH 29 //# TCP Authentication Option (TCP-AO) [RFC5925]
|
||||
#define LIBOSFP_TCP_OPT_MULTIPATH 30 //# Multipath TCP (MPTCP)
|
||||
#define LIBOSFP_TCP_OPT_FASTOPEN 34 //# TCP Fast Open Cookie [RFC7413]
|
||||
#define LIBOSFP_TCP_OPY_ENCNEG 69 //# Encryption Negotiation (TCP-ENO) [RFC8547]
|
||||
#define LIBOSFP_TCP_OPT_EXP1 253 //# RFC3692-style Experiment 1 (also improperly used for shipping products)
|
||||
#define LIBOSFP_TCP_OPT_EXP2 254 //# RFC3692-style Experiment 2 (also improperly used for shipping products)
|
||||
|
||||
#define LIBOSFP_TCP_OPT_SACKOK_LEN 2
|
||||
#define LIBOSFP_TCP_OPT_WS_LEN 3
|
||||
#define LIBOSFP_TCP_OPT_TS_LEN 10
|
||||
#define LIBOSFP_TCP_OPT_MSS_LEN 4
|
||||
#define LIBOSFP_TCP_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */
|
||||
#define LIBOSFP_TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */
|
||||
#define LIBOSFP_TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */
|
||||
#define LIBOSFP_TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */
|
||||
|
||||
|
||||
#define LIBOSFP_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)
|
||||
|
||||
#define LIBOSFP_BIT_U32(n) (1UL << (n))
|
||||
|
||||
typedef enum libosfp_error_code {
|
||||
LIBOSFP_NOERR,
|
||||
LIBOSFP_EINVAL,
|
||||
LIBOSFP_ENOMEM,
|
||||
LIBOSFP_ERR_SCORE_DB_READ_FILE,
|
||||
LIBOSFP_ERR_SCORE_DB_PARSE_FILE,
|
||||
LIBOSFP_ERR_SCORE_DB_UNSUPPORTED,
|
||||
|
||||
LIBOSFP_ERR_FINGERPRINTING_UNSUPPORTED,
|
||||
|
||||
} libosfp_error_code_t;
|
||||
|
||||
typedef enum libosfp_os_class_id {
|
||||
LIBOSFP_OS_CLASS_WINDOWS,
|
||||
LIBOSFP_OS_CLASS_LINUX,
|
||||
LIBOSFP_OS_CLASS_MAC_OS,
|
||||
LIBOSFP_OS_CLASS_IOS,
|
||||
LIBOSFP_OS_CLASS_ANDROID,
|
||||
LIBOSFP_OS_CLASS_MAX,
|
||||
} libosfp_os_class_id_t;
|
||||
|
||||
#define LIBOSFP_OS_CLASS_FLAG_WINDOWS LIBOSFP_BIT_U32(LIBOSFP_OS_CLASS_WINDOWS)
|
||||
#define LIBOSFP_OS_CLASS_FLAG_LINUX LIBOSFP_BIT_U32(LIBOSFP_OS_CLASS_LINUX)
|
||||
#define LIBOSFP_OS_CLASS_FLAG_MAC_OS LIBOSFP_BIT_U32(LIBOSFP_OS_CLASS_MAC_OS)
|
||||
#define LIBOSFP_OS_CLASS_FLAG_IOS LIBOSFP_BIT_U32(LIBOSFP_OS_CLASS_IOS)
|
||||
#define LIBOSFP_OS_CLASS_FLAG_ANDROID LIBOSFP_BIT_U32(LIBOSFP_OS_CLASS_ANDROID)
|
||||
|
||||
typedef struct libosfp_score {
|
||||
unsigned int likely_os_class;
|
||||
unsigned int likely_score;
|
||||
unsigned int os_class_score[LIBOSFP_OS_CLASS_MAX];
|
||||
} libosfp_score_t;
|
||||
|
||||
libosfp_os_class_id_t libosfp_os_class_name_to_id(char *name);
|
||||
const char *libosfp_os_class_id_to_name(libosfp_os_class_id_t os_class);
|
||||
|
||||
#endif
|
||||
4
src/libosfp_default_fingerprints.c
Normal file
4
src/libosfp_default_fingerprints.c
Normal file
File diff suppressed because one or more lines are too long
5
src/libosfp_default_fingerprints.h
Normal file
5
src/libosfp_default_fingerprints.h
Normal file
@@ -0,0 +1,5 @@
|
||||
// File generated by gen_c.sh
|
||||
#ifndef _LIBOSFP_DEFAULT_FINGERPRINTS_H__
|
||||
#define _LIBOSFP_DEFAULT_FINGERPRINTS_H__
|
||||
extern const char *g_default_fingerprints;
|
||||
#endif
|
||||
@@ -1,25 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_common.h"
|
||||
#include "libosfp_fingerprint.h"
|
||||
#include "libosfp_log.h"
|
||||
|
||||
#define LIBOSFP_ETHERNET_HEADER_LEN 14
|
||||
#define LIBOSFP_VLAN_HEADER_LEN 4
|
||||
#define LIBOSFP_IPV4_HEADER_LEN 20
|
||||
#define LIBOSFP_IPV6_HEADER_LEN 40
|
||||
#define LIBOSFP_TCP_HEADER_LEN 20
|
||||
|
||||
#define LIBOSFP_FINGERPRINT_FIELD_NAME_IP_ID "ip_id"
|
||||
#define LIBOSFP_FINGERPRINT_FIELD_NAME_IP_TOS "ip_tos"
|
||||
@@ -36,6 +18,7 @@
|
||||
#define LIBOSFP_FINGERPRINT_FIELD_NAME_TCP_OPTIONS_ORDERED "tcp_options_ordered"
|
||||
#define LIBOSFP_FINGERPRINT_FIELD_NAME_OS "os"
|
||||
|
||||
#define LIBOSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME "LIBOSFP_UNKNOWN"
|
||||
|
||||
typedef struct libosfp_tcp_opt {
|
||||
unsigned char type;
|
||||
@@ -98,7 +81,7 @@ static unsigned int compute_ip_ttl(unsigned int ip_ttl)
|
||||
ip_ttl = 64;
|
||||
} else if (ip_ttl > 64 && ip_ttl <= 128) {
|
||||
ip_ttl = 128;
|
||||
} else if (ip_ttl > 128) {
|
||||
} else {
|
||||
ip_ttl = 255;
|
||||
}
|
||||
return ip_ttl;
|
||||
@@ -109,11 +92,11 @@ static unsigned int decode_tcp_options(libosfp_tcp_opt_t *tcp_opts, unsigned int
|
||||
unsigned int offset = 0;
|
||||
unsigned int tcp_opt_cnt = 0;
|
||||
|
||||
while (offset < len && tcp_opt_cnt < max_opt_cnt) {
|
||||
unsigned char type;
|
||||
unsigned char olen;
|
||||
unsigned char *odata;
|
||||
unsigned char type;
|
||||
unsigned char olen;
|
||||
unsigned char *odata;
|
||||
|
||||
while (offset < len && tcp_opt_cnt < max_opt_cnt) {
|
||||
type = *(data + offset);
|
||||
|
||||
if (type == LIBOSFP_TCP_OPT_EOL || type == LIBOSFP_TCP_OPT_NOP) {
|
||||
@@ -217,15 +200,9 @@ void libosfp_fingerprint_setup_field(libosfp_fingerprint_t *fp, libosfp_field_id
|
||||
}
|
||||
}
|
||||
|
||||
void libosfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, libosfp_fingerprint_t *fp)
|
||||
void libosfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_len, libosfp_fingerprint_t *fp)
|
||||
{
|
||||
int ret,i;
|
||||
char options[LIBOSFP_TCP_OPTLENMAX];
|
||||
char options_ordered[LIBOSFP_TCP_OPTLENMAX];
|
||||
unsigned int maxoffset = sizeof(options) - 3;
|
||||
unsigned int ordered_maxoffset = sizeof(options_ordered) - 1;
|
||||
unsigned int offset = 0;
|
||||
unsigned int ordered_offset = 0;
|
||||
|
||||
unsigned int tcp_mss;
|
||||
unsigned int tcp_ws;
|
||||
@@ -233,7 +210,14 @@ void libosfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen,
|
||||
unsigned int tcp_opt_cnt;
|
||||
libosfp_tcp_opt_t tcp_opts[LIBOSFP_TCP_OPTMAX];
|
||||
|
||||
tcp_opt_cnt = decode_tcp_options(tcp_opts, LIBOSFP_TCP_OPTMAX, pkt, pktlen);
|
||||
char options[LIBOSFP_TCP_OPTLENMAX];
|
||||
char options_ordered[LIBOSFP_TCP_OPTLENMAX];
|
||||
unsigned int offset = 0;
|
||||
unsigned int maxoffset = sizeof(options) - 3; //for shortest "E,"
|
||||
unsigned int ordered_offset = 0;
|
||||
unsigned int ordered_maxoffset = sizeof(options_ordered) - 1;
|
||||
|
||||
tcp_opt_cnt = decode_tcp_options(tcp_opts, LIBOSFP_TCP_OPTMAX, opt_data, opt_len);
|
||||
|
||||
for (i = 0; i < tcp_opt_cnt && offset < maxoffset && ordered_offset < ordered_maxoffset; i++) {
|
||||
libosfp_tcp_opt_t *opt = &tcp_opts[i];
|
||||
@@ -324,7 +308,7 @@ int libosfp_fingerprinting_tcp(struct tcphdr *tcph, libosfp_fingerprint_t *fp)
|
||||
|
||||
// tcp options
|
||||
if (tcp_off > LIBOSFP_TCP_HEADER_LEN) {
|
||||
libosfp_fingerprinting_tcp_option((unsigned char *)tcph + LIBOSFP_TCP_HEADER_LEN, tcp_off - LIBOSFP_TCP_HEADER_LEN, fp);
|
||||
libosfp_fingerprinting_tcp_option((unsigned char *)tcph + LIBOSFP_TCP_HEADER_LEN, 20 + tcp_off - LIBOSFP_TCP_HEADER_LEN, fp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -376,7 +360,8 @@ exit:
|
||||
|
||||
int libosfp_fingerprinting(unsigned char *iph, unsigned char *tcph, libosfp_fingerprint_t *fp)
|
||||
{
|
||||
int ret, ip_version;
|
||||
int ret = LIBOSFP_EINVAL;
|
||||
int ip_version;
|
||||
|
||||
if (iph == NULL || tcph == NULL || fp == NULL) {
|
||||
goto exit;
|
||||
@@ -407,7 +392,7 @@ int libosfp_fingerprinting(unsigned char *iph, unsigned char *tcph, libosfp_fing
|
||||
goto exit;
|
||||
}
|
||||
|
||||
libosfp_fingerprint_setup_field(fp, LIBOSFP_FIELD_OS, "", strlen("") + 1);
|
||||
libosfp_fingerprint_setup_field(fp, LIBOSFP_FIELD_OS, LIBOSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME, strlen(LIBOSFP_FINGERPRINT_DEFAULT_OS_CLASS_NAME) + 1);
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
|
||||
@@ -1,59 +1,8 @@
|
||||
#ifndef __LIBOSFP_FINGERPRINT_H__
|
||||
#define __LIBOSFP_FINGERPRINT_H__
|
||||
|
||||
#include "libosfp.h"
|
||||
|
||||
#define LIBOSFP_FINGERPRINT_VALUE_BUFFER_MAX 128
|
||||
|
||||
#define LIBOSFP_TCP_OPTLENMAX 64
|
||||
#define LIBOSFP_TCP_OPTMAX 20
|
||||
|
||||
//# TCP Options (opt_type) - http://www.iana.org/assignments/tcp-parameters
|
||||
#define LIBOSFP_TCP_OPT_EOL 0 //# end of option list
|
||||
#define LIBOSFP_TCP_OPT_NOP 1 //# no operation
|
||||
#define LIBOSFP_TCP_OPT_MSS 2 //# maximum segment size
|
||||
#define LIBOSFP_TCP_OPT_WSCALE 3 //# window scale factor, RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_SACKOK 4 //# SACK permitted, RFC 2018
|
||||
#define LIBOSFP_TCP_OPT_SACK 5 //# SACK, RFC 2018
|
||||
#define LIBOSFP_TCP_OPT_ECHO 6 //# echo (obsolete), RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_ECHOREPLY 7 //# echo reply (obsolete), RFC 1072
|
||||
#define LIBOSFP_TCP_OPT_TIMESTAMP 8 //# timestamps, RFC 1323
|
||||
#define LIBOSFP_TCP_OPT_POCONN 9 //# partial order conn, RFC 1693
|
||||
#define LIBOSFP_TCP_OPT_POSVC 10 //# partial order service, RFC 1693
|
||||
#define LIBOSFP_TCP_OPT_CC 11 //# connection count, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_CCNEW 12 //# CC.NEW, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_CCECHO 13 //# CC.ECHO, RFC 1644
|
||||
#define LIBOSFP_TCP_OPT_ALTSUM 14 //# alt checksum request, RFC 1146
|
||||
#define LIBOSFP_TCP_OPT_ALTSUMDATA 15 //# alt checksum data, RFC 1146
|
||||
#define LIBOSFP_TCP_OPT_SKEETER 16 //# Skeeter
|
||||
#define LIBOSFP_TCP_OPT_BUBBA 17 //# Bubba
|
||||
#define LIBOSFP_TCP_OPT_TRAILSUM 18 //# trailer checksum
|
||||
#define LIBOSFP_TCP_OPT_MD5 19 //# MD5 signature, RFC 2385
|
||||
#define LIBOSFP_TCP_OPT_SCPS 20 //# SCPS capabilities
|
||||
#define LIBOSFP_TCP_OPT_SNACK 21 //# selective negative acks
|
||||
#define LIBOSFP_TCP_OPT_REC 22 //# record boundaries
|
||||
#define LIBOSFP_TCP_OPT_CORRUPT 23 //# corruption experienced
|
||||
#define LIBOSFP_TCP_OPT_SNAP 24 //# SNAP
|
||||
#define LIBOSFP_TCP_OPT_TCPCOMP 26 //# TCP compression filter
|
||||
#define LIBOSFP_TCP_OPT_MAX 27 //# Quick-Start Response
|
||||
#define LIBOSFP_TCP_OPT_USRTO 28 //# User Timeout Option (also, other known unauthorized use) [***][1] [RFC5482]
|
||||
#define LIBOSFP_TCP_OPT_AUTH 29 //# TCP Authentication Option (TCP-AO) [RFC5925]
|
||||
#define LIBOSFP_TCP_OPT_MULTIPATH 30 //# Multipath TCP (MPTCP)
|
||||
#define LIBOSFP_TCP_OPT_FASTOPEN 34 //# TCP Fast Open Cookie [RFC7413]
|
||||
#define LIBOSFP_TCP_OPY_ENCNEG 69 //# Encryption Negotiation (TCP-ENO) [RFC8547]
|
||||
#define LIBOSFP_TCP_OPT_EXP1 253 //# RFC3692-style Experiment 1 (also improperly used for shipping products)
|
||||
#define LIBOSFP_TCP_OPT_EXP2 254 //# RFC3692-style Experiment 2 (also improperly used for shipping products)
|
||||
|
||||
#define LIBOSFP_TCP_OPT_SACKOK_LEN 2
|
||||
#define LIBOSFP_TCP_OPT_WS_LEN 3
|
||||
#define LIBOSFP_TCP_OPT_TS_LEN 10
|
||||
#define LIBOSFP_TCP_OPT_MSS_LEN 4
|
||||
#define LIBOSFP_TCP_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */
|
||||
#define LIBOSFP_TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */
|
||||
#define LIBOSFP_TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */
|
||||
#define LIBOSFP_TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */
|
||||
|
||||
|
||||
typedef enum libosfp_field_id {
|
||||
LIBOSFP_FIELD_IP_ID,
|
||||
LIBOSFP_FIELD_IP_TOS,
|
||||
@@ -99,8 +48,13 @@ char *libosfp_fingerprint_get_field_name(libosfp_field_id_t field_id);
|
||||
unsigned int libosfp_fingerprint_get_field_enabled(libosfp_field_id_t field_id);
|
||||
unsigned int libosfp_fingerprint_get_field_importance(libosfp_field_id_t field_id);
|
||||
unsigned int libosfp_fingerprint_get_field_type(libosfp_field_id_t field_id);
|
||||
|
||||
int libosfp_fingerprint_to_json_buf(libosfp_fingerprint_t *fp, char *strbuf, unsigned int buf_len);
|
||||
void libosfp_fingerprint_setup_field(libosfp_fingerprint_t *fp, libosfp_field_id_t field_id, void *value, unsigned int len);
|
||||
|
||||
void libosfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, libosfp_fingerprint_t *fp);
|
||||
int libosfp_fingerprinting_tcp(struct tcphdr *tcph, libosfp_fingerprint_t *fp);
|
||||
int libosfp_fingerprinting_ipv4(struct iphdr *iph, libosfp_fingerprint_t *fp);
|
||||
int libosfp_fingerprinting_ipv6(struct ipv6hdr *iph, libosfp_fingerprint_t *fp);
|
||||
int libosfp_fingerprinting(unsigned char *iphdr, unsigned char *tcphdr, libosfp_fingerprint_t *fp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_common.h"
|
||||
#include "libosfp_log.h"
|
||||
|
||||
/* The maximum length of the log message */
|
||||
@@ -24,22 +19,22 @@ void libosfp_log_message(unsigned int x, const char *file, const int line, const
|
||||
|
||||
switch (x) {
|
||||
case LIBOSFP_LOG_LEVEL_DEBUG:
|
||||
snprintf(buffer, sizeof(buffer), "[%s][DEBUG][%s:%d %s] %s", log_time_buf, file, line, func, msg);
|
||||
snprintf(buffer, sizeof(buffer), "[%s][DEBUG][%s:%d %s] %s\n", log_time_buf, file, line, func, msg);
|
||||
break;
|
||||
case LIBOSFP_LOG_LEVEL_INFO:
|
||||
snprintf(buffer, sizeof(buffer), "[%s][INFO][%s:%d %s] %s", log_time_buf, file, line, func, msg);
|
||||
snprintf(buffer, sizeof(buffer), "[%s][INFO][%s:%d %s] %s\n", log_time_buf, file, line, func, msg);
|
||||
break;
|
||||
case LIBOSFP_LOG_LEVEL_WARNING:
|
||||
snprintf(buffer, sizeof(buffer), "[%s][WARN][%s:%d %s] %s", log_time_buf, file, line, func, msg);
|
||||
snprintf(buffer, sizeof(buffer), "[%s][WARN][%s:%d %s] %s\n", log_time_buf, file, line, func, msg);
|
||||
break;
|
||||
case LIBOSFP_LOG_LEVEL_ERROR:
|
||||
snprintf(buffer, sizeof(buffer), "[%s][ERROR][%s:%d %s] %s", log_time_buf, file, line, func, msg);
|
||||
snprintf(buffer, sizeof(buffer), "[%s][ERROR][%s:%d %s] %s\n", log_time_buf, file, line, func, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void libosfp_log(unsigned int x, const char *file, const char *func, const int line, const char *fmt, ...)
|
||||
void libosfp_log(unsigned int x, const char *file, const int line, const char *func, const char *fmt, ...)
|
||||
{
|
||||
if (libosfp_log_level >= x ) {
|
||||
char msg[LIBOSFP_MAX_LOG_MSG_LEN];
|
||||
|
||||
@@ -8,13 +8,17 @@ typedef enum libosfp_log_level {
|
||||
LIBOSFP_LOG_LEVEL_ERROR
|
||||
} libosfp_log_level_t;
|
||||
|
||||
#ifndef DEBUG
|
||||
#define libosfp_log_debug(...) do { } while (0)
|
||||
#else
|
||||
#define libosfp_log_debug(...) libosfp_log(LIBOSFP_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
#endif
|
||||
#define libosfp_log_info(...) libosfp_log(LIBOSFP_LOG_LEVEL_INFO, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
#define libosfp_log_warning(...) libosfp_log(LIBOSFP_LOG_LEVEL_WARNING, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
#define libosfp_log_error(...) libosfp_log(LIBOSFP_LOG_LEVEL_ERROR, __FILE__, __LINE__, __FUNCTION__,__VA_ARGS__)
|
||||
|
||||
|
||||
void libosfp_log_level_set(libosfp_log_level_t level);
|
||||
void libosfp_log(unsigned int x, const char *file, const char *func, const int line, const char *fmt, ...);
|
||||
void libosfp_log(unsigned int x, const char *file, const int line, const char *func, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,26 +1,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include "libosfp_common.h"
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "uthash.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_fingerprint.h"
|
||||
#include "libosfp_default_fingerprints.h"
|
||||
#include "libosfp_score_db.h"
|
||||
#include "libosfp_log.h"
|
||||
|
||||
#define LIBOSFP_PERCENTILE 100
|
||||
|
||||
#define LIBOSFP_SCORE_DB_FIELD_UINT_VALUE_MAX 65536
|
||||
|
||||
typedef struct libosfp_score_db_array_data {
|
||||
@@ -353,25 +339,34 @@ exit:
|
||||
int libosfp_score_db_load(libosfp_score_db_t *score_db, char *fp_file)
|
||||
{
|
||||
int ret = LIBOSFP_EINVAL, i;
|
||||
char *file_buffer;
|
||||
const char *file_buffer;
|
||||
libosfp_field_score_db_t *field_score_db;
|
||||
|
||||
cJSON *root = NULL;
|
||||
cJSON *entry = NULL;
|
||||
|
||||
if (score_db == NULL || fp_file == NULL) {
|
||||
if (score_db == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
file_buffer = libosfp_score_db_read_file(fp_file);
|
||||
if (file_buffer == NULL) {
|
||||
ret = LIBOSFP_ERR_READ_FILE;
|
||||
goto exit;
|
||||
if (fp_file == NULL) {
|
||||
file_buffer = g_default_fingerprints;
|
||||
} else {
|
||||
file_buffer = (const char *)libosfp_score_db_read_file(fp_file);
|
||||
if (file_buffer == NULL) {
|
||||
ret = LIBOSFP_ERR_SCORE_DB_READ_FILE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
root = cJSON_Parse(file_buffer);
|
||||
|
||||
if (file_buffer != g_default_fingerprints) {
|
||||
free((char*)file_buffer);
|
||||
}
|
||||
|
||||
if (root == NULL) {
|
||||
ret = LIBOSFP_ERR_PARSE_FILE;
|
||||
ret = LIBOSFP_ERR_SCORE_DB_PARSE_FILE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -389,7 +384,7 @@ int libosfp_score_db_load(libosfp_score_db_t *score_db, char *fp_file)
|
||||
if (entry) {
|
||||
ret = libosfp_score_db_load_entry(score_db, entry);
|
||||
if (ret != 0) {
|
||||
printf("json entry load failed.\n%s\n", cJSON_Print(entry));
|
||||
libosfp_log_debug("json entry load failed.\n%s\n", cJSON_Print(entry));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -397,54 +392,58 @@ int libosfp_score_db_load(libosfp_score_db_t *score_db, char *fp_file)
|
||||
|
||||
cJSON_Delete(root);
|
||||
|
||||
return 0;
|
||||
return LIBOSFP_NOERR;
|
||||
exit:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int libosfp_score_db_score(libosfp_context_t *libosfp_context, libosfp_fingerprint_t *fp, libosfp_result_t *result)
|
||||
int libosfp_score_db_score(libosfp_score_db_t *score_db, unsigned int flags, libosfp_fingerprint_t *fp, libosfp_score_t *result_score)
|
||||
{
|
||||
int ret = -1, i, j;
|
||||
void *field_value;
|
||||
int ret = LIBOSFP_EINVAL, i, j;
|
||||
unsigned int os_class_score;
|
||||
unsigned int likely_score;
|
||||
unsigned int perfect_score;
|
||||
unsigned int entry_count;
|
||||
unsigned int importance;
|
||||
unsigned int field_len;
|
||||
libosfp_score_t *score;
|
||||
libosfp_score_db_t *score_db;
|
||||
libosfp_score_t *matched_score;
|
||||
libosfp_os_class_id_t likely_os_class;
|
||||
libosfp_fingerprint_field_t *field;
|
||||
libosfp_field_score_db_t *field_score_db;
|
||||
|
||||
if (libosfp_context == NULL || fp == NULL || result == NULL) {
|
||||
if (score_db == NULL || fp == NULL || result_score == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(result, 0, sizeof(libosfp_result_t));
|
||||
memset(result_score, 0, sizeof(libosfp_score_t));
|
||||
|
||||
score_db = (libosfp_score_db_t*)libosfp_context->score_db;
|
||||
perfect_score = score_db->perfect_score;
|
||||
if (perfect_score == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < LIBOSFP_FIELD_MAX; i++) {
|
||||
if (!fp->fields[i].enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
field_score_db = &score_db->field_score_dbs[i];
|
||||
if (!field_score_db->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
field_value = fp->fields[i].value;
|
||||
field_len = fp->fields[i].value_len;
|
||||
field = &fp->fields[i];
|
||||
if (!field->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
score = libosfp_score_db_filed_match(field_score_db, field_value, field_len);
|
||||
if (score == NULL) {
|
||||
matched_score = libosfp_score_db_filed_match(field_score_db, field->value, field->value_len);
|
||||
if (matched_score == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
importance = libosfp_fingerprint_get_field_importance(i);
|
||||
|
||||
for (j = 0; j < LIBOSFP_OS_CLASS_MAX; j++) {
|
||||
result->score.os_class_score[j] += score->os_class_score[j] * importance;
|
||||
if (0 == flags || flags & LIBOSFP_BIT_U32(j)) {
|
||||
result_score->os_class_score[j] += matched_score->os_class_score[j] * importance / perfect_score;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == LIBOSFP_FIELD_TCP_OPTIONS) {
|
||||
@@ -452,66 +451,103 @@ int libosfp_score_db_score(libosfp_context_t *libosfp_context, libosfp_fingerpri
|
||||
}
|
||||
}
|
||||
|
||||
likely_score = result_score->likely_score;
|
||||
likely_os_class = result_score->likely_os_class;
|
||||
|
||||
perfect_score = score_db->perfect_score;
|
||||
result->perfect_score = perfect_score;
|
||||
|
||||
for (j = 0; j < LIBOSFP_OS_CLASS_MAX; j++) {
|
||||
entry_count = score_db->os_class_entry_count[j];
|
||||
os_class_score = result->score.os_class_score[j];
|
||||
for (i = 0; i < LIBOSFP_OS_CLASS_MAX; i++) {
|
||||
entry_count = score_db->os_class_entry_count[i];
|
||||
os_class_score = result_score->os_class_score[i];
|
||||
|
||||
if (entry_count == 0 || perfect_score == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
os_class_score = 100 * os_class_score / entry_count;
|
||||
os_class_score = (unsigned int)((float)os_class_score / (float)perfect_score);
|
||||
// calc percentile score
|
||||
os_class_score = (LIBOSFP_PERCENTILE * os_class_score) / entry_count;
|
||||
|
||||
if (result->likely_score < os_class_score) {
|
||||
result->likely_score = os_class_score;
|
||||
result->likely_os_class = j;
|
||||
// calc likely os class and score
|
||||
if (likely_score < os_class_score) {
|
||||
likely_score = os_class_score;
|
||||
likely_os_class = i;
|
||||
}
|
||||
result->score.os_class_score[j] = os_class_score;
|
||||
|
||||
result_score->os_class_score[i] = os_class_score;
|
||||
}
|
||||
|
||||
return 0;
|
||||
result_score->likely_score = likely_score;
|
||||
result_score->likely_os_class = likely_os_class;
|
||||
|
||||
return LIBOSFP_NOERR;
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void libosfp_score_db_debug_print(libosfp_score_db_t *score_db)
|
||||
{
|
||||
int i;
|
||||
printf("score_db:\n");
|
||||
printf("entry_count: %u\n", score_db->entry_count);
|
||||
printf("perfect_score: %u\n", score_db->perfect_score);
|
||||
|
||||
for (i = 0; i < LIBOSFP_OS_CLASS_MAX; i++) {
|
||||
const char *name = libosfp_os_class_id_to_name(i);
|
||||
printf("os class %p ", name);
|
||||
|
||||
printf("entry_count: %u\n", score_db->os_class_entry_count[i]);
|
||||
printf("os class %s entry_count: %u\n", libosfp_os_class_id_to_name(i), score_db->os_class_entry_count[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < LIBOSFP_FIELD_MAX; i++) {
|
||||
printf("field %s enabled: %u\n", libosfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].enabled);
|
||||
printf("field %s type: %u\n", libosfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].type);
|
||||
printf("field %s entry_count: %u\n", libosfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].entry_count);
|
||||
printf("field %s enabled: %p\n", libosfp_fingerprint_get_field_name(i), score_db->field_score_dbs[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
libosfp_score_db_t *libosfp_score_db_create(void)
|
||||
{
|
||||
int ret = -1, i;
|
||||
int i;
|
||||
libosfp_score_db_t *score_db;
|
||||
libosfp_field_score_db_t *db;
|
||||
|
||||
score_db = calloc(1, sizeof(libosfp_score_db_t));
|
||||
if (score_db == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < LIBOSFP_FIELD_MAX; i++) {
|
||||
db = &score_db->field_score_dbs[i];
|
||||
db->enabled = libosfp_fingerprint_get_field_enabled(i);
|
||||
db->type = libosfp_fingerprint_get_field_type(i);
|
||||
|
||||
switch (score_db->field_score_dbs[i].type) {
|
||||
db->enabled = libosfp_fingerprint_get_field_enabled(i);
|
||||
if (!db->enabled) {
|
||||
libosfp_log_warning("field disabled: %s", "");
|
||||
continue;
|
||||
}
|
||||
|
||||
db->type = libosfp_fingerprint_get_field_type(i);
|
||||
switch (db->type) {
|
||||
case LIBOSFP_FIELD_TYPE_UINT:
|
||||
score_db->field_score_dbs[i].create = libosfp_score_db_array_create;
|
||||
score_db->field_score_dbs[i].destroy = libosfp_score_db_array_destroy;
|
||||
score_db->field_score_dbs[i].add = libosfp_score_db_array_add;
|
||||
score_db->field_score_dbs[i].match = libosfp_score_db_array_match;
|
||||
db->create = libosfp_score_db_array_create;
|
||||
db->destroy = libosfp_score_db_array_destroy;
|
||||
db->add = libosfp_score_db_array_add;
|
||||
db->match = libosfp_score_db_array_match;
|
||||
break;
|
||||
case LIBOSFP_FIELD_TYPE_STRING:
|
||||
score_db->field_score_dbs[i].create = libosfp_score_db_hash_create;
|
||||
score_db->field_score_dbs[i].destroy = libosfp_score_db_hash_destroy;
|
||||
score_db->field_score_dbs[i].add = libosfp_score_db_hash_add;
|
||||
score_db->field_score_dbs[i].match = libosfp_score_db_hash_match;
|
||||
db->create = libosfp_score_db_hash_create;
|
||||
db->destroy = libosfp_score_db_hash_destroy;
|
||||
db->add = libosfp_score_db_hash_add;
|
||||
db->match = libosfp_score_db_hash_match;
|
||||
break;
|
||||
default:
|
||||
libosfp_log_debug("unsupported type: %u", db->type);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
db->data = score_db->field_score_dbs[i].create();
|
||||
db->data = db->create();
|
||||
if (db->data == NULL) {
|
||||
continue;
|
||||
libosfp_log_debug("create failed. field: %s", libosfp_fingerprint_get_field_name(i));
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __LIBOSFP_SCORE_DB_H__
|
||||
#define __LIBOSFP_SCORE_DB_H__
|
||||
|
||||
#include "libosfp.h"
|
||||
#include "libosfp_common.h"
|
||||
#include "libosfp_fingerprint.h"
|
||||
|
||||
typedef struct libosfp_field_score_db {
|
||||
@@ -25,10 +25,10 @@ typedef struct libosfp_score_db {
|
||||
} libosfp_score_db_t;
|
||||
|
||||
int libosfp_score_db_load(libosfp_score_db_t *score_db, char *fp_file);
|
||||
int libosfp_score_db_score(libosfp_context_t *libosfp_context, libosfp_fingerprint_t *fp, libosfp_result_t *result);
|
||||
int libosfp_score_db_score(libosfp_score_db_t *score_db, unsigned int flags, libosfp_fingerprint_t *fp, libosfp_score_t *result);
|
||||
|
||||
void libosfp_score_db_debug_print(libosfp_score_db_t *score_db);
|
||||
libosfp_score_db_t *libosfp_score_db_create(void);
|
||||
void libosfp_score_db_destroy(libosfp_score_db_t *score_db);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user