mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-16 21:10:57 +08:00
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:
parent
32da035db9
commit
2ea1229938
@ -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})
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ******************************************************* */
|
/* ******************************************************* */
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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"),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
32
app/src/main/jni/tests/CMakeLists.txt
Normal file
32
app/src/main/jni/tests/CMakeLists.txt
Normal 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)
|
||||||
59
app/src/main/jni/tests/blacklist.c
Normal file
59
app/src/main/jni/tests/blacklist.c
Normal 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;
|
||||||
|
}
|
||||||
104
app/src/main/jni/tests/pcap_reader.c
Normal file
104
app/src/main/jni/tests/pcap_reader.c
Normal 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);
|
||||||
|
}
|
||||||
4
app/src/main/jni/tests/run_tests.sh
Executable file
4
app/src/main/jni/tests/run_tests.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
cd build && cmake .. && make -j$(nproc) run_tests
|
||||||
90
app/src/main/jni/tests/test_utils.c
Normal file
90
app/src/main/jni/tests/test_utils.c
Normal 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;
|
||||||
|
}
|
||||||
38
app/src/main/jni/tests/test_utils.h
Normal file
38
app/src/main/jni/tests/test_utils.h
Normal 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
|
||||||
Loading…
Reference in New Issue
Block a user