From a458518de9569cd36237743a54b3d40ab55e4e13 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 28 Jan 2019 13:07:18 +0100 Subject: extcap: add ssh-dumpcap example Based on ssh-tcpdump, but uses dumpcap and supports specifying the hostname and interface through capture options. Should probably integrate that with ssh-tcpdump, but I quickly needed something working. Known issues: - On exit Wireshark assumes that stderr is an error. - dumpcap does not exit on the remote server, tracked by https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=14431 - Stopping a capture, killing dumpcap and starting a capture again results in a corrupted dissection (interpreted as ERF). The pcapng file on the filesystem is ok, it is just a GUI problem. Tested with Wireshark v2.9.1rc0-558-geec3ce3bb2. --- extcap/ssh-dumpcap | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100755 extcap/ssh-dumpcap diff --git a/extcap/ssh-dumpcap b/extcap/ssh-dumpcap new file mode 100755 index 0000000..55c9f8d --- /dev/null +++ b/extcap/ssh-dumpcap @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# Capture from a remote server over SSH which has dumpcap. +# +# After copying this file to the extcap folder (see Help -> About +# for location), you can capture with: +# +# wireshark -i ssh-dumpcap -k \ +# -oextcap.ssh_dumpcap.remotehost:user@host \ +# -oextcap.ssh_dumpcap.remoteinterface:nflog:0x1234 + +#from __future__ import print_function + +import argparse, os, sys +from shlex import quote +from signal import SIGINT + +parser = argparse.ArgumentParser() + +# Actions +parser.add_argument('--extcap-interfaces', action='store_true') +parser.add_argument('--extcap-dlts', action='store_true') +parser.add_argument('--extcap-config', action='store_true') +parser.add_argument('--capture', action='store_true') +parser.add_argument('--extcap-version') + +parser.add_argument('--extcap-interface', metavar='IFACE') + +parser.add_argument('--extcap-capture-filter', metavar='CFILTER') +parser.add_argument('--fifo', metavar='FIFO') + +parser.add_argument('--remote-host', metavar='HOST') +parser.add_argument('--remote-interface', metavar='IFACE') + +def extcap_interfaces(): + print("extcap {version=1.0}") + print("interface {value=ssh-dumpcap}{display=Remote dumpcap}") + +def extcap_dlts(iface): + # Required for the interface to show up in the interace + print("dlt {number=147}{name=USER0}{display=Remote capture dependent DLT}") + +def extcap_config(iface): + print(""" +arg {number=0}{call=--remote-host}{display=Remote SSH server address}{type=string}{tooltip=The remote SSH host. It can be both an IP address or a hostname}{required=true}{group=Server} +arg {number=1}{call=--remote-interface}{display=Remote interface}{type=string}{tooltip=The remote network interface used for capture}{group=Capture} +""".strip()) + +def redirect_stdout(outfile): + STDOUT_FILENO = 1 + try: os.close(STDOUT_FILENO) + except OSError: pass + fd = os.open(outfile, os.O_WRONLY, 0o600) + # TODO this requires Py 3.4, maybe old version can use dup2 + os.set_inheritable(fd, True) + if fd != STDOUT_FILENO: + os.dup2(fd, STDOUT_FILENO) + os.close(fd) + +def extcap_capture(iface, ssh_host, cfilter, outfile): + tcpdump_args = [ + "dumpcap", + "-i", iface, + "-p", + "-q", + "-w", "-", + ] + if cfilter: + tcpdump_args += [cfilter] + args = [ + "ssh", ssh_host, + " ".join(quote(c) for c in tcpdump_args), + ] + #import subprocess; subprocess.call(["ls", "-l", "/proc/%d/fd/" % os.getpid()], stdout=2) + redirect_stdout(outfile) + os.execvp(args[0], args) + +def main(): + args = parser.parse_args() + if args.extcap_interfaces: + return extcap_interfaces() + + if not args.extcap_interface: + parser.error('Missing --extcap-interface option') + #if args.extcap_interface != "ssh-dumpcap": + # parser.error('only ssh-dumpcap is supported as interface name') + + iface = args.remote_interface + + if args.extcap_dlts: + return extcap_dlts(iface) + elif args.extcap_config: + return extcap_config(iface) + elif args.capture: + if not args.fifo: + parser.error('Missing --fifo option for --capture') + return extcap_capture(iface, args.remote_host, args.extcap_capture_filter, args.fifo) + else: + parser.error('Missing action') + return 1 + +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(128 + SIGINT) + except OSError as e: + print(e, file=sys.stderr) + sys.exit(1) -- cgit v1.2.1