# git+https://github.com/secdev/scapy.git import fcntl import os import struct import sys from scapy.all import * from scapy.arch.bpf.consts import BIOCGBLEN, BIOCGDLT, BIOCSDLT, BIOCSETIF, BIOCIMMEDIATE from ctypes import Structure, c_char, c_long, c_int, c_uint, c_ushort, c_uint16, c_uint32, sizeof class ReprStructureMixin: def format_field(self, k): try: bits = getattr(self, '_bits_%s' % k) return str(makebits(getattr(self, k), bits)) except AttributeError: return repr(getattr(self, k)) def __repr__(self): args = tuple(self.format_field(x[0]) for x in self._fields_) return '%s(%s)' % (self.__class__.__name__, ', '.join(args)) class Timeval(Structure, ReprStructureMixin): _fields_ = [ ('tv_sec', c_long), ('tv_usec', c_long), ] class bpf_hdr(Structure, ReprStructureMixin): _fields_ = [ ('bh_tstamp', Timeval), ('bh_caplen', c_uint32), ('bh_datalen', c_uint32), ('bh_hdrlen', c_ushort), ] pkthdrbits = { 1: 'CSUM', 2: 'VLAN_TAG', 4: 'TSTMP' } # awk '{ print $3 ": '"'"'" $2 "'"'"'," }' csumflagbits = { 0x00000001: 'CSUM_IP', 0x00000002: 'CSUM_IP_UDP', 0x00000004: 'CSUM_IP_TCP', 0x00000008: 'CSUM_IP_SCTP', 0x00000010: 'CSUM_IP_TSO', 0x00000020: 'CSUM_IP_ISCSI', 0x00000040: 'CSUM_INNER_IP6_UDP', 0x00000080: 'CSUM_INNER_IP6_TCP', 0x00000100: 'CSUM_INNER_IP6_TSO', 0x00000200: 'CSUM_IP6_UDP', 0x00000400: 'CSUM_IP6_TCP', 0x00000800: 'CSUM_IP6_SCTP', 0x00001000: 'CSUM_IP6_TSO', 0x00002000: 'CSUM_IP6_ISCSI', 0x00004000: 'CSUM_INNER_IP', 0x00008000: 'CSUM_INNER_IP_UDP', 0x00010000: 'CSUM_INNER_IP_TCP', 0x00020000: 'CSUM_INNER_IP_TSO', 0x00040000: 'CSUM_ENCAP_VXLAN', 0x00080000: 'CSUM_ENCAP_RSVD1', 0x00100000: 'CSUM_INNER_L3_CALC', 0x00200000: 'CSUM_INNER_L3_VALID', 0x00400000: 'CSUM_INNER_L4_CALC', 0x00800000: 'CSUM_INNER_L4_VALID', 0x01000000: 'CSUM_L3_CALC', 0x02000000: 'CSUM_L3_VALID', 0x04000000: 'CSUM_L4_CALC', 0x08000000: 'CSUM_L4_VALID', 0x10000000: 'CSUM_L5_CALC', 0x20000000: 'CSUM_L5_VALID', 0x40000000: 'CSUM_COALESCED', 0x80000000: 'CSUM_SND_TAG', } class fbsdpkthdr(Structure, ReprStructureMixin): _bits_fph_bits = pkthdrbits _bits_fph_csum_flags = csumflagbits _fields_ = [ ('fph_magic', c_char * 4), ('fph_hdrlen', c_uint32), ('fph_recvif', c_char * 16), ('fph_bits', c_uint32), ('fph_flowid', c_uint32), ('fph_csum_flags', c_uint32), ('fph_csum_data', c_uint32), ('fph_vlan_tag', c_uint16), ] class BPF: def __init__(self, iface): f = self._fp = os.open('/dev/bpf', os.O_RDONLY) l = fcntl.ioctl(f, BIOCGBLEN, b'\x00'*4, True) sz = c_int.from_buffer_copy(l) self._blen = sz.value fcntl.ioctl(f, BIOCIMMEDIATE, struct.pack('I', 1)) fcntl.ioctl(f, BIOCSETIF, struct.pack('16s16x', iface.encode())) fcntl.ioctl(f, BIOCSDLT, struct.pack('I', 154)) def getpkt(self): bytes = os.read(self._fp, self._blen) bpfhdr = bpf_hdr.from_buffer_copy(bytes) off = bpfhdr.bh_hdrlen fbsdhdr = fbsdpkthdr.from_buffer_copy(bytes, off) off += fbsdhdr.fph_hdrlen pkt = bytes[off:] return fbsdhdr, pkt def makebits(val, bits): r = [ v for k, v in bits.items() if k & val ] if not r: return 0 return '|'.join(r) if __name__ == '__main__': bpf = BPF(sys.argv[1]) while True: hdr, pkt = bpf.getpkt() print(repr(hdr)) #pkthdr = struct.unpack(fbsdpkthdr, pkt[hdrlen:hdrlen + fbsdpkthdrlen]) #pkthdr = list(pkthdr) #pkthdr[2] = pkthdr[2].strip(b'\x00').decode('us-ascii') #print(repr(pkthdr), fbsdpkthdrlen) if hdr.fph_magic != b'FBSD': print('magic wrong') continue # XXX calcsize is wrong here if sizeof(hdr) != hdr.fph_hdrlen: print('length mismatch') continue print(repr(Ether(pkt))[:300])