mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-11 21:01:45 +08:00
Add DPI and malware detection tests
This commit is contained in:
parent
44cda96718
commit
a59664415a
@ -254,18 +254,13 @@ 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;
|
||||
zdtun_ip_t parsed;
|
||||
|
||||
if(ipver == 4)
|
||||
ip.ip4 = addr.ipv4;
|
||||
else if(ipver == 6)
|
||||
memcpy(&ip.ip6, &addr.ipv6, 16);
|
||||
else
|
||||
int ipver = zdtun_parse_ip(ip_str, &parsed);
|
||||
if(ipver < 0)
|
||||
return false;
|
||||
|
||||
return blacklist_match_ip(bl, &ip, ipver);
|
||||
return blacklist_match_ip(bl, &parsed, ipver);
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
@ -14,10 +14,9 @@ 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})
|
||||
add_custom_target(run_tests COMMAND CTEST_OUTPUT_ON_FAILURE=1 ${CMAKE_CTEST_COMMAND})
|
||||
|
||||
# build_tests(target)
|
||||
macro(build_tests)
|
||||
@ -30,5 +29,9 @@ endmacro()
|
||||
|
||||
build_tests(pcap_reader)
|
||||
|
||||
add_test(NAME dpi_extract COMMAND ./dpi extract)
|
||||
build_tests(dpi)
|
||||
|
||||
add_test(NAME blacklist_match COMMAND ./blacklist match)
|
||||
add_test(NAME blacklist_detection COMMAND ./blacklist detection)
|
||||
build_tests(blacklist)
|
||||
|
||||
@ -51,9 +51,73 @@ static void test_match() {
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static void detection_cb(pcapdroid_t *pd) {
|
||||
conn_and_tuple_t *conn;
|
||||
|
||||
// IP blacklist
|
||||
conn = assert_conn(pd, IPPROTO_ICMP, "1.1.1.1", 0, NULL);
|
||||
assert1(conn->data->blacklisted_ip);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "216.58.208.164", 80, NULL);
|
||||
assert1(conn->data->blacklisted_ip);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "2c9b:a9b9:83dd:d9d1::2003", 443, NULL);
|
||||
assert1(conn->data->blacklisted_ip);
|
||||
|
||||
// Host blacklist
|
||||
conn = assert_conn(pd, IPPROTO_UDP, "8.8.8.8", 53, "www.google.it");
|
||||
assert0(conn->data->blacklisted_ip);
|
||||
assert1(conn->data->blacklisted_domain);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "146.112.255.155", 80, "www.internetbadguys.com");
|
||||
assert1(conn->data->blacklisted_domain);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "3a5d:15fe:e3cb:9c5f::2003", 443, "www.google.it");
|
||||
assert0(conn->data->blacklisted_ip);
|
||||
assert1(conn->data->blacklisted_domain);
|
||||
|
||||
// Whitelist
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "149.202.95.241", 80, "f-droid.org");
|
||||
assert0(conn->data->blacklisted_domain);
|
||||
assert0(conn->data->blacklisted_ip);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "2ed5:9050:81e9:4b68:248:1893:25c8:1946", 443, "example.org");
|
||||
assert0(conn->data->blacklisted_domain);
|
||||
assert0(conn->data->blacklisted_ip);
|
||||
}
|
||||
|
||||
static void test_detection() {
|
||||
pcapdroid_t *pd = pd_init(PCAP_PATH "/metadata.pcap");
|
||||
|
||||
blacklist_t *bl = blacklist_init();
|
||||
assert(bl != NULL);
|
||||
blacklist_t *wl = blacklist_init();
|
||||
assert(wl != NULL);
|
||||
pd->malware_detection.enabled = true;
|
||||
pd->malware_detection.bl = bl;
|
||||
pd->malware_detection.whitelist = wl;
|
||||
|
||||
// Load blacklist
|
||||
blacklist_add_ipstr(bl, "1.1.1.1");
|
||||
blacklist_add_ipstr(bl, "216.58.208.164");
|
||||
blacklist_add_ipstr(bl, "2c9b:a9b9:83dd:d9d1::2003");
|
||||
blacklist_add_ipstr(bl, "149.202.95.241");
|
||||
blacklist_add_domain(bl, "google.it");
|
||||
blacklist_add_domain(bl, "www.internetbadguys.com");
|
||||
blacklist_add_domain(bl, "example.org");
|
||||
|
||||
// Load whitelist
|
||||
blacklist_add_ipstr(wl, "149.202.95.241");
|
||||
blacklist_add_domain(wl, "example.org");
|
||||
|
||||
// Run
|
||||
pd->cb.send_connections_dump = detection_cb;
|
||||
pd_run(pd);
|
||||
|
||||
pd_free(pd);
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
add_test("match", test_match);
|
||||
run_test(argc, argv);
|
||||
add_test("detection", test_detection);
|
||||
|
||||
run_test(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
70
app/src/main/jni/tests/dpi.c
Normal file
70
app/src/main/jni/tests/dpi.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
// Called on send_connections_dump. pd->new_conns contains the dumped
|
||||
// connections. Ensures that metadata is correctly extracted from
|
||||
// network traffic.
|
||||
static void extract_metadata_cb(pcapdroid_t *pd) {
|
||||
conn_and_tuple_t *conn;
|
||||
|
||||
// DNS request without reply
|
||||
conn = assert_conn(pd, IPPROTO_UDP, "8.8.8.8", 53, "example.org");
|
||||
assert(conn->tuple.src_port == htons(48037));
|
||||
|
||||
// DNS (TCP)
|
||||
assert_conn(pd, IPPROTO_TCP, "8.8.8.8", 53, "f-droid.org");
|
||||
|
||||
// Guess host name from previous DNS request
|
||||
assert_conn(pd, IPPROTO_TCP, "149.202.95.241", 80, "f-droid.org");
|
||||
|
||||
// HTTP
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "216.58.208.164", 80, "www.google.com");
|
||||
assert(!strcmp(conn->data->url, "www.google.com/imghp?test=1&v2=2"));
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "385d:1ee:e3c9:9c5f::2004", 80, "www.google.com");
|
||||
assert(!strcmp(conn->data->url, "www.google.com/imghp?test=1&v2=2"));
|
||||
|
||||
// TLS
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "142.250.180.131", 443, "google.it");
|
||||
assert(conn->data->l7proto == NDPI_PROTOCOL_TLS);
|
||||
conn = assert_conn(pd, IPPROTO_TCP, "2ed5:9050:81e9:4b68:248:1893:25c8:1946", 443, "example.org");
|
||||
assert(conn->data->l7proto == NDPI_PROTOCOL_TLS);
|
||||
}
|
||||
|
||||
static void test_metadata_extraction() {
|
||||
conn_and_tuple_t *conn;
|
||||
pcapdroid_t *pd = pd_init(PCAP_PATH "/metadata.pcap");
|
||||
|
||||
pd->cb.send_connections_dump = extract_metadata_cb;
|
||||
pd_run(pd);
|
||||
|
||||
pd_free(pd);
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
add_test("extract", test_metadata_extraction);
|
||||
|
||||
run_test(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
27
app/src/main/jni/tests/pcap/README.md
Normal file
27
app/src/main/jni/tests/pcap/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
## metadata.pcap
|
||||
|
||||
Contains HTTP, TLS and DNS connections for both IPv4 and IPv6, suitable to test DPI.
|
||||
|
||||
Connections:
|
||||
|
||||
```
|
||||
[UDP4] 192.168.1.10:48037 -> 8.8.8.8:53 [example.org]
|
||||
[UDP4] 192.168.1.10:38793 -> 8.8.8.8:53 [www.google.com]
|
||||
[TCP4] 192.168.1.10:36922 -> 216.58.208.164:80 [www.google.com]
|
||||
[UDP4] 192.168.1.10:48772 -> 8.8.8.8:53 [www.google.com]
|
||||
[TCP6] 2001:db8:1234::1:49936 -> 385d:1ee:e3c9:9c5f::2004:80 [www.google.com]
|
||||
[UDP4] 192.168.1.10:51080 -> 8.8.8.8:53 [google.it]
|
||||
[TCP6] 2001:db8:1234::1:44904 -> 2c9b:a9b9:83dd:d9d1::2003:443 []
|
||||
[TCP4] 192.168.1.10:51588 -> 142.250.180.131:443 [google.it]
|
||||
[UDP4] 192.168.1.10:42218 -> 8.8.8.8:53 [www.google.it]
|
||||
[TCP6] 2001:db8:1234::1:59424 -> 3a5d:15fe:e3cb:9c5f::2003:443 [www.google.it]
|
||||
[ICMP4] 192.168.1.10:4 -> 1.1.1.1:0 []
|
||||
[UDP4] 192.168.1.10:47987 -> 8.8.8.8:53 [www.internetbadguys.com]
|
||||
[TCP4] 192.168.1.10:46312 -> 146.112.255.155:80 [www.internetbadguys.com]
|
||||
[UDP4] 192.168.1.10:51165 -> 8.8.8.8:53 [www.internetbadguys.com]
|
||||
[UDP4] 192.168.1.10:52176 -> 8.8.8.8:53 [example.org]
|
||||
[TCP6] 2001:db8:1234::1:45226 -> 2ed5:9050:81e9:4b68:248:1893:25c8:1946:443 [example.org]
|
||||
[TCP4] 192.168.1.10:43453 -> 8.8.8.8:53 [f-droid.org]
|
||||
[UDP4] 192.168.1.10:41011 -> 8.8.8.8:53 [f-droid.org]
|
||||
[TCP4] 192.168.1.10:52782 -> 149.202.95.241:80 [f-droid.org]
|
||||
```
|
||||
BIN
app/src/main/jni/tests/pcap/metadata.pcap
Normal file
BIN
app/src/main/jni/tests/pcap/metadata.pcap
Normal file
Binary file not shown.
@ -98,7 +98,7 @@ int main(int argc, char *argv[]) {
|
||||
log_i("Capturing packets from %s", ifname);
|
||||
pd_run(pd);
|
||||
|
||||
log_i("Terminated");
|
||||
log_i("Cleanup...");
|
||||
pd_free(pd);
|
||||
free(ifname);
|
||||
}
|
||||
|
||||
@ -88,3 +88,36 @@ pcapdroid_t* pd_init(const char *ifname) {
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
/* To be called during send_connections_dump. Looks up a connection
|
||||
* matching the specified protocol, IP port and info (if not NULL).
|
||||
* If no connection is found, abort is called. Only the first match is
|
||||
* returned.
|
||||
*/
|
||||
conn_and_tuple_t* assert_conn(pcapdroid_t *pd, int ipproto, const char *dst_ip,
|
||||
uint16_t dst_port, const char *info) {
|
||||
conn_and_tuple_t *found = NULL;
|
||||
zdtun_ip_t ip;
|
||||
dst_port = htons(dst_port);
|
||||
|
||||
int ipver = zdtun_parse_ip(dst_ip, &ip);
|
||||
assert((ipver == 4) || (ipver == 6));
|
||||
|
||||
for(int i=0; i < pd->new_conns.cur_items; i++) {
|
||||
conn_and_tuple_t *conn = &pd->new_conns.items[i];
|
||||
|
||||
if((conn->tuple.ipproto == ipproto) &&
|
||||
(conn->tuple.dst_port == dst_port) &&
|
||||
(conn->tuple.ipver == ipver) &&
|
||||
(!zdtun_cmp_ip(ipver, &conn->tuple.dst_ip, &ip)) &&
|
||||
((info == NULL) || ((conn->data->info != NULL) && !strcmp(info, conn->data->info)))) {
|
||||
found = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(found);
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -26,13 +26,14 @@
|
||||
#define assert0(x) assert((x) == 0)
|
||||
#define assert1(x) assert((x) == 1)
|
||||
|
||||
#define PCAP_PATH "../pcap"
|
||||
|
||||
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); }
|
||||
|
||||
static inline void pd_free(pcapdroid_t *pd) {
|
||||
free(pd);
|
||||
}
|
||||
conn_and_tuple_t* assert_conn(pcapdroid_t *pd, int ipproto, const char *dst_ip, uint16_t dst_port, const char *info);
|
||||
|
||||
#endif
|
||||
|
||||
23
docs/testing.md
Normal file
23
docs/testing.md
Normal file
@ -0,0 +1,23 @@
|
||||
Tests in PCAPdroid can be split in the following categories:
|
||||
|
||||
- [Java tests](https://github.com/emanuele-f/PCAPdroid/tree/dev/app/src/test/java):
|
||||
they can be run via `./gradlew test`. They use the
|
||||
[robolectric framework](https://github.com/robolectric/robolectric)
|
||||
to mock the Android API, allowing them to be run locally (without an emulator)
|
||||
|
||||
- [Native tests](https://github.com/emanuele-f/PCAPdroid/tree/dev/app/src/main/jni/tests):
|
||||
they can be run with `./run_tests.sh` on a linux host. They are built
|
||||
with the [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
|
||||
to detect memory issues and leaks
|
||||
|
||||
The tests are executed on every push via the
|
||||
[Github workflows](https://github.com/emanuele-f/PCAPdroid/tree/dev/.github/workflows)
|
||||
|
||||
Apart from automatic tests, the following manual tests should be performed
|
||||
before every release:
|
||||
|
||||
- Test on devices matching the `minSdkVersion` (currently Android SDK 21)
|
||||
- Test on devices matching the `targetSdkVersion` (currently Android SDK 31)
|
||||
- Rotate the device, put activity in background, clear from recent activities
|
||||
- Java memory consumption tests via the [Memory Profiler](https://developer.android.com/studio/profile/memory-profiler)
|
||||
- Manual malware detection test against `internetbadguys.com` and `0.0.0.1`
|
||||
@ -1 +1 @@
|
||||
Subproject commit e536c593d1fe49c67617911b18bda23a13138e5d
|
||||
Subproject commit 240ae6459c9ef55c90ab8fd4fea1e60d8b5ad8b2
|
||||
Loading…
Reference in New Issue
Block a user