Skip to content

Commit

Permalink
[feat] SCTP checksum compute
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinlampin committed Jan 9, 2025
1 parent 289d30e commit 1464f9c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
4 changes: 3 additions & 1 deletion microschc/protocol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
from .ipv4 import IPv4ComputeFunctions, IPv4Fields
from .ipv6 import IPv6ComputeFunctions, IPv6Fields
from .udp import UDPComputeFunctions, UDPFields
from .sctp import SCTPComputeFunctions, SCTPFields

ComputeFunctions: Dict[str, Tuple[ComputeFunctionType, ComputeFunctionDependenciesType]] = {
IPv4Fields.TOTAL_LENGTH: IPv4ComputeFunctions[IPv4Fields.TOTAL_LENGTH],
IPv4Fields.HEADER_CHECKSUM: IPv4ComputeFunctions[IPv4Fields.HEADER_CHECKSUM],
IPv6Fields.PAYLOAD_LENGTH: IPv6ComputeFunctions[IPv6Fields.PAYLOAD_LENGTH],
UDPFields.LENGTH: UDPComputeFunctions[UDPFields.LENGTH],
UDPFields.CHECKSUM: UDPComputeFunctions[UDPFields.CHECKSUM]
UDPFields.CHECKSUM: UDPComputeFunctions[UDPFields.CHECKSUM],
SCTPFields.CHECKSUM: SCTPComputeFunctions[SCTPFields.CHECKSUM]
}


Expand Down
31 changes: 28 additions & 3 deletions microschc/protocol/sctp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@


from enum import Enum
from functools import reduce

from microschc.crypto.crc import CRC32C_TABLE, crc32c
from microschc.protocol.registry import PARSERS, REGISTER_PARSER, ProtocolsIDs

SCTP_HEADER_ID = 'SCTP'

from enum import Enum
from typing import Dict, List, Tuple, Type
from microschc.binary.buffer import Buffer
from microschc.binary.buffer import Buffer, Padding
from microschc.parser import HeaderParser, ParserError
from microschc.protocol.compute import ComputeFunctionDependenciesType, ComputeFunctionType
from microschc.rfc8724 import FieldDescriptor, HeaderDescriptor

SCTP_HEADER_ID = 'SCTP'
Expand Down Expand Up @@ -604,9 +607,9 @@ def _parse_parameter(self, buffer: Buffer) -> Tuple[List[FieldDescriptor], int]:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Parameter Type | Parameter Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\ \
\ \
/ Parameter Value /
\ \
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
"""
fields: List[FieldDescriptor] = []
Expand All @@ -632,4 +635,26 @@ def _parse_parameter(self, buffer: Buffer) -> Tuple[List[FieldDescriptor], int]:
)
return fields, parameter_length_value + parameter_padding_length


def _compute_checksum(decompressed_fields: List[Tuple[str, Buffer]], rule_field_position: int) -> Buffer:
"""
Checksum algorithm is the Castagnoli CRC32C Checksum Algorithm (CRC32c).
"""
fields_values: List[Buffer] = [field_value for _, field_value in decompressed_fields]

sctp_checksum_position: int = rule_field_position
# - SCTP checksum is the 4th field of UDP
sctp_header_and_payload_fields: List[Buffer] = [field for field in fields_values[sctp_checksum_position-3:]]
sctp_header_and_payload: Buffer = reduce(lambda x, y: x+y, sctp_header_and_payload_fields)

crc_init: int = 0xffffffff
checksum = crc32c(buffer=sctp_header_and_payload, crc_init=crc_init)
checksum = ~checksum
checksum_buffer = reduce(lambda x,y : x+y, list(checksum.chunks(length=8))[::-1])
return checksum_buffer

SCTPComputeFunctions: Dict[str, Tuple[ComputeFunctionType, ComputeFunctionDependenciesType]] = {
SCTPFields.CHECKSUM: (_compute_checksum, { f.value for f in SCTPFields if f is not SCTPFields.CHECKSUM })
}

REGISTER_PARSER(protocol_id=ProtocolsIDs.SCTP, parser_class=SCTPParser)
23 changes: 21 additions & 2 deletions tests/protocol/test_sctp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Dict, List, Tuple
from microschc.protocol.sctp import SCTPParser, SCTPFields
from microschc.protocol.sctp import SCTPParser, SCTPFields, SCTPComputeFunctions
from microschc.parser.parser import HeaderDescriptor
from microschc.rfc8724 import FieldDescriptor
from microschc.binary.buffer import Buffer
Expand Down Expand Up @@ -1104,4 +1104,23 @@ def test_sctp_parser_parse_cookie_ack():
chunk_length_fd:FieldDescriptor = sctp_header_descriptor.fields[6]
assert chunk_length_fd.id == SCTPFields.CHUNK_LENGTH
assert chunk_length_fd.position == 0
assert chunk_length_fd.value == Buffer(content=b'\x00\x04', length=16)
assert chunk_length_fd.value == Buffer(content=b'\x00\x04', length=16)

def test_sctp_compute_checksum():

partially_reconstructed_content: bytes = bytes(
b'\x00\x07\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x20'
b'\x43\x23\x25\x44\x00\x00\xff\xff\x00\x11\x00\x11\x5c\xfe\x37\x9f'
b'\xc0\x00\x00\x04\x00\x0c\x00\x06\x00\x05\x00\x00'

)
expected_checksum: Buffer = Buffer(content=b'\x37\x61\xa7\x46', length=32)
parser:SCTPParser = SCTPParser()

partially_reconstructed_packet: Buffer = Buffer(content=partially_reconstructed_content, length=len(partially_reconstructed_content)*8)
sctp_header_descriptor: HeaderDescriptor = parser.parse(buffer=partially_reconstructed_packet)


decompressed_fields: List[Tuple[str, Buffer]] = [ (field.id,field.value) for field in sctp_header_descriptor.fields]
checksum_buffer: Buffer = SCTPComputeFunctions[SCTPFields.CHECKSUM][0](decompressed_fields, 3)
assert checksum_buffer == expected_checksum

0 comments on commit 1464f9c

Please sign in to comment.