Merge pull request #136 from jantman/issues/119
fixes #119 - add support for pcap capture filters
This commit is contained in:
@@ -14,12 +14,31 @@ import threading
|
||||
# until network activity occurs and the callback is executed. By using 2 threads, we can have the
|
||||
# main thread listen for SIGINT while the secondary thread is blocked in the monitor loop.
|
||||
|
||||
#######################
|
||||
# BEGIN CONFIGURATION #
|
||||
#######################
|
||||
|
||||
# You can use this to monitor only certain devices, like:
|
||||
# device_names = ['enp4s0', 'docker0']
|
||||
device_names = []
|
||||
|
||||
# LIBRARY_NAME has to be exact, although it doesn't need to include the full path.
|
||||
# The version tagged as 0.8.5 (download link below) builds a library with this name.
|
||||
# https://github.com/raboof/nethogs/archive/v0.8.5.tar.gz
|
||||
LIBRARY_NAME = 'libnethogs.so.0.8.5'
|
||||
|
||||
# EXPERIMENTAL: Optionally, specify a capture filter in pcap format (same as
|
||||
# used by tcpdump(1)) or None. See `man pcap-filter` for full information.
|
||||
# Note that this feature is EXPERIMENTAL (in libnethogs) and may be removed or
|
||||
# changed in an incompatible way in a future release.
|
||||
# example:
|
||||
# FILTER = 'port 80 or port 8080 or port 443'
|
||||
FILTER = None
|
||||
|
||||
#####################
|
||||
# END CONFIGURATION #
|
||||
#####################
|
||||
|
||||
# Here are some definitions from libnethogs.h
|
||||
# https://github.com/raboof/nethogs/blob/master/src/libnethogs.h
|
||||
# Possible actions are NETHOGS_APP_ACTION_SET & NETHOGS_APP_ACTION_REMOVE
|
||||
@@ -89,18 +108,25 @@ def run_monitor_loop(lib, devnames):
|
||||
# params an int and a pointer to a NethogsMonitorRecord instance.
|
||||
# The params and return type of the callback function are mandated by nethogsmonitor_loop().
|
||||
# See libnethogs.h.
|
||||
CALLBACK_FUNC_TYPE = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.POINTER(NethogsMonitorRecord))
|
||||
CALLBACK_FUNC_TYPE = ctypes.CFUNCTYPE(
|
||||
ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(NethogsMonitorRecord)
|
||||
)
|
||||
|
||||
filter_arg = FILTER
|
||||
if filter_arg is not None:
|
||||
filter_arg = ctypes.c_char_p(filter_arg.encode('ascii'))
|
||||
|
||||
if len(devnames) < 1:
|
||||
# monitor all devices
|
||||
rc = lib.nethogsmonitor_loop(
|
||||
CALLBACK_FUNC_TYPE(network_activity_callback)
|
||||
CALLBACK_FUNC_TYPE(network_activity_callback),
|
||||
filter_arg
|
||||
)
|
||||
else:
|
||||
devc, devicenames = dev_args(devnames)
|
||||
rc = lib.nethogsmonitor_loop_devices(
|
||||
CALLBACK_FUNC_TYPE(network_activity_callback),
|
||||
filter_arg,
|
||||
devc,
|
||||
devicenames,
|
||||
ctypes.c_bool(False)
|
||||
@@ -136,10 +162,6 @@ signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
lib = ctypes.CDLL(LIBRARY_NAME)
|
||||
|
||||
device_names = []
|
||||
# You can use this to monitor only certain devices, like:
|
||||
# device_names = ['enp4s0', 'docker0']
|
||||
|
||||
monitor_thread = threading.Thread(
|
||||
target=run_monitor_loop, args=(lib, device_names,)
|
||||
)
|
||||
|
||||
@@ -77,13 +77,42 @@ struct dp_handle *dp_open_offline(char *fname, char *ebuf) {
|
||||
}
|
||||
|
||||
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||
int to_ms, char *errbuf) {
|
||||
int to_ms, char *filter, char *errbuf) {
|
||||
struct bpf_program fp; // compiled filter program
|
||||
bpf_u_int32 maskp; // subnet mask
|
||||
bpf_u_int32 netp; // interface IP
|
||||
|
||||
pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
|
||||
|
||||
if (temp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (filter != NULL) {
|
||||
pcap_lookupnet(device, &netp, &maskp, errbuf);
|
||||
|
||||
/* Compile the filter */
|
||||
if(pcap_compile(temp, &fp, filter, 1, netp) == -1) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error calling pcap_compile for filter on device %s: %s\n",
|
||||
device, pcap_geterr(temp)
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set the filter */
|
||||
if(pcap_setfilter(temp, &fp) == -1) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error setting capture filter on device %s: %s\n",
|
||||
device, pcap_geterr(temp)
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return dp_fillhandle(temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ struct dp_handle {
|
||||
/* functions to set up a handle (which is basically just a pcap handle) */
|
||||
|
||||
struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc,
|
||||
int to_ms, char *errbuf);
|
||||
int to_ms, char *filter, char *errbuf);
|
||||
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
|
||||
|
||||
/* functions to add callbacks */
|
||||
|
||||
@@ -72,7 +72,8 @@ static bool wait_for_next_trigger() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nethogsmonitor_init(int devc, char **devicenames, bool all) {
|
||||
static int nethogsmonitor_init(int devc, char **devicenames,
|
||||
bool all, char *filter) {
|
||||
process_init();
|
||||
|
||||
device *devices = get_devices(devc, devicenames, all);
|
||||
@@ -100,7 +101,8 @@ static int nethogsmonitor_init(int devc, char **devicenames, bool all) {
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
dp_handle *newhandle =
|
||||
dp_open_live(current_dev->name, BUFSIZ, promiscuous, 100, errbuf);
|
||||
dp_open_live(current_dev->name, BUFSIZ, promiscuous,
|
||||
100, filter, errbuf);
|
||||
if (newhandle != NULL) {
|
||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||
@@ -271,17 +273,17 @@ static void nethogsmonitor_clean_up() {
|
||||
procclean();
|
||||
}
|
||||
|
||||
int nethogsmonitor_loop(NethogsMonitorCallback cb) {
|
||||
return nethogsmonitor_loop_devices(cb, 0, NULL, false);
|
||||
int nethogsmonitor_loop(NethogsMonitorCallback cb, char *filter) {
|
||||
return nethogsmonitor_loop_devices(cb, filter, 0, NULL, false);
|
||||
}
|
||||
|
||||
int nethogsmonitor_loop_devices(NethogsMonitorCallback cb,
|
||||
int nethogsmonitor_loop_devices(NethogsMonitorCallback cb, char *filter,
|
||||
int devc, char **devicenames, bool all) {
|
||||
if (monitor_run_flag) {
|
||||
return NETHOGS_STATUS_FAILURE;
|
||||
}
|
||||
|
||||
int return_value = nethogsmonitor_init(devc, devicenames, all);
|
||||
int return_value = nethogsmonitor_init(devc, devicenames, all, filter);
|
||||
if (return_value != NETHOGS_STATUS_OK) {
|
||||
return return_value;
|
||||
}
|
||||
|
||||
@@ -53,9 +53,15 @@ typedef void (*NethogsMonitorCallback)(int action,
|
||||
* occurs.
|
||||
* @param cb A pointer to a callback function following the
|
||||
* NethogsMonitorCallback definition
|
||||
* @param filter EXPERIMENTAL: A string (char array) pcap filter to restrict
|
||||
* what packets are captured, or NULL. The filter string format is the same as
|
||||
* that of tcpdump(1); for full details, see the man page for pcap-filter(7).
|
||||
* Note that this is EXPERIMENTAL, and may be removed or changed in a future
|
||||
* version.
|
||||
*/
|
||||
|
||||
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
||||
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb,
|
||||
char *filter);
|
||||
|
||||
/**
|
||||
* @brief Enter the process monitoring loop and reports updates using the
|
||||
@@ -65,6 +71,11 @@ NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
||||
* occurs.
|
||||
* @param cb A pointer to a callback function following the
|
||||
* NethogsMonitorCallback definition
|
||||
* @param filter EXPERIMENTAL: A string (char array) pcap filter to restrict
|
||||
* what packets are captured, or NULL. The filter string format is the same as
|
||||
* that of tcpdump(1); for full details, see the man page for pcap-filter(7).
|
||||
* Note that this is EXPERIMENTAL, and may be removed or changed in a future
|
||||
* version.
|
||||
* @param devc number of values in devicenames array
|
||||
* @param devicenames pointer to array of devicenames (char arrays)
|
||||
* @param all when false, loopback interface and down/not running interfaces
|
||||
@@ -72,7 +83,8 @@ NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
||||
*/
|
||||
|
||||
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop_devices(NethogsMonitorCallback cb,
|
||||
int devc, char **devicenames,
|
||||
char *filter, int devc,
|
||||
char **devicenames,
|
||||
bool all);
|
||||
|
||||
/**
|
||||
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -27,7 +27,8 @@ static void help(bool iserror) {
|
||||
// output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))]
|
||||
// [device [device [device ...]]]\n";
|
||||
output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] "
|
||||
"[-t] [-p] [-s] [-a] [-l] [device [device [device ...]]]\n";
|
||||
"[-t] [-p] [-s] [-a] [-l] [-f filter] "
|
||||
"[device [device [device ...]]]\n";
|
||||
output << " -V : prints version.\n";
|
||||
output << " -h : prints this help.\n";
|
||||
output << " -b : bughunt mode - implies tracemode.\n";
|
||||
@@ -43,6 +44,8 @@ static void help(bool iserror) {
|
||||
output << " -s : sort output by sent column.\n";
|
||||
output << " -l : display command line.\n";
|
||||
output << " -a : monitor all devices, even loopback/stopped ones.\n";
|
||||
output << " -f : EXPERIMENTAL: specify string pcap filter (like tcpdump)."
|
||||
" This may be removed or changed in a future version.\n";
|
||||
output << " device : device(s) to monitor. default is all "
|
||||
"interfaces up and running excluding loopback\n";
|
||||
output << std::endl;
|
||||
@@ -133,9 +136,10 @@ int main(int argc, char **argv) {
|
||||
|
||||
int promisc = 0;
|
||||
bool all = false;
|
||||
char *filter = NULL;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:la")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:laf:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'V':
|
||||
versiondisplay();
|
||||
@@ -171,6 +175,9 @@ int main(int argc, char **argv) {
|
||||
case 'a':
|
||||
all = true;
|
||||
break;
|
||||
case 'f':
|
||||
filter = optarg;
|
||||
break;
|
||||
default:
|
||||
help(true);
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -216,16 +223,20 @@ int main(int argc, char **argv) {
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
int nb_devices = 0;
|
||||
int nb_failed_devices = 0;
|
||||
|
||||
handle *handles = NULL;
|
||||
device *current_dev = devices;
|
||||
while (current_dev != NULL) {
|
||||
++nb_devices;
|
||||
|
||||
if (!getLocal(current_dev->name, tracemode)) {
|
||||
forceExit(false, "getifaddrs failed while establishing local IP.");
|
||||
}
|
||||
|
||||
dp_handle *newhandle =
|
||||
dp_open_live(current_dev->name, BUFSIZ, promisc, 100, errbuf);
|
||||
dp_open_live(current_dev->name, BUFSIZ, promisc, 100, filter, errbuf);
|
||||
if (newhandle != NULL) {
|
||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||
@@ -258,11 +269,16 @@ int main(int argc, char **argv) {
|
||||
} else {
|
||||
fprintf(stderr, "Error opening handler for device %s\n",
|
||||
current_dev->name);
|
||||
++nb_failed_devices;
|
||||
}
|
||||
|
||||
current_dev = current_dev->next;
|
||||
}
|
||||
|
||||
if (nb_devices == nb_failed_devices) {
|
||||
forceExit(false, "Error opening pcap handlers for all devices.\n");
|
||||
}
|
||||
|
||||
signal(SIGINT, &quit_cb);
|
||||
|
||||
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
||||
|
||||
Reference in New Issue
Block a user