mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-16 21:10:57 +08:00
Fix UDP exporter and HTTP dump modes with root
When exporting traffic over the network, we must exclude this traffic from the monitoring, otherwise the traffic will be captured in a loop
This commit is contained in:
parent
91cc995eff
commit
9d427461cb
@ -617,6 +617,8 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
return((dump_mode != Prefs.DumpMode.NONE) ? 1 : 0);
|
||||
}
|
||||
|
||||
public String getPcapDumperBpf() { return((mDumper != null) ? mDumper.getBpf() : ""); }
|
||||
|
||||
@Override
|
||||
public boolean protect(int socket) {
|
||||
// Do not call protect in root mode
|
||||
|
||||
@ -6,6 +6,13 @@ import java.io.IOException;
|
||||
* It has the following lifecycle:
|
||||
*
|
||||
* startDumper -> ... dumpData ... -> stopDumper
|
||||
*
|
||||
* In order to avoid monitoring the dumper traffic (which would cause a loop), a dumper must implement
|
||||
* the following policy:
|
||||
* - for root capture, the getBpf method must return a BPF filter to exclude the traffic. This will
|
||||
* be set at the start of the catpure.
|
||||
* - for non-root capture, the dumper must pass each socket it opens to the CaptureService.protect
|
||||
* method.
|
||||
*/
|
||||
public interface PcapDumper {
|
||||
/**
|
||||
@ -20,6 +27,12 @@ public interface PcapDumper {
|
||||
*/
|
||||
void stopDumper() throws IOException;
|
||||
|
||||
/** Get a BPF to use to ignore the connections made by the dumper.
|
||||
*
|
||||
* @return the BPF string
|
||||
*/
|
||||
String getBpf();
|
||||
|
||||
/**
|
||||
* Dump an unspecified number of PCAP records. The dumper must check if this is the first data
|
||||
* sent, in which case it should send the Utils.PCAP_HEADER bofore the PCAP records data.
|
||||
|
||||
@ -34,6 +34,11 @@ public class FileDumper implements PcapDumper {
|
||||
mOutputStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBpf() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpData(byte[] data) throws IOException {
|
||||
if(mSendHeader) {
|
||||
|
||||
@ -34,6 +34,7 @@ import fi.iki.elonen.NanoHTTPD.Response.Status;
|
||||
public class HTTPServer extends NanoHTTPD implements PcapDumper {
|
||||
private static final String PCAP_MIME = "application/vnd.tcpdump.pcap";
|
||||
private boolean mAcceptConnections = false;
|
||||
private int mPort;
|
||||
private final Context mContext;
|
||||
|
||||
/* NOTE: access to mActiveResponses must be synchronized */
|
||||
@ -41,6 +42,7 @@ public class HTTPServer extends NanoHTTPD implements PcapDumper {
|
||||
|
||||
public HTTPServer(Context context, int port) {
|
||||
super(port);
|
||||
mPort = port;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@ -103,6 +105,11 @@ public class HTTPServer extends NanoHTTPD implements PcapDumper {
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBpf() {
|
||||
return "not (host " + Utils.getLocalIPAddress(mContext) + " and tcp port " + mPort + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpData(byte[] data) throws IOException {
|
||||
synchronized (this) {
|
||||
|
||||
@ -7,16 +7,16 @@ import com.emanuelef.remote_capture.interfaces.PcapDumper;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class UDPDumper implements PcapDumper {
|
||||
public static final String TAG = "UDPDumper";
|
||||
private final SocketAddress mServer;
|
||||
private final InetSocketAddress mServer;
|
||||
private boolean mSendHeader;
|
||||
private DatagramSocket mSocket;
|
||||
|
||||
public UDPDumper(SocketAddress server) {
|
||||
public UDPDumper(InetSocketAddress server) {
|
||||
mServer = server;
|
||||
mSendHeader = true;
|
||||
}
|
||||
@ -32,6 +32,11 @@ public class UDPDumper implements PcapDumper {
|
||||
mSocket.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBpf() {
|
||||
return "not (host " + mServer.getAddress().getHostAddress() + " and udp port " + mServer.getPort() + ")";
|
||||
}
|
||||
|
||||
private void sendDatagram(byte[] data, int offset, int len) throws IOException {
|
||||
DatagramPacket request = new DatagramPacket(data, offset, len, mServer);
|
||||
mSocket.send(request);
|
||||
|
||||
@ -58,6 +58,7 @@ typedef struct {
|
||||
int nlsock;
|
||||
int client;
|
||||
|
||||
char bpf[512];
|
||||
pcap_t *pd;
|
||||
int dlink;
|
||||
int ipoffset;
|
||||
@ -214,24 +215,6 @@ static int get_iface_ip6(const char *iface, struct in6_addr *ip) {
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static int list_interfaces() {
|
||||
pcap_if_t *devs, *pd;
|
||||
|
||||
if(pcap_findalldevs(&devs, errbuf) != 0) {
|
||||
fprintf(stderr, "pcap_findalldevs failed: %s\n", errbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(pd = devs; pd; pd = pd->next)
|
||||
printf("%s\n", pd->name);
|
||||
|
||||
pcap_freealldevs(devs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static void sighandler(__unused int signo) {
|
||||
log_i("SIGTERM received, terminating");
|
||||
unlink(PCAPD_PID);
|
||||
@ -400,7 +383,7 @@ static void check_capture_interface(pcapd_runtime_t *rt) {
|
||||
struct bpf_program fcode;
|
||||
|
||||
// Only IP traffic
|
||||
if(pcap_compile(pd, &fcode, "ip or ip6", 1, PCAP_NETMASK_UNKNOWN) < 0) {
|
||||
if(pcap_compile(pd, &fcode, rt->bpf, 1, PCAP_NETMASK_UNKNOWN) < 0) {
|
||||
log_i("[%s] could not set capture filter: %s", ifname, pcap_geterr(pd));
|
||||
pcap_close(pd);
|
||||
return;
|
||||
@ -565,7 +548,7 @@ static int is_tx_packet(pcapd_runtime_t *rt, const u_char *pkt, u_int16_t len) {
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static int run_pcap_dump(int uid_filter) {
|
||||
static int run_pcap_dump(int uid_filter, const char *bpf) {
|
||||
int rv = -1;
|
||||
struct pcap_stat stats = {0};
|
||||
pcapd_runtime_t rt = {0};
|
||||
@ -583,6 +566,13 @@ static int run_pcap_dump(int uid_filter) {
|
||||
if(init_pcapd_capture(&rt) < 0)
|
||||
goto cleanup;
|
||||
|
||||
int l = snprintf(rt.bpf, sizeof(rt.bpf), "ip or ip6");
|
||||
|
||||
if(bpf[0])
|
||||
snprintf(rt.bpf + l, sizeof(rt.bpf) - l, " and (%s)", bpf);
|
||||
|
||||
log_d("Using BPF: %s", rt.bpf);
|
||||
|
||||
rt.pf = -1;
|
||||
rt.ifidx = -1;
|
||||
check_capture_interface(&rt);
|
||||
@ -702,9 +692,9 @@ cleanup:
|
||||
static void usage() {
|
||||
fprintf(stderr, "pcapd - root companion for PCAPdroid\n"
|
||||
"Copyright 2021 Emanuele Faranda <black.silver@hotmail.it>\n\n"
|
||||
"Usage: pcapd [--interfaces|-d]\n"
|
||||
" --interfaces list the interfaces of the system\n"
|
||||
" -d [uid] daemonize and dump packets from the internet interface, possibly filtered by uid\n"
|
||||
"Usage: pcapd -d uid [-b bpf]\n"
|
||||
" -d [uid] daemonize and dump packets from the internet interface, filtered by uid (-1 for no filter)\n"
|
||||
" -b [bpf] specify a BPF filter to apply"
|
||||
);
|
||||
|
||||
exit(1);
|
||||
@ -715,20 +705,16 @@ static void usage() {
|
||||
int main(int argc, char *argv[]) {
|
||||
logtag = "pcapd";
|
||||
logcallback = log_to_file;
|
||||
int uid_filter;
|
||||
char *bpf = "";
|
||||
|
||||
if(argc < 2)
|
||||
if((argc < 3) || (strcmp(argv[1], "-d") != 0))
|
||||
usage();
|
||||
|
||||
if(!strcmp(argv[1], "--interfaces"))
|
||||
return list_interfaces();
|
||||
else if(!strcmp(argv[1], "-d")) {
|
||||
int uid_filter = -1;
|
||||
uid_filter = atoi(argv[2]);
|
||||
|
||||
if(argc >= 3)
|
||||
uid_filter = atoi(argv[2]);
|
||||
if((argc == 5) && (strcmp(argv[3], "-b") == 0))
|
||||
bpf = argv[4];
|
||||
|
||||
return run_pcap_dump(uid_filter);
|
||||
}
|
||||
|
||||
usage();
|
||||
return run_pcap_dump(uid_filter, bpf);
|
||||
}
|
||||
|
||||
@ -109,8 +109,10 @@ static void kill_pcapd(vpnproxy_data_t *proxy) {
|
||||
static int connectPcapd(vpnproxy_data_t *proxy) {
|
||||
int sock;
|
||||
int client = -1;
|
||||
char bpf[256];
|
||||
char workdir[PATH_MAX], pcapd[PATH_MAX];
|
||||
|
||||
getStringPref(proxy, "getPcapDumperBpf", bpf, sizeof(bpf));
|
||||
getStringPref(proxy, "getPcapdWorkingDir", workdir, PATH_MAX);
|
||||
get_libprog_path(proxy, "pcapd", pcapd, sizeof(pcapd));
|
||||
|
||||
@ -150,9 +152,12 @@ static int connectPcapd(vpnproxy_data_t *proxy) {
|
||||
|
||||
log_d("AF_UNIX socket listening at '%s'", addr.sun_path);
|
||||
|
||||
if(bpf[0])
|
||||
log_d("Using dumper BPF \"%s\"", bpf);
|
||||
|
||||
// Start the daemon
|
||||
char args[32];
|
||||
snprintf(args, sizeof(args), "-d %d", proxy->app_filter);
|
||||
char args[256];
|
||||
snprintf(args, sizeof(args), "-d %d -b \"%s\"", proxy->app_filter, bpf);
|
||||
su_cmd(pcapd, args);
|
||||
|
||||
// Wait for pcapd to start
|
||||
|
||||
@ -59,11 +59,6 @@ static size_t init_pcap_rec_hdr(struct pcaprec_hdr_s *pcap_rec, int length) {
|
||||
pcap_rec->incl_len = (guint32_t) incl_len;
|
||||
pcap_rec->orig_len = (guint32_t) length;
|
||||
|
||||
pcap_rec->ts_sec = (guint32_t) ts.tv_sec;
|
||||
pcap_rec->ts_usec = (guint32_t) (ts.tv_nsec / 1000);
|
||||
pcap_rec->incl_len = (guint32_t) incl_len;
|
||||
pcap_rec->orig_len = (guint32_t) length;
|
||||
|
||||
return(incl_len);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user