diff options
author | Peter Wu <peter@lekensteyn.nl> | 2016-09-24 11:22:47 +0200 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2016-09-24 11:22:47 +0200 |
commit | 6951d901827e9d31a8c09a3a30d6d65ac25514c7 (patch) | |
tree | c575480d6e2cafb83f06b52c35de5d38e88cedf1 | |
parent | 21651a6e4c8ac21b1989c5847c04e96fd6c8b333 (diff) | |
download | wireshark-notes-6951d901827e9d31a8c09a3a30d6d65ac25514c7.tar.gz |
extcap/ssh-tcpdump: example remote tcpdump
Requires Python 3.4, but it can be adapted for older versions. It
demonstrates how "easy" it is to capture remotely over SSH when only
tcpdump is installed without dumpcap (in that case you could use
sshdump).
Note that on stopping/restarting captures, you still get some stderr
messages ("Dropped privileges", but that can be ignored). See also
https://ask.wireshark.org/questions/55768/remote-interface-linux
-rwxr-xr-x | extcap/ssh-tcpdump | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/extcap/ssh-tcpdump b/extcap/ssh-tcpdump new file mode 100755 index 0000000..02fcca6 --- /dev/null +++ b/extcap/ssh-tcpdump @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# Capture from a remote server over SSH which has tcpdump but no dumpcap. +# +# After copying this file to the extcap folder (see Help -> About +# for location), you can use the name "ssh-tcpdump:" followed by the interface +# name: +# +# SSHHOST=peterw@someserver wireshark -i ssh-tcpdump:eth0 -p -k +# +# Note: interface names are currently hard-coded (lo and eth0). + +#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-interface', metavar='IFACE') + +parser.add_argument('--extcap-capture-filter', metavar='CFILTER') +parser.add_argument('--fifo', metavar='FIFO') + +IFACE_PREFIX = 'ssh-tcpdump:' +# TODO currently hard-coded interfaces, maybe add preferences? +ifaces = [ + 'lo', + 'eth0', +] + +def extcap_interfaces(): + print("extcap {version=1.0}") + for iface in ifaces: + print("interface {value=%s%s}{display=Remote tcpdump: %s}" % ( + IFACE_PREFIX, iface, iface + )) + +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}") + +# TODO consider configuration option for setting the SSH host? +def extcap_config(iface): + pass + +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, cfilter, outfile): + ssh_host = os.getenv("SSHHOST") + if not ssh_host: + raise RuntimeError("Missing SSHHOST") + ssh_user = os.getenv('SSHUSER') + if not ssh_user: + if '@' in ssh_host: + ssh_user = ssh_host.split('@')[0] + else: + ssh_user = os.getenv('USER') + tcpdump_args = [ + "sudo", + "tcpdump", + "-i", iface, + "-p", + "-U", + "-w", "-", + ] + # Change to a less-privileged user + if ssh_user: + tcpdump_args += ["-Z", ssh_user] + 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') + + iface = args.extcap_interface[len(IFACE_PREFIX):] + + 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.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) |