diff --git a/doc/scapy/usage.rst b/doc/scapy/usage.rst index a6e14a84fcc..0a5bb16da2b 100644 --- a/doc/scapy/usage.rst +++ b/doc/scapy/usage.rst @@ -847,6 +847,8 @@ The ``data`` argument is bytes and the ``metadata`` argument is a dictionary whi - ``metadata.get("tcp_psh", False)``: will be present if the PUSH flag is set - ``metadata.get("tcp_end", False)``: will be present if the END or RESET flag is set +If ``tcp_reassemble`` **returns any padding**, it will be kept for the next payload. + Filters ------- diff --git a/scapy/contrib/bgp.py b/scapy/contrib/bgp.py index d8564a9b795..0060e5f9f32 100644 --- a/scapy/contrib/bgp.py +++ b/scapy/contrib/bgp.py @@ -461,6 +461,17 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): return _bgp_dispatcher(_pkt) + @classmethod + def tcp_reassemble(cls, data, *args, **kwargs): + if len(data) < 18: + return None + if data[:16] == _BGP_HEADER_MARKER: + length = struct.unpack("!H", data[16:18])[0] + if len(data) >= length: + return cls(data[:length]) / conf.padding_layer(data[length:]) + else: + return cls(data) + def post_build(self, p, pay): if self.len is None: length = len(p) @@ -520,6 +531,8 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): return _bgp_dispatcher(_pkt) + tcp_reassemble = BGPHeader.tcp_reassemble + def guess_payload_class(self, p): cls = None if len(p) > 15 and p[:16] == _BGP_HEADER_MARKER: @@ -755,7 +768,8 @@ class ORFTuple(Packet): "entries", [], ORFTuple, - count_from=lambda p: p.orf_number + count_from=lambda p: p.orf_number, + max_count=20000, ) ] @@ -811,7 +825,8 @@ class BGPCapORF(BGPCapability): "orf", [], BGPCapORFBlock, - length_from=lambda p: p.length + length_from=lambda p: p.length, + max_count=20000, ) ] @@ -1910,7 +1925,8 @@ class BGPPAMPReachNLRI(Packet): ConditionalField(IP6Field("nh_v6_link_local", "::"), lambda x: x.afi == 2 and x.nh_addr_len == 32), ByteField("reserved", 0), - MPReachNLRIPacketListField("nlri", [], BGPNLRI_IPv6)] + MPReachNLRIPacketListField("nlri", [], BGPNLRI_IPv6, + max_count=20000)] def post_build(self, p, pay): if self.nlri is None: @@ -2216,7 +2232,8 @@ class BGPUpdate(BGP): BGPPathAttr, length_from=lambda p: p.path_attr_len ), - BGPNLRIPacketListField("nlri", [], "IPv4") + BGPNLRIPacketListField("nlri", [], "IPv4", + max_count=20000) ] def post_build(self, p, pay): @@ -2574,6 +2591,7 @@ class BGPORF(Packet): [], Packet, length_from=lambda p: p.orf_len, + max_count=20000, ) ] diff --git a/test/contrib/bgp.uts b/test/contrib/bgp.uts index cebb1bfafe4..3d8e30f2431 100644 --- a/test/contrib/bgp.uts +++ b/test/contrib/bgp.uts @@ -87,6 +87,13 @@ h = BGP(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x assert h.type == BGP.OPEN_TYPE assert h.len == 19 += BGP - Test TCP reassembly +pkts = sniff(offline=scapy_path("/test/pcaps/bgp_fragmented.pcap.gz"), session=TCPSession) +assert len(pkts) == 1 +assert BGPUpdate in pkts[0] +assert len(pkts[0].nlri) == 512 +assert pkts[0].nlri[511].prefix == '91.0.177.0/24' + ############################### BGPKeepAlive ################################# + BGPKeepAlive class tests diff --git a/test/pcaps/bgp_fragmented.pcap.gz b/test/pcaps/bgp_fragmented.pcap.gz new file mode 100644 index 00000000000..71d84784e31 Binary files /dev/null and b/test/pcaps/bgp_fragmented.pcap.gz differ