Instance variables not being updated Python when u

2019-07-22 20:30发布

问题:

I've come across an unusual problem in regards to updating variables. I've built a simple class object to help me with some network sniffing. I wanted to make a parallel process which allows me to run some network tests and capture the traffic generated using python so I can extend the program to do amazing things. I'm using scapy's sniffing function to help with the interface sniffing.

Scapy's sniffer allows you to pass a function into itself function that allows you to create a 'stop sniffing' condition. In my case I've created function stop_filter and I wish to stop the Scapy sniff function by simply updating the self.stop_sniffing instance variable. I've presented the program output below, which shows self.stop_sniffing getting set to True in Function stop, but is then set back to False (or is not updated at all) when printed in stop_filter. I have no clue why this is happening and no solution comes to mind as it's such a weird problem.

If anyone with fresh eyes can see what insane thing I've done here it would be greatly appreciated!

from scapy.all import *
from multiprocessing import Process


class DatasetSniffer:
    def __init__(self, iface, local_dir='.'):
        self.iface = iface
        self.master = None
        self.local_dir = local_dir
        self.stop_sniffing = False # Never updates! why!?
        self.writer = PcapWriter(local_dir+"/master.pcap", append=True, sync=True)

    def stop_filter(self, p):
        # Note: 'p' gets passed in by Scapy function 'sniff'
        print self.stop_sniffing
        # Return 'True' to stop sniffer
        return self.stop_sniffing

    def sniff(self):
        sniff(store=0, prn=self.writer.write, iface=self.iface, stop_filter=self.stop_filter)

    def start(self):
        self.master = Process(target=self.sniff)
        self.master.start()

    def stop(self):
        self.stop_sniffing = True
        # Shows that self.stop_sniffing is 'True'
        print self.stop_sniffing
        self.master.join()


if __name__ == "__main__":
    interface = 'en3'
    sniffer = DatasetSniffer(interface)
    sniffer.start()
    #   some process
    time.sleep(5)
    sniffer.stop()

Shell output:

sudo python sniffing.py
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
True
False
False
False
False

回答1:

The Problem

You are not using multiple threads in this example code you are using multiple processes.

Here you have two separate processes, that do not share memory:

  • the original process
  • a new process, started by multiprocessing.Process.start

    • this process will have been started by forking the original process, creating a copy of its memory at the time of the fork. They do not "share" memory.

Now, when you call DatasetSniffer.stop within your original process, this will not alter the value of stop_sniffing in the new ("master") process.

How to Communicate Then?

When using multiprocessing, you can communicate using a Pipe. Something like this:

readable_pipe, writable_pipe = multiprocessing.Pipe(duplex=False)
process = Process(target=do_something)

Now, our original process can send a message by writing to the pipe:

writable_pipe.send("stop")

while the new process can check for messages using:

if readable_pipe.poll():
    msg = readable_pipe.recv()

Try working this into your code.



回答2:

Thanks for all your suggestions. After a glass of inspiration I managed to knock up this script. Probably a nicer way to approach my problem without making too many changes. So this code allows the threads to use the stop function outside the class, thus allowing all the asynchronous tasks to use the stop_filter.

Found this information in the link below. Hopfully this post will be useful to someone else! http://www.tutorialspoint.com/python/python_multithreading.htm

Cheers!

import threading
from scapy.all import *
from datetime import datetime

directory = str(datetime.now().strftime("%Y%m%d%H%M%S"))
os.makedirs(directory)

DatasetSnifferExit = 0

class DatasetSniffer(threading.Thread):
    def __init__(self, iface, local_dir='.', filename=str(datetime.now())):
        self.iface = iface
        self.filename = filename
        self.local_dir = local_dir
        self.stop_sniffing = False
        self.writer = PcapWriter(local_dir+"/"+filename+".pcap", append=True, sync=True)
        threading.Thread.__init__(self)

    def run(self):
        sniff_interface(self.writer.write, self.iface)


def stop_filter(p):
    if DatasetSnifferExit:
        return True
    else:
        return False


def sniff_interface(write, iface):
    sniff(store=0, prn=write, iface=iface, stop_filter=stop_filter)


if __name__ == "__main__":
    DatasetSnifferExit = False
    # Create new threads
    pcap1 = DatasetSniffer('en3', directory, "master")
    pcap2 = DatasetSniffer('en0', directory, "slave")

    # Start new Threads
    pcap1.start()
    pcap2.start()

    # Do stuff
    time.sleep(10)

    # Finished doing stuff
    DatasetSnifferExit = True