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
|
# 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.
|
# 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.
|
# 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.
|
# 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
|
# https://github.com/raboof/nethogs/archive/v0.8.5.tar.gz
|
||||||
LIBRARY_NAME = 'libnethogs.so.0.8.5'
|
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
|
# Here are some definitions from libnethogs.h
|
||||||
# https://github.com/raboof/nethogs/blob/master/src/libnethogs.h
|
# https://github.com/raboof/nethogs/blob/master/src/libnethogs.h
|
||||||
# Possible actions are NETHOGS_APP_ACTION_SET & NETHOGS_APP_ACTION_REMOVE
|
# 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.
|
# params an int and a pointer to a NethogsMonitorRecord instance.
|
||||||
# The params and return type of the callback function are mandated by nethogsmonitor_loop().
|
# The params and return type of the callback function are mandated by nethogsmonitor_loop().
|
||||||
# See libnethogs.h.
|
# See libnethogs.h.
|
||||||
CALLBACK_FUNC_TYPE = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_int,
|
CALLBACK_FUNC_TYPE = ctypes.CFUNCTYPE(
|
||||||
ctypes.POINTER(NethogsMonitorRecord))
|
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:
|
if len(devnames) < 1:
|
||||||
# monitor all devices
|
# monitor all devices
|
||||||
rc = lib.nethogsmonitor_loop(
|
rc = lib.nethogsmonitor_loop(
|
||||||
CALLBACK_FUNC_TYPE(network_activity_callback)
|
CALLBACK_FUNC_TYPE(network_activity_callback),
|
||||||
|
filter_arg
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
devc, devicenames = dev_args(devnames)
|
devc, devicenames = dev_args(devnames)
|
||||||
rc = lib.nethogsmonitor_loop_devices(
|
rc = lib.nethogsmonitor_loop_devices(
|
||||||
CALLBACK_FUNC_TYPE(network_activity_callback),
|
CALLBACK_FUNC_TYPE(network_activity_callback),
|
||||||
|
filter_arg,
|
||||||
devc,
|
devc,
|
||||||
devicenames,
|
devicenames,
|
||||||
ctypes.c_bool(False)
|
ctypes.c_bool(False)
|
||||||
@@ -136,10 +162,6 @@ signal.signal(signal.SIGTERM, signal_handler)
|
|||||||
|
|
||||||
lib = ctypes.CDLL(LIBRARY_NAME)
|
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(
|
monitor_thread = threading.Thread(
|
||||||
target=run_monitor_loop, args=(lib, device_names,)
|
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,
|
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);
|
pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
|
||||||
|
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
return 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);
|
return dp_fillhandle(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ struct dp_handle {
|
|||||||
/* functions to set up a handle (which is basically just a pcap 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,
|
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);
|
struct dp_handle *dp_open_offline(char *fname, char *ebuf);
|
||||||
|
|
||||||
/* functions to add callbacks */
|
/* functions to add callbacks */
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ static bool wait_for_next_trigger() {
|
|||||||
return true;
|
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();
|
process_init();
|
||||||
|
|
||||||
device *devices = get_devices(devc, devicenames, all);
|
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];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
dp_handle *newhandle =
|
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) {
|
if (newhandle != NULL) {
|
||||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||||
@@ -271,17 +273,17 @@ static void nethogsmonitor_clean_up() {
|
|||||||
procclean();
|
procclean();
|
||||||
}
|
}
|
||||||
|
|
||||||
int nethogsmonitor_loop(NethogsMonitorCallback cb) {
|
int nethogsmonitor_loop(NethogsMonitorCallback cb, char *filter) {
|
||||||
return nethogsmonitor_loop_devices(cb, 0, NULL, false);
|
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) {
|
int devc, char **devicenames, bool all) {
|
||||||
if (monitor_run_flag) {
|
if (monitor_run_flag) {
|
||||||
return NETHOGS_STATUS_FAILURE;
|
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) {
|
if (return_value != NETHOGS_STATUS_OK) {
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,15 @@ typedef void (*NethogsMonitorCallback)(int action,
|
|||||||
* occurs.
|
* occurs.
|
||||||
* @param cb A pointer to a callback function following the
|
* @param cb A pointer to a callback function following the
|
||||||
* NethogsMonitorCallback definition
|
* 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
|
* @brief Enter the process monitoring loop and reports updates using the
|
||||||
@@ -65,6 +71,11 @@ NETHOGS_DSO_VISIBLE int nethogsmonitor_loop(NethogsMonitorCallback cb);
|
|||||||
* occurs.
|
* occurs.
|
||||||
* @param cb A pointer to a callback function following the
|
* @param cb A pointer to a callback function following the
|
||||||
* NethogsMonitorCallback definition
|
* 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 devc number of values in devicenames array
|
||||||
* @param devicenames pointer to array of devicenames (char arrays)
|
* @param devicenames pointer to array of devicenames (char arrays)
|
||||||
* @param all when false, loopback interface and down/not running interfaces
|
* @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,
|
NETHOGS_DSO_VISIBLE int nethogsmonitor_loop_devices(NethogsMonitorCallback cb,
|
||||||
int devc, char **devicenames,
|
char *filter, int devc,
|
||||||
|
char **devicenames,
|
||||||
bool all);
|
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))]
|
// output << "usage: nethogs [-V] [-b] [-d seconds] [-t] [-p] [-f (eth|ppp))]
|
||||||
// [device [device [device ...]]]\n";
|
// [device [device [device ...]]]\n";
|
||||||
output << "usage: nethogs [-V] [-h] [-b] [-d seconds] [-v mode] [-c count] "
|
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 << " -V : prints version.\n";
|
||||||
output << " -h : prints this help.\n";
|
output << " -h : prints this help.\n";
|
||||||
output << " -b : bughunt mode - implies tracemode.\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 << " -s : sort output by sent column.\n";
|
||||||
output << " -l : display command line.\n";
|
output << " -l : display command line.\n";
|
||||||
output << " -a : monitor all devices, even loopback/stopped ones.\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 "
|
output << " device : device(s) to monitor. default is all "
|
||||||
"interfaces up and running excluding loopback\n";
|
"interfaces up and running excluding loopback\n";
|
||||||
output << std::endl;
|
output << std::endl;
|
||||||
@@ -133,9 +136,10 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
int promisc = 0;
|
int promisc = 0;
|
||||||
bool all = false;
|
bool all = false;
|
||||||
|
char *filter = NULL;
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:la")) != -1) {
|
while ((opt = getopt(argc, argv, "Vhbtpsd:v:c:laf:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'V':
|
case 'V':
|
||||||
versiondisplay();
|
versiondisplay();
|
||||||
@@ -171,6 +175,9 @@ int main(int argc, char **argv) {
|
|||||||
case 'a':
|
case 'a':
|
||||||
all = true;
|
all = true;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
filter = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
help(true);
|
help(true);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -216,16 +223,20 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
|
||||||
|
int nb_devices = 0;
|
||||||
|
int nb_failed_devices = 0;
|
||||||
|
|
||||||
handle *handles = NULL;
|
handle *handles = NULL;
|
||||||
device *current_dev = devices;
|
device *current_dev = devices;
|
||||||
while (current_dev != NULL) {
|
while (current_dev != NULL) {
|
||||||
|
++nb_devices;
|
||||||
|
|
||||||
if (!getLocal(current_dev->name, tracemode)) {
|
if (!getLocal(current_dev->name, tracemode)) {
|
||||||
forceExit(false, "getifaddrs failed while establishing local IP.");
|
forceExit(false, "getifaddrs failed while establishing local IP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
dp_handle *newhandle =
|
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) {
|
if (newhandle != NULL) {
|
||||||
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
dp_addcb(newhandle, dp_packet_ip, process_ip);
|
||||||
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
dp_addcb(newhandle, dp_packet_ip6, process_ip6);
|
||||||
@@ -258,11 +269,16 @@ int main(int argc, char **argv) {
|
|||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error opening handler for device %s\n",
|
fprintf(stderr, "Error opening handler for device %s\n",
|
||||||
current_dev->name);
|
current_dev->name);
|
||||||
|
++nb_failed_devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_dev = current_dev->next;
|
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);
|
signal(SIGINT, &quit_cb);
|
||||||
|
|
||||||
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
|
||||||
|
|||||||
Reference in New Issue
Block a user