How to pickle a scapy packet?
I need to pickle a scapy
packet. Most of the time this works, but sometimes the pic开发者_Python百科kler complains about a function object. As a rule of thumb: ARP packets pickle fine. Some UDP packets are problematic.
My solution (as inspired by the scapy mailing list) is as follows:
class PicklablePacket:
"""A container for scapy packets that can be pickled (in contrast
to scapy packets themselves)."""
def __init__(self, pkt):
self.contents = bytes(pkt)
self.time = pkt.time
def __call__(self):
"""Get the original scapy packet."""
pkt = scapy.Ether(self.contents)
pkt.time = self.time
return pkt
Anywhere I wish to pass a scapy
Packet
through a Queue
I simply wrap it in a PicklablePacket
and __call__
it afterwards. I am not aware of data that is not retained this way. However this approach only works with Ethernet
packets. (All packets sniffed on a regular NIC (not WLAN) are Ethernet.) It could probably be extended to work for other types, too.
If by pickle you mean generically serialize you can always use the pcap import/export methods: rdpcap and wrpcap.
wrpcap("pkt.pcap",pkt)
pkt = rdpcap("pkt.pcap")
Or you could start up your process and grab the packets in another process. If there is some pattern you can match, say a known port or source IP tcpdump will work:
tcpdump -i eth0 -w FOO.pcap host 172.20.33.12 and \(udp or arp\)
You can then read the generated pcap in as above:
pkts = rdpcap('FOO.pcap')
(This is more for reference, so no votes expected)
The Scapy list scapy.ml@secdev.org is well-monitored and tends to be very responsive. If you don't get answers here, try there as well.
As inspired by this question one can use the dill library (or others like sPickle etc - see pypi search pickle) to save scapy packets. E.g. Install dill using sudo easy_install dill
or sudo pip install dill
. Here's a basic usage scenario:
import dill as pickle
# E.g. Dump an array of packets stored in variable mypackets to a file
pickle.dump(mypackets, open('mypackets.dill-pickle', 'w'))
# Restore them from the file
mypackets = pickle.load(open('mypackets.dill-pickle', 'rb'))
Also one can of course just use scapy's native functions to dump the packets to a pcap file (readable by tcpdump/wireshark etc) - if one just has an array of packets:
wrpcap("packets_array.pcap",packets_array)
You can monkeypatch the Packet
class and inject __getstate__
and __setstate__
methods that convert the function in the object from and to a picklable representation. See here for details.
def packet_getstate(self):
# todo
def packet_setstate(self, state):
# todo
from scapy.packet import Packet
Packet.__getstate__ = packet_getstate
Packet.__setstate__ = packet_setstate
To get the PicklabePacket class to work with scapy 3.0.0 you can use this class definition:
class PicklablePacket:
"""A container for scapy packets that can be pickled (in contrast
to scapy packets themselves).
This works for python 3.5.1 and scapy 3.0.0 """
def __init__(self, pkt):
self.__contents = pkt.__bytes__()
self.__time = pkt.time
def __call__(self):
"""Get the original scapy packet."""
pkt = scapy.all.Ether(self.__contents)
pkt.time = self.__time
return pkt
精彩评论