summaryrefslogtreecommitdiff
path: root/extcap/ssh-tcpdump
diff options
context:
space:
mode:
Diffstat (limited to 'extcap/ssh-tcpdump')
-rwxr-xr-xextcap/ssh-tcpdump124
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)