From c8aedce97942cf1963c137902d50d14cd5c28bf0 Mon Sep 17 00:00:00 2001 From: gpotter2 <gabriel@potter.fr> Date: Tue, 2 May 2017 21:45:05 +0200 Subject: [PATCH] Use the automaton's util to make pipetools work on windows --- scapy/automaton.py | 10 ++++- scapy/pipetool.py | 94 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/scapy/automaton.py b/scapy/automaton.py index b39e08b3..489126b8 100644 --- a/scapy/automaton.py +++ b/scapy/automaton.py @@ -324,12 +324,18 @@ class Automaton_metaclass(type): s += "}\n" return do_graph(s, **kargs) -def select_objects(inputs, remain): +def select_objects(inputs, remain, customTypes=()): + """ + Select object that have checkRecv function. + inputs: objects to process + remain: timeout. If 0, return []. + customTypes: types of the objects that have the checkRecv function. + """ if WINDOWS: r = [] def look_for_select(): for fd in inputs: - if isinstance(fd, ObjectPipe) or isinstance(fd, Automaton._IO_fdwrapper): + if isinstance(fd, ObjectPipe) or isinstance(fd, Automaton._IO_fdwrapper) or (isinstance(fd, customTypes)): if fd.checkRecv(): r.append(fd) else: diff --git a/scapy/pipetool.py b/scapy/pipetool.py index 613ae614..e9a6fb80 100644 --- a/scapy/pipetool.py +++ b/scapy/pipetool.py @@ -5,16 +5,20 @@ ## Copyright (C) Philippe Biondi <phil@secdev.org> ## This program is published under a GPLv2 license -import os, thread, select +import os, thread import subprocess import itertools import collections import time import Queue -import scapy.utils +from scapy.automaton import Message, select_objects +from scapy.consts import WINDOWS from scapy.error import log_interactive, warning from scapy.config import conf +from scapy.utils import get_temp_file, do_graph + +import scapy.arch class PipeEngine: pipes = {} @@ -41,6 +45,7 @@ class PipeEngine: self._add_pipes(*pipes) self.thread_lock = thread.allocate_lock() self.command_lock = thread.allocate_lock() + self.__fd_queue = [] self.__fdr,self.__fdw = os.pipe() self.threadid = None def __getattr__(self, attr): @@ -55,6 +60,20 @@ class PipeEngine: return f raise AttributeError(attr) + def checkRecv(self): + return len(self.__fd_queue) > 0 + + def fileno(self): + return self.__fdr + + def _read_cmd(self): + self.__fd_queue.pop() + return os.read(self.__fdr,1) + + def _write_cmd(self, _cmd): + os.write(self.__fdw, _cmd) + self.__fd_queue.append("X") + def add_one_pipe(self, pipe): self.active_pipes.add(pipe) if isinstance(pipe, Source): @@ -90,15 +109,15 @@ class PipeEngine: for p in self.active_pipes: p.start() sources = self.active_sources - sources.add(self.__fdr) + sources.add(self) exhausted = set([]) RUN=True STOP_IF_EXHAUSTED = False while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): - fds,fdo,fde=select.select(sources,[],[]) + fds = select_objects(sources, 2, customTypes=(AutoSource, PipeEngine)) for fd in fds: - if fd is self.__fdr: - cmd = os.read(self.__fdr,1) + if fd is self: + cmd = self._read_cmd() if cmd == "X": RUN=False break @@ -139,7 +158,7 @@ class PipeEngine: try: with self.command_lock: if self.threadid is not None: - os.write(self.__fdw, _cmd) + self._write_cmd(_cmd) while not self.thread_lock.acquire(0): time.sleep(0.01) # interruptible wait for thread to terminate self.thread_lock.release() # (not using .join() because it needs 'threading' module) @@ -154,7 +173,7 @@ class PipeEngine: if self.threadid is not None: for p in pipes: p.start() - os.write(self.__fdw, "A") + self._write_cmd("A") def graph(self,**kargs): g=['digraph "pipe" {',"\tnode [shape=rectangle];",] @@ -177,7 +196,7 @@ class PipeEngine: g.append('\t"%i" -> "%i";' % (id(p), id(q))) g.append('}') graph = "\n".join(g) - scapy.utils.do_graph(graph, **kargs) + do_graph(graph, **kargs) class _ConnectorLogic(object): @@ -286,7 +305,6 @@ class Source(Pipe): Pipe.__init__(self, name=name) self.is_exhausted = False def _read_message(self): - from scapy.automaton import Message return Message() def deliver(self): msg = self._read_message @@ -335,6 +353,8 @@ class AutoSource(Source): self._queue = collections.deque() def fileno(self): return self.__fdr + def checkRecv(self): + return len(self._queue) > 0 def _gen_data(self, msg): self._queue.append((msg,False)) self._wake_up() @@ -474,26 +494,51 @@ class TermSink(Sink): def start(self): if not self.opened: self.opened = True - self.__r,self.__w = os.pipe() - cmd = ["xterm"] - if self.name is not None: - cmd.extend(["-title",self.name]) - if self.keepterm: - cmd.append("-hold") - cmd.extend(["-e", "cat 0<&%i" % self.__r]) - self.__p = subprocess.Popen(cmd) - os.close(self.__r) + if WINDOWS: + self.__f = get_temp_file() + self.name = "Scapy" if self.name is None else self.name + # Start a powershell in a new window and print the PID + cmd = "$app = Start-Process PowerShell -ArgumentList '-command &{$host.ui.RawUI.WindowTitle=\\\"%s\\\";Get-Content \\\"%s\\\" -wait}' -passthru; echo $app.Id" % (self.name, self.__f.replace("\\", "\\\\")) + print([conf.prog.powershell, cmd]) + _p = subprocess.Popen([conf.prog.powershell, cmd], stdout=subprocess.PIPE) + _output, _stderr = _p.communicate() + # This is the process PID + self.__p = int(_output) + print("PID:" + str(self.__p)) + else: + self.__r,self.__w = os.pipe() + cmd = ["xterm"] + if self.name is not None: + cmd.extend(["-title",self.name]) + if self.keepterm: + cmd.append("-hold") + cmd.extend(["-e", "cat 0<&%i" % self.__r]) + self.__p = subprocess.Popen(cmd, shell=True, executable="/bin/bash") + os.close(self.__r) def stop(self): if not self.keepterm: self.opened = False - os.close(self.__w) - self.__p.kill() - self.__p.wait() + if not WINDOWS: + os.close(self.__w) + self.__p.kill() + self.__p.wait() + else: + # Recipe to kill process with PID + # http://code.activestate.com/recipes/347462-terminating-a-subprocess-on-windows/ + import ctypes + PROCESS_TERMINATE = 1 + handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.__p) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + ctypes.windll.kernel32.CloseHandle(handle) def _print(self, s): if self.newlines: s+="\n" - os.write(self.__w, s) - + if WINDOWS: + self.__w = open(self.__f, "a") + self.__w.write(s) + self.__w.close() + else: + os.write(self.__w, s) def push(self, msg): self._print(str(msg)) def high_push(self, msg): @@ -581,7 +626,6 @@ def _testmain(): p.graph(type="png",target="> /tmp/pipe.png") p.start() - print p.threadid time.sleep(5) p.stop() -- GitLab