Skip to content

Commit

Permalink
Dump capture interface via the Pcapng IDB
Browse files Browse the repository at this point in the history
When capturing as root, the interface name and incremental id are
now correctly reported in the Pcapng file

Closes #438
  • Loading branch information
emanuele-f committed Jan 4, 2025
1 parent 4f7b7a7 commit 222d44e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 14 deletions.
2 changes: 1 addition & 1 deletion app/src/main/jni/core/capture_libpcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ int run_libpcap(pcapdroid_t *pd) {
if(!handle_packet(pd, &hdr, buffer, ipoffset)) {
// packet was rejected (unsupported/corrupted), dump to PCAP file anyway
struct timeval tv = hdr.ts;
pd_dump_packet(pd, buffer + ipoffset, hdr.len - ipoffset, &tv, hdr.uid);
pd_dump_packet(pd, buffer + ipoffset, hdr.len - ipoffset, &tv, hdr.uid, hdr.ifid);
}

housekeeping:
Expand Down
93 changes: 86 additions & 7 deletions app/src/main/jni/core/pcap_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include <linux/if_ether.h>
#include <net/if.h>
#include <pthread.h>
#include "common/utils.h"
#include "pcapdroid.h"
Expand All @@ -38,6 +39,12 @@ typedef struct {
UT_hash_handle hh;
} mapped_uid_t;

typedef struct {
u_int ifidx;
u_int pcapng_ifid;
UT_hash_handle hh;
} dumped_interface_t;

struct pcap_dumper {
pcap_dump_format_t format;
bool dump_extensions;
Expand All @@ -49,6 +56,8 @@ struct pcap_dumper {
uint64_t dump_size;
uint64_t last_dump_ms;
mapped_uid_t *mapped_uids;
dumped_interface_t *dumped_interfaces;
u_int num_dumped_interfaces;

// the crc32 implementation requires 4-bytes aligned accesses.
// frames are padded to honor the 4-bytes alignment.
Expand Down Expand Up @@ -195,9 +204,18 @@ static int8_t* alloc_dump_buffer(pcap_dumper_t *dumper, int size) {
void pcap_destroy_dumper(pcap_dumper_t *dumper) {
export_dump_buffer(dumper);

mapped_uid_t *entry, *tmp;
HASH_ITER(hh, dumper->mapped_uids, entry, tmp) {
pd_free(entry);
{
mapped_uid_t *entry, *tmp;
HASH_ITER(hh, dumper->mapped_uids, entry, tmp) {
pd_free(entry);
}
}

{
dumped_interface_t *entry, *tmp;
HASH_ITER(hh, dumper->dumped_interfaces, entry, tmp) {
pd_free(entry);
}
}

pthread_mutex_destroy(&dumper->keylog_mutex);
Expand Down Expand Up @@ -471,8 +489,69 @@ static bool dump_pcapng_uid_mapping(pcap_dumper_t *dumper, int uid) {
return true;
}

static bool dump_pcapng_interface(pcap_dumper_t *dumper, u_int ifidx) {
int total_length = sizeof(pcapng_intf_descr_block_t) + 4 /* total length */;

// try to get the interface name
char ifname[IF_NAMESIZE];
uint8_t ifname_padding = 0;
if (!if_indextoname(ifidx, ifname))
ifname[0] = '\0';

if (ifname[0]) {
total_length += sizeof(pcapng_enh_option_t) + strlen(ifname);
ifname_padding = (~total_length + 1) & 0x3;
total_length += ifname_padding;
}

int8_t *buffer = alloc_dump_buffer(dumper, total_length);
if (!buffer)
return false;

pcapng_intf_descr_block_t *idb = (pcapng_intf_descr_block_t*) buffer;
idb->type = 0x00000001;
idb->total_length = total_length;
idb->reserved = 0;
idb->linktype = LINKTYPE_RAW /* even with root, we always dump IP packets */;
idb->snaplen = dumper->snaplen;
buffer += sizeof(*idb);

if (ifname[0]) {
pcapng_enh_option_t *opt = (pcapng_enh_option_t*) buffer;
opt->code = 2; // if_name
opt->length = strlen(ifname);
buffer += sizeof(*opt);

memcpy(buffer, ifname, opt->length);
buffer += opt->length;

for(uint8_t i=0; i<ifname_padding; i++)
*(buffer++) = 0x00;
}

*buffer = idb->total_length;
return true;
}

static bool dump_packet_pcapng(pcap_dumper_t *dumper, const char *pkt, int pktlen,
const struct timeval *tv, int uid) {
const struct timeval *tv, int uid, u_int ifidx) {
uint_t pcapng_ifid = 0;

if(ifidx > 0) {
dumped_interface_t *item;
HASH_FIND_INT(dumper->dumped_interfaces, &ifidx, item);

if (!item) {
if (dump_pcapng_interface(dumper, ifidx)) {
item = pd_calloc(sizeof(dumped_interface_t), 1);
item->ifidx = ifidx;
item->pcapng_ifid = pcapng_ifid = ++dumper->num_dumped_interfaces;
HASH_ADD_INT(dumper->dumped_interfaces, ifidx, item);
}
} else
pcapng_ifid = item->pcapng_ifid;
}

if(dumper->dump_extensions) {
mapped_uid_t *item;
HASH_FIND_INT(dumper->mapped_uids, &uid, item);
Expand Down Expand Up @@ -510,7 +589,7 @@ static bool dump_packet_pcapng(pcap_dumper_t *dumper, const char *pkt, int pktle
pcapng_enh_packet_block_t *epb = (pcapng_enh_packet_block_t*) buffer;
epb->type = 0x00000006;
epb->total_length = total_length;
epb->interface_id = 0;
epb->interface_id = pcapng_ifid;
epb->timestamp_high = now_usec >> 32;
epb->timestamp_low = now_usec;
epb->captured_len = incl_len;
Expand Down Expand Up @@ -546,10 +625,10 @@ static bool dump_packet_pcapng(pcap_dumper_t *dumper, const char *pkt, int pktle
/* Dump a single packet into the buffer. Returns false if PCAP dump must be stopped (e.g. if max
* dump size reached or an error occurred). */
bool pcap_dump_packet(pcap_dumper_t *dumper, const char *pkt, int pktlen,
const struct timeval *tv, int uid) {
const struct timeval *tv, int uid, u_int ifidx) {
bool rv;
if (dumper->format == PCAPNG_DUMP)
rv = dump_packet_pcapng(dumper, pkt, pktlen, tv, uid);
rv = dump_packet_pcapng(dumper, pkt, pktlen, tv, uid, ifidx);
else
rv = dump_packet_pcap(dumper, pkt, pktlen, tv, uid);

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/jni/core/pcap_dump.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ typedef void pcap_dump_callback(struct pcapdroid *pd, const int8_t *buf, int dum
pcap_dumper_t* pcap_new_dumper(pcap_dump_format_t format, bool dump_extensions, int snaplen, uint64_t max_dump_size,
pcap_dump_callback dumpcb, struct pcapdroid *pd);
void pcap_destroy_dumper(pcap_dumper_t *dumper);
bool pcap_dump_packet(pcap_dumper_t *dumper, const char *pkt, int pktlen, const struct timeval *tv, int uid);
bool pcap_dump_packet(pcap_dumper_t *dumper, const char *pkt, int pktlen, const struct timeval *tv, int uid, u_int ifidx);
bool pcap_dump_secret(pcap_dumper_t *dumper, int8_t *sec_data, int seclen);
int pcap_get_preamble(pcap_dumper_t *dumper, char **out);
uint64_t pcap_get_dump_size(pcap_dumper_t *dumper);
Expand Down
10 changes: 6 additions & 4 deletions app/src/main/jni/core/pcapdroid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1114,11 +1114,11 @@ void pd_process_packet(pcapdroid_t *pd, zdtun_pkt_t *pkt, bool is_tx, const zdtu

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

void pd_dump_packet(pcapdroid_t *pd, const char *pktbuf, int pktlen, const struct timeval *tv, int uid) {
void pd_dump_packet(pcapdroid_t *pd, const char *pktbuf, int pktlen, const struct timeval *tv, int uid, u_int ifidx) {
if(!pd->pcap_dump.dumper)
return;

if(!pcap_dump_packet(pd->pcap_dump.dumper, pktbuf, pktlen, tv, uid))
if(!pcap_dump_packet(pd->pcap_dump.dumper, pktbuf, pktlen, tv, uid, ifidx))
stop_pcap_dump(pd);
}

Expand Down Expand Up @@ -1156,8 +1156,10 @@ void pd_account_stats(pcapdroid_t *pd, pkt_context_t *pctx) {

if((pd->pcap_dump.dumper) &&
((pd->pcap_dump.max_pkts_per_flow <= 0) ||
((data->sent_pkts + data->rcvd_pkts) <= pd->pcap_dump.max_pkts_per_flow)))
pd_dump_packet(pd, pkt->buf, pkt->len, &pctx->tv, pctx->data->uid);
((data->sent_pkts + data->rcvd_pkts) <= pd->pcap_dump.max_pkts_per_flow))) {
u_int ifidx = !pd->vpn_capture ? pctx->data->pcap.ifidx : 0;
pd_dump_packet(pd, pkt->buf, pkt->len, &pctx->tv, pctx->data->uid, ifidx);
}
}

/* ******************************************************* */
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/jni/core/pcapdroid.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,8 @@ void pd_refresh_time(pcapdroid_t *pd);
void pd_process_packet(pcapdroid_t *pd, zdtun_pkt_t *pkt, bool is_tx, const zdtun_5tuple_t *tuple,
pd_conn_t *data, struct timeval *tv, pkt_context_t *pctx);
void pd_account_stats(pcapdroid_t *pd, pkt_context_t *pctx);
void pd_dump_packet(pcapdroid_t *pd, const char *pktbuf, int pktlen, const struct timeval *tv, int uid);
void pd_dump_packet(pcapdroid_t *pd, const char *pktbuf, int pktlen, const struct timeval *tv,
int uid, u_int ifidx);
void pd_housekeeping(pcapdroid_t *pd);
pd_conn_t* pd_new_connection(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, int uid);
void pd_purge_connection(pcapdroid_t *pd, pd_conn_t *data);
Expand Down

0 comments on commit 222d44e

Please sign in to comment.