Add pcap_reader and blacklist tests

The pcap_reader can be used to test the native PCAPdroid implementation.
Native tests can be run with run_tests.sh
This commit is contained in:
emanuele-f 2022-01-20 12:05:31 +01:00
parent 32da035db9
commit 2ea1229938
16 changed files with 422 additions and 44 deletions

View File

@ -13,6 +13,10 @@ set(ZDTUN_ROOT ${ROOTDIR}/submodules/zdtun)
include_directories(${ZDTUN_ROOT}) include_directories(${ZDTUN_ROOT})
add_subdirectory(${ZDTUN_ROOT} zdtun_build) add_subdirectory(${ZDTUN_ROOT} zdtun_build)
# nDPI
set(NDPI_ROOT ${ROOTDIR}/submodules/nDPI)
include_directories(${NDPI_ROOT}/src/include ${NDPI_ROOT}/src/lib/third_party/include)
# base # base
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -108,6 +108,7 @@ ssize_t xwrite(int fd, const void *buf, size_t count) {
/* ******************************************************* */ /* ******************************************************* */
// returns < 0 on error, 0 if fd is closed
ssize_t xread(int fd, void *buf, size_t count) { ssize_t xread(int fd, void *buf, size_t count) {
size_t sofar = 0; size_t sofar = 0;
ssize_t rv; ssize_t rv;
@ -125,9 +126,9 @@ ssize_t xread(int fd, void *buf, size_t count) {
} while((sofar != count) && (rv != 0)); } while((sofar != count) && (rv != 0));
if(sofar != count) if(sofar != count)
return -1; return (rv == 0) ? 0 : -1;
return 0; return count;
} }
/* ******************************************************* */ /* ******************************************************* */

View File

@ -12,9 +12,7 @@ add_library(capture SHARED
jni_impl.c) jni_impl.c)
# nDPI # nDPI
set(NDPI_ROOT ${ROOTDIR}/submodules/nDPI)
add_definitions(-DNDPI_LIB_COMPILATION) add_definitions(-DNDPI_LIB_COMPILATION)
include_directories(${NDPI_ROOT}/src/include ${NDPI_ROOT}/src/lib/third_party/include)
AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib ndpiSources) AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib ndpiSources)
AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib/third_party/src ndpiSources) AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib/third_party/src ndpiSources)
AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib/protocols ndpiSources) AUX_SOURCE_DIRECTORY(${NDPI_ROOT}/src/lib/protocols ndpiSources)

View File

@ -253,6 +253,23 @@ bool blacklist_match_ip(blacklist_t *bl, const zdtun_ip_t *ip, int ipver) {
/* ******************************************************* */ /* ******************************************************* */
bool blacklist_match_ipstr(blacklist_t *bl, const char *ip_str) {
ndpi_ip_addr_t addr;
int ipver = ndpi_parse_ip_string(ip_str, &addr);
zdtun_ip_t ip;
if(ipver == 4)
ip.ip4 = addr.ipv4;
else if(ipver == 6)
memcpy(&ip.ip6, &addr.ipv6, 16);
else
return false;
return blacklist_match_ip(bl, &ip, ipver);
}
/* ******************************************************* */
bool blacklist_match_domain(blacklist_t *bl, const char *domain) { bool blacklist_match_domain(blacklist_t *bl, const char *domain) {
string_entry_t *entry = NULL; string_entry_t *entry = NULL;

View File

@ -76,6 +76,7 @@ int blacklist_load_file(blacklist_t *bl, const char *path, blacklist_type btype,
int blacklist_load_list_descriptor(blacklist_t *bl, JNIEnv *env, jobject ld); int blacklist_load_list_descriptor(blacklist_t *bl, JNIEnv *env, jobject ld);
#endif #endif
bool blacklist_match_ip(blacklist_t *bl, const zdtun_ip_t *ip, int ipver); bool blacklist_match_ip(blacklist_t *bl, const zdtun_ip_t *ip, int ipver);
bool blacklist_match_ipstr(blacklist_t *bl, const char *ip);
bool blacklist_match_domain(blacklist_t *bl, const char *domain); bool blacklist_match_domain(blacklist_t *bl, const char *domain);
bool blacklist_match_uid(blacklist_t *bl, int uid); bool blacklist_match_uid(blacklist_t *bl, int uid);
void blacklist_get_stats(const blacklist_t *bl, blacklists_stats_t *stats); void blacklist_get_stats(const blacklist_t *bl, blacklists_stats_t *stats);

View File

@ -45,7 +45,7 @@ struct pcap_conn {
/* ******************************************************* */ /* ******************************************************* */
static int su_cmd(const char *prog, const char *args, bool check_error) { static int run_cmd(const char *prog, const char *args, bool as_root, bool check_error) {
int in_p[2], out_p[2]; int in_p[2], out_p[2];
int rv = -1; int rv = -1;
pid_t pid; pid_t pid;
@ -57,7 +57,7 @@ static int su_cmd(const char *prog, const char *args, bool check_error) {
if((pid = fork()) == 0) { if((pid = fork()) == 0) {
// child // child
char *argp[] = {"sh", "-c", "su", NULL}; char *argp[] = {"sh", "-c", as_root ? "su" : "sh", NULL};
close(in_p[1]); close(in_p[1]);
close(out_p[0]); close(out_p[0]);
@ -76,7 +76,7 @@ static int su_cmd(const char *prog, const char *args, bool check_error) {
close(out_p[1]); close(out_p[1]);
// write "su" command input // write "su" command input
log_d("su_cmd[%d]: %s %s", pid, prog, args); log_d("run_cmd[%d]: %s %s", pid, prog, args);
write(in_p[1], prog, strlen(prog)); write(in_p[1], prog, strlen(prog));
write(in_p[1], " ", 1); write(in_p[1], " ", 1);
write(in_p[1], args, strlen(args)); write(in_p[1], args, strlen(args));
@ -133,7 +133,7 @@ static void kill_pcapd(pcapdroid_t *nc) {
if(pid != 0) { if(pid != 0) {
log_d("Killing old pcapd with pid %d", pid); log_d("Killing old pcapd with pid %d", pid);
su_cmd("kill", pid_s, false); run_cmd("kill", pid_s, true, false);
} }
fclose(f); fclose(f);
@ -144,15 +144,8 @@ static void kill_pcapd(pcapdroid_t *nc) {
static int connectPcapd(pcapdroid_t *pd) { static int connectPcapd(pcapdroid_t *pd) {
int sock; int sock;
int client = -1; int client = -1;
char bpf[256];
char pcapd[PATH_MAX]; char pcapd[PATH_MAX];
char capture_interface[16] = "@inet"; char *bpf = pd->root.bpf ? pd->root.bpf : "";
bpf[0] = '\0';
#if ANDROID
getStringPref(pd, "getPcapDumperBpf", bpf, sizeof(bpf));
getStringPref(pd, "getCaptureInterface", capture_interface, sizeof(capture_interface));
#endif
if(pd->cb.get_libprog_path) if(pd->cb.get_libprog_path)
pd->cb.get_libprog_path(pd, "pcapd", pcapd, sizeof(pcapd)); pd->cb.get_libprog_path(pd, "pcapd", pcapd, sizeof(pcapd));
@ -198,8 +191,8 @@ static int connectPcapd(pcapdroid_t *pd) {
// Start the daemon // Start the daemon
char args[256]; char args[256];
snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -t -b \"%s\"", capture_interface, pd->app_filter, bpf); snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -t -b \"%s\"", pd->root.capture_interface, pd->app_filter, bpf);
if(su_cmd(pcapd, args, true) != 0) if(run_cmd(pcapd, args, pd->root.as_root, true) != 0)
goto cleanup; goto cleanup;
// Wait for pcapd to start // Wait for pcapd to start
@ -497,6 +490,16 @@ int run_root(pcapdroid_t *pd) {
u_int64_t next_purge_ms; u_int64_t next_purge_ms;
zdtun_callbacks_t callbacks = {.send_client = (void*)1}; zdtun_callbacks_t callbacks = {.send_client = (void*)1};
#if ANDROID
char capture_interface[16] = "@inet";
char bpf[256];
bpf[0] = '\0';
pd->root.as_root = true; // TODO support read from PCAP file
pd->root.bpf = getStringPref(pd, "getPcapDumperBpf", bpf, sizeof(bpf));
pd->root.capture_interface = getStringPref(pd, "getCaptureInterface", capture_interface, sizeof(capture_interface));
#endif
if((pd->zdt = zdtun_init(&callbacks, NULL)) == NULL) if((pd->zdt = zdtun_init(&callbacks, NULL)) == NULL)
return(-1); return(-1);
@ -531,15 +534,17 @@ int run_root(pcapdroid_t *pd) {
if(!FD_ISSET(sock, &fdset)) if(!FD_ISSET(sock, &fdset))
goto housekeeping; goto housekeeping;
if(xread(sock, &hdr, sizeof(hdr)) < 0) { ssize_t xrv = xread(sock, &hdr, sizeof(hdr));
log_e("read hdr from pcapd failed[%d]: %s", errno, strerror(errno)); if(xrv != sizeof(hdr)) {
if(xrv < 0)
log_e("read hdr from pcapd failed[%d]: %s", errno, strerror(errno));
goto cleanup; goto cleanup;
} }
if(hdr.len > sizeof(buffer)) { if(hdr.len > sizeof(buffer)) {
log_e("packet too big (%d B)", hdr.len); log_e("packet too big (%d B)", hdr.len);
goto cleanup; goto cleanup;
} }
if(xread(sock, buffer, hdr.len) < 0) { if(xread(sock, buffer, hdr.len) != hdr.len) {
log_e("read %d B packet from pcapd failed[%d]: %s", hdr.len, errno, strerror(errno)); log_e("read %d B packet from pcapd failed[%d]: %s", hdr.len, errno, strerror(errno));
goto cleanup; goto cleanup;
} }

View File

@ -473,10 +473,8 @@ Java_com_emanuelef_remote_1capture_CaptureService_runPacketLoop(JNIEnv *env, jcl
.notify_service_status = notifyServiceStatus, .notify_service_status = notifyServiceStatus,
.notify_blacklists_loaded = notifyBlacklistsLoaded, .notify_blacklists_loaded = notifyBlacklistsLoaded,
}, },
.ip_to_host = ip_lru_init(MAX_HOST_LRU_SIZE),
.app_filter = getIntPref(env, vpn, "getAppFilterUid"), .app_filter = getIntPref(env, vpn, "getAppFilterUid"),
.root_capture = (bool) getIntPref(env, vpn, "isRootCapture"), .root_capture = (bool) getIntPref(env, vpn, "isRootCapture"),
.new_conn_id = 0,
.pcap_dump = { .pcap_dump = {
.enabled = (bool) getIntPref(env, vpn, "pcapDumpEnabled"), .enabled = (bool) getIntPref(env, vpn, "pcapDumpEnabled"),
}, },

View File

@ -1039,6 +1039,8 @@ int pd_run(pcapdroid_t *pd) {
return(-1); return(-1);
} }
pd->ip_to_host = ip_lru_init(MAX_HOST_LRU_SIZE);
if(pd->malware_detection.enabled && pd->cb.load_blacklists_info) if(pd->malware_detection.enabled && pd->cb.load_blacklists_info)
pd->cb.load_blacklists_info(pd); pd->cb.load_blacklists_info(pd);
@ -1075,6 +1077,10 @@ int pd_run(pcapdroid_t *pd) {
log_d("Stopped packet loop"); log_d("Stopped packet loop");
// send last dump
if(pd->cb.send_connections_dump)
pd->cb.send_connections_dump(pd);
conns_clear(&pd->new_conns, true); conns_clear(&pd->new_conns, true);
conns_clear(&pd->conns_updates, true); conns_clear(&pd->conns_updates, true);

View File

@ -138,7 +138,7 @@ struct pcapdroid;
// Used to decouple pcapdroid.c from the JNI calls // Used to decouple pcapdroid.c from the JNI calls
typedef struct { typedef struct {
void (*get_libprog_path)(struct pcapdroid *pd, const char *prog_name, char *buf, int bufsize); void (*get_libprog_path)(struct pcapdroid *pd, const char *prog_name, char *buf, int bufsize);
int (*load_blacklists_info)(struct pcapdroid *pd); int (*load_blacklists_info)(struct pcapdroid *pd);
void (*send_stats_dump)(struct pcapdroid *pd); void (*send_stats_dump)(struct pcapdroid *pd);
void (*send_connections_dump)(struct pcapdroid *pd); void (*send_connections_dump)(struct pcapdroid *pd);
void (*send_pcap_dump)(struct pcapdroid *pd); void (*send_pcap_dump)(struct pcapdroid *pd);
@ -193,7 +193,10 @@ typedef struct pcapdroid {
} vpn; } vpn;
struct { struct {
pcap_conn_t *connections; pcap_conn_t *connections;
} root; bool as_root;
char *bpf;
char *capture_interface;
} root; // TODO rename: it can run without root to read a PCAP file
}; };
struct { struct {

View File

@ -73,6 +73,7 @@ typedef struct {
char name[IFNAMSIZ]; char name[IFNAMSIZ];
int ifidx; int ifidx;
uint8_t ifid; // positional interface index uint8_t ifid; // positional interface index
uint8_t is_file;
pcap_t *pd; pcap_t *pd;
int pf; int pf;
int dlink; int dlink;
@ -395,22 +396,28 @@ static void init_interface(pcapd_iface_t *iface) {
static int open_interface(pcapd_iface_t *iface, pcapd_runtime_t *rt, const char *ifname, int ifid) { static int open_interface(pcapd_iface_t *iface, pcapd_runtime_t *rt, const char *ifname, int ifid) {
#ifndef READ_FROM_PCAP #ifndef READ_FROM_PCAP
int is_file = 0;
int mtu = get_iface_mtu(ifname); int mtu = get_iface_mtu(ifname);
if(mtu < 0) {
mtu = 1500;
log_w("Could not get \"%s\" interface MTU, assuming %d", ifname, mtu);
}
/* The snaplen includes the datalink overhead. Max datalink overhead (SLL2): 20 B */ /* The snaplen includes the datalink overhead. Max datalink overhead (SLL2): 20 B */
int snaplen = mtu + SLL2_HDR_LEN; int snaplen = mtu + SLL2_HDR_LEN;
log_d("Using a %d snaplen (MTU %d)", snaplen, mtu);
pcap_t *pd = pcap_open_live(ifname, snaplen, 0, 1, errbuf); pcap_t *pd = pcap_open_live(ifname, snaplen, 0, 1, errbuf);
if(!pd) { if(!pd) {
log_i("pcap_open_live(%s) failed: %s", ifname, errbuf); // try to open as file
return -1; pd = pcap_open_offline(ifname, errbuf);
if(!pd) {
log_i("pcap_open(%s) failed: %s", ifname, errbuf);
return -1;
}
is_file = 1;
} else {
if(mtu < 0) {
mtu = 1500;
log_w("Could not get \"%s\" interface MTU, assuming %d", ifname, mtu);
}
log_d("Using a %d snaplen (MTU %d)", snaplen, mtu);
} }
// Fixes pcap_next_ex sometimes hanging on interface down // Fixes pcap_next_ex sometimes hanging on interface down
@ -479,20 +486,21 @@ static int open_interface(pcapd_iface_t *iface, pcapd_runtime_t *rt, const char
// Success // Success
iface->pd = pd; iface->pd = pd;
iface->is_file = is_file;
iface->mac = 0; iface->mac = 0;
iface->ifid = ifid; iface->ifid = ifid;
iface->ifidx = if_nametoindex(ifname); iface->ifidx = if_nametoindex(ifname);
errno = 0; errno = 0;
if((dlink == DLT_EN10MB) && (get_iface_mac(ifname, &iface->mac) < 0)) if(!is_file && (dlink == DLT_EN10MB) && (get_iface_mac(ifname, &iface->mac) < 0))
log_i("Could not get interface \"%s\" MAC[%d]: %s", ifname, errno, strerror(errno)); log_i("Could not get interface \"%s\" MAC[%d]: %s", ifname, errno, strerror(errno));
uint32_t netmask; uint32_t netmask;
iface->ip = 0; iface->ip = 0;
if(get_iface_ip(ifname, &iface->ip, &netmask) < 0) if(!is_file && get_iface_ip(ifname, &iface->ip, &netmask) < 0)
log_i("Could not get interface \"%s\" IP[%d]: %s", ifname, errno, strerror(errno)); log_i("Could not get interface \"%s\" IP[%d]: %s", ifname, errno, strerror(errno));
if(get_iface_ip6(ifname, &iface->ip6) < 0) { if(!is_file && get_iface_ip6(ifname, &iface->ip6) < 0) {
log_i("Could not get interface \"%s\" IPv6[%d]: %s", ifname, errno, strerror(errno)); log_i("Could not get interface \"%s\" IPv6[%d]: %s", ifname, errno, strerror(errno));
memset(&iface->ip6, 0, sizeof(iface->ip6)); memset(&iface->ip6, 0, sizeof(iface->ip6));
} }
@ -744,9 +752,12 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) {
// abort, resuming other interfaces is not supported yet // abort, resuming other interfaces is not supported yet
return -1; return -1;
} else if(rv != 1) {
// TODO handle EOF without error
return -1;
} }
if((rv == 1) && (hdr->caplen >= to_skip)) { if(hdr->caplen >= to_skip) {
pcapd_hdr_t phdr; pcapd_hdr_t phdr;
zdtun_pkt_t zpkt; zdtun_pkt_t zpkt;
int len = hdr->caplen; int len = hdr->caplen;
@ -764,11 +775,15 @@ static int read_pkt(pcapd_runtime_t *rt, pcapd_iface_t *iface, time_t now) {
tupleSwapPeers(&zpkt.tuple); tupleSwapPeers(&zpkt.tuple);
} }
int uid = uid_lru_find(rt->lru, &zpkt.tuple); int uid = UID_UNKNOWN;
if(uid == -2) { if(!iface->is_file) {
uid = get_uid(rt->resolver, &zpkt.tuple); uid = uid_lru_find(rt->lru, &zpkt.tuple);
uid_lru_add(rt->lru, &zpkt.tuple, uid);
if(uid == -2) {
uid = get_uid(rt->resolver, &zpkt.tuple);
uid_lru_add(rt->lru, &zpkt.tuple, uid);
}
} }
if((rt->conf->uid_filter == -1) || (rt->conf->uid_filter == uid)) { if((rt->conf->uid_filter == -1) || (rt->conf->uid_filter == uid)) {
@ -1011,6 +1026,9 @@ int main(int argc, char *argv[]) {
rv = run_pcap_dump(&conf); rv = run_pcap_dump(&conf);
unlink(PCAPD_PID); unlink(PCAPD_PID);
for(int i=0; i<conf.num_interfaces; i++)
free(conf.ifnames[i]);
if(conf.bpf) if(conf.bpf)
free(conf.bpf); free(conf.bpf);
if(conf.log_file) if(conf.log_file)

View File

@ -0,0 +1,32 @@
project(test)
cmake_minimum_required(VERSION 3.18.1)
set(ROOTDIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/main)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
include_directories(${ROOTDIR}/submodules/zdtun)
include_directories(${ROOTDIR}/submodules/nDPI/src/include)
include(CTest)
list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure")
# Target to run tests and build them if necessary
add_custom_target(run_tests COMMAND ${CMAKE_CTEST_COMMAND})
# build_tests(target)
macro(build_tests)
ADD_EXECUTABLE(${ARGV0} ${ARGV0}.c test_utils.c)
add_dependencies(${ARGV0} libpcapd.so)
add_dependencies(run_tests ${ARGV0})
target_link_libraries(${ARGV0}
capture
pthread
m)
endmacro()
build_tests(pcap_reader)
add_test(NAME blacklist_match COMMAND ./blacklist match)
build_tests(blacklist)

View File

@ -0,0 +1,59 @@
/*
* This file is part of PCAPdroid.
*
* PCAPdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PCAPdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2022 - Emanuele Faranda
*/
#include "test_utils.h"
/* ******************************************************* */
static void test_match() {
blacklist_t *bl = blacklist_init();
assert(bl != NULL);
// Load blacklist
assert0(blacklist_add_domain(bl, "example.org"));
assert0(blacklist_add_ipstr(bl, "1.2.3.4"));
assert0(blacklist_add_ipstr(bl, "::2"));
assert0(blacklist_add_uid(bl, 777));
assert0(blacklist_add_uid(bl, 888));
// Use blacklist
assert1(blacklist_match_domain(bl, "www.example.org"));
//assert1(blacklist_match_domain(bl, "some.example.org")); // TODO support subdomains matching
assert0(blacklist_match_ipstr(bl, "1.2.3.0"));
assert1(blacklist_match_ipstr(bl, "1.2.3.4"));
assert0(blacklist_match_ipstr(bl, "::1"));
assert1(blacklist_match_ipstr(bl, "::2"));
assert0(blacklist_match_uid(bl, 0));
assert0(blacklist_match_uid(bl, 999));
assert1(blacklist_match_uid(bl, 777));
blacklist_destroy(bl);
}
/* ******************************************************* */
int main(int argc, char **argv) {
add_test("match", test_match);
run_test(argc, argv);
return 0;
}

View File

@ -0,0 +1,104 @@
/*
* This file is part of PCAPdroid.
*
* PCAPdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PCAPdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2022 - Emanuele Faranda
*/
#include <stdio.h>
#include <signal.h>
#include "test_utils.h"
#include "common/utils.h"
/* ******************************************************* */
static void usage() {
fprintf(stderr, "pcap_reader - test for PCAPdroid\n"
"Copyright 2022 Emanuele Faranda <black.silver@hotmail.it>\n\n"
"Usage: pcap_reader -i ifname\n"
" -i [ifname] capture packets on the specified interface or PCAP file.\n"
" The '@inet' keyword can be used to capture from the internet\n"
" interface\n"
);
exit(1);
}
/* ******************************************************* */
static void sig_handler(int signo) {
if(running) {
running = false;
return;
}
fprintf(stderr, "exit now");
exit(1);
}
/* ******************************************************* */
static void dump_connections(pcapdroid_t *pd) {
char buf[256];
for(int i=0; i < pd->new_conns.cur_items; i++) {
conn_and_tuple_t *conn = &pd->new_conns.items[i];
zdtun_5tuple2str(&conn->tuple, buf, sizeof(buf));
printf("%s [%s]\n", buf,
//pd_get_proto_name(pd, conn->data->l7proto, conn->tuple.ipproto),
conn->data->info ? conn->data->info : "");
}
}
/* ******************************************************* */
int main(int argc, char *argv[]) {
int c;
char *ifname = NULL;
uint8_t verbose = 0;
while((c = getopt(argc, argv, "hi:v")) != -1) {
switch(c) {
case 'i':
ifname = strdup(optarg);
break;
case 'v':
verbose = 1;
break;
default:
usage();
}
}
if(ifname == NULL)
usage();
loglevel = verbose ? ANDROID_LOG_DEBUG : ANDROID_LOG_INFO;
pcapdroid_t *pd = pd_init(ifname);
pd->cb.send_connections_dump = dump_connections;
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
signal(SIGHUP, sig_handler);
log_i("Capturing packets from %s", ifname);
pd_run(pd);
log_i("Terminated");
pd_free(pd);
free(ifname);
}

View File

@ -0,0 +1,4 @@
#!/bin/bash
mkdir -p build
cd build && cmake .. && make -j$(nproc) run_tests

View File

@ -0,0 +1,90 @@
/*
* This file is part of PCAPdroid.
*
* PCAPdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PCAPdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2022 - Emanuele Faranda
*/
#include "test_utils.h"
#define TEST_NAME_MAX_LENGTH 32
#define MAX_TESTS 32
typedef struct {
char name[TEST_NAME_MAX_LENGTH];
void (*cb)();
} test_spec;
static test_spec all_tests[MAX_TESTS] = {0};
static void getPcapdPath(struct pcapdroid *pd, const char *prog_name, char *buf, int bufsize) {
snprintf(buf, bufsize, "main/pcapd/libpcapd.so");
}
/* ******************************************************* */
void add_test(const char *name, void (*test_cb)()) {
int len = strlen(name);
assert(len < TEST_NAME_MAX_LENGTH);
for(int i=0; i<MAX_TESTS; i++) {
if(all_tests[i].cb == NULL) {
memcpy(all_tests[i].name, name, len); // \0 is already there
all_tests[i].cb = test_cb;
return;
}
}
// MAX_TESTS exceeded
assert(0);
}
/* ******************************************************* */
void run_test(int argc, char **argv) {
assert(argc == 2);
const char *test_name = argv[1];
test_spec *test = NULL;
for(int i=0; ((i < MAX_TESTS) && (all_tests[i].cb != NULL)); i++) {
if(!strcmp(all_tests[i].name, test_name)) {
test = &all_tests[i];
break;
}
}
assert(test != NULL);
// run the test
test->cb();
}
/* ******************************************************* */
pcapdroid_t* pd_init(const char *ifname) {
pcapdroid_t *pd = calloc(1, sizeof(pcapdroid_t));
assert(pd != NULL);
pd->root_capture = true;
pd->root.capture_interface = (char*) ifname;
pd->root.as_root = false; // don't run as root
pd->app_filter = -1; // don't filter
pd->cb.get_libprog_path = getPcapdPath;
strcpy(pd->cachedir, ".");
pd->cachedir_len = 1;
return pd;
}

View File

@ -0,0 +1,38 @@
/*
* This file is part of PCAPdroid.
*
* PCAPdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PCAPdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2022 - Emanuele Faranda
*/
#ifndef __TEST_UTILS_H__
#define __TEST_UTILS_H__
#include "core/pcapdroid.h"
#include <assert.h>
#define assert0(x) assert((x) == 0)
#define assert1(x) assert((x) == 1)
void add_test(const char *name, void (*test_cb)());
void run_test(int argc, char **argv);
pcapdroid_t* pd_init(const char *ifname);
static inline void pd_free(pcapdroid_t *pd) {
free(pd);
}
#endif