from collections import namedtuple, OrderedDict
import pandas as pd
import pcapy
from .packet import IPPacket
base_columns = ['time', 'src_host', 'src_port', 'dst_host', 'dst_port', 'protocol']
BasePacket = namedtuple('BasePacket', base_columns)
FullPacket = namedtuple('FullPacket', base_columns + ['payload'])
[docs]class PacketStream(object):
def __init__(self, reader, protocol, payload):
self._reader = reader
self._payload = payload
self.set_filter(protocol)
@property
def dtype(self):
items = [
('time', 'datetime64[ns]'),
('src_host', 'object'),
('src_port', 'u4'),
('dst_host', 'object'),
('dst_port', 'u4'),
('protocol', 'str')]
if self._payload:
items.append(('payload', 'object'))
return OrderedDict(items)
[docs] def set_filter(self, protocol):
"""
Filters all IP traffic except packets matching given protocol.
Parameters:
protocol : str
Show only traffic for given IP protocol.
Allowed values are icmp, icmp6, igmp, igrp, pim, ah,
esp, vrrp, udp, and tcp. If None, all traffic is shown.
"""
if protocol:
self._bpf = "ip proto \{0} || (vlan && ip proto \{0})".format(protocol)
else:
self._bpf = "ip || (vlan && ip)"
def to_dataframe(self, n=-1):
packets = []
def decode_ip_packet(header, data):
seconds, fractional = header.getts() # fractional is in microseconds
ts = seconds * 10**9 + fractional * 10**3 # convert to nanoseconds
packet = IPPacket(data)
if self._payload:
return FullPacket(ts,
packet.source_ip_address,
packet.source_ip_port,
packet.destination_ip_address,
packet.destination_ip_port,
packet.ip_protocol,
data[packet.header_size:])
return BasePacket(ts,
packet.source_ip_address,
packet.source_ip_port,
packet.destination_ip_address,
packet.destination_ip_port,
packet.ip_protocol)
def decoder(header, data):
packets.append(decode_ip_packet(header, data))
self._reader.setfilter(self._bpf)
self._reader.loop(n, decoder)
columns = FullPacket._fields if self._payload else BasePacket._fields
df = pd.DataFrame(packets, columns=columns)
return df.astype(dtype=self.dtype)
[docs]class LiveStream(PacketStream):
def __init__(self, interface, protocol=None, payload=False, max_packet=2**16, timeout=1000):
"""
Parameters:
interface : str
Network interface from which to capture packets.
protocol : str
Exclude all other IP traffic except packets matching this
protocol. If None, all traffic is shown.
payload : bool
Toggle whether to include packet data.
max_packet : int
Maximum allowed packet size.
timeout: int
Maximum time to wait for packets from interface.
"""
reader = pcapy.open_live(interface, max_packet, 1, timeout)
super(LiveStream, self).__init__(reader, protocol, payload)
[docs]class OfflineStream(PacketStream):
def __init__(self, path, protocol=None, payload=False):
"""
Parameters:
path : str
Absolute path to source file.
protocol : str
Exclude all other IP traffic except packets matching this
protocol. If None, all traffic is shown.
payload : bool
Toggle whether to include packet data.
"""
reader = pcapy.open_offline(path)
super(OfflineStream, self).__init__(reader, protocol, payload)