Skip to content

Commit

Permalink
wireshark: extcap: fix output data link type
Browse files Browse the repository at this point in the history
Avoid forcing `DLT_EN10MB` but use the same data link type of the input
pcap.
This way, we can use extcap functionality with input traces having Linux
"cooked" capture encapsulation, i.e. traces captured on "any" interface
  • Loading branch information
IvanNardi committed Sep 3, 2024
1 parent bf93f77 commit a57415d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 15 deletions.
39 changes: 28 additions & 11 deletions example/ndpiReader.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ static pcap_t *extcap_fifo_h = NULL;
static char extcap_buf[16384];
static char *extcap_capture_fifo = NULL;
static u_int16_t extcap_packet_filter = (u_int16_t)-1;
static int do_extcap_capture = 0;
static int extcap_add_crc = 0;

// struct associated to a workflow for a thread
struct reader_thread {
Expand Down Expand Up @@ -903,12 +905,12 @@ void extcap_config() {

/* ********************************** */

void extcap_capture() {
void extcap_capture(int datalink_type) {
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### %s #### \n", __FUNCTION__);
#endif

if((extcap_fifo_h = pcap_open_dead(DLT_EN10MB, 16384 /* MTU */)) == NULL) {
if((extcap_fifo_h = pcap_open_dead(datalink_type, 16384 /* MTU */)) == NULL) {
fprintf(stderr, "Error pcap_open_dead");

#ifdef DEBUG_TRACE
Expand Down Expand Up @@ -1051,7 +1053,7 @@ static void parseOptions(int argc, char **argv) {
int opt;
#ifndef USE_DPDK
char *__pcap_file = NULL;
int thread_id, do_capture = 0;
int thread_id;
#ifdef __linux__
char *bind_mask = NULL;
u_int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
Expand Down Expand Up @@ -1357,7 +1359,7 @@ static void parseOptions(int argc, char **argv) {

#ifndef USE_DPDK
case '5':
do_capture = 1;
do_extcap_capture = 1;
break;
#endif

Expand Down Expand Up @@ -1434,9 +1436,8 @@ static void parseOptions(int argc, char **argv) {
printCSVHeader();

#ifndef USE_DPDK
if(do_capture) {
if(do_extcap_capture) {
quiet_mode = 1;
extcap_capture();
}

if(!domain_to_check && !ip_port_to_check) {
Expand Down Expand Up @@ -4526,15 +4527,18 @@ static void ndpi_process_packet(u_char *args,
)
) {
struct pcap_pkthdr h;
u_int32_t *crc, delta = sizeof(struct ndpi_packet_trailer) + 4 /* ethernet trailer */;
u_int32_t *crc, delta = sizeof(struct ndpi_packet_trailer);
struct ndpi_packet_trailer *trailer;
u_int16_t cli_score, srv_score;

memcpy(&h, header, sizeof(h));

if(h.caplen > (sizeof(extcap_buf)-sizeof(struct ndpi_packet_trailer) - 4)) {
if(extcap_add_crc)
delta += 4; /* ethernet trailer */

if(h.caplen > (sizeof(extcap_buf) - delta)) {
printf("INTERNAL ERROR: caplen=%u\n", h.caplen);
h.caplen = sizeof(extcap_buf)-sizeof(struct ndpi_packet_trailer) - 4;
h.caplen = sizeof(extcap_buf) - delta;
}

trailer = (struct ndpi_packet_trailer*)&extcap_buf[h.caplen];
Expand Down Expand Up @@ -4596,8 +4600,10 @@ static void ndpi_process_packet(u_char *args,
tlv->length = ntohs(WIRESHARK_METADATA_SIZE - tot_len - 4);
/* The remaining bytes are already set to 0 */

crc = (uint32_t*)&extcap_buf[h.caplen+sizeof(struct ndpi_packet_trailer)];
*crc = ndpi_crc32((const void*)extcap_buf, h.caplen+sizeof(struct ndpi_packet_trailer), 0);
if(extcap_add_crc) {
crc = (uint32_t*)&extcap_buf[h.caplen+sizeof(struct ndpi_packet_trailer)];
*crc = ndpi_crc32((const void*)extcap_buf, h.caplen+sizeof(struct ndpi_packet_trailer), 0);
}
h.caplen += delta, h.len += delta;

#ifdef DEBUG_TRACE
Expand Down Expand Up @@ -4654,6 +4660,17 @@ static void ndpi_process_packet(u_char *args,
static void runPcapLoop(u_int16_t thread_id) {
if((!shutdown_app) && (ndpi_thread_info[thread_id].workflow->pcap_handle != NULL)) {
int datalink_type = pcap_datalink(ndpi_thread_info[thread_id].workflow->pcap_handle);

/* When using as extcap interface, the output/dumper pcap must have the same datalink
type of the input traffic [to be able to use, for example, input pcaps with
Linux "cooked" capture encapsulation (i.e. captured with "any" interface...) where
there isn't an ethernet header] */
if(do_extcap_capture) {
extcap_capture(datalink_type);
if(datalink_type == DLT_EN10MB)
extcap_add_crc = 1;
}

if(!ndpi_is_datalink_supported(datalink_type)) {
printf("Unsupported datalink %d. Skip pcap\n", datalink_type);
return;
Expand Down
18 changes: 14 additions & 4 deletions wireshark/ndpi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ ntop_fds.appl_latency_rtt = ProtoField.new("Application Latency RTT (msec)", "nt
local f_eth_source = Field.new("eth.src")
local f_eth_trailer = Field.new("eth.trailer")
local f_vlan_trailer = Field.new("vlan.trailer")
local f_sll_trailer = Field.new("sll.trailer")
local f_vlan_id = Field.new("vlan.id")
local f_arp_opcode = Field.new("arp.opcode")
local f_arp_sender_mac = Field.new("arp.src.hw_mac")
Expand Down Expand Up @@ -1055,28 +1056,37 @@ function ndpi_proto.dissector(tvb, pinfo, tree)
if(dissect_ndpi_trailer) then
local eth_trailer = {f_eth_trailer()}
local vlan_trailer = {f_vlan_trailer()}
local sll_trailer = {f_sll_trailer()}

-- nDPI trailer is usually the (only one) ethernet trailer.
-- But, depending on Wireshark configuration and on L2 protocols, the
-- But, depending on Wireshark configuration, on L2 protocols and on data link type, the
-- situation may be more complex. Let's try to handle the most common cases:
-- 1) with (multiple) ethernet trailers, nDPI trailer is usually the last one
-- 2) with VLAN encapsulation, nDPI trailer is usually recognized as vlan trailer
-- 3) with Linux "cooked" capture encapsulation, nDPI trailer is usually recognized as sll trailer
-- Note that it might not work with PPP-like encapsulations
if(eth_trailer[#eth_trailer] ~= nil or
vlan_trailer[#vlan_trailer] ~= nil) then
vlan_trailer[#vlan_trailer] ~= nil or
sll_trailer[#sll_trailer] ~= nil) then

local ndpi_trailer
local trailer_tvb
if (eth_trailer[#eth_trailer] ~= nil) then
ndpi_trailer = getval(eth_trailer[#eth_trailer])
else
trailer_tvb = eth_trailer[#eth_trailer].range()
elseif(vlan_trailer[#vlan_trailer] ~= nil) then
ndpi_trailer = getval(vlan_trailer[#vlan_trailer])
trailer_tvb = vlan_trailer[#vlan_trailer].range()
else
ndpi_trailer = getval(sll_trailer[#sll_trailer])
trailer_tvb = sll_trailer[#sll_trailer].range()
end
local magic = string.sub(ndpi_trailer, 1, 11)

if(magic == "19:68:09:24") then
local ndpikey, srckey, dstkey, flowkey, flow_risk
local flow_risk_tree, metadata_list_tree, metadata_tree
local name
local trailer_tvb = tvb(tvb:len() - 294 , 290) -- The last 4 bytes are the CRC. Even if nDPI needs to update it, it is not part of the nDPI trailer, strictly speaking
local ndpi_subtree = tree:add(ndpi_proto, trailer_tvb, "nDPI Protocol")

ndpi_subtree:add(ndpi_fds.magic, trailer_tvb(0, 4))
Expand Down

0 comments on commit a57415d

Please sign in to comment.