mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-05-08 21:12:26 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule submodules/zdtun updated: 611c5460a6...7336ffbd41
Reference in New Issue
Block a user