Rename vpnproxy to pcapdroid

This commit is contained in:
emanuele-f 2021-12-06 16:29:37 +01:00
parent c74d15658f
commit c079474917
18 changed files with 558 additions and 549 deletions

View File

@ -142,7 +142,7 @@ public class CaptureService extends VpnService implements Runnable {
static {
/* Load native library */
System.loadLibrary("vpnproxy-jni");
System.loadLibrary("capture");
}
@Override

View File

@ -30,7 +30,7 @@ import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
/* Equivalent of zdtun_conn_t from zdtun and conn_data_t from vpnproxy.c */
/* Equivalent of zdtun_conn_t from zdtun and pd_conn_t from pcapdroid.c */
public class ConnectionDescriptor implements Serializable {
// sync with zdtun_conn_status_t

View File

@ -18,4 +18,4 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(common)
add_subdirectory(pcapd)
add_subdirectory(vpnproxy-jni)
add_subdirectory(core)

View File

@ -24,7 +24,7 @@
memtrack_t memtrack = {0};
int loglevel = 0;
const char *logtag = "VPNProxy";
const char *logtag = "pcapdroid-native";
void (*logcallback)(int lvl, const char *msg) = NULL;
/* ******************************************************* */
@ -211,4 +211,4 @@ char* humanSize(char *buf, int bufsize, double bytes) {
snprintf(buf, bufsize, "%.02f %s", bytes, suffix[i]);
return buf;
}
}

View File

@ -1,8 +1,8 @@
project(vpnproxy-jni)
project(core)
add_library(vpnproxy-jni SHARED
vpnproxy.c
capture_proxy.c
add_library(capture SHARED
pcapdroid.c
capture_vpn.c
capture_root.c
ip_lru.c
ndpi_master_protos.c
@ -27,7 +27,7 @@ ADD_LIBRARY(ndpi SHARED ${ndpiSources} ${NDPI_ROOT}/src/include/ndpi_api.h)
find_library(log-lib log)
target_link_libraries(vpnproxy-jni
target_link_libraries(capture
zdtun
ndpi
common

View File

@ -17,7 +17,7 @@
* Copyright 2020-21 - Emanuele Faranda
*/
#include "vpnproxy.h"
#include "pcapdroid.h"
#include "common/utils.h"
typedef struct {

View File

@ -45,6 +45,22 @@ typedef enum {
UID_BLACKLIST
} blacklist_type;
typedef struct {
char *fname;
blacklist_type type;
} bl_info_t;
typedef struct {
char *fname;
int num_rules;
} bl_status_t;
typedef struct {
bl_status_t *items;
int size;
int cur_items;
} bl_status_arr_t;
blacklist_t* blacklist_init();
void blacklist_destroy(blacklist_t *bl);
int blacklist_add_domain(blacklist_t *bl, const char *domain);

View File

@ -21,7 +21,7 @@
#include <linux/limits.h>
#include <sys/wait.h>
#include <paths.h>
#include "vpnproxy.h"
#include "pcapdroid.h"
#include "pcapd/pcapd.h"
#include "common/utils.h"
#include "third_party/uthash.h"
@ -35,7 +35,7 @@
struct pcap_conn {
zdtun_5tuple_t tuple;
conn_data_t *data;
pd_conn_t *data;
UT_hash_handle hh;
};
@ -117,8 +117,8 @@ static int su_cmd(const char *prog, const char *args, bool check_error) {
/* ******************************************************* */
static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char *buf, int bufsize) {
JNIEnv *env = proxy->env;
static void get_libprog_path(pcapdroid_t *pd, const char *prog_name, char *buf, int bufsize) {
JNIEnv *env = pd->env;
jobject prog_str = (*env)->NewStringUTF(env, prog_name);
buf[0] = '\0';
@ -128,7 +128,7 @@ static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char
return;
}
jstring obj = (*env)->CallObjectMethod(env, proxy->vpn_service, mids.getLibprogPath, prog_str);
jstring obj = (*env)->CallObjectMethod(env, pd->vpn_service, mids.getLibprogPath, prog_str);
if(!jniCheckException(env)) {
const char *value = (*env)->GetStringUTFChars(env, obj, 0);
@ -144,7 +144,7 @@ static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char
/* ******************************************************* */
static void kill_pcapd(vpnproxy_data_t *proxy) {
static void kill_pcapd(pcapdroid_t *nc) {
int pid;
char pid_s[8];
FILE *f = fopen(PCAPD_PID, "r");
@ -165,16 +165,16 @@ static void kill_pcapd(vpnproxy_data_t *proxy) {
/* ******************************************************* */
static int connectPcapd(vpnproxy_data_t *proxy) {
static int connectPcapd(pcapdroid_t *pd) {
int sock;
int client = -1;
char bpf[256];
char pcapd[PATH_MAX];
char capture_interface[16];
getStringPref(proxy, "getPcapDumperBpf", bpf, sizeof(bpf));
getStringPref(proxy, "getCaptureInterface", capture_interface, sizeof(capture_interface));
get_libprog_path(proxy, "pcapd", pcapd, sizeof(pcapd));
getStringPref(pd, "getPcapDumperBpf", bpf, sizeof(bpf));
getStringPref(pd, "getCaptureInterface", capture_interface, sizeof(capture_interface));
get_libprog_path(pd, "pcapd", pcapd, sizeof(pcapd));
if(!pcapd[0])
return(-1);
@ -198,7 +198,7 @@ static int connectPcapd(vpnproxy_data_t *proxy) {
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, PCAPD_SOCKET_PATH);
kill_pcapd(proxy);
kill_pcapd(pd);
unlink(PCAPD_PID);
unlink(PCAPD_SOCKET_PATH);
@ -217,7 +217,7 @@ static int connectPcapd(vpnproxy_data_t *proxy) {
// Start the daemon
char args[256];
snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -b \"%s\"", capture_interface, proxy->app_filter, bpf);
snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -b \"%s\"", capture_interface, pd->app_filter, bpf);
if(su_cmd(pcapd, args, true) != 0)
goto cleanup;
@ -250,27 +250,27 @@ cleanup:
/* ******************************************************* */
static void remove_connection(vpnproxy_data_t *proxy, pcap_conn_t *conn) {
static void remove_connection(pcapdroid_t *pd, pcap_conn_t *conn) {
switch (conn->tuple.ipproto) {
case IPPROTO_TCP:
proxy->stats.num_tcp_conn--;
pd->stats.num_tcp_conn--;
break;
case IPPROTO_UDP:
proxy->stats.num_udp_conn--;
pd->stats.num_udp_conn--;
break;
case IPPROTO_ICMP:
proxy->stats.num_icmp_conn--;
pd->stats.num_icmp_conn--;
break;
}
HASH_DELETE(hh, proxy->connections, conn);
HASH_DELETE(hh, pd->connections, conn);
pd_free(conn);
}
/* ******************************************************* */
// Determines when a connection gets closed
static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn, zdtun_pkt_t *pkt, uint8_t dir) {
static void update_connection_status(pcapdroid_t *nc, pcap_conn_t *conn, zdtun_pkt_t *pkt, uint8_t dir) {
if((conn->data->status >= CONN_STATUS_CLOSED) || (pkt->flags & ZDTUN_PKT_IS_FRAGMENT))
return;
@ -322,7 +322,7 @@ static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn,
// reused for a new query, it will generated a new connection, to properly
// extract and handle the new DNS query. This also happens for AAAA + A queries.
conn->data->to_purge = true;
remove_connection(proxy, conn);
remove_connection(nc, conn);
}
}
}
@ -330,24 +330,24 @@ static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn,
if(old_status != conn->data->status) {
conn->data->update_type |= CONN_UPDATE_STATS;
notify_connection(&proxy->conns_updates, &conn->tuple, conn->data);
pd_notify_connection_update(nc, &conn->tuple, conn->data);
}
}
/* ******************************************************* */
static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char *buffer) {
static void 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
if(zdtun_parse_pkt(proxy->tun, buffer, hdr->len, &pkt) != 0) {
if(zdtun_parse_pkt(pd->tun, buffer, hdr->len, &pkt) != 0) {
log_d("zdtun_parse_pkt failed");
return;
}
struct timeval tv = hdr->ts;
set_current_packet(proxy, &pkt, is_tx, &tv);
pd_set_current_packet(pd, &pkt, is_tx, &tv);
if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) &&
(pkt.tuple.src_port == 0) && (pkt.tuple.dst_port == 0)) {
@ -356,7 +356,7 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char *
// In such a case, we can only ignore the packet as we cannot determine the connection it belongs to.
//log_d("unmatched IP fragment (ID = 0x%04x)", pkt.ip4->id);
proxy->num_discarded_fragments++;
pd->num_discarded_fragments++;
return;
}
@ -365,19 +365,19 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char *
tupleSwapPeers(&pkt.tuple);
}
HASH_FIND(hh, proxy->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn);
HASH_FIND(hh, pd->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn);
if(!conn) {
// is_tx may be wrong, search in the other direction
is_tx = !is_tx;
tupleSwapPeers(&pkt.tuple);
HASH_FIND(hh, proxy->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn);
HASH_FIND(hh, pd->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn);
if(!conn) {
if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) && !(pkt.flags & ZDTUN_PKT_IS_FIRST_FRAGMENT)) {
log_d("ignoring fragment as it cannot start a connection");
proxy->num_discarded_fragments++;
pd->num_discarded_fragments++;
return;
}
@ -385,56 +385,52 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char *
is_tx = !is_tx;
tupleSwapPeers(&pkt.tuple);
conn_data_t *data = new_connection(proxy, &pkt.tuple, hdr->uid);
if (!data)
return;
conn = pd_malloc(sizeof(pcap_conn_t));
if (!conn) {
if(!conn) {
log_e("malloc(pcap_conn_t) failed with code %d/%s",
errno, strerror(errno));
return;
}
pd_conn_t *data = pd_new_connection(pd, &pkt.tuple, hdr->uid);
if(!data) {
pd_free(conn);
return;
}
conn->tuple = pkt.tuple;
conn->data = data;
HASH_ADD(hh, proxy->connections, tuple, sizeof(zdtun_5tuple_t), conn);
data->incr_id = proxy->incr_id++;
notify_connection(&proxy->new_conns, &pkt.tuple, data);
HASH_ADD(hh, pd->connections, tuple, sizeof(zdtun_5tuple_t), conn);
switch (conn->tuple.ipproto) {
case IPPROTO_TCP:
proxy->stats.num_tcp_conn++;
proxy->stats.num_tcp_opened++;
pd->stats.num_tcp_conn++;
pd->stats.num_tcp_opened++;
break;
case IPPROTO_UDP:
proxy->stats.num_udp_conn++;
proxy->stats.num_udp_opened++;
pd->stats.num_udp_conn++;
pd->stats.num_udp_opened++;
break;
case IPPROTO_ICMP:
proxy->stats.num_icmp_conn++;
proxy->stats.num_icmp_opened++;
pd->stats.num_icmp_conn++;
pd->stats.num_icmp_opened++;
break;
}
}
}
conn->data->last_update_ms = proxy->now_ms;
conn->data->last_update_ms = pd->now_ms;
account_stats(proxy, &conn->tuple, conn->data);
update_connection_status(proxy, conn, &pkt, !is_tx);
pd_account_stats(pd, &conn->tuple, conn->data);
update_connection_status(pd, conn, &pkt, !is_tx);
}
/* ******************************************************* */
static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all) {
static void purge_expired_connections(pcapdroid_t *pd, uint8_t purge_all) {
pcap_conn_t *conn, *tmp;
HASH_ITER(hh, proxy->connections, conn, tmp) {
HASH_ITER(hh, pd->connections, conn, tmp) {
uint64_t timeout = 0;
switch(conn->tuple.ipproto) {
@ -449,7 +445,7 @@ static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all)
break;
}
if(purge_all || (proxy->now_ms >= (conn->data->last_update_ms + timeout))) {
if(purge_all || (pd->now_ms >= (conn->data->last_update_ms + timeout))) {
//log_d("IDLE (type=%d)", conn->tuple.ipproto);
// The connection data will be purged
@ -462,34 +458,34 @@ static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all)
if(conn->data->update_type != 0) {
// Will free the data in sendConnectionsDump
notify_connection(&proxy->conns_updates, &conn->tuple, conn->data);
pd_notify_connection_update(pd, &conn->tuple, conn->data);
} else
conn_free_data(conn->data);
pd_destroy_connection(conn->data);
remove_connection(proxy, conn);
remove_connection(pd, conn);
}
}
}
/* ******************************************************* */
int run_root(vpnproxy_data_t *proxy) {
int run_root(pcapdroid_t *pd) {
int sock = -1;
int rv = -1;
char buffer[65535];
u_int64_t next_purge_ms;
zdtun_callbacks_t callbacks = {.send_client = (void*)1};
if((proxy->tun = zdtun_init(&callbacks, NULL)) == NULL)
if((pd->tun = zdtun_init(&callbacks, NULL)) == NULL)
return(-1);
if((sock = connectPcapd(proxy)) < 0) {
if((sock = connectPcapd(pd)) < 0) {
rv = -1;
goto cleanup;
}
refresh_time(proxy);
next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
pd_refresh_time(pd);
next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
log_d("Starting packet loop");
@ -506,7 +502,7 @@ int run_root(vpnproxy_data_t *proxy) {
goto cleanup;
}
refresh_time(proxy);
pd_refresh_time(pd);
if(!running)
break;
@ -527,24 +523,24 @@ int run_root(vpnproxy_data_t *proxy) {
goto cleanup;
}
proxy->num_dropped_pkts = hdr.pkt_drops;
handle_packet(proxy, &hdr, buffer);
pd->num_dropped_pkts = hdr.pkt_drops;
handle_packet(pd, &hdr, buffer);
housekeeping:
run_housekeeping(proxy);
pd_housekeeping(pd);
if(proxy->now_ms >= next_purge_ms) {
purge_expired_connections(proxy, 0);
next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
if(pd->now_ms >= next_purge_ms) {
purge_expired_connections(pd, 0);
next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
}
}
rv = 0;
cleanup:
purge_expired_connections(proxy, 1 /* purge_all */);
purge_expired_connections(pd, 1 /* purge_all */);
if(proxy->tun) zdtun_finalize(proxy->tun);
if(pd->tun) zdtun_finalize(pd->tun);
if(sock > 0) close(sock);
return rv;

View File

@ -17,17 +17,54 @@
* Copyright 2021 - Emanuele Faranda
*/
#include "vpnproxy.h"
#include "pcapdroid.h"
#include "common/utils.h"
static void protectSocketCallback(zdtun_t *tun, socket_t sock) {
vpnproxy_data_t *proxy = ((vpnproxy_data_t*)zdtun_userdata(tun));
vpn_protect_socket(proxy, sock);
static void vpn_protect_socket(pcapdroid_t *pd, socket_t sock) {
JNIEnv *env = pd->env;
if(pd->root_capture)
return;
/* Call VpnService protect */
jboolean isProtected = (*env)->CallBooleanMethod(
env, pd->vpn_service, mids.protect, sock);
jniCheckException(env);
if (!isProtected)
log_e("socket protect failed");
}
/* ******************************************************* */
static void add_known_dns_server(vpnproxy_data_t *proxy, const char *ip) {
static int resolve_uid(pcapdroid_t *pd, const zdtun_5tuple_t *conn_info) {
char buf[256];
jint uid;
zdtun_5tuple2str(conn_info, buf, sizeof(buf));
uid = get_uid(pd->resolver, conn_info);
if(uid >= 0) {
char appbuf[64];
get_appname_by_uid(pd, uid, appbuf, sizeof(appbuf));
log_i( "%s [%d/%s]", buf, uid, appbuf);
} else {
uid = UID_UNKNOWN;
log_w("%s => UID not found!", buf);
}
return(uid);
}
static void protectSocketCallback(zdtun_t *tun, socket_t sock) {
pcapdroid_t *pd = ((pcapdroid_t*)zdtun_userdata(tun));
vpn_protect_socket(pd, sock);
}
/* ******************************************************* */
static void add_known_dns_server(pcapdroid_t *pd, const char *ip) {
ndpi_ip_addr_t parsed;
if(ndpi_parse_ip_string(ip, &parsed) < 0) {
@ -35,12 +72,12 @@ static void add_known_dns_server(vpnproxy_data_t *proxy, const char *ip) {
return;
}
ndpi_ptree_insert(proxy->known_dns_servers, &parsed, ndpi_is_ipv6(&parsed) ? 128 : 32, 1);
ndpi_ptree_insert(pd->known_dns_servers, &parsed, ndpi_is_ipv6(&parsed) ? 128 : 32, 1);
}
/* ******************************************************* */
static struct timeval* get_pkt_timestamp(vpnproxy_data_t *proxy, struct timeval *tv) {
static struct timeval* get_pkt_timestamp(pcapdroid_t *pd, struct timeval *tv) {
struct timespec ts;
if(!clock_gettime(CLOCK_REALTIME, &ts)) {
@ -51,7 +88,7 @@ static struct timeval* get_pkt_timestamp(vpnproxy_data_t *proxy, struct timeval
// use the last pkt timestamp
log_w("clock_gettime failed[%d]: %s", errno, strerror(errno));
return &proxy->cur_pkt.tv;
return &pd->cur_pkt.tv;
}
/* ******************************************************* */
@ -60,17 +97,17 @@ static int net2tun(zdtun_t *tun, zdtun_pkt_t *pkt, const zdtun_conn_t *conn_info
if(!running)
return 0;
vpnproxy_data_t *proxy = (vpnproxy_data_t*) zdtun_userdata(tun);
conn_data_t *data = zdtun_conn_get_userdata(conn_info);
pcapdroid_t *pd = (pcapdroid_t*) zdtun_userdata(tun);
pd_conn_t *data = zdtun_conn_get_userdata(conn_info);
struct timeval tv;
refresh_time(proxy);
set_current_packet(proxy, pkt, false, get_pkt_timestamp(proxy, &tv));
pd_refresh_time(pd);
pd_set_current_packet(pd, pkt, false, get_pkt_timestamp(pd, &tv));
if(data->to_block) // NOTE: blocked_pkts accounted in account_stats
if(data->to_block) // NOTE: blocked_pkts accounted in pd_account_stats
return 0;
int rv = write(proxy->tunfd, pkt->buf, pkt->len);
int rv = write(pd->tunfd, pkt->buf, pkt->len);
if(rv < 0) {
if(errno == ENOBUFS) {
@ -96,8 +133,8 @@ static int net2tun(zdtun_t *tun, zdtun_pkt_t *pkt, const zdtun_conn_t *conn_info
/* ******************************************************* */
static void check_socks5_redirection(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, zdtun_conn_t *conn) {
conn_data_t *data = zdtun_conn_get_userdata(conn);
static void check_socks5_redirection(pcapdroid_t *pd, zdtun_pkt_t *pkt, zdtun_conn_t *conn) {
pd_conn_t *data = zdtun_conn_get_userdata(conn);
if((pkt->tuple.ipproto == IPPROTO_TCP) && (((data->sent_pkts + data->rcvd_pkts) == 0)))
zdtun_conn_proxy(conn);
@ -111,17 +148,17 @@ static void check_socks5_redirection(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, z
* Moreover, if a private DNS connection is detected in opportunistic mode (block_private_dns true),
* then block this connection to force the fallback to non-private DNS mode.
*/
static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
static bool check_dns_req_allowed(pcapdroid_t *pd, zdtun_conn_t *conn) {
const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn);
if(new_dns_server != 0) {
// Reload DNS server
proxy->dns_server = new_dns_server;
pd->dns_server = new_dns_server;
new_dns_server = 0;
zdtun_ip_t ip = {0};
ip.ip4 = proxy->dns_server;
zdtun_set_dnat_info(proxy->tun, &ip, htons(53), 4);
ip.ip4 = pd->dns_server;
zdtun_set_dnat_info(pd->tun, &ip, htons(53), 4);
log_d("Using new DNS server");
}
@ -129,9 +166,9 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
if(zdtun_conn_get_5tuple(conn)->ipproto == IPPROTO_ICMP)
return true;
bool is_internal_dns = (tuple->ipver == 4) && (tuple->dst_ip.ip4 == proxy->vpn_dns);
bool is_internal_dns = (tuple->ipver == 4) && (tuple->dst_ip.ip4 == pd->vpn_dns);
bool is_dns_server = is_internal_dns
|| ((tuple->ipver == 6) && (memcmp(&tuple->dst_ip.ip6, &proxy->ipv6.dns_server, 16) == 0));
|| ((tuple->ipver == 6) && (memcmp(&tuple->dst_ip.ip6, &pd->ipv6.dns_server, 16) == 0));
if(!is_dns_server) {
// try with known DNS servers
@ -143,7 +180,7 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
else
memcpy(&addr.ipv6, &tuple->dst_ip.ip6, 16);
ndpi_ptree_match_addr(proxy->known_dns_servers, &addr, &matched);
ndpi_ptree_match_addr(pd->known_dns_servers, &addr, &matched);
if(matched) {
char ip[INET6_ADDRSTRLEN];
@ -161,7 +198,7 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
return(true);
if((tuple->ipproto == IPPROTO_UDP) && (ntohs(tuple->dst_port) == 53)) {
zdtun_pkt_t *pkt = proxy->cur_pkt.pkt;
zdtun_pkt_t *pkt = pd->cur_pkt.pkt;
int dns_length = pkt->l7_len;
if(dns_length >= sizeof(dns_packet_t)) {
@ -171,12 +208,12 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
return(true);
log_d("Detected DNS query[%u]", dns_length);
proxy->num_dns_requests++;
pd->num_dns_requests++;
if(is_internal_dns) {
/*
* Direct the packet to the public DNS server. Checksum recalculation is not strictly necessary
* here as zdtun will proxy the connection.
* here as zdtun will pd the connection.
*/
zdtun_conn_dnat(conn);
}
@ -197,20 +234,17 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) {
/* ******************************************************* */
static int handle_new_connection(zdtun_t *tun, zdtun_conn_t *conn_info) {
vpnproxy_data_t *proxy = ((vpnproxy_data_t *) zdtun_userdata(tun));
pcapdroid_t *pd = ((pcapdroid_t *) zdtun_userdata(tun));
const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn_info);
conn_data_t *data = new_connection(proxy, tuple, resolve_uid(proxy, tuple));
pd_conn_t *data = pd_new_connection(pd, tuple, resolve_uid(pd, tuple));
if(!data) {
/* reject connection */
return (1);
}
zdtun_conn_set_userdata(conn_info, data);
data->to_block = !check_dns_req_allowed(proxy, conn_info);
data->incr_id = proxy->incr_id++;
notify_connection(&proxy->new_conns, tuple, data);
data->to_block = !check_dns_req_allowed(pd, conn_info);
/* accept connection */
return(0);
@ -219,8 +253,8 @@ static int handle_new_connection(zdtun_t *tun, zdtun_conn_t *conn_info) {
/* ******************************************************* */
static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) {
vpnproxy_data_t *proxy = (vpnproxy_data_t*) zdtun_userdata(tun);
conn_data_t *data = zdtun_conn_get_userdata(conn_info);
pcapdroid_t *pd = (pcapdroid_t*) zdtun_userdata(tun);
pd_conn_t *data = zdtun_conn_get_userdata(conn_info);
if(!data) {
log_e("Missing data in connection");
@ -232,9 +266,9 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) {
// Send last notification
// Will free the data in sendConnectionsDump
data->update_type |= CONN_UPDATE_STATS;
notify_connection(&proxy->conns_updates, tuple, data);
pd_notify_connection_update(pd, tuple, data);
conn_end_ndpi_detection(data, proxy, tuple);
pd_giveup_dpi(pd, data, tuple);
data->status = zdtun_conn_get_status(conn_info);
data->to_purge = true;
}
@ -242,10 +276,10 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) {
/* ******************************************************* */
static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, const zdtun_conn_t *conn_info) {
vpnproxy_data_t *proxy = ((vpnproxy_data_t*)zdtun_userdata(tun));
pcapdroid_t *pd = ((pcapdroid_t*)zdtun_userdata(tun));
const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn_info);
conn_data_t *data = zdtun_conn_get_userdata(conn_info);
pd_conn_t *data = zdtun_conn_get_userdata(conn_info);
if(!data) {
log_e("Missing data in connection");
return;
@ -255,11 +289,11 @@ static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, co
if(data->to_block) {
data->blocked_pkts++;
data->last_seen = proxy->cur_pkt.ms;
data->last_seen = pd->cur_pkt.ms;
return;
}
account_stats(proxy, tuple, data);
pd_account_stats(pd, tuple, data);
if(data->status >= CONN_STATUS_CLOSED)
data->to_purge = true;
@ -267,13 +301,13 @@ static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, co
/* ******************************************************* */
int run_proxy(vpnproxy_data_t *proxy) {
int run_vpn(pcapdroid_t *pd) {
zdtun_t *tun;
char buffer[32768];
u_int64_t next_purge_ms;
int flags = fcntl(proxy->tunfd, F_GETFL, 0);
if (flags < 0 || fcntl(proxy->tunfd, F_SETFL, flags & ~O_NONBLOCK) < 0) {
int flags = fcntl(pd->tunfd, F_GETFL, 0);
if (flags < 0 || fcntl(pd->tunfd, F_SETFL, flags & ~O_NONBLOCK) < 0) {
log_f("fcntl ~O_NONBLOCK error [%d]: %s", errno,
strerror(errno));
return (-1);
@ -288,39 +322,39 @@ int run_proxy(vpnproxy_data_t *proxy) {
};
// List of known DNS servers
add_known_dns_server(proxy, "8.8.8.8");
add_known_dns_server(proxy, "8.8.4.4");
add_known_dns_server(proxy, "1.1.1.1");
add_known_dns_server(proxy, "1.0.0.1");
add_known_dns_server(proxy, "2001:4860:4860::8888");
add_known_dns_server(proxy, "2001:4860:4860::8844");
add_known_dns_server(proxy, "2606:4700:4700::64");
add_known_dns_server(proxy, "2606:4700:4700::6400");
add_known_dns_server(pd, "8.8.8.8");
add_known_dns_server(pd, "8.8.4.4");
add_known_dns_server(pd, "1.1.1.1");
add_known_dns_server(pd, "1.0.0.1");
add_known_dns_server(pd, "2001:4860:4860::8888");
add_known_dns_server(pd, "2001:4860:4860::8844");
add_known_dns_server(pd, "2606:4700:4700::64");
add_known_dns_server(pd, "2606:4700:4700::6400");
tun = zdtun_init(&callbacks, proxy);
tun = zdtun_init(&callbacks, pd);
if(tun == NULL) {
log_f("zdtun_init failed");
return(-2);
}
proxy->tun = tun;
pd->tun = tun;
new_dns_server = 0;
if(proxy->socks5.enabled) {
if(pd->socks5.enabled) {
zdtun_ip_t dnatip = {0};
dnatip.ip4 = proxy->socks5.proxy_ip;
zdtun_set_socks5_proxy(tun, &dnatip, proxy->socks5.proxy_port, 4);
dnatip.ip4 = pd->socks5.proxy_ip;
zdtun_set_socks5_proxy(tun, &dnatip, pd->socks5.proxy_port, 4);
}
zdtun_ip_t ip = {0};
ip.ip4 = proxy->dns_server;
ip.ip4 = pd->dns_server;
zdtun_set_dnat_info(tun, &ip, ntohs(53), 4);
refresh_time(proxy);
next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
pd_refresh_time(pd);
next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
log_d("Starting packet loop [tunfd=%d]", proxy->tunfd);
log_d("Starting packet loop [tunfd=%d]", pd->tunfd);
while(running) {
int max_fd;
@ -331,8 +365,8 @@ int run_proxy(vpnproxy_data_t *proxy) {
zdtun_fds(tun, &max_fd, &fdset, &wrfds);
FD_SET(proxy->tunfd, &fdset);
max_fd = max(max_fd, proxy->tunfd);
FD_SET(pd->tunfd, &fdset);
max_fd = max(max_fd, pd->tunfd);
if(select(max_fd + 1, &fdset, &wrfds, NULL, &timeout) < 0) {
log_e("select failed[%d]: %s", errno, strerror(errno));
@ -342,12 +376,12 @@ int run_proxy(vpnproxy_data_t *proxy) {
if(!running)
break;
if(FD_ISSET(proxy->tunfd, &fdset)) {
if(FD_ISSET(pd->tunfd, &fdset)) {
/* Packet from VPN */
size = read(proxy->tunfd, buffer, sizeof(buffer));
size = read(pd->tunfd, buffer, sizeof(buffer));
if(size > 0) {
zdtun_pkt_t pkt;
refresh_time(proxy);
pd_refresh_time(pd);
if(zdtun_parse_pkt(tun, buffer, size, &pkt) != 0) {
log_d("zdtun_parse_pkt failed");
@ -356,14 +390,14 @@ int run_proxy(vpnproxy_data_t *proxy) {
if(pkt.flags & ZDTUN_PKT_IS_FRAGMENT) {
log_d("discarding IP fragment");
proxy->num_discarded_fragments++;
pd->num_discarded_fragments++;
goto housekeeping;
}
struct timeval tv;
set_current_packet(proxy, &pkt, true, get_pkt_timestamp(proxy, &tv));
pd_set_current_packet(pd, &pkt, true, get_pkt_timestamp(pd, &tv));
if((pkt.tuple.ipver == 6) && (!proxy->ipv6.enabled)) {
if((pkt.tuple.ipver == 6) && (!pd->ipv6.enabled)) {
char buf[512];
log_d("ignoring IPv6 packet: %s",
@ -380,7 +414,7 @@ int run_proxy(vpnproxy_data_t *proxy) {
if(!is_tcp_established) {
char buf[512];
proxy->num_dropped_connections++;
pd->num_dropped_connections++;
log_e("zdtun_lookup failed: %s",
zdtun_5tuple2str(&pkt.tuple, buf, sizeof(buf)));
} else {
@ -392,17 +426,17 @@ int run_proxy(vpnproxy_data_t *proxy) {
goto housekeeping;
}
conn_data_t *data = zdtun_conn_get_userdata(conn);
pd_conn_t *data = zdtun_conn_get_userdata(conn);
if(data->to_block) {
data->blocked_pkts++;
data->last_seen = proxy->cur_pkt.ms;
data->last_seen = pd->cur_pkt.ms;
if(!data->first_seen)
data->first_seen = data->last_seen;
goto housekeeping;
}
if(proxy->socks5.enabled)
check_socks5_redirection(proxy, &pkt, conn);
if(pd->socks5.enabled)
check_socks5_redirection(pd, &pkt, conn);
if(zdtun_forward(tun, &pkt, conn) != 0) {
char buf[512];
@ -410,27 +444,27 @@ int run_proxy(vpnproxy_data_t *proxy) {
log_e("zdtun_forward failed: %s",
zdtun_5tuple2str(&pkt.tuple, buf, sizeof(buf)));
proxy->num_dropped_connections++;
pd->num_dropped_connections++;
zdtun_destroy_conn(tun, conn);
goto housekeeping;
}
} else {
refresh_time(proxy);
pd_refresh_time(pd);
if(size < 0)
log_e("recv(tunfd) returned error [%d]: %s", errno,
strerror(errno));
}
} else {
refresh_time(proxy);
pd_refresh_time(pd);
zdtun_handle_fd(tun, &fdset, &wrfds);
}
housekeeping:
run_housekeeping(proxy);
pd_housekeeping(pd);
if(proxy->now_ms >= next_purge_ms) {
if(pd->now_ms >= next_purge_ms) {
zdtun_purge_expired(tun);
next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS;
}
}

View File

@ -19,7 +19,7 @@
#include <linux/if_ether.h>
#include "common/utils.h"
#include "vpnproxy.h"
#include "pcapdroid.h"
#include "pcap_utils.h"
#define SNAPLEN 65535
@ -66,13 +66,13 @@ int pcap_rec_size(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(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn) {
const zdtun_pkt_t *pkt = proxy->cur_pkt.pkt;
void pcap_dump_rec(u_char *buffer, pcapdroid_t *pd, pd_conn_t *conn) {
const zdtun_pkt_t *pkt = pd->cur_pkt.pkt;
struct pcaprec_hdr_s *pcap_rec = (pcaprec_hdr_s*) buffer;
int offset = 0;
pcap_rec->ts_sec = proxy->cur_pkt.tv.tv_sec;
pcap_rec->ts_usec = proxy->cur_pkt.tv.tv_usec;
pcap_rec->ts_sec = pd->cur_pkt.tv.tv_sec;
pcap_rec->ts_usec = pd->cur_pkt.tv.tv_usec;
pcap_rec->incl_len = pcap_rec_size(pkt->len) - (int)sizeof(struct pcaprec_hdr_s);
pcap_rec->orig_len = pkt->len;
buffer += sizeof(struct pcaprec_hdr_s);
@ -107,7 +107,7 @@ void pcap_dump_rec(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn) {
// Populate the custom data
pcapdroid_trailer_t *cdata = (pcapdroid_trailer_t*)(buffer + offset);
fill_custom_data(cdata, proxy, conn);
fill_custom_data(cdata, pd, conn);
//clock_t start = clock();
cdata->fcs = crc32(buffer, pcap_rec->incl_len - 4, 0);

View File

@ -60,6 +60,6 @@ typedef struct pcapdroid_trailer {
void pcap_set_pcapdroid_trailer(uint8_t enabled);
void pcap_build_hdr(struct pcap_hdr_s *pcap_hdr);
int pcap_rec_size(int pkt_len);
void pcap_dump_rec(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn);
void pcap_dump_rec(u_char *buffer, pcapdroid_t *pd, pd_conn_t *conn);
#endif // __MY_PCAP_H__

View File

@ -57,17 +57,17 @@ typedef struct {
u_int64_t last_update_ms;
} capture_stats_t;
// This tracks the packet processing phases, to ensure that the vpnproxy functions are called in
// This tracks the packet processing phases, to ensure that the API functions are called in
// the correct order.
typedef enum {
PKT_PHASE_REFRESH_TIME = 0, // refresh_time
PKT_PHASE_PKT_SET, // set_current_packet
PKT_PHASE_ACCOUNT_STATS, // account_stats
PKT_PHASE_HOUSEKEEPING, // run_housekeeping
PKT_PHASE_REFRESH_TIME = 0, // pd_refresh_time
PKT_PHASE_PKT_SET, // pd_set_current_packet
PKT_PHASE_ACCOUNT_STATS, // pd_account_stats
PKT_PHASE_HOUSEKEEPING, // pd_housekeeping
} pkt_processing_phase_t;
typedef struct {
jint incr_id; /* an incremental identifier */
jint incr_id; // an incremental number which identifies a specific connection
/* nDPI */
struct ndpi_flow_struct *ndpi_flow;
@ -99,15 +99,15 @@ typedef struct {
char *request_data;
char *url;
uint8_t update_type;
} conn_data_t;
} pd_conn_t;
typedef struct {
zdtun_5tuple_t tuple;
conn_data_t *data;
} vpn_conn_t;
pd_conn_t *data;
} conn_and_tuple_t;
typedef struct {
vpn_conn_t *items;
conn_and_tuple_t *items;
int size;
int cur_items;
} conn_array_t;
@ -118,22 +118,6 @@ typedef struct {
UT_hash_handle hh;
} uid_to_app_t;
typedef struct {
char *fname;
blacklist_type type;
} bl_info_t;
typedef struct {
char *fname;
int num_rules;
} bl_status_t;
typedef struct {
bl_status_t *items;
int size;
int cur_items;
} bl_status_arr_t;
typedef struct pcap_conn pcap_conn_t;
typedef struct {
@ -154,7 +138,7 @@ typedef struct {
char filesdir[PATH_MAX];
int cachedir_len;
int filesdir_len;
uint64_t now_ms; // Monotonic timestamp, see refresh_time
uint64_t now_ms; // Monotonic timestamp, see pd_refresh_time
u_int num_dropped_pkts;
long num_discarded_fragments;
u_int32_t num_dropped_connections;
@ -168,7 +152,7 @@ typedef struct {
pcap_conn_t *connections; // root only
pkt_processing_phase_t pkt_phase;
// populated via set_current_packet
// populated via pd_set_current_packet
struct {
zdtun_pkt_t *pkt;
struct timeval tv; // Packet timestamp, need by pcap_dump_rec
@ -214,7 +198,7 @@ typedef struct {
} firewall;
capture_stats_t capture_stats;
} vpnproxy_data_t;
} pcapdroid_t;
/* ******************************************************* */
@ -274,32 +258,31 @@ extern bool running;
extern uint32_t new_dns_server;
extern bool block_private_dns;
struct pcapdroid_trailer;
// capture API
void pd_refresh_time(pcapdroid_t *pd);
void pd_set_current_packet(pcapdroid_t *pd, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv);
void pd_account_stats(pcapdroid_t *pd, const zdtun_5tuple_t *conn_tuple, pd_conn_t *data);
void pd_housekeeping(pcapdroid_t *pd);
pd_conn_t* pd_new_connection(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, int uid);
void pd_destroy_connection(pd_conn_t *data);
void pd_notify_connection_update(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data);
void pd_giveup_dpi(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple);
conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, int uid);
void conn_free_data(conn_data_t *data);
void notify_connection(conn_array_t *arr, const zdtun_5tuple_t *tuple, conn_data_t *data);
void conn_end_ndpi_detection(conn_data_t *data, vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple);
void run_housekeeping(vpnproxy_data_t *proxy);
void set_current_packet(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv);
void account_stats(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_tuple, conn_data_t *data);
int resolve_uid(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_info);
void refresh_time(vpnproxy_data_t *proxy);
void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b);
void vpn_protect_socket(vpnproxy_data_t *proxy, socket_t sock);
void fill_custom_data(struct pcapdroid_trailer *cdata, vpnproxy_data_t *proxy, conn_data_t *conn);
uint32_t crc32(u_char *buf, size_t len, uint32_t crc);
// Utility
const char* get_cache_path(const char *subpath);
const char* get_file_path(const char *subpath);
static inline const char* get_cache_dir() { return get_cache_path(""); }
static inline const char* get_files_dir() { return get_file_path(""); }
char* getStringPref(vpnproxy_data_t *proxy, const char *key, char *buf, int bufsize);
char* get_appname_by_uid(pcapdroid_t *pd, int uid, char *buf, int bufsize);
char* getStringPref(pcapdroid_t *pd, const char *key, char *buf, int bufsize);
int getIntPref(JNIEnv *env, jobject vpn_inst, const char *key);
uint32_t getIPv4Pref(JNIEnv *env, jobject vpn_inst, const char *key);
struct in6_addr getIPv6Pref(JNIEnv *env, jobject vpn_inst, const char *key);
int run_proxy(vpnproxy_data_t *proxy);
int run_root(vpnproxy_data_t *proxy);
// Internals
struct pcapdroid_trailer;
void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn);
void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b);
uint32_t crc32(u_char *buf, size_t len, uint32_t crc);
#endif //__PCAPDROID_H__

View File

@ -58,7 +58,7 @@ Here are the steps to make it communicate with your app:
5. The app can now receive the packets on the UNIX socket.
6. When the app closes the UNIX socket, the pcapd daemon is automatically stopped.
Check out the [capture_root.c source](https://github.com/emanuele-f/PCAPdroid/blob/master/app/src/main/jni/vpnproxy-jni/capture_root.c) to see an example of integration.
Check out the [capture_root.c source](https://github.com/emanuele-f/PCAPdroid/blob/master/app/src/main/jni/core/capture_root.c) to see an example of integration.
Packets Data
------------