Fix export of invalid/unsupported pkts in root

This ensures that the PCAP file obtained with the root capture does not
excludes invalid/unsupported packets.

Fixes #209
This commit is contained in:
emanuele-f
2022-05-20 15:47:14 +02:00
parent 45dbe0dacc
commit 528438e6de
7 changed files with 101 additions and 85 deletions
+16 -9
View File
@@ -361,7 +361,9 @@ static void update_connection_status(pcapdroid_t *nc, pcap_conn_t *conn, zdtun_p
/* ******************************************************* */
static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer) {
/* Returns true if packet is valid. If false is returned, the pkt must still be dumped, so a call to
* pd_dump_packet is required. */
static bool handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer) {
zdtun_pkt_t pkt;
pcap_conn_t *conn = NULL;
uint8_t is_tx = (hdr->flags & PCAPD_FLAG_TX); // NOTE: the direction uses an heuristic so it may be wrong
@@ -382,17 +384,17 @@ static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer)
break;
default:
log_e("invalid datalink: %d", hdr->linktype);
return;
return false;
}
if(hdr->len < ipoffset) {
log_e("invalid length: %d, expected at least %d", hdr->len, ipoffset);
return;
return false;
}
if(zdtun_parse_pkt(pd->zdt, buffer + ipoffset, hdr->len - ipoffset, &pkt) != 0) {
log_d("zdtun_parse_pkt failed");
return;
return false;
}
if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) &&
@@ -403,7 +405,7 @@ static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer)
//log_d("unmatched IP fragment (ID = 0x%04x)", pkt.ip4->id);
pd->num_discarded_fragments++;
return;
return false;
}
if(!is_tx) {
@@ -423,7 +425,7 @@ static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer)
if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) && !(pkt.flags & ZDTUN_PKT_IS_FIRST_FRAGMENT)) {
log_d("ignoring fragment as it cannot start a connection");
pd->num_discarded_fragments++;
return;
return false;
}
// assume is_tx was correct
@@ -434,13 +436,13 @@ static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer)
if(!conn) {
log_e("malloc(pcap_conn_t) failed with code %d/%s",
errno, strerror(errno));
return;
return false;
}
pd_conn_t *data = pd_new_connection(pd, &pkt.tuple, hdr->uid);
if(!data) {
pd_free(conn);
return;
return false;
}
if(hdr->linktype == PCAPD_DLT_LINUX_SLL2)
@@ -483,6 +485,7 @@ static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer)
update_connection_status(pd, conn, &pkt, !is_tx);
pd_account_stats(pd, &pinfo);
return true;
}
/* ******************************************************* */
@@ -625,7 +628,11 @@ int run_root(pcapdroid_t *pd) {
#endif
pd->num_dropped_pkts = hdr.pkt_drops;
handle_packet(pd, &hdr, buffer);
if(!handle_packet(pd, &hdr, buffer)) {
// packet was rejected (unsupported/corrupted), dump to PCAP file anyway
struct timeval tv = hdr.ts;
pd_dump_packet(pd, buffer, hdr.len, &tv, hdr.uid);
}
housekeeping:
pd_housekeeping(pd);
+11 -10
View File
@@ -64,16 +64,17 @@ int pcap_rec_size(int snaplen, int pkt_len) {
/* Dumps a packet into the provided buffer. The buffer must have at least pcap_rec_size()
* bytes available */
void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, pkt_context_t *pctx) {
const zdtun_pkt_t *pkt = pctx->pkt;
void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, const char *pkt, int pktlen,
const struct timeval *tv, int uid) {
//const zdtun_pkt_t *pkt = pctx->pkt;
struct pcaprec_hdr_s *pcap_rec = (pcaprec_hdr_s*) buffer;
int offset = 0;
int snaplen = pd->pcap_dump.snaplen;
pcap_rec->ts_sec = pctx->tv.tv_sec;
pcap_rec->ts_usec = pctx->tv.tv_usec;
pcap_rec->incl_len = pcap_rec_size(snaplen, pkt->len) - (int)sizeof(struct pcaprec_hdr_s);
pcap_rec->orig_len = pkt->len;
pcap_rec->ts_sec = tv->tv_sec;
pcap_rec->ts_usec = tv->tv_usec;
pcap_rec->incl_len = pcap_rec_size(snaplen, pktlen) - (int)sizeof(struct pcaprec_hdr_s);
pcap_rec->orig_len = pktlen;
buffer += sizeof(struct pcaprec_hdr_s);
if(pcapdroid_trailer) {
@@ -83,14 +84,14 @@ void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, pkt_context_t *pctx) {
// Insert the bogus header: both the MAC addresses are 0
struct ethhdr *eth = (struct ethhdr*) buffer;
memset(eth, 0, sizeof(struct ethhdr));
eth->h_proto = htons((((*pkt->buf) >> 4) == 4) ? ETH_P_IP : ETH_P_IPV6);
eth->h_proto = htons((((*pkt) >> 4) == 4) ? ETH_P_IP : ETH_P_IPV6);
pcap_rec->orig_len += sizeof(struct ethhdr);
offset += sizeof(struct ethhdr);
}
int payload_to_copy = min(pkt->len, pcap_rec->incl_len - offset);
memcpy(buffer + offset, pkt->buf, payload_to_copy);
int payload_to_copy = min(pktlen, pcap_rec->incl_len - offset);
memcpy(buffer + offset, pkt, payload_to_copy);
offset += payload_to_copy;
if(pcapdroid_trailer &&
@@ -106,7 +107,7 @@ void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, pkt_context_t *pctx) {
// Populate the custom data
pcapdroid_trailer_t *cdata = (pcapdroid_trailer_t*)(buffer + offset);
fill_custom_data(cdata, pd, pctx->data);
fill_custom_data(cdata, pd, uid);
//clock_t start = clock();
cdata->fcs = crc32(buffer, pcap_rec->incl_len - 4, 0);
+2 -1
View File
@@ -61,6 +61,7 @@ typedef struct pcapdroid_trailer {
void pcap_set_pcapdroid_trailer(uint8_t enabled);
void pcap_build_hdr(int snaplen, struct pcap_hdr_s *pcap_hdr);
int pcap_rec_size(int snaplen, int pkt_len);
void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, pkt_context_t *pctx);
void pcap_dump_rec(pcapdroid_t *pd, u_char *buffer, const char *pkt, int pktlen,
const struct timeval *tv, int uid);
#endif // __MY_PCAP_H__
+33 -27
View File
@@ -1035,12 +1035,12 @@ void pd_refresh_time(pcapdroid_t *pd) {
/* ******************************************************* */
void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn) {
void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, int uid) {
memset(cdata, 0, sizeof(*cdata));
cdata->magic = htonl(PCAPDROID_TRAILER_MAGIC);
cdata->uid = htonl(conn->uid);
get_appname_by_uid(pd, conn->uid, cdata->appname, sizeof(cdata->appname));
cdata->uid = htonl(uid);
get_appname_by_uid(pd, uid, cdata->appname, sizeof(cdata->appname));
}
/* ******************************************************* */
@@ -1071,6 +1071,34 @@ 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) {
if(!pd->pcap_dump.buffer)
return;
int rec_size = pcap_rec_size(pd->pcap_dump.snaplen, pktlen);
if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size) {
// Flush the buffer
sendPcapDump(pd);
}
if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size)
log_e("Invalid buffer size [size=%d, idx=%d, tot_size=%d]",
JAVA_PCAP_BUFFER_SIZE, pd->pcap_dump.buffer_idx, rec_size);
else if((pd->pcap_dump.max_dump_size > 0) &&
((pd->pcap_dump.tot_size + rec_size) >= pd->pcap_dump.max_dump_size)) {
log_d("Max dump size reached, stop the dump");
stop_pcap_dump(pd);
} else {
pcap_dump_rec(pd, (u_char *) pd->pcap_dump.buffer + pd->pcap_dump.buffer_idx,
pktbuf, pktlen, tv, uid);
pd->pcap_dump.buffer_idx += rec_size;
pd->pcap_dump.tot_size += rec_size;
}
}
/* ******************************************************* */
/* Update the stats for the current packet and dump it if requested. */
void pd_account_stats(pcapdroid_t *pd, pkt_context_t *pctx) {
zdtun_pkt_t *pkt = pctx->pkt;
@@ -1092,35 +1120,13 @@ void pd_account_stats(pcapdroid_t *pd, pkt_context_t *pctx) {
/* New stats to notify */
pd->capture_stats.new_stats = true;
data->update_type |= CONN_UPDATE_STATS;
pd_notify_connection_update(pd, pctx->tuple, pctx->data);
if((pd->pcap_dump.buffer) &&
((pd->pcap_dump.max_pkts_per_flow <= 0) ||
((data->sent_pkts + data->rcvd_pkts) <= pd->pcap_dump.max_pkts_per_flow))) {
int rec_size = pcap_rec_size(pd->pcap_dump.snaplen, pkt->len);
if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size) {
// Flush the buffer
sendPcapDump(pd);
}
if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size)
log_e("Invalid buffer size [size=%d, idx=%d, tot_size=%d]",
JAVA_PCAP_BUFFER_SIZE, pd->pcap_dump.buffer_idx, rec_size);
else if((pd->pcap_dump.max_dump_size > 0) &&
((pd->pcap_dump.tot_size + rec_size) >= pd->pcap_dump.max_dump_size)) {
log_d("Max dump size reached, stop the dump");
stop_pcap_dump(pd);
} else {
pcap_dump_rec(pd, (u_char *) pd->pcap_dump.buffer + pd->pcap_dump.buffer_idx,
pctx);
pd->pcap_dump.buffer_idx += rec_size;
pd->pcap_dump.tot_size += rec_size;
}
}
((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);
}
/* ******************************************************* */
+2 -1
View File
@@ -360,6 +360,7 @@ 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_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);
@@ -386,7 +387,7 @@ void getApplicationByUid(pcapdroid_t *pd, jint uid, char *buf, int bufsize);
// Internals
struct pcapdroid_trailer;
void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn);
void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, int uid);
void init_ndpi_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b);
void load_ndpi_hosts(struct ndpi_detection_module_struct *ndpi);
uint32_t crc32(u_char *buf, size_t len, uint32_t crc);
+36 -36
View File
@@ -733,6 +733,7 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) {
pcapd_hdr_t phdr;
zdtun_pkt_t zpkt;
int len = hdr->caplen;
int uid = UID_UNKNOWN;
uint8_t is_tx = is_tx_packet(iface, pkt, len);
if(hdr->caplen < hdr->len)
@@ -747,8 +748,6 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) {
tupleSwapPeers(&zpkt.tuple);
}
int uid = UID_UNKNOWN;
if(!iface->is_file) {
uid = uid_lru_find(rt->lru, &zpkt.tuple);
@@ -763,45 +762,46 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) {
uid_lru_add(rt->lru, &zpkt.tuple, uid);
}
}
}
if((rt->conf->uid_filter == -1) || (rt->conf->uid_filter == uid)) {
if(rt->conf->dump_datalink) {
// Include the datalink header
pkt -= to_skip;
len += to_skip;
phdr.linktype = iface->dlink;
} else
phdr.linktype = DLT_RAW;
// export packet even if zdtun_parse_pkt failed
if((rt->conf->uid_filter == -1) || (rt->conf->uid_filter == uid)) {
if(rt->conf->dump_datalink) {
// Include the datalink header
pkt -= to_skip;
len += to_skip;
phdr.linktype = iface->dlink;
} else
phdr.linktype = DLT_RAW;
phdr.ts = hdr->ts;
phdr.len = len;
phdr.pkt_drops = iface->stats.ps_drop;
phdr.uid = uid;
phdr.flags = is_tx ? PCAPD_FLAG_TX : 0;
phdr.ifid = iface->ifid;
phdr.ts = hdr->ts;
phdr.len = len;
phdr.pkt_drops = iface->stats.ps_drop;
phdr.uid = uid;
phdr.flags = is_tx ? PCAPD_FLAG_TX : 0;
phdr.ifid = iface->ifid;
if(!rt->conf->no_client) {
// Send the pcapd_hdr_t first, then the packet data. The packet data always starts with
// the IP header.
if((xwrite(rt->client, &phdr, sizeof(phdr)) < 0) ||
(xwrite(rt->client, pkt, phdr.len) < 0)) {
log_e("write failed[%d]: %s", errno, strerror(errno));
return -1;
}
} else if(!rt->conf->quiet) {
char buf[512];
zdtun_5tuple2str(&zpkt.tuple, buf, sizeof(buf));
printf("[%s:%d] %s (%u B) [%cX] (%d)\n", iface->name,
iface->ifid, buf, phdr.len, is_tx ? 'T' : 'R',
uid);
if(!rt->conf->no_client) {
// Send the pcapd_hdr_t first, then the packet data. The packet data always starts with
// the IP header.
if((xwrite(rt->client, &phdr, sizeof(phdr)) < 0) ||
(xwrite(rt->client, pkt, phdr.len) < 0)) {
log_e("write failed[%d]: %s", errno, strerror(errno));
return -1;
}
} else if(!rt->conf->quiet) {
char buf[512];
zdtun_5tuple2str(&zpkt.tuple, buf, sizeof(buf));
if(iface->is_file) {
// libpcap does not provide stats for savefiles
// https://www.tcpdump.org/manpages/pcap_stats.3pcap.html
iface->stats.ps_recv++;
}
printf("[%s:%d] %s (%u B) [%cX] (%d)\n", iface->name,
iface->ifid, buf, phdr.len, is_tx ? 'T' : 'R',
uid);
}
if(iface->is_file) {
// libpcap does not provide stats for savefiles
// https://www.tcpdump.org/manpages/pcap_stats.3pcap.html
iface->stats.ps_recv++;
}
}
}