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
2 changes: 0 additions & 2 deletions scapy/contrib/diameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4828,7 +4828,5 @@ def DiamAns(cmd, **fields):

bind_layers(TCP, DiamG, dport=3868)
bind_layers(TCP, DiamG, sport=3868)
bind_layers(SCTPChunkData, DiamG, dport=3868)
bind_layers(SCTPChunkData, DiamG, sport=3868)
bind_layers(SCTPChunkData, DiamG, proto_id=46)
bind_layers(SCTPChunkData, DiamG, proto_id=47)
24 changes: 23 additions & 1 deletion scapy/layers/sctp.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
IntEnumField,
IntField,
MultipleTypeField,
PacketLenField,
PacketListField,
PadField,
ShortEnumField,
Expand Down Expand Up @@ -624,6 +625,26 @@ class SCTPChunkParamAdaptationLayer(_SCTPChunkParam, Packet):
}


class _SCTPChunkDataField(PacketLenField):
"""PacketLenField that dispatches using bind_layers bindings."""

def m2i(self, pkt, m):
# Only dissect complete messages
if pkt.beginning != 1 or pkt.ending != 1:
return m
# Check bind_layers bindings
for fval, cls in pkt.payload_guess:
if all(
hasattr(pkt, k) and v == pkt.getfieldval(k)
for k, v in fval.items()
):
try:
return cls(m)
except Exception:
pass
return m


class SCTPChunkData(_SCTPChunkGuessPayload, Packet):
# TODO : add a padding function in post build if this layer is used to generate SCTP chunk data # noqa: E501
fields_desc = [ByteEnumField("type", 0, sctpchunktypes),
Expand All @@ -637,7 +658,8 @@ class SCTPChunkData(_SCTPChunkGuessPayload, Packet):
XShortField("stream_id", None),
XShortField("stream_seq", None),
IntEnumField("proto_id", None, SCTP_PAYLOAD_PROTOCOL_INDENTIFIERS), # noqa: E501
PadField(StrLenField("data", None, length_from=lambda pkt: pkt.len - 16), # noqa: E501
PadField(_SCTPChunkDataField("data", None, conf.raw_layer,
length_from=lambda pkt: pkt.len - 16), # noqa: E501
4, padwith=b"\x00"),
]

Expand Down
30 changes: 30 additions & 0 deletions test/contrib/diameter.uts
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,33 @@ r3b = DiamReq ('Multimedia-Auth', drHbHId=0x5478, drEtEId=0x1234,

raw(r3b) == raw(r3)


#######################################################################
+ Diameter over SCTP
#######################################################################

= Diameter decoded from SCTPChunkData via proto_id binding

from scapy.layers.sctp import SCTP, SCTPChunkData

diam_pkt = DiamAns('Capabilities-Exchange', drHbHId=0x1234, drEtEId=0x5678,
avpList=[AVP('Origin-Host', val='host.example.com'),
AVP('Origin-Realm', val='example.com')])

pkt = SCTP(raw(SCTP() / SCTPChunkData(proto_id=46, beginning=1, ending=1, data=raw(diam_pkt))))
chunk = pkt[SCTPChunkData]
assert isinstance(chunk.data, DiamG)
assert chunk.proto_id == 46
assert chunk.data.drHbHId == 0x1234
assert chunk.data.avpList[0].avpCode == 264

= SCTPChunkData with unknown proto_id keeps raw bytes

pkt = SCTP(raw(SCTP() / SCTPChunkData(proto_id=0, data=b"test")))
assert pkt[SCTPChunkData].data == b"test"

= SCTPChunkData fragment is not decoded

pkt = SCTP(raw(SCTP() / SCTPChunkData(proto_id=46, beginning=1, ending=0, data=raw(diam_pkt))))
assert not isinstance(pkt[SCTPChunkData].data, DiamG)

Loading