예제 #1
0
파일: ethernet.py 프로젝트: wau/pypacker
class Dot1Q(pypacker.Packet):
    __hdr__ = (
        ("type", "H", ETH_TYPE_8021Q),
        ("tci", "H", 0
         )  # tag control information PCP(3 bits),CFI(1 bit), VID(12 bits)
    )

    def __get_prio(self):
        return (self.tci & 0xE000) >> 13

    def __set_prio(self, value):
        self.tci = (self.tci & ~0xE000) | (value << 13)

    prio = property(__get_prio, __set_prio)

    def __get_cfi(self):
        return (self.tci & 0x1000) >> 12

    def __set_cfi(self, value):
        self.tci = (self.tci & ~0x1000) | (value << 12)

    cfi = property(__get_cfi, __set_cfi)

    def __get_vid(self):
        return self.tci & 0x0FFF

    def __set_vid(self, value):
        self.tci = self.tci & 0xF000 | value

    vid = property(__get_vid, __set_vid)

    type_t = pypacker.get_property_translator("type", "ETH_TYPE_")
예제 #2
0
파일: tcp.py 프로젝트: wau/pypacker
class TCPOptMulti(pypacker.Packet):
	"""
	len = total length (header + data)
	"""
	__hdr__ = (
		("type", "B", 0),
		("len", "B", 2, FIELD_FLAG_AUTOUPDATE)
	)

	type_t = pypacker.get_property_translator("type", "TCP_OPT_")

	def _update_fields(self):
		if self.len_au_active:
			self.len = len(self)
예제 #3
0
class IP(pypacker.Packet):
	__hdr__ = (
		("v_hl", "B", 69, FIELD_FLAG_AUTOUPDATE),  # = 0x45
		("tos", "B", 0),
		("len", "H", 20, FIELD_FLAG_AUTOUPDATE),
		("id", "H", 0),
		("frag_off", "H", 0),
		("ttl", "B", 64),
		("p", "B", IP_PROTO_TCP, FIELD_FLAG_IS_TYPEFIELD),
		("sum", "H", 0, FIELD_FLAG_AUTOUPDATE),
		("src", "4s", b"\x00" * 4),
		("dst", "4s", b"\x00" * 4),
		("opts", None, triggerlist.TriggerList)
	)

	__handler__ = {
		IP_PROTO_ICMP: icmp.ICMP,
		IP_PROTO_IGMP: igmp.IGMP,
		IP_PROTO_TCP: tcp.TCP,
		IP_PROTO_UDP: udp.UDP,
		IP_PROTO_IP6: ip6.IP6,
		IP_PROTO_ESP: esp.ESP,
		IP_PROTO_PIM: pim.PIM,
		IP_PROTO_IPXIP: ipx.IPX,
		IP_PROTO_SCTP: sctp.SCTP,
		IP_PROTO_OSPF: ospf.OSPF
	}

	UPDATE_DEPENDANTS = {tcp.TCP, udp.UDP}

	def __get_v(self):
		return self.v_hl >> 4

	def __set_v(self, value):
		self.v_hl = (value << 4) | (self.v_hl & 0xF)
	# version
	v = property(__get_v, __set_v)

	def __get_hl(self):
		return self.v_hl & 0x0F

	def __set_hl(self, value):
		self.v_hl = (self.v_hl & 0xF0) | value
	# header length
	hl = property(__get_hl, __set_hl)

	def __get_flags(self):
		return (self.frag_off & 0xE000) >> 13

	def __set_flags(self, value):
		self.frag_off = (self.frag_off & ~0xE000) | (value << 13)
	flags = property(__get_flags, __set_flags)

	def __get_offset(self):
		return self.frag_off & ~0xE000

	def __set_offset(self, value):
		self.frag_off = (self.frag_off & 0xE000) | value
	offset = property(__get_offset, __set_offset)

	def create_fragments(self, fragment_len=1480):
		"""
		Create fragment packets from this IP packet with max fragment_len bytes each.
		This will set the flags and offset values accordingly (see header field off).

		fragment_len -- max length of a fragment (IP header + payload)
		return -- fragment IP packets created from this packet
		"""
		if fragment_len % 8 != 0:
			raise Exception("fragment_len not multipe of 8 bytes: %r" % fragment_len)

		fragments = []
		length_ip_total = len(self.bin())
		payload = self.body_bytes
		length_ip_header = length_ip_total - len(payload)
		length_payload = length_ip_total - length_ip_header

		off = 0

		while off < length_payload:
			payload_sub = payload[off: off + fragment_len]

			ip_frag = IP(id=self.id, p=self.p, src=self.src, dst=self.dst)

			if length_payload - off > fragment_len:
				# more fragments follow
				ip_frag.flags = 0x1
			else:
				# last fragment
				ip_frag.flags = 0x0

			ip_frag.offset = int(off / 8)
			ip_frag.body_bytes = payload_sub
			fragments.append(ip_frag)
			off += fragment_len

		return fragments

	# Convenient access for: src[_s], dst[_s]
	src_s = pypacker.get_property_ip4("src")
	dst_s = pypacker.get_property_ip4("dst")
	p_t = pypacker.get_property_translator("p", "IP_PROTO_")

	def _dissect(self, buf):
		total_header_length = ((buf[0] & 0xF) << 2)
		options_length = total_header_length - 20  # total IHL - standard IP-len = options length

		if options_length > 0:
			# logger.debug("got some IP options: %s" % tl_opts)
			self._init_triggerlist("opts", buf[20: 20 + options_length], self._parse_opts)
		elif options_length < 0:
			# invalid header length: assume no options at all
			raise Exception()
		# TODO: extract real data length:
		# There are some cases where padding can not be identified on ethernet -> do it here (eg VSS shit trailer)
		self._init_handler(buf[9], buf[total_header_length:])
		return total_header_length

	__IP_OPT_SINGLE = {IP_OPT_EOOL, IP_OPT_NOP}

	@staticmethod
	def _parse_opts(buf):
		"""Parse IP options and return them as list."""
		optlist = []
		i = 0
		p = None

		while i < len(buf):
			# logger.debug("got IP-option type %s" % buf[i])
			if buf[i] in IP.__IP_OPT_SINGLE:
				p = IPOptSingle(type=buf[i])
				i += 1
			else:
				olen = buf[i + 1]
				# logger.debug("IPOptMulti")
				p = IPOptMulti(type=buf[i], len=olen, body_bytes=buf[i + 2: i + olen])
				# logger.debug("body bytes: %s" % buf[i + 2: i + olen])
				i += olen		# typefield + lenfield + data-len
				# logger.debug("IPOptMulti 2")
			optlist.append(p)
		return optlist

	def _update_fields(self):
		self._update_higherlayer_id()

		if self.len_au_active:
			self.len = len(self)
		if self.v_hl_au_active:
			# Update header length. NOTE: needs to be a multiple of 4 Bytes.
			# logger.debug("updating: %r" % self._packet)
				# options length need to be multiple of 4 Bytes
			self.hl = int(self.header_len / 4) & 0xF
		if self.sum_au_active:
			# length changed so we have to recalculate checksum
			# logger.debug(">>> IP: calculating sum, current: %0X" % self.sum)
			# reset checksum for recalculation,  mark as changed / clear cache
			self.sum = 0
			# logger.debug(">>> IP: bytes for sum: %s" % self.header_bytes)
			self.sum = in_cksum(self._pack_header())
			# logger.debug("IP: new hl: %d / %d" % (self._packet.hdr_len, hdr_len_off))
			# logger.debug("new sum: %0X" % self.sum)

	def direction(self, other):
		# logger.debug("checking direction: %s<->%s" % (self, next))
		direction = 0
		if self.src == other.src and self.dst == other.dst:
			direction |= pypacker.Packet.DIR_SAME
		if self.src == other.dst and self.dst == other.src:
			direction |= pypacker.Packet.DIR_REV
		if direction == 0:
			direction = pypacker.Packet.DIR_UNKNOWN
		return direction

	def reverse_address(self):
		self.src, self.dst = self.dst, self.src
예제 #4
0
파일: ethernet.py 프로젝트: wau/pypacker
class Ethernet(pypacker.Packet):
    __hdr__ = [("dst", "6s", b"\xff" * 6), ("src", "6s", b"\xff" * 6),
               ("vlan", None, triggerlist.TriggerList),
               ("type", "H", ETH_TYPE_IP, FIELD_FLAG_IS_TYPEFIELD)]

    dst_s = pypacker.get_property_mac("dst")
    src_s = pypacker.get_property_mac("src")
    type_t = pypacker.get_property_translator("type", "ETH_TYPE_")

    __handler__ = {
        ETH_TYPE_IP: ip.IP,
        ETH_TYPE_ARP: arp.ARP,
        ETH_TYPE_DTP: dtp.DTP,
        ETH_TYPE_IPX: ipx.IPX,
        ETH_TYPE_IP6: ip6.IP6,
        ETH_TYPE_PPOE_DISC: pppoe.PPPoE,
        ETH_TYPE_PPOE_SESS: pppoe.PPPoE,
        ETH_TYPE_PTPv2: ptpv2.PTPv2,
        ETH_TYPE_EFC: flow_control.FlowControl,
        ETH_TYPE_LLDP: lldp.LLDP,
        ETH_TYPE_SP: lacp.LACP,
        ETH_TYPE_SLAC: slac.Slac
    }

    def _dissect(self, buf):
        hlen = 14
        # Ethernet formats:
        # RFC 894 (Ethernet II) -> type = -> value >1500
        # 802.[2,3] (LLC format) -> type = length field -> value <=1500, not supported
        eth_type = unpack_H(buf[hlen - 2:hlen])[0]

        # any VLAN tag present? in this case: type field is actually a vlan tag
        if eth_type in VLAN_TAG_START:
            # TODO: use _init_triggerlist()
            if eth_type == ETH_TYPE_8021Q:
                # logger.debug(">>> got vlan tag")
                vlan_tag = Dot1Q(buf[12:16])
                self.vlan.append(vlan_tag)
                hlen += 4
                # get real higher layer type
                eth_type = unpack_H(buf[16:18])[0]
            # 802.1ad: support up to 2 tags (double tagging aka QinQ)
            else:
                # logger.debug(">>> got vlan tag")
                vlan_tag1 = Dot1Q(buf[12:16])
                vlan_tag2 = Dot1Q(buf[16:20])
                self.vlan.extend([vlan_tag1, vlan_tag2])
                hlen += 8
                # get real higher layer type
                eth_type = unpack_H(buf[20:22])[0]

        # logger.debug("eth type is: %d" % eth_type)

        # handle ethernet-padding: remove it but save for later use
        # don't use headers for this because this is a rare situation
        dlen = len(buf) - hlen  # data length [+ padding?]

        # assume padding only present if len(higher_layer.bin()) <= 46
        if dlen <= 46:
            try:
                # this will only work on complete headers: Ethernet + IP + ...
                # handle padding using IPv4, IPv6 etc (min size "eth + ..." = 60 bytes)
                # logger.debug(">>> checking for padding")
                if eth_type == ETH_TYPE_IP:
                    dlen_ip = unpack_H(buf[hlen + 2:hlen +
                                           4])[0]  # real data length

                    if dlen_ip < dlen:
                        # padding found
                        self._padding = buf[hlen + dlen_ip:]
                        # logger.debug("got padding for IPv4: %r" % self._padding)
                        dlen = dlen_ip
                # handle padding using IPv6
                # IPv6 is a piece of sh$§! payloadlength (in header) = exclusive standard header
                # but INCLUSIVE options!
                elif eth_type == ETH_TYPE_IP6:
                    dlen_ip = unpack_H(buf[hlen + 4:hlen +
                                           6])[0]  # real data length
                    # logger.debug("eth.hlen=%d, data length based on header: %d" % (hlen, dlen_ip))

                    if 40 + dlen_ip < dlen:
                        # padding found
                        self._padding = buf[hlen + 40 + dlen_ip:]
                        # logger.debug("got padding for IPv6: %r" % self._padding)
                        dlen = 40 + dlen_ip
                elif eth_type == ETH_TYPE_LLDP:
                    # this is a bit redundant as we re-parse TLV when accessing the LLDP layer
                    dlen_lldp, _ = lldp.count_and_dissect_tlvs(buf[hlen:])
                    self._padding = buf[hlen + dlen_lldp:]
                    dlen = dlen_lldp
                elif eth_type == ETH_TYPE_SP:
                    lacppdu_len = 110
                    self._padding = buf[hlen + lacppdu_len:]
                    dlen = lacppdu_len
            except:
                # Could not extract padding info, assuming incomplete ethernet frame.
                # Init of handler will take place after all.
                pass
        # logger.debug("len(buf)=%d, len(higher)=%d" % (len(buf), dlen))
        self._init_handler(eth_type, buf[hlen:hlen + dlen])
        return hlen

    def _update_fields(self):
        self._update_higherlayer_id()

    def bin(self, update_auto_fields=True):
        # padding needs to be placed at the very end
        return pypacker.Packet.bin(
            self, update_auto_fields=update_auto_fields) + self.padding

    def __len__(self):
        return super().__len__() + len(self.padding)

    def direction(self, other):
        # logger.debug("checking direction: %s<->%s" % (self, other))
        if self.dst == other.dst and self.src == other.src:
            # consider packet to itself: can be DIR_REV
            return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV
        if (self.dst == other.src and self.src == other.dst) or\
         (self.dst == b"\xff\xff\xff\xff\xff\xff" and other.dst == self.src):  # broadcast
            return pypacker.Packet.DIR_REV
        return pypacker.Packet.DIR_UNKNOWN

    padding = pypacker.get_ondemand_property("padding", lambda: b"")

    def reverse_address(self):
        self.dst, self.src = self.src, self.dst
예제 #5
0
class IP6(pypacker.Packet):
    __hdr__ = (
        ("v_fc_flow", "I", 0x60000000),
        ("dlen", "H", 0, FIELD_FLAG_AUTOUPDATE
         ),  # length of extension header (opts header) + body
        # body handler type OR type of first extension hedader (opts header)
        ("nxt", "B", 0),
        ("hlim", "B", 0),  # hop limit
        ("src", "16s", b"\x00" * 16),
        ("dst", "16s", b"\x00" * 16),
        ("opts", None, triggerlist.TriggerList))

    def __get_v(self):
        return self.v_fc_flow >> 28

    def __set_v(self, v):
        self.v_fc_flow = (self.v_fc_flow & ~0xF0000000) | (v << 28)

    v = property(__get_v, __set_v)

    def __get_fc(self):
        return (self.v_fc_flow >> 20) & 0xFF

    def __set_fc(self, v):
        self.v_fc_flow = (self.v_fc_flow & ~0xFF00000) | (v << 20)

    fc = property(__get_fc, __set_fc)

    def __get_flow(self):
        return self.v_fc_flow & 0xFFFFF

    def __set_flow(self, v):
        self.v_fc_flow = (self.v_fc_flow & ~0xFFFFF) | (v & 0xFFFFF)

    flow = property(__get_flow, __set_flow)

    # Convenient access for: src[_s], dst[_s]
    src_s = pypacker.get_property_ip6("src")
    dst_s = pypacker.get_property_ip6("dst")
    nxt_t = pypacker.get_property_translator("nxt", "IP_PROTO_")

    __handler__ = {
        IP_PROTO_ICMP6: icmp6.ICMP6,
        IP_PROTO_IGMP: igmp.IGMP,
        IP_PROTO_TCP: tcp.TCP,
        IP_PROTO_UDP: udp.UDP,
        IP_PROTO_ESP: esp.ESP,
        IP_PROTO_PIM: pim.PIM,
        IP_PROTO_IPXIP: ipx.IPX,
        IP_PROTO_SCTP: sctp.SCTP,
        IP_PROTO_OSPF: ospf.OSPF
    }

    update_dependants = {tcp.TCP, udp.UDP}

    def _dissect(self, buf):
        type_nxt = buf[6]
        off = 40
        opts = []

        # logger.debug("type: %d buflen: %d" % (type_nxt, len(buf)))
        # logger.debug("parsing opts from bytes (dst: %s): (len: %d) %s" %
        #	 (buf[24:40], self.hdr_len, buf[off:]))
        # parse options until type is an upper layer one
        while type_nxt in ext_hdrs:
            length = 8 + buf[off + 1] * 8
            # logger.debug("next type is: %s, len: %d, %r" % (type_nxt, length, buf[off:off + length]))
            opt = ext_hdrs_cls[type_nxt](buf[off:off + length])
            opts.append(opt)
            type_nxt = buf[off]
            off += length

        # TODO: lazy dissect possible?
        self.opts.extend(opts)
        # IPv6 and IPv4 share same handler
        # There are some cases where padding can not be identified on ethernet -> do it here (eg VSS shit trailer)
        self._init_handler(type_nxt, buf[off:])
        return off

    def _update_fields(self):
        if self.dlen_au_active:
            self.dlen = len(self.opts.bin()) + len(self.body_bytes)
        # Set type value in nxt OR in last opts element (if present)
        # Updating is a bit more complicated so we can't use FIELD_FLAG_IS_TYPEFIELD
        # idval is None if body handler is None
        # logger.debug("handler %r -> %r", self.__class__, self.higher_layer.__class__)
        idval = pypacker.Packet.get_id_for_handlerclass(
            self.__class__, self.higher_layer.__class__)
        #logger.debug("nxt will be %r", idval)

        if idval is not None:
            if len(self.opts) == 0:
                self.nxt = idval
            else:
                # problem if opts[-1] is immutable
                try:
                    self.opts[-1].nxt = idval
                except:
                    pass

    def direction(self, other):
        # logger.debug("checking direction: %s<->%s" % (self, next))
        if self.src == other.src and self.dst == other.dst:
            # consider packet to itself: can be DIR_REV
            return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV
        if self.src == other.dst and self.dst == other.src:
            return pypacker.Packet.DIR_REV
        return pypacker.Packet.DIR_UNKNOWN

    def reverse_address(self):
        self.src, self.dst = self.dst, self.src
예제 #6
0
파일: tcp.py 프로젝트: wau/pypacker
class TCPOptSingle(pypacker.Packet):
	__hdr__ = (
		("type", "B", 0),
	)

	type_t = pypacker.get_property_translator("type", "TCP_OPT_")
예제 #7
0
파일: tcp.py 프로젝트: wau/pypacker
class TCP(pypacker.Packet):
	__hdr__ = (
		("sport", "H", 0xDEAD),
		("dport", "H", 0, FIELD_FLAG_IS_TYPEFIELD),
		("seq", "I", 0xDEADBEEF),
		("ack", "I", 0),
		("off_x2", "B", ((5 << 4) | 0), FIELD_FLAG_AUTOUPDATE),  # 10*4 Byte
		("flags", "B", TH_SYN),  # acces via (obj.flags & TH_XYZ)
		("win", "H", TCP_WIN_MAX),
		("sum", "H", 0, FIELD_FLAG_AUTOUPDATE),
		("urp", "H", 0),
		("opts", None, triggerlist.TriggerList)
	)

	# 4 bits | 4 bits
	# offset | reserved
	# offset * 4 = header length
	def __get_off(self):
		return self.off_x2 >> 4

	def __set_off(self, value):
		self.off_x2 = (value << 4) | (self.off_x2 & 0xF)
	off = property(__get_off, __set_off)

	# return real header length based on header info
	def __get_hlen(self):
		return self.off * 4

	# set real header length based on header info (should be n*4)
	def __set_hlen(self, value):
		self.off = int(value / 4)

	hlen = property(__get_hlen, __set_hlen)
	flags_t = pypacker.get_property_translator("flags", "TH_", cb_get_description=cb_get_flag_description)

	__handler__ = {
		TCP_PROTO_BGP: bgp.BGP,
		TCP_PROTO_TELNET: telnet.Telnet,
		TCP_PROTO_TPKT: tpkt.TPKT,
		TCP_PROTO_PMAP: pmap.Pmap,
		TCP_PROTO_MQTT: mqtt.MQTTBase,
		TCP_PROTO_HTTP: http.HTTP,
		TCP_PROTO_SSL: ssl.SSL,
		TCP_PROTO_RTP: rtp.RTP,
		TCP_PROTO_SIP: sip.SIP
	}

	def _update_fields(self):
		# TCP-checksum needs to be updated on one of the following:
		# - this layer itself or any higher layer changed
		# - changes to the IP-pseudoheader
		update = True
		# update header length. NOTE: needs to be a multiple of 4 Bytes.
		# options length need to be multiple of 4 Bytes
		if self._header_changed and self.off_x2_au_active:
			self.off = int(self.header_len / 4) & 0xF

		# we need some IP as lower layer
		if self._lower_layer is None:
			return

		#self._update_higherlayer_id()

		try:
			# changes to IP-layer, don't mind if this isn't IP
			if not self._lower_layer._header_changed:
				# pseudoheader didn't change, further check for changes in layers
				update = self._changed()
			# logger.debug("lower layer found!")
		except:
			# Assume not an IP packet: we can't calculate the checksum
			# logger.debug("no lower layer found!")
			update = False

		if update and self.sum_au_active:
			# logger.debug(">>> updating checksum")
			self._calc_sum()

	def _dissect(self, buf):
		# update dynamic header parts. buf: 1010???? -clear reserved-> 1010 -> *4
		ol = ((buf[12] >> 4) << 2) - 20	 # dataoffset - TCP-standard length

		if ol > 0:
			# parse options, add offset-length to standard-length
			opts_bytes = buf[20: 20 + ol]
			self._init_triggerlist("opts", opts_bytes, self._parse_opts)
		elif ol < 0:
			raise Exception("invalid header length")

		ports = [unpack_H(buf[0:2])[0], unpack_H(buf[2:4])[0]]

		try:
			# source or destination port should match
			# logger.debug("TCP handler: %r" % self._id_handlerclass_dct[TCP])
			htype = [x for x in ports if x in self._id_handlerclass_dct[TCP]][0]
			#logger.debug("TCP: trying to set handler, type: %d = %s" %
			#(type, self._id_handlerclass_dct[TCP][type]))
			self._init_handler(htype, buf[20 + ol:])
		except:
			# no type found
			pass
		return 20 + ol

	__TCP_OPT_SINGLE = {TCP_OPT_EOL, TCP_OPT_NOP}

	@staticmethod
	def _parse_opts(buf):
		"""Parse TCP options using buf and return them as List."""
		optlist = []
		i = 0

		while i < len(buf):
			# logger.debug("got TCP-option type %s" % buf[i])
			if buf[i] in TCP.__TCP_OPT_SINGLE:
				p = TCPOptSingle(type=buf[i])
				i += 1
			else:
				olen = buf[i + 1]
				# p = TCPOptMulti(type=buf[i], len=olen, body_bytes=buf[i + 2: i + olen])
				p = TCPOptMulti(buf[i: i + olen])
				i += olen     # typefield + lenfield + data-len
			optlist.append(p)
		# logger.debug("tcp: parseopts finished, length: %d" % len(optlist))
		return optlist

	def _calc_sum(self):
		"""Recalculate the TCP-checksum. This won't reset changed state."""
		# TCP and underwriting are freaky bitches: we need the IP pseudoheader
		# to calculate their checksum.
		try:
			# we need src/dst for checksum-calculation
			src, dst = self._lower_layer.src, self._lower_layer.dst
			self.sum = 0
			# logger.debug("TCP sum recalc: IP=%d / %s / %s" % (len(src), src, dst))

			tcp_bin = self.header_bytes + self.body_bytes
			# IP-pseudoheader, check if version 4 or 6
			if len(src) == 4:
				s = pack_ipv4_header(src, dst, 6, len(tcp_bin))  # 6 = TCP
			else:
				s = pack_ipv6_header(src, dst, 6, len(tcp_bin))  # 6 = TCP

			# Get checksum of concatenated pseudoheader+TCP packet
			# logger.debug("pseudoheader: %r" % s)
			# logger.debug("tcp_bin: %r" % tcp_bin)
			# assign via non-shadowed variable to trigger re-packing
			self.sum = in_cksum(s + tcp_bin)
			# logger.debug(">>> new checksum: %0X" % self._sum)
		except:
			# Not an IP packet as lower layer (src, dst not present) or invalid src/dst
			# logger.debug("could not calculate checksum: %r" % e)
			pass

	def direction(self, other):
		direction = 0
		# logger.debug("checking direction: %s<->%s" % (self, other))
		if self.sport == other.sport and self.dport == other.dport:
			direction |= pypacker.Packet.DIR_SAME
		if self.sport == other.dport and self.dport == other.sport:
			direction |= pypacker.Packet.DIR_REV
		if direction == 0:
			direction = pypacker.Packet.DIR_UNKNOWN
		return direction

	def reverse_address(self):
		self.sport, self.dport = self.dport, self.sport

	ra_segments = pypacker.get_ondemand_property("ra_segments", lambda: {})

	def ra_collect(self, pkt_list):
		"""
		Collect TCP segments which have the same direction as this packet.
		Concatenated segments can be retrieved via ra_bin(). Does not check for missing
		segments.
		return -- bytes_cnt, [True|False]: amount of bytes added (sum of body bytes),
			final packet found (RST or FIN). True indicates that ra_bin() can be called.
		"""
		if type(pkt_list) is not list:
			pkt_list = [pkt_list]

		bts_cnt = 0

		for segment in pkt_list:
			if self.direction(segment) != pypacker.Packet.DIR_SAME or len(segment.body_bytes) == 0:
				continue

			seq_store = segment.seq
			# final packet found: connection is going to be terminated
			if (segment.flags & TH_FIN) != 0 or (segment.flags & TH_RST) != 0:
				return 0, True

			if seq_store < self.seq:
				logger.warning("seq of new segment is lower than start")
				seq_store += 0xFFFF

			#logger.debug("adding tcp segment: %r", segment.body_bytes)
			self.ra_segments[seq_store] = segment.body_bytes
			bts_cnt += len(segment.body_bytes)

		return bts_cnt, False

	def ra_bin(self):
		"""
		Assemble retrieved TCP segments in sorted order (body bytes of TCP segments).
		Does NOT flush the internal buffer; this is done via self.ra_segments.clear()
		"""
		self.ra_segments[self.seq] = self.body_bytes
		sorted_list = sorted(self.ra_segments.items(), key=lambda t: t[0])
		bts_lst = [value for key, value in sorted_list]
		self.ra_segments.clear()
		return b"".join(bts_lst)
예제 #8
0
파일: icmp.py 프로젝트: wau/pypacker
class ICMP(pypacker.Packet):
	__hdr__ = (
		("type", "B", ICMP_ECHO, FIELD_FLAG_IS_TYPEFIELD),
		("code", "B", 0),
		("sum", "H", 0, FIELD_FLAG_AUTOUPDATE)
	)
	type_t = pypacker.get_property_translator("type", "ICMP_")

	def _update_fields(self):
		# logger.debug("sum is: %d" % self.sum)
		if self.sum_au_active and self._changed():
			# logger.debug("sum is: %d" % self.sum)
			# logger.debug("header: %r", self.header_bytes)
			# logger.debug("body: %r", self.body_bytes)
			self.sum = 0
			self.sum = checksum.in_cksum(self.header_bytes + self.body_bytes)
			# logger.debug("sum is: %d" % self.sum)

	def _dissect(self, buf):
		# logger.debug("ICMP: adding fields for type: %d" % buf[0])
		self._init_handler(buf[0], buf[4:])
		return 4

	class Echo(pypacker.Packet):
		__hdr__ = (
			("id", "H", 0),
			("seq", "H", 1),
			("ts", "Q", 0)
		)

		def _dissect(self, buf):
			hlen = 12

			if len(buf) < 12:
				# not enough bytes for ts
				self.ts = None
				hlen = 4
			return hlen

	class Unreach(pypacker.Packet):
		__hdr__ = (
			("pad", "I", 0),
		)

		CODE_UNREACH_NET = 0  # bad net
		CODE_UNREACH_HOST = 1  # bad host
		CODE_UNREACH_PROTO = 2  # bad protocol
		CODE_UNREACH_PORT = 3  # bad port
		CODE_UNREACH_NEEDFRAG = 4  # IP_DF caused drop
		CODE_UNREACH_SRCFAIL = 5  # src route failed
		CODE_UNREACH_NET_UNKNOWN = 6  # unknown net
		CODE_UNREACH_HOST_UNKNOWN = 7  # unknown host
		CODE_UNREACH_ISOLATED = 8  # src host isolated
		CODE_UNREACH_NET_PROHIB = 9  # for crypto devs
		CODE_UNREACH_HOST_PROHIB = 10  # ditto
		CODE_UNREACH_TOSNET = 11  # bad tos for net
		CODE_UNREACH_TOSHOST = 12  # bad tos for host
		CODE_UNREACH_FILTER_PROHIB = 13  # prohibited access
		CODE_UNREACH_HOST_PRECEDENCE = 14  # precedence error
		CODE_UNREACH_PRECEDENCE_CUTOFF = 15  # precedence cutoff

	class Quench(pypacker.Packet):
		__hdr__ = (
			("pad", "I", 0),
		)

	class Redirect(pypacker.Packet):
		__hdr__ = (
			("gw", "I", 0),
		)
		CODE_REDIRECT_NET = 0  # for network
		CODE_REDIRECT_HOST = 1  # for host
		CODE_REDIRECT_TOSNET = 2  # for tos and net
		CODE_REDIRECT_TOSHOST = 3  # for tos and host

	class RouterAdvertisement(pypacker.Packet):
		__hdr__ = (
			("numaddr", "B", 0),
			("addrsize", "B", 0),
			("lifetime", "H", 0)
		)

		CODE_RTRADVERT_NORMAL = 0  # normal
		CODE_RTRADVERT_NOROUTE_COMMON = 16  # selective routing
		CODE_RTRSOLICIT = 10  # router solicitation

	class RouterSelection(pypacker.Packet):
		__hdr__ = (
			("numaddr", "B", 0),
			("addrsize", "B", 0),
			("lifetime", "H", 0)
		)

	class TimeExceed(pypacker.Packet):
		__hdr__ = (
			("pad", "I", 0),
		)

		CODE_TIMEXCEED_INTRANS = 0  # ttl==0 in transit
		CODE_TIMEXCEED_REASS = 1  # ttl==0 in reass

	class ParamProblem(pypacker.Packet):
		__hdr__ = (
			("pointer", "B", 0),
			("unused", "3s", b"\x00" * 3)
		)

		CODE_PARAMPROB_ERRATPTR = 0  # req. opt. absent
		CODE_PARAMPROB_OPTABSENT = 1  # req. opt. absent
		CODE_PARAMPROB_LENGTH = 2  # bad length

	class Photuris(pypacker.Packet):
		class ParamProblem(pypacker.Packet):
			__hdr__ = (
				("reserved", "H", 0),
				("pointer", "H", 0)
			)

		CODE_PHOTURIS_UNKNOWN_INDEX = 0  # unknown sec index
		CODE_PHOTURIS_AUTH_FAILED = 1  # auth failed
		CODE_PHOTURIS_DECOMPRESS_FAILED = 2  # decompress failed
		CODE_PHOTURIS_DECRYPT_FAILED = 3  # decrypt failed
		CODE_PHOTURIS_NEED_AUTHN = 4  # no authentication
		CODE_PHOTURIS_NEED_AUTHZ = 5  # no authorization

	__handler__ = {
		(ICMP_ECHO, ICMP_ECHO_REPLY): Echo,
		ICMP_UNREACH: Unreach,
		ICMP_SRCQUENCH: Quench,
		ICMP_REDIRECT: Redirect,
		ICMP_RTRADVERT: RouterAdvertisement,
		ICMP_RTRSEL: RouterSelection,
		ICMP_TIMEXCEED: TimeExceed,
		ICMP_PARAMPROB: ParamProblem,
		ICMP_PHOTURIS: Photuris
	}