[netsniff-ng] [PATCH 0/2] flowtop: Move & refactor walk_processes(...) to proc.c
Add proc_find_by_inode(...) to find pid & it's command line by inode. The main motivation for this is to have process specific function located in proc.c and only call it from flowtop.c. proc_find_by_inode(...) its just a refactored version of walk_processes(...) from the flowtop.c. Vadim Kochan (2): proc: Add function for find process by inode flowtop: Replace walk_processes(...) by proc_find_by_inode(...) flowtop.c | 76 --- proc.c| 74 + proc.h| 1 + 3 files changed, 84 insertions(+), 67 deletions(-) -- 2.10.2 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[netsniff-ng] [PATCH 1/2] proc: Add function for find process by inode
Add proc_find_by_inode(...) which finds pid by inode & gets processe's command line. Actually this function was taken from flowtop.c walk_process(...) and refactored to look more generic. Signed-off-by: Vadim Kochan--- proc.c | 74 ++ proc.h | 1 + 2 files changed, 75 insertions(+) diff --git a/proc.c b/proc.c index 76e3c93..8119226 100644 --- a/proc.c +++ b/proc.c @@ -3,11 +3,13 @@ #endif #include #include +#include #include #include #include #include #include +#include #include "proc.h" #include "die.h" @@ -83,6 +85,78 @@ ssize_t proc_get_cmdline(unsigned int pid, char *cmdline, size_t len) return ret; } +int __match_pid_by_inode(pid_t pid, ino_t ino) +{ + struct dirent *ent; + char path[1024]; + DIR *dir; + + if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1) + panic("giant process name! %u\n", pid); + + dir = opendir(path); + if (!dir) + return -1; + + while ((ent = readdir(dir))) { + struct stat statbuf; + + if (snprintf(path, sizeof(path), "/proc/%u/fd/%s", +pid, ent->d_name) < 0) + continue; + + if (stat(path, ) < 0) + continue; + + if (S_ISSOCK(statbuf.st_mode) && ino == statbuf.st_ino) { + closedir(dir); + return 0; + } + } + + closedir(dir); + return -1; +} + +int proc_find_by_inode(ino_t ino, char *cmdline, size_t len, pid_t *pid) +{ + struct dirent *ent; + DIR *dir; + + if (ino <= 0) { + cmdline[0] = '\0'; + return 0; + } + + dir = opendir("/proc"); + if (!dir) + panic("Cannot open /proc: %s\n", strerror(errno)); + + while ((ent = readdir(dir))) { + int ret; + char *end; + const char *name = ent->d_name; + pid_t _pid = strtoul(name, , 10); + + /* not a PID */ + if (_pid == 0 && end == name) + continue; + + ret = __match_pid_by_inode(_pid, ino); + if (!ret) { + ret = proc_get_cmdline(_pid, cmdline, len); + if (ret < 0) + panic("Failed to get process cmdline: %s\n", strerror(errno)); + + *pid = _pid; + return ret; + } + } + + closedir(dir); + return -1; +} + int proc_exec(const char *proc, char *const argv[]) { int status; diff --git a/proc.h b/proc.h index 9220b2a..6e5f3ac 100644 --- a/proc.h +++ b/proc.h @@ -8,5 +8,6 @@ extern int set_proc_prio(int prio); extern int set_sched_status(int policy, int priority); extern ssize_t proc_get_cmdline(unsigned int pid, char *cmdline, size_t len); extern int proc_exec(const char *proc, char *const argv[]); +extern int proc_find_by_inode(ino_t ino, char *cmdline, size_t len, pid_t *pid); #endif /* PROC_H */ -- 2.10.2 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[netsniff-ng] [PATCH 1/4] pcap io: Introduce new pcap io API to simplify pcap access
Add pcap_io object which represent pcap io API to simplify and make more transparent pcap access. Signed-off-by: Vadim Kochan--- pcap_io.c | 190 ++ pcap_io.h | 143 ++ 2 files changed, 333 insertions(+) create mode 100644 pcap_io.c diff --git a/pcap_io.c b/pcap_io.c new file mode 100644 index 000..b82792a --- /dev/null +++ b/pcap_io.c @@ -0,0 +1,190 @@ +/* + * netsniff-ng - the packet sniffing beast + * Subject to the GPL, version 2. + */ + +#define _GNU_SOURCE + +#include +#include + +#include "bpf.h" +#include "pcap_io.h" +#include "xmalloc.h" + +void pcap_io_init(struct pcap_io *io, enum pcap_ops_groups ops_type) +{ + io->ops = pcap_ops[ops_type]; + io->ops_type = ops_type; + io->bpf_ops = NULL; + io->jumbo = false; + io->truncated = 0; + io->path = NULL; + io->fd = -1; + + bug_on(!io->ops); +} + +void pcap_io_open(struct pcap_io *io, const char *path, enum pcap_mode mode) +{ + if (mode == PCAP_MODE_RD) { + if (!strncmp("-", path, strlen("-"))) { + io->fd = dup_or_die(fileno(stdin)); + close(fileno(stdin)); + + if (io->ops_type == PCAP_OPS_MM) + pcap_io_init(io, PCAP_OPS_SG); + } else { + io->fd = open(path, O_RDONLY | O_LARGEFILE | O_NOATIME); + if (io->fd < 0 && errno == EPERM) + io->fd = open_or_die(path, O_RDONLY | O_LARGEFILE); + } + } else if (mode == PCAP_MODE_WR) { + if (!strncmp("-", path, strlen("-"))) { + io->fd = dup_or_die(fileno(stdout)); + close(fileno(stdout)); + + if (io->ops_type == PCAP_OPS_MM) + pcap_io_init(io, PCAP_OPS_SG); + } else { + io->fd = open_or_die_m(path, O_RDWR | O_CREAT | O_TRUNC | + O_LARGEFILE, DEFFILEMODE); + } + } else { + bug(); + } + + if (io->fd < 0) + panic("pcap_io: Cannot open file %s! %s.\n", path, strerror(errno)); + + if (io->ops->init_once_pcap) + io->ops->init_once_pcap(io->enforce_prio); + + io->path = path; + io->mode = mode; +} + +static int pcap_io_prepare_access(struct pcap_io *io) +{ + int ret; + + if (io->ops->prepare_access_pcap) { + ret = io->ops->prepare_access_pcap(io->fd, io->mode, io->jumbo); + if (ret) { + fprintf(stderr, "pcap_io: Error prepare %s pcap!\n", + io->mode == PCAP_MODE_RD ? "reading" : "writing"); + + return ret; + } + } + + return 0; +} + +void pcap_io_header_copy(struct pcap_io *to, struct pcap_io *from) +{ + to->link_type = from->link_type; + to->magic = from->magic; +} + +int pcap_io_header_read(struct pcap_io *io) +{ + int ret; + + ret = io->ops->pull_fhdr_pcap(io->fd, >magic, >link_type); + if (ret) { + fprintf(stderr, "pcap_io: Error reading pcap header!\n"); + return ret; + } + + return pcap_io_prepare_access(io); +} + +int pcap_io_header_write(struct pcap_io *io) +{ + int ret; + + ret = io->ops->push_fhdr_pcap(io->fd, io->magic, io->link_type); + if (ret) { + fprintf(stderr, "pcap_io: Error writing pcap header!\n"); + return ret; + } + + return pcap_io_prepare_access(io); +} + +int pcap_io_packet_read(struct pcap_io *io, struct pcap_packet *pkt) +{ + int ret; + + do { + ret = io->ops->read_pcap(io->fd, >phdr, io->magic, +pkt->buf, pkt->buf_len); + if (unlikely(ret < 0)) { + return 0; + } + if (unlikely(pcap_packet_len_get(pkt) == 0)) { + pkt->io->truncated++; + continue; + } + if (unlikely(pcap_packet_len_get(pkt) > pkt->buf_len)) { + pcap_packet_len_set(pkt, pkt->buf_len); + pkt->io->truncated++; + } + } while (io->bpf_ops && + !bpf_run_filter(io->bpf_ops, pkt->buf, +pcap_packet_len_get(pkt))); + + return ret; +} + +int pcap_io_packet_write(struct pcap_io *io, struct pcap_packet *pkt) +{ + size_t pcap_len = pcap_get_length(>phdr, io->magic); + uint32_t len = io->ops->write_pcap(io->fd, >phdr, io->magic, + pkt->buf, pcap_len); + + if (unlikely(len != pcap_get_total_length(>phdr,
[netsniff-ng] [PATCH 3/4] netsniff-ng: Use new pcap io API for packets dump
Convert packets dumping logic to use pcap_io_xxx API which look more simpler & generic. Signed-off-by: Vadim Kochan--- netsniff-ng.c | 152 -- 1 file changed, 53 insertions(+), 99 deletions(-) diff --git a/netsniff-ng.c b/netsniff-ng.c index a0ede4e..74446ad 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -736,31 +736,21 @@ out: } } -static void finish_multi_pcap_file(struct ctx *ctx, int fd) +static void finish_multi_pcap_file(struct pcap_io *io) { - __pcap_io->fsync_pcap(fd); - - if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); - - close(fd); + pcap_io_close(io); fmemset(, 0, sizeof(itimer)); setitimer(ITIMER_REAL, , NULL); } -static int next_multi_pcap_file(struct ctx *ctx, int fd) +static void next_multi_pcap_file(struct ctx *ctx, struct pcap_io *io) { int ret; char fname[512]; time_t ftime; - __pcap_io->fsync_pcap(fd); - - if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); - - close(fd); + pcap_io_close(io); if (sighup_time > 0) { ftime = (time_t)(start_time + sighup_time); @@ -771,20 +761,11 @@ static int next_multi_pcap_file(struct ctx *ctx, int fd) slprintf(fname, sizeof(fname), "%s/%s%lu.pcap", ctx->device_out, ctx->prefix ? : "dump-", ftime); - fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC | - O_LARGEFILE, DEFFILEMODE); + pcap_io_open(io, fname, PCAP_MODE_WR); - ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); + ret = pcap_io_header_write(io); if (ret) - panic("Error writing pcap header!\n"); - - if (__pcap_io->prepare_access_pcap) { - ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_WR, true); - if (ret) - panic("Error prepare writing pcap!\n"); - } - - return fd; + panic("Error writing multi pcap header!\n"); } static void reset_interval(struct ctx *ctx) @@ -799,12 +780,12 @@ static void reset_interval(struct ctx *ctx) } } -static int begin_multi_pcap_file(struct ctx *ctx) +static void begin_multi_pcap_file(struct ctx *ctx, struct pcap_io *io) { - int fd, ret; char fname[256]; + int ret; - bug_on(!__pcap_io); + bug_on(!io); if (ctx->device_out[strlen(ctx->device_out) - 1] == '/') ctx->device_out[strlen(ctx->device_out) - 1] = 0; @@ -812,69 +793,35 @@ static int begin_multi_pcap_file(struct ctx *ctx) slprintf(fname, sizeof(fname), "%s/%s%lu.pcap", ctx->device_out, ctx->prefix ? : "dump-", time(NULL)); - fd = open_or_die_m(fname, O_RDWR | O_CREAT | O_TRUNC | - O_LARGEFILE, DEFFILEMODE); + pcap_io_open(io, fname, PCAP_MODE_WR); - ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); + ret = pcap_io_header_write(io); if (ret) - panic("Error writing pcap header!\n"); - - if (__pcap_io->prepare_access_pcap) { - ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_WR, true); - if (ret) - panic("Error prepare writing pcap!\n"); - } + panic("Error writing multi pcap header!\n"); reset_interval(ctx); - - return fd; } -static void finish_single_pcap_file(struct ctx *ctx, int fd) +static void finish_single_pcap_file(struct pcap_io *io) { - __pcap_io->fsync_pcap(fd); - - if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_WR); - - if (strncmp("-", ctx->device_out, strlen("-"))) - close(fd); - else - dup2(fd, fileno(stdout)); + pcap_io_close(io); } -static int begin_single_pcap_file(struct ctx *ctx) +static void begin_single_pcap_file(struct ctx *ctx, struct pcap_io *io) { - int fd, ret; + int ret; - bug_on(!__pcap_io); + bug_on(!io); - if (!strncmp("-", ctx->device_out, strlen("-"))) { - fd = dup_or_die(fileno(stdout)); - close(fileno(stdout)); - if (ctx->pcap == PCAP_OPS_MM) - ctx->pcap = PCAP_OPS_SG; - } else { - fd = open_or_die_m(ctx->device_out, - O_RDWR | O_CREAT | O_TRUNC | - O_LARGEFILE, DEFFILEMODE); - } + pcap_io_open(io, ctx->device_out, PCAP_MODE_WR); - ret = __pcap_io->push_fhdr_pcap(fd, ctx->magic, ctx->link_type); + ret = pcap_io_header_write(io); if (ret) - panic("Error writing pcap header!\n"); - - if (__pcap_io->prepare_access_pcap) { - ret =
[netsniff-ng] [PATCH 4/4] netsniff-ng: Use new pcap io API for pcap to xmit case
Convert pcap_to_xmit(...) to use use pcap io API to simplify logic for pcap packets reading. Signed-off-by: Vadim Kochan--- netsniff-ng.c | 66 ++- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/netsniff-ng.c b/netsniff-ng.c index 74446ad..a6b43ee 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -250,15 +250,15 @@ static void dump_rx_stats(struct ctx *ctx, int sock, bool is_v3) static void pcap_to_xmit(struct ctx *ctx) { uint8_t *out = NULL; - int ifindex, fd = 0, ret; + int ifindex, ret; size_t size; unsigned int it = 0; - unsigned long trunced = 0; struct ring tx_ring; struct frame_map *hdr; struct sock_fprog bpf_ops; struct timeval start, end, diff; - pcap_pkthdr_t phdr; + struct pcap_io pcap_in; + struct pcap_packet *pkt; if (!device_up_and_running(ctx->device_out) && !ctx->rfraw) panic("Device not up and running!\n"); @@ -267,27 +267,11 @@ static void pcap_to_xmit(struct ctx *ctx) tx_sock = pf_socket(); - if (!strncmp("-", ctx->device_in, strlen("-"))) { - fd = dup_or_die(fileno(stdin)); - close(fileno(stdin)); - if (ctx->pcap == PCAP_OPS_MM) - ctx->pcap = PCAP_OPS_SG; - } else { - fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME); - } - - if (__pcap_io->init_once_pcap) - __pcap_io->init_once_pcap(true); - - ret = __pcap_io->pull_fhdr_pcap(fd, >magic, >link_type); - if (ret) - panic("Error reading pcap header!\n"); + pcap_io_init(_in, ctx->pcap); + pcap_io_open(_in, ctx->device_in, PCAP_MODE_RD); + pcap_io_header_read(_in); - if (__pcap_io->prepare_access_pcap) { - ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo); - if (ret) - panic("Error prepare reading pcap!\n"); - } + ctx->link_type = pcap_io_link_type_get(_in); if (ctx->rfraw) { setup_rfmon_mac80211_dev(ctx, >device_out); @@ -304,8 +288,13 @@ static void pcap_to_xmit(struct ctx *ctx) if (ctx->dump_bpf) bpf_dump_all(_ops); + pcap_io_bpf_apply(_in, _ops); + ring_tx_setup(_ring, tx_sock, size, ifindex, ctx->jumbo, ctx->verbose); + pkt = pcap_packet_alloc(_in); + pcap_packet_buf_len_set(pkt, ring_frame_size(_ring)); + dissector_init_all(ctx->print_mode); if (ctx->cpu >= 0 && ifindex > 0) { @@ -335,23 +324,13 @@ static void pcap_to_xmit(struct ctx *ctx) hdr = tx_ring.frames[it].iov_base; out = ((uint8_t *) hdr) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); - do { - ret = __pcap_io->read_pcap(fd, , ctx->magic, out, - ring_frame_size(_ring)); - if (unlikely(ret <= 0)) - goto out; - - if (ring_frame_size(_ring) < - pcap_get_length(, ctx->magic)) { - pcap_set_length(, ctx->magic, - ring_frame_size(_ring)); - trunced++; - } - } while (ctx->filter && -!bpf_run_filter(_ops, out, -pcap_get_length(, ctx->magic))); + pcap_packet_buf_set(pkt, out); - pcap_pkthdr_to_tpacket_hdr(, ctx->magic, >tp_h, NULL); + ret = pcap_io_packet_read(_in, pkt); + if (unlikely(!ret)) + goto out; + + pcap_packet_to_tpacket2(pkt, >tp_h, NULL); ctx->tx_bytes += hdr->tp_h.tp_len;; ctx->tx_packets++; @@ -396,19 +375,14 @@ out: if (ctx->rfraw) leave_rfmon_mac80211(ctx->device_out); - if (__pcap_io->prepare_close_pcap) - __pcap_io->prepare_close_pcap(fd, PCAP_MODE_RD); - - if (!strncmp("-", ctx->device_in, strlen("-"))) - dup2(fd, fileno(stdin)); - close(fd); + pcap_io_close(_in); close(tx_sock); fflush(stdout); printf("\n"); printf("\r%12lu packets outgoing\n", ctx->tx_packets); - printf("\r%12lu packets truncated in file\n", trunced); + printf("\r%12lu packets truncated in file\n", pcap_io_truncated_get(_in)); printf("\r%12lu bytes outgoing\n", ctx->tx_bytes); printf("\r%12lu sec, %lu usec in total\n", diff.tv_sec,
[netsniff-ng] [PATCH 2/4] netsniff-ng: Use new pcap io API for read_pcap(...) function
Use new pcap io to dump & write out packets from input pcap file. Signed-off-by: Vadim Kochan--- netsniff-ng.c| 127 +-- netsniff-ng/Makefile | 1 + 2 files changed, 44 insertions(+), 84 deletions(-) diff --git a/netsniff-ng.c b/netsniff-ng.c index bbffe72..a0ede4e 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -616,49 +616,26 @@ static void translate_pcap_to_txf(int fdo, uint8_t *out, size_t len) static void read_pcap(struct ctx *ctx) { - uint8_t *out; - int ret, fd, fdo = 0; - unsigned long trunced = 0; - size_t out_len; - pcap_pkthdr_t phdr; + int ret, fdo = 0; struct sock_fprog bpf_ops; struct frame_map fm; struct timeval start, end, diff; bool is_out_pcap = ctx->device_out && strstr(ctx->device_out, ".pcap"); - const struct pcap_file_ops *pcap_out_ops = pcap_ops[PCAP_OPS_RW]; + struct pcap_io pcap_out; + struct pcap_io pcap_in; + struct pcap_packet *pkt; bug_on(!__pcap_io); - if (!strncmp("-", ctx->device_in, strlen("-"))) { - fd = dup_or_die(fileno(stdin)); - close(fileno(stdin)); - if (ctx->pcap == PCAP_OPS_MM) - ctx->pcap = PCAP_OPS_SG; - } else { - /* O_NOATIME requires privileges, in case we don't have -* them, retry without them at a minor cost of updating -* atime in case the fs has been mounted as such. -*/ - fd = open(ctx->device_in, O_RDONLY | O_LARGEFILE | O_NOATIME); - if (fd < 0 && errno == EPERM) - fd = open_or_die(ctx->device_in, O_RDONLY | O_LARGEFILE); - if (fd < 0) - panic("Cannot open file %s! %s.\n", ctx->device_in, - strerror(errno)); - } - - if (__pcap_io->init_once_pcap) - __pcap_io->init_once_pcap(false); + pcap_io_init(_in, ctx->pcap); + pcap_io_enforce_prio_set(_in, ctx->enforce); + pcap_io_open(_in, ctx->device_in, PCAP_MODE_RD); + pcap_io_header_read(_in); - ret = __pcap_io->pull_fhdr_pcap(fd, >magic, >link_type); - if (ret) - panic("Error reading pcap header!\n"); + pkt = pcap_packet_alloc(_in); + pcap_packet_buf_alloc(pkt, round_up(1024 * 1024, RUNTIME_PAGE_SIZE)); - if (__pcap_io->prepare_access_pcap) { - ret = __pcap_io->prepare_access_pcap(fd, PCAP_MODE_RD, ctx->jumbo); - if (ret) - panic("Error prepare reading pcap!\n"); - } + ctx->link_type = pcap_io_link_type_get(_in); fmemset(, 0, sizeof(fm)); @@ -666,28 +643,25 @@ static void read_pcap(struct ctx *ctx) if (ctx->dump_bpf) bpf_dump_all(_ops); - dissector_init_all(ctx->print_mode); + pcap_io_bpf_apply(_in, _ops); - out_len = round_up(1024 * 1024, RUNTIME_PAGE_SIZE); - out = xmalloc_aligned(out_len, CO_CACHE_LINE_SIZE); + dissector_init_all(ctx->print_mode); if (ctx->device_out) { if (!strncmp("-", ctx->device_out, strlen("-"))) { fdo = dup_or_die(fileno(stdout)); close(fileno(stdout)); - } else { - fdo = open_or_die_m(ctx->device_out, O_RDWR | O_CREAT | - O_TRUNC | O_LARGEFILE, DEFFILEMODE); + } else if (is_out_pcap) { + pcap_io_init(_out, PCAP_OPS_RW); + pcap_io_open(_out, ctx->device_out, PCAP_MODE_WR); + + pcap_io_header_copy(_out, _in); + ret = pcap_io_header_write(_out); + if (ret) + panic("Error writing pcap header!\n"); } } - if (is_out_pcap) { - ret = pcap_out_ops->push_fhdr_pcap(fdo, ctx->magic, - ctx->link_type); - if (ret) - panic("Error writing pcap header!\n"); - } - drop_privileges(ctx->enforce, ctx->uid, ctx->gid); printf("Running! Hang up with ^C!\n\n"); @@ -696,46 +670,34 @@ static void read_pcap(struct ctx *ctx) bug_on(gettimeofday(, NULL)); while (likely(sigint == 0)) { - do { - ret = __pcap_io->read_pcap(fd, , ctx->magic, - out, out_len); - if (unlikely(ret < 0)) - goto out; + uint8_t *pkt_buf; - if (unlikely(pcap_get_length(, ctx->magic) == 0)) { - trunced++; - continue; - } - - if
[netsniff-ng] [PATCH 0/4] Introduce new pcap io API for pcap r/w accesses
Add new pcap io API to make pcap read/write accesses more simpler and generic. Added pcap_io & pcap_packet struct's to keep some internal pcap state like magic, link type & packet header instead of to pass them like parameters and keep it all within netsniff-ng.c. Also such approach might be used to unify sniffing from ring buffer via pcap io API similary as it is done with regular files. Some fast-path sensitive or setter/getter functions were inlined in pcap_io.h. Vadim Kochan (4): pcap io: Introduce new pcap io API to simplify pcap access netsniff-ng: Use new pcap io API for read_pcap(...) function netsniff-ng: Use new pcap io API for packets dump netsniff-ng: Use new pcap io API for pcap to xmit case netsniff-ng.c| 345 +-- netsniff-ng/Makefile | 1 + pcap_io.c| 190 pcap_io.h| 143 + 4 files changed, 450 insertions(+), 229 deletions(-) create mode 100644 pcap_io.c -- 2.10.2 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.