def parse(self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg( '(arp parse) warning IP packet data too short to parse header: data len %u' % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) =\ struct.unpack('!HHBBH', raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg('(arp parse) hw type unknown %u' % self.hwtype) return if self.hwlen != 6: self.msg('(arp parse) unknown hw len %u' % self.hwlen) return else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg('(arp parse) proto type unknown %u' % self.prototype) return if self.protolen != 4: self.msg('(arp parse) unknown proto len %u' % self.protolen) return else: self.protosrc = IPAddr(struct.unpack('!I', raw[14:18])[0]) self.protodst = IPAddr(struct.unpack('!I', raw[24:28])[0]) self.next = raw[28:] self.parsed = True
def parse (self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg('(arp parse) warning IP packet data too short to parse header: data len %u' % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) =\ struct.unpack('!HHBBH', raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg('(arp parse) hw type unknown %u' % self.hwtype) return if self.hwlen != 6: self.msg('(arp parse) unknown hw len %u' % self.hwlen) return else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg('(arp parse) proto type unknown %u' % self.prototype) return if self.protolen != 4: self.msg('(arp parse) unknown proto len %u' % self.protolen) return else: self.protosrc = IPAddr(struct.unpack('!I',raw[14:18])[0]) self.protodst = IPAddr(struct.unpack('!I',raw[24:28])[0]) self.next = raw[28:] self.parsed = True
def _to_str(self): op = str(self.opcode) eth_type = None # Ethernet if hasattr(self.prev, 'type'): eth_type = self.prev.type # Vlan elif hasattr(self.prev, 'eth_type'): eth_type = self.prev.eth_type else: self.err('(arp) unknown datalink type') eth_type = ethernet.ARP_TYPE if eth_type == ethernet.ARP_TYPE: if self.opcode == arp.REQUEST: op = "REQUEST" elif self.opcode == arp.REPLY: op = "REPLY" elif eth_type == ethernet.RARP_TYPE: if self.opcode == arp.REV_REQUEST: op = "REV_REQUEST" elif self.opcode == arp.REV_REPLY: op = "REV_REPLY" s = "[ARP {0} hw:{1} p:{2} {3}>{4} {5}>{6}]".format( op, self.hwtype, self.prototype, EthAddr(self.hwsrc), EthAddr(self.hwdst), IPAddr(self.protosrc), IPAddr(self.protodst)) return s
def __str__(self): if self.subtype == chassis_id.SUB_MAC: assert len(self.id) == 6 id_str = str(EthAddr(self.id)) else: id_str = ":".join(["%02x" % (ord(x), ) for x in self.id]) return ''.join(['<port ID:', id_str, '>'])
class arp (packet_base): "ARP/RARP packet struct" MIN_LEN = 28 HW_TYPE_ETHERNET = 1 PROTO_TYPE_IP = 0x0800 # OPCODES REQUEST = 1 # ARP REPLY = 2 # ARP REV_REQUEST = 3 # RARP REV_REPLY = 4 # RARP def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.hwtype = arp.HW_TYPE_ETHERNET self.prototype = arp.PROTO_TYPE_IP self.hwsrc = ETHER_ANY self.hwdst = ETHER_ANY self.hwlen = 6 self.opcode = 0 self.protolen = 4 self.protosrc = IP_ANY self.protodst = IP_ANY self.next = b'' if raw is not None: self.parse(raw) self._init(kw) def parse (self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg('(arp parse) warning IP packet data too short to parse header: data len %u' % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) =\ struct.unpack('!HHBBH', raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg('(arp parse) hw type unknown %u' % self.hwtype) return if self.hwlen != 6: self.msg('(arp parse) unknown hw len %u' % self.hwlen) return else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg('(arp parse) proto type unknown %u' % self.prototype) return if self.protolen != 4: self.msg('(arp parse) unknown proto len %u' % self.protolen) return else: self.protosrc = IPAddr(struct.unpack('!I',raw[14:18])[0]) self.protodst = IPAddr(struct.unpack('!I',raw[24:28])[0]) self.next = raw[28:] self.parsed = True def hdr(self, payload): buf = struct.pack('!HHBBH', self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) if type(self.hwsrc) == bytes: buf += self.hwsrc else: buf += self.hwsrc.toRaw() if type(self.protosrc) is IPAddr: buf += struct.pack('!I',self.protosrc.toUnsigned()) else: buf += struct.pack('!I',self.protosrc) if type(self.hwdst) == bytes: buf += self.hwdst else: buf += self.hwdst.toRaw() if type(self.protodst) is IPAddr: buf += struct.pack('!I',self.protodst.toUnsigned()) else: buf += struct.pack('!I',self.protodst) return buf def _to_str(self): op = str(self.opcode) eth_type = None # Ethernet if hasattr(self.prev, 'type'): eth_type = self.prev.type # Vlan elif hasattr(self.prev, 'eth_type'): eth_type = self.prev.eth_type else: self.err('(arp) unknown datalink type') eth_type = ethernet.ARP_TYPE if eth_type == ethernet.ARP_TYPE: if self.opcode == arp.REQUEST: op = "REQUEST" elif self.opcode == arp.REPLY: op = "REPLY" elif eth_type == ethernet.RARP_TYPE: if self.opcode == arp.REV_REQUEST: op = "REV_REQUEST" elif self.opcode == arp.REV_REPLY: op = "REV_REPLY" s = "[ARP {0} hw:{1} p:{2} {3}>{4} {5}>{6}]".format(op, self.hwtype, self.prototype, EthAddr(self.hwsrc), EthAddr(self.hwdst), IPAddr(self.protosrc), IPAddr(self.protodst)) return s
def _unpack_new (cls, raw, offset, t, length, prev): return offset+length,cls(address = EthAddr(raw[offset:offset+length]), prev=prev)
def _init (self, *args, **kw): a = kw.pop('address',None) if a is None: self.address = None else: self.address = EthAddr(a)
class arp(packet_base): "ARP/RARP packet struct" MIN_LEN = 28 HW_TYPE_ETHERNET = 1 PROTO_TYPE_IP = 0x0800 # OPCODES REQUEST = 1 # ARP REPLY = 2 # ARP REV_REQUEST = 3 # RARP REV_REPLY = 4 # RARP def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.hwtype = arp.HW_TYPE_ETHERNET self.prototype = arp.PROTO_TYPE_IP self.hwsrc = ETHER_ANY self.hwdst = ETHER_ANY self.hwlen = 6 self.opcode = 0 self.protolen = 4 self.protosrc = IP_ANY self.protodst = IP_ANY self.next = b'' if raw is not None: self.parse(raw) self._init(kw) def parse(self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg( '(arp parse) warning IP packet data too short to parse header: data len %u' % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) =\ struct.unpack('!HHBBH', raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg('(arp parse) hw type unknown %u' % self.hwtype) return if self.hwlen != 6: self.msg('(arp parse) unknown hw len %u' % self.hwlen) return else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg('(arp parse) proto type unknown %u' % self.prototype) return if self.protolen != 4: self.msg('(arp parse) unknown proto len %u' % self.protolen) return else: self.protosrc = IPAddr(struct.unpack('!I', raw[14:18])[0]) self.protodst = IPAddr(struct.unpack('!I', raw[24:28])[0]) self.next = raw[28:] self.parsed = True def hdr(self, payload): buf = struct.pack('!HHBBH', self.hwtype, self.prototype, self.hwlen, self.protolen, self.opcode) if type(self.hwsrc) == bytes: buf += self.hwsrc else: buf += self.hwsrc.toRaw() if type(self.protosrc) is IPAddr: buf += struct.pack('!I', self.protosrc.toUnsigned()) else: buf += struct.pack('!I', self.protosrc) if type(self.hwdst) == bytes: buf += self.hwdst else: buf += self.hwdst.toRaw() if type(self.protodst) is IPAddr: buf += struct.pack('!I', self.protodst.toUnsigned()) else: buf += struct.pack('!I', self.protodst) return buf def _to_str(self): op = str(self.opcode) eth_type = None # Ethernet if hasattr(self.prev, 'type'): eth_type = self.prev.type # Vlan elif hasattr(self.prev, 'eth_type'): eth_type = self.prev.eth_type else: self.err('(arp) unknown datalink type') eth_type = ethernet.ARP_TYPE if eth_type == ethernet.ARP_TYPE: if self.opcode == arp.REQUEST: op = "REQUEST" elif self.opcode == arp.REPLY: op = "REPLY" elif eth_type == ethernet.RARP_TYPE: if self.opcode == arp.REV_REQUEST: op = "REV_REQUEST" elif self.opcode == arp.REV_REPLY: op = "REV_REPLY" s = "[ARP {0} hw:{1} p:{2} {3}>{4} {5}>{6}]".format( op, self.hwtype, self.prototype, EthAddr(self.hwsrc), EthAddr(self.hwdst), IPAddr(self.protosrc), IPAddr(self.protodst)) return s
class dns(packet_base): "DNS Packet struct" MDNS_ADDRESS = IPAddr('224.0.0.251') MDNS6_ADDRESS = IPAddr6('ff02::fb') MDNS_ETH = EthAddr('01:00:5E:00:00:fb') MDNS6_ETH = EthAddr('33:33:00:00:00:fb') SERVER_PORT = 53 MDNS_PORT = 5353 MIN_LEN = 12 def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.questions = [] self.answers = [] self.authorities = [] self.additional = [] self.id = 0 self.qr = False # Is Query self.opcode = 0 self.aa = False # Authoritative Answer self.tc = False # Truncated self.rd = False # Recursion Desired self.ra = False # Recursion Available self.z = False self.ad = False self.cd = False self.rcode = 0 # TODO: everything else here if raw is not None: self.parse(raw) self._init(kw) def _exc (self, e, part = None): """ Turn exception into log message """ msg = "(dns)" if part is not None: msg += " " + part msg += ": " msg += str(e) if isinstance(e, Trunc): self.msg(msg) else: self.err(msg) def hdr (self, payload): bits0 = 0 if self.qr: bits0 |= 0x80 bits0 |= (self.opcode & 0x7) << 4 if self.rd: bits0 |= 1 if self.tc: bits0 |= 2 if self.aa: bits0 |= 4 bits1 = 0 if self.ra: bits1 |= 0x80 if self.z: bits1 |= 0x40 if self.ad: bits1 |= 0x20 if self.cd: bits1 |= 0x10 bits1 |= (self.rcode & 0xf) s = struct.pack("!HBBHHHH", self.id, bits0, bits1, len(self.questions), len(self.answers), len(self.authorities), len(self.additional)) def makeName (labels, term): o = '' #TODO: unicode for l in labels.split('.'): o += chr(len(l)) o += l if term: o += '\x00' return o name_map = {} def putName (s, name): pre = '' post = name while True: at = s.find(makeName(post, True)) if at == -1: if post in name_map: at = name_map[post] if at == -1: post = post.split('.', 1) if pre: pre += '.' pre += post[0] if len(post) == 1: if len(pre) == 0: s += '\x00' else: name_map[name] = len(s) s += makeName(pre, True) break post = post[1] else: if len(pre) > 0: name_map[name] = len(s) s += makeName(pre, False) s += struct.pack("!H", at | 0xc000) break return s def putData (s, r): if r.qtype in (2,12,5,15): # NS, PTR, CNAME, MX return putName(s, r.rddata) elif r.qtype == 1: # A assert isinstance(r.rddata, IPAddr) return s + r.rddata.raw elif r.qtype == 28: # AAAA assert isinstance(r.rddata, IPAddr6) return s + r.rddata.raw else: return s + r.rddata for r in self.questions: s = putName(s, r.name) s += struct.pack("!HH", r.qtype, r.qclass) rest = self.answers + self.authorities + self.additional for r in rest: s = putName(s, r.name) s += struct.pack("!HHIH", r.qtype, r.qclass, r.ttl, 0) fixup = len(s) - 2 s = putData(s, r) fixlen = len(s) - fixup - 2 s = s[:fixup] + struct.pack('!H', fixlen) + s[fixup+2:] return s def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < dns.MIN_LEN: self.msg('(dns) packet data too short to ' + 'parse header: data len %u' % (dlen,)) return None bits0 = 0 bits1 = 0 total_questions = 0 total_answers = 0 total_auth_rr = 0 total_add_rr = 0 (self.id, bits0,bits1, total_questions, total_answers, total_auth_rr, total_add_rr)\ = struct.unpack('!HBBHHHH', raw[:12]) self.qr = True if (bits0 & 0x80) else False self.opcode = (bits0 >> 4) & (0x07) self.aa = True if (bits0 & (0x04)) else False self.tc = True if (bits0 & (0x02)) else False self.rd = True if (bits0 & (0x01)) else False self.ra = True if (bits1 & 0x80) else False self.z = True if (bits1 & 0x40) else False self.ad = True if (bits1 & 0x20) else False self.cd = True if (bits1 & 0x10) else False self.rcode = bits1 & 0x0f query_head = 12 # questions for i in range(0,total_questions): try: query_head = self.next_question(raw, query_head) except Exception, e: self._exc(e, 'parsing questions') return None # answers for i in range(0,total_answers): try: query_head = self.next_rr(raw, query_head, self.answers) except Exception, e: self._exc(e, 'parsing answers') return None