class ICMPHeader(Header, PayloadMixin): header_len = 4 @property def type(self): """ The ICMP message type. """ return i(self.raw[0]) @type.setter def type(self, val): self.raw[0] = i(val) @property def code(self): """ The ICMP message code. """ return i(self.raw[1]) @code.setter def code(self, val): self.raw[1] = i(val) cksum = raw_property('!H', 2, docs='The ICMP header checksum field.')
class UDPHeader(PseudoCksumHeaderMixin, PayloadMixin, PortMixin): header_len = 8 @property def payload(self): return PayloadMixin.payload.fget(self) @payload.setter def payload(self, val): PayloadMixin.payload.fset(self, val) self.payload_len = len(val) if not PY2 and not PY34: payload.__doc__ = PayloadMixin.payload.__doc__ @property def payload_len(self): return struct.unpack_from("!H", self.raw, 4)[0] - 8 @payload_len.setter def payload_len(self, val): self.raw[4:6] = struct.pack("!H", val + 8) cksum = raw_property('!H', 6, docs='The UDP header checksum field.')
class IPv4Header(IPHeader, PseudoCksumHeaderMixin): _src_addr = slice(12, 16) _dst_addr = slice(16, 20) _af = socket.AF_INET @property def header_len(self): """ The IP header length in bytes. """ return self.hdr_len * 4 @property def hdr_len(self): """ The header length in words of 32bit. """ return i(self.raw[0]) & 0x0F @hdr_len.setter def hdr_len(self, val): if val < 5: raise ValueError("IP header length must be greater or equal than 5.") struct.pack_into('!B', self.raw, 0, 0x40 | val) packet_len = raw_property('!H', 2, docs=IPHeader.packet_len.__doc__) tos = raw_property('!B', 1, docs='The Type Of Service field (six-bit DiffServ field and a two-bit ECN field).') ident = raw_property('!H', 4, docs='The Identification field.') reserved = flag_property('reserved', 6, 0b10000000) evil = flag_property('evil', 6, 0b10000000, docs='Just an april\'s fool joke for the RESERVED flag.') df = flag_property('df', 6, 0b01000000) mf = flag_property('mf', 6, 0b00100000) ttl = raw_property('!B', 8, docs='The Time To Live field.') protocol = raw_property('!B', 9, docs='The Protocol field.') cksum = raw_property('!H', 10, docs='The IP header Checksum field.') @property def flags(self): """ The flags field: RESERVED (the evil bit), DF (don't fragment), MF (more fragments). """ return i(self.raw[6]) >> 5 @flags.setter def flags(self, val): struct.pack_into('!B', self.raw, 6, (val << 5) | (self.frag_offset & 0xFF00)) @property def frag_offset(self): """ The Fragment Offset field in blocks of 8 bytes. """ return struct.unpack_from("!H", self.raw, 6)[0] & 0x1FFF @frag_offset.setter def frag_offset(self, val): self.raw[6:8] = struct.pack("!H", (self.flags << 13) | (val & 0x1FFF)) @property def dscp(self): """ The Differentiated Services Code Point field (originally defined as Type of Service) also known as DiffServ. """ return (i(self.raw[1]) >> 2) & 0x3F @dscp.setter def dscp(self, val): struct.pack_into('!B', self.raw, 1, (val << 2) | self.ecn) diff_serv = dscp @property def ecn(self): """ The Explicit Congestion Notification field. """ return i(self.raw[1]) & 0x03 @ecn.setter def ecn(self, val): struct.pack_into('!B', self.raw, 1, (self.dscp << 2) | (val & 0x03))
class IPv6Header(IPHeader): _src_addr = slice(8, 24) _dst_addr = slice(24, 40) _af = socket.AF_INET6 header_len = 40 payload_len = raw_property('!H', 4, docs='The Payload Length field.') next_hdr = raw_property('!B', 6, docs='The Next Header field. Replaces the Protocol field in IPv4.') hop_limit = raw_property('!B', 7, docs='The Hop Limit field. Replaces the TTL field in IPv4.') @property def packet_len(self): return self.payload_len + self.header_len @packet_len.setter def packet_len(self, val): self.payload_len = val - self.header_len @property def traffic_class(self): """ The Traffic Class field (six-bit DiffServ field and a two-bit ECN field). """ return (struct.unpack_from('!H', self.raw, 0)[0] >> 4) & 0x00FF @traffic_class.setter def traffic_class(self, val): struct.pack_into('!H', self.raw, 0, 0x6000 | (val << 4) | (self.flow_label & 0x000F0000)) @property def flow_label(self): """ The Flow Label field. """ return struct.unpack_from('!I', self.raw, 0)[0] & 0x000FFFFF @flow_label.setter def flow_label(self, val): struct.pack_into('!I', self.raw, 0, 0x60000000 | (self.traffic_class << 20) | (val & 0x000FFFFF)) @property def diff_serv(self): """ The DiffServ field. """ return (self.traffic_class & 0xFC) >> 2 @diff_serv.setter def diff_serv(self, val): self.traffic_class = self.ecn | (val << 2) @property def ecn(self): """ The Explicit Congestion Notification field. """ return self.traffic_class & 0x03 @ecn.setter def ecn(self, val): self.traffic_class = (self.diff_serv << 2) | val if not PY2 and not PY34: packet_len.__doc__ = IPHeader.packet_len.__doc__
class TCPHeader(PseudoCksumHeaderMixin, PayloadMixin, PortMixin): ns = flag_property("ns", 12, 0b00000001) cwr = flag_property("cwr", 13, 0b10000000) ece = flag_property("ece", 13, 0b01000000) urg = flag_property("syn", 13, 0b00100000) ack = flag_property("ack", 13, 0b00010000) psh = flag_property("psh", 13, 0b00001000) rst = flag_property("rst", 13, 0b00000100) syn = flag_property("syn", 13, 0b00000010) fin = flag_property("fin", 13, 0b00000001) @property def header_len(self): """ The TCP header length. """ return self.data_offset * 4 seq_num = raw_property('!I', 4, docs='The sequence number field.') ack_num = raw_property('!I', 8, docs='The acknowledgement number field.') window_size = raw_property('!H', 14, docs='The size of the receive window in bytes.') cksum = raw_property('!H', 16, docs='The TCP header checksum field.') urg_ptr = raw_property('!H', 18, docs='The Urgent Pointer field.') @property def data_offset(self): """ The size of TCP header in 32bit words. """ return i(self.raw[12]) >> 4 @data_offset.setter def data_offset(self, val): if val < 5 or val > 15: raise ValueError( "TCP data offset must be greater or equal than 5 and less than 15." ) struct.pack_into('!B', self.raw, 12, (val << 4) | (self.reserved << 1) | self.ns) @property def reserved(self): """ The reserved field. """ return (i(self.raw[12]) >> 1) & 0x07 @reserved.setter def reserved(self, val): struct.pack_into('!B', self.raw, 12, (self.data_offset << 4) | (val << 1) | self.ns) @property def control_bits(self): """ The Control Bits field. """ return struct.unpack_from('!H', self.raw, 12)[0] & 0x01FF @control_bits.setter def control_bits(self, val): struct.pack_into('!H', self.raw, 12, (self.data_offset << 12) | (self.reserved << 9) | (val & 0x01FF))