Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion scapy/layers/inet.py
Original file line number Diff line number Diff line change
Expand Up @@ -1018,9 +1018,15 @@ def __init__(self):
def getfield(self, pkt, s):
# RFC4884 section 5.2 says if the ICMP packet length
# is >144 then ICMP extensions start at byte 137.
length = getattr(pkt, "length", 0) or 0
if len(pkt.original) < 144:
if not length:
return s, None
offset = length * 8
else:
offset = 136 + len(s) - len(pkt.original)
if offset > len(s):
return s, None
offset = 136 + len(s) - len(pkt.original)
data = s[offset:]
# Validate checksum
if checksum(data) == data[3:5]:
Expand Down Expand Up @@ -1061,6 +1067,25 @@ def _ICMP_extpad_post_dissection(self, pkt):
pkt.extpad = pad.load


def _icmp4884_prepare_ext_build(pkt, p, pay, length_offset):
# RFC4884: set length and pad original datagram when extensions are used
if pkt.ext is None:
return p, pay
if pkt.extpad in (None, b"", ""):
padding_index = pay.rindex(bytes(pkt.ext))
payload_len = len(pay[:padding_index])
padding_len = (8 - payload_len % 8) % 8
if payload_len + padding_len < 128:
padding_len = 128 - payload_len
padding = b"\x00" * padding_len
pay = pay[:padding_index] + padding + pay[padding_index:]
if pkt.length in (None, 0):
ext_index = pay.rindex(bytes(pkt.ext))
length = len(pay[:ext_index]) // 8
p = p[:length_offset] + chb(length) + p[length_offset + 1:]
return p, pay
Comment on lines +1072 to +1086

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand any of this code :(



icmptypes = {0: "echo-reply",
3: "dest-unreach",
4: "source-quench",
Expand Down
5 changes: 5 additions & 0 deletions scapy/layers/inet6.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
XShortField,
)
from scapy.layers.inet import (
_icmp4884_prepare_ext_build,
_ICMPExtensionField,
_ICMPExtensionPadField,
_ICMP_extpad_post_dissection,
Expand Down Expand Up @@ -1510,6 +1511,10 @@ class ICMPv6TimeExceeded(_ICMPv6Error):
_ICMPExtensionField()]
post_dissection = _ICMP_extpad_post_dissection

def post_build(self, p, pay):
p, pay = _icmp4884_prepare_ext_build(self, p, pay, length_offset=4)
return _ICMPv6.post_build(self, p, pay)


# The default pointer value is set to the next header field of
# the encapsulated IPv6 packet
Expand Down
23 changes: 21 additions & 2 deletions test/scapy/layers/inet6.uts
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,27 @@ a[ICMPv6PacketTooBig][TCPerror].chksum == b.chksum


########### ICMPv6TimeExceeded Class ################################
# To be done but not critical. Same mechanisms and format as
# previous ones.

= ICMPv6TimeExceeded extension - length field build (GH4353)

pkt = IPv6() / ICMPv6TimeExceeded(ext=ICMPExtension_Header()) / IPv6() / ICMPv6EchoRequest()
raw = bytes(pkt)
pkt2 = IPv6(raw)
assert pkt2[ICMPv6TimeExceeded].length == 16

= ICMPv6TimeExceeded extension - Ether round-trip (GH4353)

pkt = Ether() / IPv6() / ICMPv6TimeExceeded(ext=ICMPExtension_Header()) / IPv6() / ICMPv6EchoRequest()
pkt = Ether(bytes(pkt))
assert pkt[ICMPv6TimeExceeded].length == 16

= ICMPv6TimeExceeded extension - rebuild stability (GH4353)

pkt = IPv6() / ICMPv6TimeExceeded(ext=ICMPExtension_Header()) / IPv6() / ICMPv6EchoRequest()
raw = bytes(pkt)
pkt2 = IPv6(raw)
assert isinstance(pkt2[ICMPv6TimeExceeded].ext, ICMPExtension_Header)
assert bytes(pkt2) == raw

########### ICMPv6ParamProblem Class ################################
# See previous note
Expand Down
Loading