Skip to content

SCTP decoder and sticky buffers v2#15226

Open
glongo wants to merge 13 commits intoOISF:mainfrom
glongo:dev-4251-sctp-v2
Open

SCTP decoder and sticky buffers v2#15226
glongo wants to merge 13 commits intoOISF:mainfrom
glongo:dev-4251-sctp-v2

Conversation

@glongo
Copy link
Copy Markdown
Contributor

@glongo glongo commented Apr 19, 2026

Link to ticket: https://redmine.openinfosecfoundation.org/issues/4251

Describe changes:

  • SCTP decoder extracts up to 16 chunk types
  • sctp.chunk_type matches on one for the chunks extracted
  • Replaced decoder-sctp.c#L166 with const SCTPHdr *sctph = PacketSetSCTP(p, pkt);
  • Replaced decoder-sctp.c#L145 with hlen = SCTP_HEADER_LEN + MIN(offset, len);
  • Replaced pkthdr with sctp in rules/sctp-events.rules
  • sctp.has_init matches only on INIT (INIT_ACK removed)

Previous PR: #15129

SV_BRANCH=OISF/suricata-verify#2999

glongo added 13 commits April 19, 2026 15:59
Extend the SCTP decoder to parse chunk headers after the 12-byte common
header. Each chunk is validated for minimum header size and length
consistency per RFC 4960 sec 3.2.

Add SCTPChunkHdr and SCTPVars structs to track per-packet chunk metadata

Add five new decoder events for protocol violations:
- SCTP_CHUNK_TOO_SMALL: insufficient data for a chunk header
- SCTP_CHUNK_LEN_INVALID: chunk length < 4 or exceeds packet
- SCTP_INIT_CHUNK_NOT_ALONE: INIT/INIT_ACK bundled (RFC 4960 sec 6.10)
- SCTP_INIT_WITH_NON_ZERO_VTAG: INIT with vtag != 0 (RFC 4960 sec 8.5.1)
- SCTP_DATA_WITH_ZERO_VTAG: DATA chunk with vtag == 0

Ticket OISF#4251
Implement a sticky buffer to match the raw SCTP header
(common header + chunks)

Ticket OISF#4251
Add a U8 numeric keyword to match the first SCTP chunk type in a packet
with prefilter support.

Ticket OISF#4251
Add a U8 numeric keyword to match the number of SCTP chunks
parsed in a packet with prefilter support.

Ticket OISF#4251
Add a U32 numeric keyword to match the SCTP verification tag
from the common header with prefilter support.

Ticket OISF#4251
Add a boolean NOOPT keyword to match SCTP packets containing
an INIT or INIT_ACK chunk.

Ticket OISF#4251
Add a boolean NOOPT keyword to match SCTP packets containing
a DATA chunk.

Ticket OISF#4251
Add a boolean NOOPT keyword to match SCTP packets containing
an ABORT chunk.

Ticket OISF#4251
Log SCTP-specific fields in the EVE JSON "sctp" object for alert events.

Ticket OISF#4251
Track the first DATA chunk's data offset and length during chunk iteration,
then reassign p->payload to point at the user data.

When no DATA chunk is present (INIT, SACK, HEARTBEAT, etc.),
payload_len is set to 0 since there is no application data.

Ticket OISF#4251
Add a sctp.data sticky buffer that allows content matching on the bytes inside
the first SCTP DATA chunk.

Ticket OISF#4251
Add documentation for all sctp keywords.

Ticket OISF#4251
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 19, 2026

Codecov Report

❌ Patch coverage is 90.24691% with 79 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.69%. Comparing base (214e47b) to head (6b23469).

Additional details and impacted files
@@           Coverage Diff            @@
##             main   #15226    +/-   ##
========================================
  Coverage   82.68%   82.69%            
========================================
  Files         993     1010    +17     
  Lines      271880   272682   +802     
========================================
+ Hits       224807   225493   +686     
- Misses      47073    47189   +116     
Flag Coverage Δ
fuzzcorpus 60.98% <46.89%> (-0.03%) ⬇️
livemode 18.38% <20.98%> (+0.01%) ⬆️
netns 22.61% <20.98%> (-0.02%) ⬇️
pcap 45.25% <43.26%> (-0.05%) ⬇️
suricata-verify 66.29% <73.57%> (-0.04%) ⬇️
unittests 58.91% <80.49%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

sctp.chunk_type
---------------

Match on the type of the first SCTP chunk in the packet.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

forgot to update this doc

@glongo
Copy link
Copy Markdown
Contributor Author

glongo commented Apr 19, 2026

clang-format is formatting the code weirdly:

diff --git a/src/tests/detect-sctp-chunk-type.c b/src/tests/detect-sctp-chunk-type.c
index 958c132f0..c921ac415 100644
--- a/src/tests/detect-sctp-chunk-type.c
+++ b/src/tests/detect-sctp-chunk-type.c
@@ -46,18 +46,56 @@ static int DetectSCTPChunkTypeParseTest01(void)
 static int DetectSCTPChunkTypeMatchNonFirstTest(void)
 {
     uint8_t raw_sctp[] = {
-        0x04, 0xd2, 0x00, 0x50, /* sport=1234, dport=80 */
-        0x00, 0x00, 0x00, 0x01, /* vtag=1 */
-        0x00, 0x00, 0x00, 0x00, /* checksum=0 */
+        0x04,
+        0xd2,
+        0x00,
+        0x50, /* sport=1234, dport=80 */
+        0x00,
+        0x00,
+        0x00,
+        0x01, /* vtag=1 */
+        0x00,
+        0x00,
+        0x00,
+        0x00, /* checksum=0 */
         /* DATA chunk: type=0x00, flags=0x03, len=20 */
-        0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, /* TSN=0 */
-        0x00, 0x01, 0x00, 0x00,                         /* stream_id=1, stream_seq=0 */
-        0x00, 0x00, 0x00, 0x00,                         /* PPID=0 */
-        0x41, 0x42, 0x43, 0x44,                         /* data="ABCD" */
+        0x00,
+        0x03,
+        0x00,
+        0x14,
+        0x00,
+        0x00,
+        0x00,
+        0x00, /* TSN=0 */

@suricata-qa
Copy link
Copy Markdown

Information: QA ran without warnings.

Pipeline = 30979

@victorjulien
Copy link
Copy Markdown
Member

Array like this can be wrapped in clang-format off/on

Comment thread src/detect-sctp-data.c
void DetectSCTPDataRegister(void)
{
sigmatch_table[DETECT_SCTP_DATA].name = "sctp.data";
sigmatch_table[DETECT_SCTP_DATA].desc = "sticky buffer to match on the SCTP DATA chunk payload";
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 think this should be sctp.chunk_data to clearly indicate it's not reassembled.

And it also should be a multibuffer so we can inspect each chunk that may be in the packet, not just the first.

Copy link
Copy Markdown
Contributor

@jufajardini jufajardini left a comment

Choose a reason for hiding this comment

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

Inline, a few things docs / schema related.

I tried to check whether the progress-tracking for buffer keywords work (8f82445) would be relevant here, but it doesn't seem so. (In any case, highlighting, in case I'm wrong and in the chance it's unknown)

Comment on lines +114 to +115
Match if the SCTP packet contains an INIT or INIT_ACK chunk. This is a
boolean keyword that takes no arguments.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this piece also missing an update (based on previous PR's review comments)?

Comment thread etc/schema.json
"properties": {
"chunk_cnt": {
"type": "integer",
"suricata": {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is probably the best time to also add a description to these, isn't it? :P

Comment thread etc/schema.json
Comment on lines +8069 to +8072
"init": {
"type": "integer",
"description": "Number of SCTP packets with INIT or INIT_ACK chunk"
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Has this been decoupled? (as per the counter below and https://github.com/OISF/suricata/pull/15129/changes#r3021634492)

Comment thread rules/sctp-events.rules
@@ -0,0 +1,8 @@
# SCTP decoder event rules.
# SID's fall in the 2200000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2200000+ seems too generic, looking at examples from some other app-proto event rules (ldap, pgsql, ftp...) and the 2200130.. 2200135 sids present here.

Copy link
Copy Markdown
Contributor

@catenacyber catenacyber left a comment

Choose a reason for hiding this comment

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

Looks like there are remarks to be taken care of like the clang-format off


Syntax::

sctp.chunk_type:[op]<number>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do these chunk-types have a stringer ?

sctp.has_init
-------------

Match if the SCTP packet contains an INIT or INIT_ACK chunk. This is a
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why a dedicated keyword instead of sctp.chunk_type:INIT; ?


alert ipv4 any any -> any any (msg:"SURICATA IPv4 unknown protocol"; decode-event:ipv4.unknown_protocol; threshold: type limit, track by_src, seconds 60, count 1;classtype:protocol-command-decode; sid:2200125;)
# next sid is 2200130
# next sid is 2200136
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2200126 ?

"(msg:\"test\"; sctp.chunk_cnt:>5; sid:2;)"));

FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx, "alert sctp any any -> any any "
"(msg:\"test\"; sctp.chunk_cnt:bar; sid:3;)"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it not better to do SV tests than unit tests ?

/** \test match on a non-first chunk: bundled [DATA, SACK], match sctp.chunk_type:3 */
static int DetectSCTPChunkTypeMatchNonFirstTest(void)
{
uint8_t raw_sctp[] = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks even more like it should be a SV test

Comment thread src/decode-sctp.h
#define SCTP_DATA_CHUNK_HDR_LEN 16

/* SCTP chunk types (RFC 4960 sec 3.2) */
#define SCTP_CHUNK_TYPE_DATA 0x00
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like we have a stringer :-)

Did you think about trying rust here ?

sigmatch_table[transform_id].Transform = (void (*)(DetectEngineThreadCtx * det_ctx,
InspectionBuffer * buffer, const void *options)) kw->Transform;
sigmatch_table[transform_id].Transform = (void (*)(DetectEngineThreadCtx *det_ctx,
InspectionBuffer *buffer, const void *options))kw->Transform;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You have a too recent clang-format ;-)


const DetectU8Data *data = (const DetectU8Data *)ctx;
const uint8_t cnt = MIN(p->l4.vars.sctp.chunk_cnt, SCTP_MAX_TRACKED_CHUNKS);
for (uint8_t i = 0; i < cnt; i++) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like you could try to implement SIGMATCH_INFO_MULTI_UINT ;-)


static int DetectSCTPChunkTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (!(DetectProtoContainsProto(s->proto, IPPROTO_SCTP)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could I not write alert ip any any -> any any (sctp.chunk_type: 1;) ?

@catenacyber catenacyber added the needs rebase Needs rebase to main label Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs rebase Needs rebase to main

Development

Successfully merging this pull request may close these issues.

5 participants