aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/ndpiReader.c3
-rw-r--r--example/reader_util.c32
-rw-r--r--example/reader_util.h2
-rw-r--r--src/include/ndpi_typedefs.h4
-rw-r--r--src/lib/ndpi_main.c96
-rw-r--r--src/lib/ndpi_utils.c6
-rw-r--r--wireshark/ndpi.lua367
7 files changed, 414 insertions, 96 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index b98bb3374..22f7f3215 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -2056,6 +2056,9 @@ static void printFlow(u_int32_t id, struct ndpi_flow_info *flow, u_int16_t threa
fprintf(out, "[Risk Info: %s]", flow->risk_str);
}
+ if(flow->tcp_fingerprint)
+ fprintf(out, "[TCP Fingerprint: %s]", flow->tcp_fingerprint);
+
if(flow->ssh_tls.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(buf_ver, sizeof(buf_ver),
flow->ssh_tls.ssl_version, &known_tls));
diff --git a/example/reader_util.c b/example/reader_util.c
index 28596eb4f..8f9dae101 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -609,8 +609,9 @@ void ndpi_flow_info_free_data(struct ndpi_flow_info *flow) {
ndpi_free_bin(&flow->payload_len_bin);
#endif
- if(flow->risk_str) ndpi_free(flow->risk_str);
- if(flow->flow_payload) ndpi_free(flow->flow_payload);
+ if(flow->tcp_fingerprint) ndpi_free(flow->tcp_fingerprint);
+ if(flow->risk_str) ndpi_free(flow->risk_str);
+ if(flow->flow_payload) ndpi_free(flow->flow_payload);
}
/* ***************************************************** */
@@ -623,7 +624,7 @@ void ndpi_workflow_free(struct ndpi_workflow * workflow) {
if(addr_dump_path != NULL)
ndpi_cache_address_dump(workflow->ndpi_struct, addr_dump_path, 0);
-
+
ndpi_exit_detection_module(workflow->ndpi_struct);
ndpi_free(workflow->ndpi_flows_root);
ndpi_free(workflow);
@@ -1131,7 +1132,7 @@ static void dump_flow_fingerprint(struct ndpi_workflow * workflow,
if(flow->server_hostname)
ndpi_serialize_string_string(&serializer, "server_hostname", flow->server_hostname);
-
+
buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len);
fprintf(fingerprint_fp, "%s\n", buffer);
}
@@ -1408,24 +1409,24 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
/* For consistency across platforms replace :0: with :: */
ndpi_patchIPv6Address(flow->info);
}
-
+
if(flow->ndpi_flow->protos.dns.geolocation_iata_code[0] != '\0')
strcpy(flow->dns.geolocation_iata_code, flow->ndpi_flow->protos.dns.geolocation_iata_code);
if(0) {
u_int8_t i;
-
+
for(i=0; i<flow->ndpi_flow->protos.dns.num_rsp_addr; i++) {
char buf[64];
-
+
if(flow->ndpi_flow->protos.dns.is_rsp_addr_ipv6[i] == 0) {
inet_ntop(AF_INET, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv4, buf, sizeof(buf));
} else {
- inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf));
+ inet_ntop(AF_INET6, &flow->ndpi_flow->protos.dns.rsp_addr[i].ipv6, buf, sizeof(buf));
}
printf("(%s) %s [ttl: %u]\n", flow->host_server_name, buf, flow->ndpi_flow->protos.dns.rsp_addr_ttl[i]);
- }
+ }
}
}
/* MDNS */
@@ -1520,7 +1521,7 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
if(flow->ndpi_flow->protos.tls_quic.ja4_client_raw)
flow->ssh_tls.ja4_client_raw = strdup(flow->ndpi_flow->protos.tls_quic.ja4_client_raw);
-
+
ndpi_snprintf(flow->ssh_tls.ja3_server, sizeof(flow->ssh_tls.ja3_server), "%s",
flow->ndpi_flow->protos.tls_quic.ja3_server);
flow->ssh_tls.server_unsafe_cipher = flow->ndpi_flow->protos.tls_quic.server_unsafe_cipher;
@@ -1585,6 +1586,9 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
flow->multimedia_flow_type = flow->ndpi_flow->flow_multimedia_type;
+ if(flow->ndpi_flow->tcp.fingerprint)
+ flow->tcp_fingerprint = ndpi_strdup(flow->ndpi_flow->tcp.fingerprint);
+
/* HTTP metadata are "global" not in `flow->ndpi_flow->protos` union; for example, we can have
HTTP/BitTorrent and in that case we want to export also HTTP attributes */
if(is_ndpi_proto(flow, NDPI_PROTOCOL_HTTP)
@@ -1608,16 +1612,16 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
{
ndpi_ip_addr_t ip_addr;
struct ndpi_address_cache_item *c;
-
+
memset(&ip_addr, 0, sizeof(ip_addr));
-
+
if(flow->ip_version == 4)
ip_addr.ipv4 = flow->dst_ip;
else
memcpy(&ip_addr.ipv6, &flow->dst_ip6, sizeof(struct ndpi_in6_addr));
c = ndpi_cache_address_find(workflow->ndpi_struct, ip_addr);
-
+
if(c) {
flow->server_hostname = ndpi_strdup(c->hostname);
}
@@ -2205,7 +2209,7 @@ struct ndpi_proto ndpi_workflow_process_packet(struct ndpi_workflow * workflow,
/* At the first packet flush expired cached addresses */
ndpi_cache_address_flush_expired(workflow->ndpi_struct, header->ts.tv_sec);
}
-
+
/* Increment raw packet counter */
workflow->stats.raw_packet_count++;
diff --git a/example/reader_util.h b/example/reader_util.h
index 9eb49accd..4b9d90beb 100644
--- a/example/reader_util.h
+++ b/example/reader_util.h
@@ -324,7 +324,7 @@ typedef struct ndpi_flow_info {
ndpi_multimedia_flow_type multimedia_flow_type;
void *src_id, *dst_id;
-
+ char *tcp_fingerprint;
struct ndpi_entropy *entropy;
struct ndpi_entropy *last_entropy;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 82eaabcc3..2074181bf 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1312,6 +1312,10 @@ struct ndpi_flow_struct {
ndpi_risk risk, risk_shadow; /* Issues found with this flow [bitmask of ndpi_risk] */
struct ndpi_risk_information risk_infos[MAX_NUM_RISK_INFOS]; /* String that contains information about the risks found */
u_int8_t num_risk_infos;
+
+ struct {
+ char *fingerprint;
+ } tcp;
/*
This structure below will not not stay inside the protos
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index bcd3520fb..3265ef80f 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -60,6 +60,8 @@
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
+#define TH_ECE 0x40
+#define TH_CWR 0x80
#endif
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
@@ -4400,7 +4402,7 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) {
if(ndpi_str->address_cache)
ndpi_term_address_cache(ndpi_str->address_cache);
-
+
ndpi_free(ndpi_str);
}
@@ -4794,7 +4796,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str,
def = NULL;
else
def = &ndpi_str->proto_defaults[subprotocol_id];
-
+
if(def == NULL) {
ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS];
char *equal = strchr(proto, '=');
@@ -6724,6 +6726,9 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
ndpi_free(flow->risk_infos[i].info);
}
+ if(flow->tcp.fingerprint)
+ ndpi_free(flow->tcp.fingerprint);
+
if(flow->http.url)
ndpi_free(flow->http.url);
@@ -6904,14 +6909,86 @@ static int ndpi_init_packet(struct ndpi_detection_module_struct *ndpi_str,
/* TCP / UDP detection */
if(l4protocol == IPPROTO_TCP) {
+ u_int16_t header_len;
+
if(l4_packet_len < 20 /* min size of tcp */)
return(1);
/* tcp */
packet->tcp = (struct ndpi_tcphdr *) l4ptr;
- if(l4_packet_len >= packet->tcp->doff * 4) {
- packet->payload_packet_len = l4_packet_len - packet->tcp->doff * 4;
- packet->payload = ((u_int8_t *) packet->tcp) + (packet->tcp->doff * 4);
+ header_len = packet->tcp->doff * 4;
+
+ if(l4_packet_len >= header_len) {
+ if(flow->tcp.fingerprint == NULL) {
+ u_int8_t *t = (u_int8_t*)packet->tcp;
+ u_int16_t flags = ntohs(*((u_int16_t*)&t[12]));
+
+ if((flags & (TH_SYN | TH_ECE | TH_CWR)) == TH_SYN) {
+ u_int8_t *options = (u_int8_t*)(&t[sizeof(struct ndpi_tcphdr)]);
+ char fingerprint[128], options_fp[128];
+ u_int8_t i, fp_idx = 0, options_fp_idx = 0;
+ u_int8_t options_len = header_len - sizeof(struct ndpi_tcphdr);
+ u_int16_t tcp_win = ntohs(packet->tcp->window);
+ u_int8_t ip_ttl;
+ u_int8_t sha_hash[NDPI_SHA256_BLOCK_SIZE];
+
+ if(packet->iph)
+ ip_ttl = packet->iph->ttl;
+ else
+ ip_ttl = packet->iphv6->ip6_hdr.ip6_un1_hlim;
+
+ if(ip_ttl <= 32) ip_ttl = 32;
+ else if(ip_ttl <= 64) ip_ttl = 64;
+ else if(ip_ttl <= 128) ip_ttl = 128;
+ else if(ip_ttl <= 192) ip_ttl = 192;
+ else ip_ttl = 255;
+
+ fp_idx = snprintf(fingerprint, sizeof(fingerprint), "%u_%u_", ip_ttl, tcp_win);
+
+ for(i=0; i<options_len; ) {
+ u_int8_t kind = options[i];
+ int rc;
+
+ rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", kind);
+ options_fp_idx += rc;
+
+ if(kind == 0) /* EOF */
+ break;
+ else if(kind == 1) /* NOP */
+ i++;
+ else {
+ u_int8_t len = options[i+1];
+
+ if(len == 0)
+ break;
+ else if(kind == 8) {
+ /* Timestamp: ignore it */
+ } else {
+ int j = i+2;
+ u_int8_t opt_len = len - 2;
+
+ while(opt_len > 0) {
+ rc = snprintf(&options_fp[options_fp_idx], sizeof(options_fp)-options_fp_idx, "%02x", options[j]);
+ options_fp_idx += rc;
+ j++, opt_len--;
+ }
+ }
+
+ i += len;
+ }
+ } /* for */
+
+ ndpi_sha256((const u_char*)options_fp, options_fp_idx, sha_hash);
+ snprintf(&fingerprint[fp_idx], sizeof(fingerprint)-fp_idx, "%02x%02x%02x%02x%02x%02x",
+ sha_hash[0], sha_hash[1], sha_hash[2],
+ sha_hash[3], sha_hash[4], sha_hash[5]);
+
+ flow->tcp.fingerprint = ndpi_strdup(fingerprint);
+ }
+ }
+
+ packet->payload_packet_len = l4_packet_len - header_len;
+ packet->payload = ((u_int8_t *) packet->tcp) + header_len;
} else {
/* tcp header not complete */
return(1);
@@ -7546,7 +7623,7 @@ static void ndpi_reconcile_msteams_udp(struct ndpi_detection_module_struct *ndpi
struct ndpi_flow_struct *flow,
u_int16_t master) {
/* This function can NOT access &ndpi_str->packet since it is called also from ndpi_detection_giveup(), via ndpi_reconcile_protocols() */
-
+
if(flow->l4_proto == IPPROTO_UDP) {
u_int16_t sport = ntohs(flow->c_port);
u_int16_t dport = ntohs(flow->s_port);
@@ -7694,7 +7771,7 @@ static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_s
NDPI_CONFIDENCE_DPI_PARTIAL);
}
break;
-
+
case NDPI_PROTOCOL_SKYPE_TEAMS:
case NDPI_PROTOCOL_SKYPE_TEAMS_CALL:
if(flow->l4_proto == IPPROTO_UDP && ndpi_str->msteams_cache) {
@@ -9066,8 +9143,7 @@ struct header_line {
struct ndpi_int_one_line_struct *line;
};
-static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str)
-{
+static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_str) {
struct ndpi_packet_struct *packet = &ndpi_str->packet;
struct ndpi_int_one_line_struct *line;
size_t length;
@@ -11366,7 +11442,7 @@ static const struct cfg_param {
{ "tls", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_subclassification_enabled), NULL },
{ "quic", "subclassification", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(quic_subclassification_enabled), NULL },
-
+
{ "smtp", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(smtp_opportunistic_tls_enabled), NULL },
{ "imap", "tls_dissection", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(imap_opportunistic_tls_enabled), NULL },
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 9b7cc387e..26efd20a2 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -1651,7 +1651,11 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_string_uint32(serializer, "ip", ip_version);
- ndpi_serialize_string_string(serializer, "proto", ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name)));
+ if(flow->tcp.fingerprint)
+ ndpi_serialize_string_string(serializer, "tcp_fingerprint", flow->tcp.fingerprint);
+
+ ndpi_serialize_string_string(serializer, "proto",
+ ndpi_get_ip_proto_name(l4_protocol, l4_proto_name, sizeof(l4_proto_name)));
return(ndpi_dpi2json(ndpi_struct, flow, l7_protocol, serializer));
}
diff --git a/wireshark/ndpi.lua b/wireshark/ndpi.lua
index 3db686206..c1758c03d 100644
--- a/wireshark/ndpi.lua
+++ b/wireshark/ndpi.lua
@@ -32,10 +32,13 @@ end
-- ##############################################
-local ndpi_proto = Proto("ndpi", "nDPI Protocol Interpreter")
+local ndpi_proto = Proto("ndpi", "nDPI Protocol Interpreter")
+local tcp_fprint = Proto("ndpi.tcp_fingerprint", "TCP Fingerprint")
+
ndpi_proto.fields = {}
local ndpi_fds = ndpi_proto.fields
+local tcp_fprint_fds = tcp_fprint.fields
ndpi_fds.magic = ProtoField.new("nDPI Magic", "ndpi.magic", ftypes.UINT32, nil, base.HEX)
ndpi_fds.network_protocol = ProtoField.new("nDPI Network Protocol", "ndpi.protocol.network", ftypes.UINT8, nil, base.DEC)
ndpi_fds.application_protocol = ProtoField.new("nDPI Application Protocol", "ndpi.protocol.application", ftypes.UINT16, nil, base.DEC)
@@ -153,9 +156,10 @@ local ntop_proto = Proto("ntop", "ntop Extensions")
ntop_proto.fields = {}
local ntop_fds = ntop_proto.fields
-ntop_fds.client_nw_rtt = ProtoField.new("TCP client network RTT (msec)", "ntop.latency.client_rtt", ftypes.FLOAT, nil, base.NONE)
-ntop_fds.server_nw_rtt = ProtoField.new("TCP server network RTT (msec)", "ntop.latency.server_rtt", ftypes.FLOAT, nil, base.NONE)
-ntop_fds.appl_latency_rtt = ProtoField.new("Application Latency RTT (msec)", "ntop.latency.appl_rtt", ftypes.FLOAT, nil, base.NONE)
+ntop_fds.client_nw_rtt = ProtoField.new("TCP client network RTT (msec)", "ntop.latency.client_rtt", ftypes.FLOAT, nil, base.NONE)
+ntop_fds.server_nw_rtt = ProtoField.new("TCP server network RTT (msec)", "ntop.latency.server_rtt", ftypes.FLOAT, nil, base.NONE)
+ntop_fds.appl_latency_rtt = ProtoField.new("Application Latency RTT (msec)", "ntop.latency.appl_rtt", ftypes.FLOAT, nil, base.NONE)
+ntop_fds.tcp_fingerprint = ProtoField.new("TCP Fingerprint", "ntop.tcp_fingerprint", ftypes.STRING, nil, base.NONE)
local f_eth_source = Field.new("eth.src")
local f_eth_trailer = Field.new("eth.trailer")
@@ -171,8 +175,6 @@ local f_dns_response = Field.new("dns.flags.response")
local f_udp_len = Field.new("udp.length")
local f_tcp_header_len = Field.new("tcp.hdr_len")
local f_tcp_win = Field.new("tcp.window_size_value")
-local f_tcp_mss = Field.new("tcp.options.mss_val")
-local f_tcp_wscale = Field.new("tcp.options.wscale.shift")
local f_tcp_stream = Field.new("tcp.stream")
local f_tcp_options = Field.new("tcp.options")
local f_ip_len = Field.new("ip.len")
@@ -368,11 +370,211 @@ local ja4_db = {
}
-- ##############################################
+-- ##############################################
+
+-- From http://pastebin.com/gsFrNjbt linked from http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/
+
+--
+-- Adaptation of the Secure Hashing Algorithm (SHA-244/256)
+-- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm
+--
+-- Using an adapted version of the bit library
+-- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua
+--
+
+local MOD = 2^32
+local MODM = MOD-1
+
+local function memoize(f)
+ local mt = {}
+ local t = setmetatable({}, mt)
+ function mt:__index(k)
+ local v = f(k)
+ t[k] = v
+ return v
+ end
+ return t
+end
+
+local function make_bitop_uncached(t, m)
+ local function bitop(a, b)
+ local res,p = 0,1
+ while a ~= 0 and b ~= 0 do
+ local am, bm = a % m, b % m
+ res = res + t[am][bm] * p
+ a = (a - am) / m
+ b = (b - bm) / m
+ p = p*m
+ end
+ res = res + (a + b) * p
+ return res
+ end
+ return bitop
+end
+
+local function make_bitop(t)
+ local op1 = make_bitop_uncached(t,2^1)
+ local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)
+ return make_bitop_uncached(op2, 2 ^ (t.n or 1))
+end
+
+local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})
+
+local function bxor(a, b, c, ...)
+ local z = nil
+ if b then
+ a = a % MOD
+ b = b % MOD
+ z = bxor1(a, b)
+ if c then z = bxor(z, c, ...) end
+ return z
+ elseif a then return a % MOD
+ else return 0 end
+end
+
+local function band(a, b, c, ...)
+ local z
+ if b then
+ a = a % MOD
+ b = b % MOD
+ z = ((a + b) - bxor1(a,b)) / 2
+ if c then z = bit32_band(z, c, ...) end
+ return z
+ elseif a then return a % MOD
+ else return MODM end
+end
+
+local function bnot(x) return (-1 - x) % MOD end
+
+local function rshift1(a, disp)
+ if disp < 0 then return lshift(a,-disp) end
+ return math.floor(a % 2 ^ 32 / 2 ^ disp)
+end
+
+local function rshift(x, disp)
+ if disp > 31 or disp < -31 then return 0 end
+ return rshift1(x % MOD, disp)
+end
+
+local function lshift(a, disp)
+ if disp < 0 then return rshift(a,-disp) end
+ return (a * 2 ^ disp) % 2 ^ 32
+end
+
+local function rrotate(x, disp)
+ x = x % MOD
+ disp = disp % 32
+ local low = band(x, 2 ^ disp - 1)
+ return rshift(x, disp) + lshift(low, 32 - disp)
+end
+
+local k = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+}
+
+local function str2hexa(s)
+ return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end))
+end
+
+local function num2s(l, n)
+ local s = ""
+ for i = 1, n do
+ local rem = l % 256
+ s = string.char(rem) .. s
+ l = (l - rem) / 256
+ end
+ return s
+end
+
+local function s232num(s, i)
+ local n = 0
+ for i = i, i + 3 do n = n*256 + string.byte(s, i) end
+ return n
+end
+
+local function preproc(msg, len)
+ local extra = 64 - ((len + 9) % 64)
+ len = num2s(8 * len, 8)
+ msg = msg .. "\128" .. string.rep("\0", extra) .. len
+ assert(#msg % 64 == 0)
+ return msg
+end
+
+local function initH256(H)
+ H[1] = 0x6a09e667
+ H[2] = 0xbb67ae85
+ H[3] = 0x3c6ef372
+ H[4] = 0xa54ff53a
+ H[5] = 0x510e527f
+ H[6] = 0x9b05688c
+ H[7] = 0x1f83d9ab
+ H[8] = 0x5be0cd19
+ return H
+end
+
+local function digestblock(msg, i, H)
+ local w = {}
+ for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end
+ for j = 17, 64 do
+ local v = w[j - 15]
+ local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
+ v = w[j - 2]
+ w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
+ end
+
+ local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
+ for i = 1, 64 do
+ local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
+ local maj = bxor(band(a, b), band(a, c), band(b, c))
+ local t2 = s0 + maj
+ local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
+ local ch = bxor (band(e, f), band(bnot(e), g))
+ local t1 = h + s1 + ch + k[i] + w[i]
+ h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2
+ end
+
+ H[1] = band(H[1] + a)
+ H[2] = band(H[2] + b)
+ H[3] = band(H[3] + c)
+ H[4] = band(H[4] + d)
+ H[5] = band(H[5] + e)
+ H[6] = band(H[6] + f)
+ H[7] = band(H[7] + g)
+ H[8] = band(H[8] + h)
+end
+
+-- Made this global
+function sha256(msg)
+ msg = preproc(msg, #msg)
+ local H = initH256({})
+ for i = 1, #msg, 64 do digestblock(msg, i, H) end
+ return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..
+ num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))
+end
+
+-- ##############################################
+-- ##############################################
function string.contains(String,Start)
if type(String) ~= 'string' or type(Start) ~= 'string' then
return false
end
+
return(string.find(String,Start,1) ~= nil)
end
@@ -1088,81 +1290,103 @@ end
function tcp_fingerprint(tvb, pinfo, tree, ip_version)
local tcp_flags = getval(f_tcp_flags())
- if(tcp_flags == "0x0002") then -- SYN
- local tcp_win = getval(f_tcp_win())
- local tcp_mss = getval(f_tcp_mss())
- local tcp_wss = getval(f_tcp_wscale())
+ if(tcp_flags == "0x0002") then -- SYN
local tcp_options = f_tcp_options()
- local d_tcp_options = tcp_options.display
- local fingerprint = ""
- local d_tcp_options_len = d_tcp_options:len()
- local tcp_opt_debug = false
- i = 1
- while(i < d_tcp_options_len) do
- if(tcp_opt_debug) then tprint("[offset "..i .. "/".. d_tcp_options:len().."]") end
+ if(tcp_options ~= nil) then
+ local tcp_win = getval(f_tcp_win())
+ local fingerprint = ""
+ local d_tcp_options = tcp_options.display
+ local d_tcp_options_len = d_tcp_options:len()
+ local tcp_opt_debug = false
+
+ if(tcp_win == "nil") then tcp_win = 0 end
- local kind = d_tcp_options:sub(i,i+1)
-
- if(tcp_opt_debug) then tprint("[Kind: " .. kind .."] *** ") end
-
- i = i + 2 -- Skip kind
+ i = 1
+ while(i < d_tcp_options_len) do
+ if(tcp_opt_debug) then tprint("[offset "..i .. "/".. d_tcp_options:len().."]") end
+
+ local kind = d_tcp_options:sub(i,i+1)
+
+ if(tcp_opt_debug) then tprint("[Kind: " .. kind .."] *** ") end
+
+ i = i + 2 -- Skip kind
+
+ fingerprint = fingerprint .. kind
+
+ if(kind == "00") then
+ -- EOL
+ if(tcp_opt_debug) then tprint("[" .. kind .."][EOL]") end
+ elseif(kind == "01") then
+ -- NOP
+ if(tcp_opt_debug) then tprint("[" .. kind .."][NOP]") end
+ else
+ local len = d_tcp_options:sub(i, i+1)
- fingerprint = fingerprint .. kind
-
- if(kind == "00") then
- -- EOL
- if(tcp_opt_debug) then tprint("[" .. kind .."][EOL]") end
- elseif(kind == "01") then
- -- NOP
- if(tcp_opt_debug) then tprint("[" .. kind .."][NOP]") end
- else
- local len = d_tcp_options:sub(i, i+1)
+ if(tcp_opt_debug) then tprint("[Len: " .. len .."] *** ") end
- if(tcp_opt_debug) then tprint("[Len: " .. len .."] *** ") end
+ len = tonumber(len, 16)
+ i = i + 2 -- Skip len
- len = tonumber(len, 16)
- i = i + 2 -- Skip len
+ if((len ~= nil) and (len > 0)) then
+ local value_len = 2 * (len-2)
+ local value
+
+ if(tcp_opt_debug) then tprint("[ValueLen: " .. value_len .."] *** ") end
- if(len > 0) then
- local value_len = 2 * (len-2)
- local value
-
- if(tcp_opt_debug) then tprint("[ValueLen: " .. value_len .."] *** ") end
-
- value = d_tcp_options:sub(i, i+value_len)
- if(tcp_opt_debug) then tprint("[" .. kind .."][len: ".. len .."][value: ".. value.."]") end
+ -- Skip timestamps
+ if((kind ~= "08") and (value_len > 0)) then
+ value = d_tcp_options:sub(i, i+value_len)
+ value = value:sub(1, value_len) -- make sure the lenght is correct
+ if(tcp_opt_debug) then tprint("[" .. kind .."][len: ".. len .."][value: ".. value.."]") end
- -- Skip timestamps
- if(kind ~= "08") then
- fingerprint = fingerprint .. value
+ fingerprint = fingerprint .. value
+ end
+
+ i = i + value_len
end
-
- i = i + value_len
end
+ end -- while
+
+ local ip_ttl
+ local src_ip
+
+ if(ip_version == 6) then
+ ip_ttl = getval(f_ipv6_hlim())
+ src_ip = f_src_ipv6()
+ else
+ ip_ttl = getval(f_ip_ttl())
+ src_ip = f_src_ip()
end
+
+ src_ip = getval(src_ip)
+
+ -- Normalize TTL
+ ip_ttl = tonumber(ip_ttl)
+ if(ip_ttl <= 32) then ip_ttl = 32
+ elseif(ip_ttl <= 64) then ip_ttl = 64
+ elseif(ip_ttl <= 128) then ip_ttl = 128
+ elseif(ip_ttl <= 192) then ip_ttl = 192
+ else ip_ttl = 255 end
+
+ fingerprint = string.lower(fingerprint)
+ local f_print
+
+ if(true) then
+ -- Use SHA256
+ f_print = string.lower(ip_ttl .."_".. tcp_win .."_".. string.sub(sha256(fingerprint), 1, 12))
+ else
+ f_print = string.upper(ip_ttl .."_".. tcp_win .."_".. fingerprint)
+ end
+
+ if(tcp_opt_debug) then tprint("Fingerprint: " .. f_print) end
+
+ local tcp_f_entry = tree:add(ntop_proto, tvb())
+ tcp_f_entry:add(ntop_fds.tcp_fingerprint, f_print)
+
+ tcp_host_fingerprints[src_ip] = f_print
+ tcp_fingerprint_hosts[f_print] = src_ip
end
-
- -- tprint("Fingerprint: "..fingerprint)
-
- local ip_ttl
- local src_ip
-
- if(ip_version == 6) then
- ip_ttl = getval(f_ipv6_hlim())
- src_ip = f_src_ipv6()
- else
- ip_ttl = getval(f_ip_ttl())
- src_ip = f_src_ip()
- end
-
- src_ip = getval(src_ip)
-
- -- local f_print = string.upper(ip_ttl .."_".. tcp_win .."_".. tcp_mss .."_".. tcp_wss.."_".. fingerprint)
- local f_print = string.upper(tcp_win .."_".. tcp_mss .."_".. tcp_wss.."_".. fingerprint)
- tcp_host_fingerprints[src_ip] = f_print
-
- tcp_fingerprint_hosts[f_print] = src_ip
end
end
@@ -2305,13 +2529,16 @@ end
local function tcp_dialog_menu()
local win = TextWindow.new("TCP Packets Analysis");
local label = ""
+ local i
+ i = 0
label = label .. "TCP Host Fingerprints\n"
for k,v in pairsByValues(tcp_host_fingerprints, rev) do
label = label .. string.format("%-32s", shortenString(k,32)).."\t"..v.."\n"
if(i == 10) then break else i = i + 1 end
end
-
+
+ i = 0
label = label .. "\nTCP Fingerprint Hosts\n"
for k,v in pairsByValues(tcp_fingerprint_hosts, rev) do
label = label .. string.format("%-64s", shortenString(k,64)).."\t"..v.."\n"