diff --git a/ryu/lib/pcaplib.py b/ryu/lib/pcaplib.py new file mode 100644 index 00000000..fed45bb0 --- /dev/null +++ b/ryu/lib/pcaplib.py @@ -0,0 +1,288 @@ +""" +Parsing libpcap and reading/writing PCAP file. +Reference source: http://wiki.wireshark.org/Development/LibpcapFileFormat + + + Libpcap File Format + + +---------------------+ + | | + | Global Header | + | | + +---------------------+ + | Packet Header | + +---------------------+ + | Packet Data | + +---------------------+ + | Packet Header | + +---------------------+ + | Packet Data | + +---------------------+ + | ... + +---------------- ... + + +Sample usage of dump packets: + + from ryu.lib import pcaplib + + class SimpleSwitch13(app_manager.RyuApp): + OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] + + def __init__(self, *args, **kwargs): + super(SimpleSwitch13, self).__init__(*args, **kwargs) + self.mac_to_port = {} + + # Creating an instance with a PCAP filename + self.pcap_pen = Writer(open('mypcap.pcap', 'wb')) + + @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) + def _packet_in_handler(self, ev): + msg = ev.msg + + # Dump the data packet into PCAP file + self.pcap_pen.write_pkt(msg.data) + + pkt = packet.Packet(msg.data) + +Sample usage of reading PCAP files: + + from ryu.lib import pcaplib + from ryu.lib.packet import packet + + frame_count = 0 + # Using the Reader iterator that yields packets in PCAP file + for ts, buf in pcaplib.Reader(open('test.pcap', 'rb')): + frame_count += 1 + pkt = packet.Packet(buf) + + eth = pkt.get_protocols(ethernet.ethernet)[0] + + dst = eth.dst + src = eth.src + # print frames count, timestamp, ethernet src, ethernet dst + # and raw packet. + print frame_count, ts, dst, src, pkt + +""" + +import struct +import sys +import time + + +class PcapFileHdr(object): + """ + Global Header + typedef struct pcap_hdr_s { + guint32 magic_number; /* magic number */ + guint16 version_major; /* major version number */ + guint16 version_minor; /* minor version number */ + gint32 thiszone; /* GMT to local correction */ + guint32 sigfigs; /* accuracy of timestamps */ + guint32 snaplen; /* max length of captured packets, + in octets */ + guint32 network; /* data link type */ + } pcap_hdr_t; + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Magic Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Version Major | Version Minor | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Thiszone | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Sigfigs | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Snaplen | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Network | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + File Format + """ + _FILE_HDR_FMT = None + + def __init__(self, magic='\xd4\xc3\xb2\xa1', version_major=2, + version_minor=4, thiszone=0, sigfigs=0, snaplen=0, + linktype=0): + self.magic = magic + self.version_major = version_major + self.version_minor = version_minor + self.thiszone = thiszone + self.sigfigs = sigfigs + self.snaplen = snaplen + self.linktype = linktype + + @classmethod + def parser(cls, buf): + if buf[:4] == '\xa1\xb2\xc3\xd4': + # Big Endian + cls._FILE_HDR_FMT = '>IHHIIII' + byteorder = '>' + elif buf[:4] == '\xd4\xc3\xb2\xa1': + # Little Endian + cls._FILE_HDR_FMT = 'IHHIIII') + self._f.write(str(p)) + + def _write_pkt_hdr(self, ts, buf_str_len): + sec = int(ts) + if sec == 0: + usec = 0 + else: + usec = int(ts * 1e6) % int(ts) + + if sys.byteorder == 'little': + # usec = int(ts * 1e6) % int(ts) + # old_usec = int((float(ts) - int(ts)) * 1e6) + pc_pkt_hdr = PcapPktHdr(ts_sec=sec, + ts_usec=usec, + incl_len=buf_str_len, + orig_len=buf_str_len) + p = pc_pkt_hdr.serialize(fmt='IIII') + self._f.write(str(p)) + + def write_pkt(self, buf, ts=None): + if ts is None: + ts = time.time() + + buf_str = str(buf) + buf_str_len = len(buf_str) + self._write_pkt_hdr(ts, buf_str_len) + self._f.write(buf_str) + + def __del__(self): + self._f.close()