diff --git a/example/osfp_example.c b/example/osfp_example.c index 146587e..2a53ac6 100644 --- a/example/osfp_example.c +++ b/example/osfp_example.c @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -145,6 +146,11 @@ typedef struct Packet_ { int vlan_layer; } Packet; +typedef struct EthernetHdr_ { + uint8_t eth_dst[6]; + uint8_t eth_src[6]; + uint16_t eth_type; +} __attribute__((__packed__)) EthernetHdr; unsigned char *fp_file_path; unsigned char *fp_output_file_path; @@ -159,6 +165,12 @@ pcap_t *pcap_handle; int processed_packet; int link_type; +struct osfp_profile_counter identify_profile; + +unsigned int identify_failed_count = 0; +unsigned int identify_count = 0; +unsigned int result_os_count[OSFP_OS_CLASS_MAX]; + void usage(void) { fprintf(stderr, "Usage: osfp_match [ ...options... ] [ 'filter rule' ]\n" @@ -172,13 +184,6 @@ void usage(void) { exit(1); } -typedef struct EthernetHdr_ { - uint8_t eth_dst[6]; - uint8_t eth_src[6]; - uint16_t eth_type; -} __attribute__((__packed__)) EthernetHdr; - - int packet_decode_tcp(Packet *p, const unsigned char *data, unsigned int len) { int ret = -1; @@ -434,13 +439,16 @@ void example_detect(struct osfp_db *osfp_db, Packet *p) unsigned int tcph_len; struct osfp_result *result = NULL; - printf("Example ipv4 header detect: --------------------------\n"); - iph = (struct iphdr *)p->iph; ip6h = (struct ip6_hdr *)p->ip6h; tcph = (struct tcphdr *)p->tcph; tcph_len = tcph->doff << 2; + osfp_profile_cycle(c1); + osfp_profile_cycle(c2); + + + osfp_profile_get_cycle(c1); if (iph) { result = osfp_ipv4_identify(osfp_db, iph, tcph, tcph_len); } else if (ip6h) { @@ -448,17 +456,28 @@ void example_detect(struct osfp_db *osfp_db, Packet *p) } else { goto exit; } + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&identify_profile, c2 - c1); + + identify_count++; if (result == NULL) { + identify_failed_count++; printf("osfp header match failed, erro: %s\n", "?"); goto exit; } - printf("Connection info: %s:%d -> %s:%d\n", p->srcip, p->sp, p->dstip, p->dp); - printf("Most likely os class: %s\n", osfp_result_os_name_get(result)); + result_os_count[result->likely_os_class]++; - printf("Details:\n"); - printf("%s\n", osfp_result_score_detail_export(result)); + char *json = osfp_result_score_detail_export(result); + + if (1) { + printf("Example ipv4 header detect: --------------------------\n"); + printf("Connection info: %s:%d -> %s:%d\n", p->srcip, p->sp, p->dstip, p->dp); + printf("Most likely os class: %s\n", osfp_result_os_name_get(result)); + printf("Details:\n"); + printf("%s\n", json); + } exit: if (result) { @@ -499,7 +518,10 @@ void process_packet(char *user, struct pcap_pkthdr *h, u_char *pkt) } // tcp/ip header detect example for user - example_detect(osfp_db, p); + int i; + for (i = 0; i < 1; i++) { + example_detect(osfp_db, p); + } printf("--------------------------- processed packet count %d\n", ++processed_packet); @@ -507,10 +529,35 @@ exit: return; } +static void signal_handler(int signum) +{ + printf("profile identify: avg: %lu max: %lu min: %lu curr: %lu total: %lu count: %lu\n", + identify_profile.total_cycle / identify_profile.count, + identify_profile.max_cycle, + identify_profile.min_cycle, + identify_profile.curr_cycle, + identify_profile.total_cycle, + identify_profile.count); + + osfp_profile_print_stats(); + + printf("total %u, failed %u\n", + identify_count, identify_failed_count); + int i; + for (i = 0; i < OSFP_OS_CLASS_MAX; i++) { + printf("%s: %u\n", osfp_os_class_id_to_name(i), result_os_count[i]); + } + + exit(0); +} + int main(int argc, char *argv[]) { int r; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + while ((r = getopt(argc, argv, "+f:i:r:o:d")) != -1) { switch(r) { case 'f': @@ -621,6 +668,8 @@ int main(int argc, char *argv[]) osfp_log_level_set(OSFP_LOG_LEVEL_DEBUG); } + osfp_profile_set(1); + struct osfp_db *osfp_db = osfp_db_new(fp_file_path); if (osfp_db == NULL) { printf("could not create osfp context. fingerprints file: %s\n", fp_file_path); diff --git a/pcap/synmerge.pcap b/pcap/synmerge.pcap new file mode 100644 index 0000000..a3a9984 Binary files /dev/null and b/pcap/synmerge.pcap differ diff --git a/src/osfp.c b/src/osfp.c index ec9a78f..e822436 100644 --- a/src/osfp.c +++ b/src/osfp.c @@ -94,6 +94,10 @@ char *osfp_result_score_detail_export(struct osfp_result *result) cJSON *array; cJSON *os_score; + osfp_profile_cycle(c1); + osfp_profile_cycle(c2); + osfp_profile_get_cycle(c1); + if (result == NULL) { goto exit; } @@ -139,6 +143,10 @@ exit: if (root) { cJSON_Delete(root); } + if (result_str) { + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&osfp_profile_result_export, c2 - c1); + } return result_str; } @@ -159,21 +167,33 @@ struct osfp_result *osfp_ipv4_identify(struct osfp_db *db, struct iphdr* l3_hdr, struct osfp_os_class_score os_class_score; struct osfp_result *result; + osfp_profile_cycle(c1); + osfp_profile_cycle(c2); + if (db == NULL || l3_hdr == NULL || l4_hdr == NULL || l4_hdr == 0) { goto exit; } + osfp_profile_get_cycle(c1); ret = osfp_fingerprinting((unsigned char *)l3_hdr, (unsigned char *)l4_hdr, (unsigned int)l4_hdr_len, &fp, 4); + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&osfp_profile_fingerprinting, c2 - c1); if (ret != 0) { goto exit; } + osfp_profile_get_cycle(c1); ret = osfp_score_db_score(db->score_db, 0, &fp, &os_class_score); + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&osfp_profile_score, c2 - c1); if (ret != 0) { goto exit; } + osfp_profile_get_cycle(c1); result = osfp_result_build(&os_class_score); + osfp_profile_get_cycle(c2); + osfp_profile_counter_update(&osfp_profile_result_build, c2 - c1); if (result == NULL) { goto exit; } @@ -190,7 +210,7 @@ struct osfp_result *osfp_ipv6_identify(struct osfp_db *db, struct ip6_hdr* l3_hd struct osfp_os_class_score os_class_score; struct osfp_result *result; - if (db == NULL || l3_hdr == NULL || l4_hdr == NULL) { + if (db == NULL || l3_hdr == NULL || l4_hdr == NULL || l4_hdr_len == 0) { goto exit; } @@ -225,7 +245,7 @@ struct osfp_result *osfp_json_identify(struct osfp_db *db, const char *json_str) goto exit; } - ret = osfp_fingerprint_from_json(&fp, json_str); + ret = osfp_fingerprint_from_json(&fp, (char *)json_str); if (ret != 0) { goto exit; } diff --git a/src/osfp_common.c b/src/osfp_common.c index ab76c67..fa80b34 100644 --- a/src/osfp_common.c +++ b/src/osfp_common.c @@ -2,6 +2,8 @@ #include "osfp.h" +unsigned int osfp_profile_enable; + const char *os_class_name[OSFP_OS_CLASS_MAX] = { OSFP_OS_CLASS_NAME_UNKNOWN, OSFP_OS_CLASS_NAME_WINDOWS, @@ -12,6 +14,54 @@ const char *os_class_name[OSFP_OS_CLASS_MAX] = { OSFP_OS_CLASS_NAME_OTHERS }; +struct osfp_profile_counter osfp_profile_fingerprinting; +struct osfp_profile_counter osfp_profile_score; +struct osfp_profile_counter osfp_profile_result_build; +struct osfp_profile_counter osfp_profile_result_export; + +void osfp_profile_counter_print(struct osfp_profile_counter *profile, const char *name) +{ + printf("profile %s: avg: %lu max: %lu min: %lu curr: %lu total: %lu count: %lu\n", + name, + profile->total_cycle / profile->count, + profile->max_cycle, + profile->min_cycle, + profile->curr_cycle, + profile->total_cycle, + profile->count); +} +void osfp_profile_counter_update(struct osfp_profile_counter *profile, unsigned long long curr_cycle) +{ + profile->count++; + profile->curr_cycle = curr_cycle; + profile->total_cycle += curr_cycle; + + if (profile->min_cycle == 0) { + profile->min_cycle = curr_cycle; + } else { + if (profile->min_cycle > curr_cycle) { + profile->min_cycle = curr_cycle; + } + } + + if (profile->max_cycle < curr_cycle) { + profile->max_cycle = curr_cycle; + } +} + +void osfp_profile_print_stats(void) +{ + osfp_profile_counter_print(&osfp_profile_fingerprinting, "fingerprinting"); + osfp_profile_counter_print(&osfp_profile_score, "score"); + osfp_profile_counter_print(&osfp_profile_result_build, "result_build"); + osfp_profile_counter_print(&osfp_profile_result_export, "result export"); +} + +void osfp_profile_set(unsigned int enabled) +{ + osfp_profile_enable = enabled; +} + enum osfp_os_class_id osfp_os_class_name_to_id(char *name) { enum osfp_os_class_id os_class; @@ -33,8 +83,3 @@ enum osfp_os_class_id osfp_os_class_name_to_id(char *name) return os_class; } -const char *osfp_os_class_id_to_name(enum osfp_os_class_id os_class) -{ - return os_class_name[os_class]; -} - diff --git a/src/osfp_common.h b/src/osfp_common.h index 023a2ee..3b25ba1 100644 --- a/src/osfp_common.h +++ b/src/osfp_common.h @@ -39,11 +39,35 @@ static inline unsigned long long osfp_rdtsc(void) return tsc.tsc_64; } +extern unsigned int osfp_profile_enable; + #define osfp_profile_cycle(x) volatile unsigned long long x = 0 #define osfp_profile_get_cycle(x) do { \ - x = osfp_rdtsc(); \ + if (__builtin_expect(!!(osfp_profile_enable), 0)) { \ + x = osfp_rdtsc(); \ + } else { \ + x = 0; \ + } \ } while(0) +struct osfp_profile_counter { + unsigned long long count; + unsigned long long curr_cycle; + unsigned long long max_cycle; + unsigned long long min_cycle; + unsigned long long total_cycle; +}; + +extern struct osfp_profile_counter osfp_profile_fingerprinting; +extern struct osfp_profile_counter osfp_profile_score; +extern struct osfp_profile_counter osfp_profile_result_build; +extern struct osfp_profile_counter osfp_profile_result_export; + +void osfp_profile_counter_update(struct osfp_profile_counter *profile, unsigned long long curr_cycle); +void osfp_profile_print_stats(void); +void osfp_profile_set(unsigned int enabled); + + #define OSFP_BIT_U32(n) (1UL << (n)) #define OSFP_PERCENTILE 100 @@ -171,7 +195,12 @@ struct osfp_db { void *score_db; // 分数数据库指针 }; -const char *osfp_os_class_id_to_name(enum osfp_os_class_id os_class); enum osfp_os_class_id osfp_os_class_name_to_id(char *name); +extern const char *os_class_name[OSFP_OS_CLASS_MAX]; +static inline const char *osfp_os_class_id_to_name(enum osfp_os_class_id os_class) +{ + return os_class_name[os_class]; +} + #endif diff --git a/src/osfp_fingerprint.c b/src/osfp_fingerprint.c index 3c212e6..6d4cc01 100644 --- a/src/osfp_fingerprint.c +++ b/src/osfp_fingerprint.c @@ -88,6 +88,30 @@ static unsigned int compute_ip_ttl(unsigned int ip_ttl) return ip_ttl; } +static void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len) +{ + fp->fields[field_id].name = osfp_fingerprint_get_field_name(field_id); + fp->fields[field_id].enabled = 1; + + if (fp->value_buffer_used + len <= sizeof(fp->value_buffer)) { + memcpy(fp->value_buffer + fp->value_buffer_used, value, len); + fp->fields[field_id].value = fp->value_buffer + fp->value_buffer_used; + fp->fields[field_id].value_len = len; + fp->value_buffer_used += len; + } else { + fp->fields[field_id].value = NULL; + fp->fields[field_id].value_len = 0; + } +} + +static void osfp_fingerprint_init_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id) +{ + fp->fields[field_id].name = osfp_fingerprint_get_field_name(field_id); + fp->fields[field_id].enabled = 0; + fp->fields[field_id].value = NULL; + fp->fields[field_id].value_len = 0; +} + static unsigned int decode_tcp_options(struct osfp_tcp_opt *tcp_opts, unsigned int max_opt_cnt, unsigned char *data, unsigned int len) { unsigned int offset = 0; @@ -125,6 +149,186 @@ static unsigned int decode_tcp_options(struct osfp_tcp_opt *tcp_opts, unsigned i return tcp_opt_cnt; } +static int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_len, struct osfp_fingerprint *fp) +{ + int ret,i; + + unsigned int tcp_mss; + unsigned int tcp_ws; + unsigned int tcp_ter; + unsigned int tcp_opt_cnt; + struct osfp_tcp_opt tcp_opts[OSFP_TCP_OPTMAX]; + + char options[OSFP_TCP_OPTLENMAX]; + char options_ordered[OSFP_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; + + if (opt_data == NULL || opt_len == 0 || fp == NULL) { + goto exit; + } + + tcp_opt_cnt = decode_tcp_options(tcp_opts, OSFP_TCP_OPTMAX, opt_data, opt_len); + + for (i = 0; i < tcp_opt_cnt && offset < maxoffset && ordered_offset < ordered_maxoffset; i++) { + struct osfp_tcp_opt *opt = &tcp_opts[i]; + + char letter = option_to_ascii(opt->type); + options[offset++] = letter; + options_ordered[ordered_offset++] = letter; + + switch (opt->type) { + case OSFP_TCP_OPT_EOL: + case OSFP_TCP_OPT_NOP: + break; + case OSFP_TCP_OPT_MSS: + if (opt->len != OSFP_TCP_OPT_MSS_LEN) { + break; + } + tcp_mss = (unsigned int)ntohs(*(unsigned short *)opt->data); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_MSS, &tcp_mss, sizeof(tcp_mss)); + ret = snprintf(options + offset, sizeof(options), "%u", tcp_mss); + if (ret < 0 || offset + ret > maxoffset) { + break; + } + offset += ret; + break; + case OSFP_TCP_OPT_WSCALE: + if (opt->len != OSFP_TCP_OPT_WS_LEN) { + break; + } + tcp_ws = (unsigned int)*(unsigned char *)opt->data; + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SCALING, &tcp_ws, sizeof(tcp_ws)); + ret = snprintf(options + offset, sizeof(options), "%u", tcp_ws); + if (ret < 0 || offset + ret > maxoffset) { + break; + } + offset += ret; + break; + case OSFP_TCP_OPT_TIMESTAMP: + if (opt->len != OSFP_TCP_OPT_TS_LEN) { + break; + } + tcp_ter = ntohl(*(unsigned int *)(opt->data + 4)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY, &tcp_ter, sizeof(tcp_ter)); + ret = snprintf(options + offset, sizeof(options), "%u", tcp_ter); + if (ret < 0 || offset + ret > maxoffset) { + break; + } + offset += ret; + break; + case OSFP_TCP_OPT_SACKOK: + case OSFP_TCP_OPT_SACK: + case OSFP_TCP_OPT_ECHO: + case OSFP_TCP_OPT_ECHOREPLY: + case OSFP_TCP_OPT_POCONN: + case OSFP_TCP_OPT_POSVC: + break; + default: + ret = snprintf(options + offset, sizeof(options), "%u", opt->type); + if (ret < 0 || offset + ret > maxoffset) { + break; + } + offset += ret; + } + + options[offset++] = ','; + options[offset] = 0; + options_ordered[ordered_offset] = 0; + } + + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS, options, strlen(options) + 1); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED, options_ordered, strlen(options_ordered) + 1); + + return 0; +exit: + return -1; +} + +static int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp) +{ + unsigned int tcp_off; + unsigned int tcp_window_size; + unsigned int tcp_flags; + + if (tcph == NULL || tcph_len > OSFP_TCP_DATA_OFF_MAX || fp == NULL) { + goto exit; + } + + tcp_off = tcph->doff << 2; + tcp_window_size = ntohs(tcph->window); + tcp_flags = *((unsigned char *)&tcph->ack_seq + 5); + + if (tcp_off != tcph_len) { + goto exit; + } + + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OFF, &tcp_off, sizeof(tcp_off)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SIZE, &tcp_window_size, sizeof(tcp_window_size)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_FLAGS, &tcp_flags, sizeof(tcp_flags)); + + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_TIMESTAMP); + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY); + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_WINDOW_SCALING); + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_MSS); + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_OPTIONS); + osfp_fingerprint_init_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED); + + // tcp options + if (tcp_off > OSFP_TCP_HEADER_LEN) { + osfp_fingerprinting_tcp_option((unsigned char *)tcph + OSFP_TCP_HEADER_LEN, tcp_off - OSFP_TCP_HEADER_LEN, fp); + } + + return 0; +exit: + return -1; +} + +static int osfp_fingerprinting_ipv4(struct iphdr *iph, struct osfp_fingerprint *fp) +{ + if (iph == NULL || fp == NULL) { + goto exit; + } + + unsigned int ip_id = !!iph->id; + unsigned int ip_tos = iph->tos; + unsigned int ip_total_length = ntohs(iph->tot_len); + unsigned int ip_ttl = compute_ip_ttl(iph->ttl); + + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_ID, &ip_id, sizeof(ip_id)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOS, &ip_tos, sizeof(ip_tos)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); + + return 0; +exit: + return -1; +} + +static int osfp_fingerprinting_ipv6(struct ip6_hdr *iph, struct osfp_fingerprint *fp) +{ + if (iph == NULL || fp == NULL) { + goto exit; + } + + //unsigned int ip_id = 0; + //unsigned int ip_tos = 0; + unsigned int ip_total_length = OSFP_IPV6_HEADER_LEN + ntohs(iph->ip6_ctlun.ip6_un1.ip6_un1_plen); + unsigned int ip_ttl = compute_ip_ttl(iph->ip6_ctlun.ip6_un1.ip6_un1_hlim); + + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); + osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); + + osfp_fingerprint_init_field(fp, OSFP_FIELD_IP_ID); + osfp_fingerprint_init_field(fp, OSFP_FIELD_IP_TOS); + + return 0; +exit: + return -1; +} + int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format) { int rlen = 0, ret, i; @@ -222,214 +426,6 @@ exit: return ret; } -unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id) -{ - return fp_fields[field_id].enabled; -} - -unsigned int osfp_fingerprint_get_field_importance(enum osfp_field_id field_id) -{ - return fp_fields[field_id].importance; -} - -const char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id) -{ - return fp_fields[field_id].name; -} - -unsigned int osfp_fingerprint_get_field_type(enum osfp_field_id field_id) -{ - return fp_fields[field_id].type; -} - -void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len) -{ - fp->fields[field_id].name = osfp_fingerprint_get_field_name(field_id); - fp->fields[field_id].enabled = 1; - - if (fp->value_buffer_used + len <= sizeof(fp->value_buffer)) { - memcpy(fp->value_buffer + fp->value_buffer_used, value, len); - fp->fields[field_id].value = fp->value_buffer + fp->value_buffer_used; - fp->fields[field_id].value_len = len; - fp->value_buffer_used += len; - } else { - fp->fields[field_id].value = NULL; - fp->fields[field_id].value_len = 0; - } -} - -int osfp_fingerprinting_tcp_option(unsigned char *opt_data, unsigned int opt_len, struct osfp_fingerprint *fp) -{ - int ret,i; - - unsigned int tcp_mss; - unsigned int tcp_ws; - unsigned int tcp_ter; - unsigned int tcp_opt_cnt; - struct osfp_tcp_opt tcp_opts[OSFP_TCP_OPTMAX]; - - char options[OSFP_TCP_OPTLENMAX]; - char options_ordered[OSFP_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; - - if (opt_data == NULL || opt_len == 0 || fp == NULL) { - goto exit; - } - - tcp_opt_cnt = decode_tcp_options(tcp_opts, OSFP_TCP_OPTMAX, opt_data, opt_len); - - for (i = 0; i < tcp_opt_cnt && offset < maxoffset && ordered_offset < ordered_maxoffset; i++) { - struct osfp_tcp_opt *opt = &tcp_opts[i]; - - char letter = option_to_ascii(opt->type); - options[offset++] = letter; - options_ordered[ordered_offset++] = letter; - - switch (opt->type) { - case OSFP_TCP_OPT_EOL: - case OSFP_TCP_OPT_NOP: - break; - case OSFP_TCP_OPT_MSS: - if (opt->len != OSFP_TCP_OPT_MSS_LEN) { - break; - } - tcp_mss = (unsigned int)ntohs(*(unsigned short *)opt->data); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_MSS, &tcp_mss, sizeof(tcp_mss)); - ret = snprintf(options + offset, sizeof(options), "%u", tcp_mss); - if (ret < 0 || offset + ret > maxoffset) { - break; - } - offset += ret; - break; - case OSFP_TCP_OPT_WSCALE: - if (opt->len != OSFP_TCP_OPT_WS_LEN) { - break; - } - tcp_ws = (unsigned int)*(unsigned char *)opt->data; - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SCALING, &tcp_ws, sizeof(tcp_ws)); - ret = snprintf(options + offset, sizeof(options), "%u", tcp_ws); - if (ret < 0 || offset + ret > maxoffset) { - break; - } - offset += ret; - break; - case OSFP_TCP_OPT_TIMESTAMP: - if (opt->len != OSFP_TCP_OPT_TS_LEN) { - break; - } - tcp_ter = ntohl(*(unsigned int *)(opt->data + 4)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_TIMESTAMP_ECHO_REPLY, &tcp_ter, sizeof(tcp_ter)); - ret = snprintf(options + offset, sizeof(options), "%u", tcp_ter); - if (ret < 0 || offset + ret > maxoffset) { - break; - } - offset += ret; - break; - case OSFP_TCP_OPT_SACKOK: - case OSFP_TCP_OPT_SACK: - case OSFP_TCP_OPT_ECHO: - case OSFP_TCP_OPT_ECHOREPLY: - case OSFP_TCP_OPT_POCONN: - case OSFP_TCP_OPT_POSVC: - break; - default: - ret = snprintf(options + offset, sizeof(options), "%u", opt->type); - if (ret < 0 || offset + ret > maxoffset) { - break; - } - offset += ret; - } - - options[offset++] = ','; - options[offset] = 0; - options_ordered[ordered_offset] = 0; - } - - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS, options, strlen(options) + 1); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OPTIONS_ORDERED, options_ordered, strlen(options_ordered) + 1); - - return 0; -exit: - return -1; -} - -int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp) -{ - unsigned int tcp_off; - unsigned int tcp_window_size; - unsigned int tcp_flags; - - if (tcph == NULL || tcph_len > OSFP_TCP_DATA_OFF_MAX || fp == NULL) { - goto exit; - } - - tcp_off = tcph->doff << 2; - tcp_window_size = ntohs(tcph->window); - tcp_flags = *((unsigned char *)&tcph->ack_seq + 5); - - if (tcp_off != tcph_len) { - goto exit; - } - - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_OFF, &tcp_off, sizeof(tcp_off)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_WINDOW_SIZE, &tcp_window_size, sizeof(tcp_window_size)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_TCP_FLAGS, &tcp_flags, sizeof(tcp_flags)); - - // tcp options - if (tcp_off > OSFP_TCP_HEADER_LEN) { - osfp_fingerprinting_tcp_option((unsigned char *)tcph + OSFP_TCP_HEADER_LEN, tcp_off - OSFP_TCP_HEADER_LEN, fp); - } - - return 0; -exit: - return -1; -} - -int osfp_fingerprinting_ipv4(struct iphdr *iph, struct osfp_fingerprint *fp) -{ - if (iph == NULL || fp == NULL) { - goto exit; - } - - unsigned int ip_id = !!iph->id; - unsigned int ip_tos = iph->tos; - unsigned int ip_total_length = ntohs(iph->tot_len); - unsigned int ip_ttl = compute_ip_ttl(iph->ttl); - - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_ID, &ip_id, sizeof(ip_id)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOS, &ip_tos, sizeof(ip_tos)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); - - return 0; -exit: - return -1; -} - -int osfp_fingerprinting_ipv6(struct ip6_hdr *iph, struct osfp_fingerprint *fp) -{ - if (iph == NULL || fp == NULL) { - goto exit; - } - - //unsigned int ip_id = 0; - //unsigned int ip_tos = 0; - unsigned int ip_total_length = OSFP_IPV6_HEADER_LEN + ntohs(iph->ip6_ctlun.ip6_un1.ip6_un1_plen); - unsigned int ip_ttl = compute_ip_ttl(iph->ip6_ctlun.ip6_un1.ip6_un1_hlim); - - //osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_ID, &ip_id, sizeof(ip_id)); - //osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOS, &ip_tos, sizeof(ip_tos)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TOTAL_LENGTH, &ip_total_length, sizeof(ip_total_length)); - osfp_fingerprint_setup_field(fp, OSFP_FIELD_IP_TTL, &ip_ttl, sizeof(ip_ttl)); - - return 0; -exit: - return -1; -} - int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version) { int ret = OSFP_EINVAL; @@ -438,7 +434,7 @@ int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tc goto exit; } - memset(fp, 0, sizeof(struct osfp_fingerprint)); + fp->value_buffer_used = 0; switch (ip_version) { case 4: diff --git a/src/osfp_fingerprint.h b/src/osfp_fingerprint.h index 59e697d..0584329 100644 --- a/src/osfp_fingerprint.h +++ b/src/osfp_fingerprint.h @@ -43,20 +43,30 @@ struct osfp_fingerprint { unsigned int value_buffer_used; }; +extern struct osfp_fingerprint_field fp_fields[OSFP_FIELD_MAX]; + +static inline unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id) +{ + return fp_fields[field_id].enabled; +} + +static inline unsigned int osfp_fingerprint_get_field_importance(enum osfp_field_id field_id) +{ + return fp_fields[field_id].importance; +} + +static inline const char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id) +{ + return fp_fields[field_id].name; +} + +static inline unsigned int osfp_fingerprint_get_field_type(enum osfp_field_id field_id) +{ + return fp_fields[field_id].type; +} + int osfp_fingerprint_from_json(struct osfp_fingerprint *fp, char *json_str); int osfp_fingerprint_to_json_buf(struct osfp_fingerprint *fp, char *strbuf, unsigned int buf_len, unsigned int format); - -void osfp_fingerprint_setup_field(struct osfp_fingerprint *fp, enum osfp_field_id field_id, void *value, unsigned int len); - -const char *osfp_fingerprint_get_field_name(enum osfp_field_id field_id); -unsigned int osfp_fingerprint_get_field_enabled(enum osfp_field_id field_id); -unsigned int osfp_fingerprint_get_field_importance(enum osfp_field_id field_id); -unsigned int osfp_fingerprint_get_field_type(enum osfp_field_id field_id); - -int osfp_fingerprinting_tcp_option(unsigned char *pkt, unsigned int pktlen, struct osfp_fingerprint *fp); -int osfp_fingerprinting_tcp(struct tcphdr *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp); -int osfp_fingerprinting_ipv4(struct iphdr *iph, struct osfp_fingerprint *fp); -int osfp_fingerprinting_ipv6(struct ip6_hdr *iph, struct osfp_fingerprint *fp); int osfp_fingerprinting(unsigned char *iph, unsigned char *tcph, unsigned int tcph_len, struct osfp_fingerprint *fp, unsigned int ip_version); #ifdef UNITTEST diff --git a/src/osfp_score_db.c b/src/osfp_score_db.c index 2e38cde..76b0ba6 100644 --- a/src/osfp_score_db.c +++ b/src/osfp_score_db.c @@ -26,7 +26,7 @@ struct osfp_score_db_hash_data { struct osfp_score_db_hash_element *hash_head; }; -int osfp_score_db_array_add(void *data, struct osfp_os_class_score *os_class_score, void *value, unsigned int len) +static int osfp_score_db_array_add(void *data, struct osfp_os_class_score *os_class_score, void *value, unsigned int len) { int ret = -1, i; unsigned int index; @@ -55,7 +55,7 @@ exit: return ret; } -struct osfp_os_class_score *osfp_score_db_array_match(void *data, void *value, unsigned int len) +static struct osfp_os_class_score *osfp_score_db_array_match(void *data, void *value, unsigned int len) { unsigned int index; struct osfp_score_db_array_data *array_data = (struct osfp_score_db_array_data *)data; @@ -77,7 +77,7 @@ struct osfp_os_class_score *osfp_score_db_array_match(void *data, void *value, u return &((array_data->array_head)[index]); } -void *osfp_score_db_array_create(void) +static void *osfp_score_db_array_create(void) { struct osfp_score_db_array_data *array_data = calloc(1, sizeof(struct osfp_score_db_array_data)); if (array_data == NULL) { @@ -95,7 +95,7 @@ void *osfp_score_db_array_create(void) return (void *)array_data; } -void osfp_score_db_array_destroy(void *data) { +static void osfp_score_db_array_destroy(void *data) { struct osfp_score_db_array_data *array_data = (struct osfp_score_db_array_data *)data; if (array_data) { @@ -106,7 +106,7 @@ void osfp_score_db_array_destroy(void *data) { } } -int osfp_score_db_hash_add(void *data, struct osfp_os_class_score *os_class_score, void *value, unsigned int len) +static int osfp_score_db_hash_add(void *data, struct osfp_os_class_score *os_class_score, void *value, unsigned int len) { int ret = -1, i; struct osfp_score_db_hash_data *hash_data = (struct osfp_score_db_hash_data *)data; @@ -142,7 +142,7 @@ exit: return ret; } -struct osfp_os_class_score *osfp_score_db_hash_match(void *data, void *value, unsigned int len) +static struct osfp_os_class_score *osfp_score_db_hash_match(void *data, void *value, unsigned int len) { struct osfp_score_db_hash_data *hash_data = (struct osfp_score_db_hash_data *)data; struct osfp_score_db_hash_element *element = NULL; @@ -163,12 +163,12 @@ struct osfp_os_class_score *osfp_score_db_hash_match(void *data, void *value, un return element->score; } -void *osfp_score_db_hash_create(void) +static void *osfp_score_db_hash_create(void) { return (void*)calloc(1, sizeof(struct osfp_score_db_hash_data)); } -void osfp_score_db_hash_destroy(void *data) { +static void osfp_score_db_hash_destroy(void *data) { struct osfp_score_db_hash_data *hash_data = (struct osfp_score_db_hash_data *)data; struct osfp_score_db_hash_element *element = NULL; struct osfp_score_db_hash_element *tmp = NULL; @@ -192,55 +192,7 @@ void osfp_score_db_hash_destroy(void *data) { } } -char *osfp_score_db_read_file(char *fp_file) -{ - int ret = -1; - char *file_buffer = NULL; - unsigned int file_len = 0; - FILE *fp = NULL; - struct stat st; - - if (0 > stat(fp_file, &st)) { - osfp_log_error("stat() failed on '%s'.\n", fp_file); - goto exit; - } - - if (st.st_size == 0) { - osfp_log_error("Empty file: '%s'.\n", fp_file); - goto exit; - } - - file_len = (unsigned int)st.st_size; - file_buffer = malloc(file_len + 1); - if (file_buffer == NULL) { - osfp_log_error("Not enough memory for file buffer. file name: '%s'\n",fp_file); - goto exit; - } - - fp = fopen(fp_file, "r"); - if (fp == NULL) { - osfp_log_error("Cannot open '%s' for reading.\n", fp_file); - goto exit; - } - - ret = fread(file_buffer, 1, file_len, fp); - if (ret < 0) { - osfp_log_error("fread() failed on '%s'.\n", fp_file); - free(file_buffer); - fclose(fp); - goto exit; - } - - fclose(fp); - - file_buffer[file_len] = 0; - - return file_buffer; -exit: - return NULL; -} - -int osfp_score_db_load_field(struct osfp_field_score_db *db, cJSON *field, enum osfp_os_class_id os_class) +static int osfp_score_db_load_field(struct osfp_field_score_db *db, cJSON *field, enum osfp_os_class_id os_class) { int ret = -1; struct osfp_os_class_score os_class_score = {0}; @@ -278,7 +230,7 @@ exit: return ret; } -int osfp_score_db_load_entry(struct osfp_score_db *score_db, cJSON *entry) +static int osfp_score_db_load_entry(struct osfp_score_db *score_db, cJSON *entry) { int ret = -1, i; cJSON *field = NULL; @@ -332,6 +284,54 @@ exit: return ret; } +char *osfp_score_db_read_file(char *fp_file) +{ + int ret = -1; + char *file_buffer = NULL; + unsigned int file_len = 0; + FILE *fp = NULL; + struct stat st; + + if (0 > stat(fp_file, &st)) { + osfp_log_error("stat() failed on '%s'.\n", fp_file); + goto exit; + } + + if (st.st_size == 0) { + osfp_log_error("Empty file: '%s'.\n", fp_file); + goto exit; + } + + file_len = (unsigned int)st.st_size; + file_buffer = malloc(file_len + 1); + if (file_buffer == NULL) { + osfp_log_error("Not enough memory for file buffer. file name: '%s'\n",fp_file); + goto exit; + } + + fp = fopen(fp_file, "r"); + if (fp == NULL) { + osfp_log_error("Cannot open '%s' for reading.\n", fp_file); + goto exit; + } + + ret = fread(file_buffer, 1, file_len, fp); + if (ret < 0) { + osfp_log_error("fread() failed on '%s'.\n", fp_file); + free(file_buffer); + fclose(fp); + goto exit; + } + + fclose(fp); + + file_buffer[file_len] = 0; + + return file_buffer; +exit: + return NULL; +} + int osfp_score_db_load(struct osfp_score_db *score_db, char *fp_file) { int ret = OSFP_EINVAL, i, count;