Skip to content

fix: reject unknown critical options - #674

Open
jkralik wants to merge 1 commit into
masterfrom
fix/issue-666
Open

jkralik wants to merge 1 commit into
masterfrom
fix/issue-666

Conversation

@jkralik

@jkralik jkralik commented Jul 5, 2026

Copy link
Copy Markdown
Member

Fixes #666

Enforce RFC 7252 behavior for unrecognized critical options by returning 4.02 Bad Option before application handlers are invoked, preventing unintended resource mutation.

Summary by CodeRabbit

  • New Features
    • Added detection of unknown critical CoAP options and automatic request rejection with a Bad Option response.
    • Applies to both TCP and UDP; UDP responds with an acknowledgement and text/plain diagnostic listing the unknown option IDs.
  • Tests
    • Added unit tests covering unknown-option detection and diagnostic formatting.
    • Added TCP and UDP integration tests verifying rejected requests return Bad Option and do not modify stored data.

Copilot AI review requested due to automatic review settings July 5, 2026 13:12
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a shared helper to detect and format unknown critical CoAP options, then updates TCP and UDP client request handling to reject matching requests with Bad Option responses and diagnostic payloads. Adds unit and integration tests covering the rejection behavior and unchanged stored state.

Changes

Unknown critical option rejection

Layer / File(s) Summary
Critical option detection and diagnostic helper
net/client/criticalOptions.go, net/client/criticalOptions_test.go
Adds GetUnknownCriticalOptions to find unrecognized odd-numbered critical option IDs and FormatUnknownCriticalOptionsDiagnostic to build a diagnostic string, with unit tests.
TCP session Bad Option handling
tcp/client/session.go, tcp/client_test.go
Refactors TCP session buffering and request handling to reject GET–DELETE requests with unknown critical options, sends a BadOption response with a diagnostic body, and verifies the /store handler does not change state.
UDP conn Bad Option handling
udp/client/conn.go, udp/client_test.go
Checks Confirmable UDP requests for unknown critical options, sends an ACK with codes.BadOption via new respondUnknownCriticalOptions, and verifies raw datagram handling leaves /store state unchanged.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: rejecting unknown critical options.
Linked Issues check ✅ Passed [#666] The fix returns 4.02 Bad Option, preserves /store, and adds diagnostics/tests for unknown critical options #99 and #13.
Out of Scope Changes check ✅ Passed The changes stay focused on critical-option rejection and supporting tests/helpers, with no clear unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-666

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

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.

Pull request overview

This PR addresses RFC 7252 handling of unrecognized critical CoAP options by detecting them early in the UDP/TCP receive paths and returning 4.02 Bad Option (with a diagnostic payload) before application handlers run, preventing unintended resource mutation (Fixes #666).

Changes:

  • Add shared utilities to detect unknown critical options and format a diagnostic message.
  • Reject inbound requests containing unknown critical options in UDP and TCP processing paths by responding with 4.02 Bad Option.
  • Add regression tests for UDP and TCP that reproduce the reported /store mutation scenario and assert it no longer occurs.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
udp/client/conn.go Adds early rejection and immediate 4.02 Bad Option response for unknown critical options (UDP).
udp/client/conn_test.go Adds UDP regression test using raw datagrams to verify rejection and no /store mutation.
tcp/client/session.go Adds early rejection and 4.02 Bad Option response for unknown critical options (TCP).
tcp/client_test.go Adds TCP regression test verifying rejection and no /store mutation.
net/client/criticalOptions.go Introduces shared logic to detect unknown critical options and format a diagnostic string.
net/client/criticalOptions_test.go Adds unit tests for the new critical-options helper functions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread udp/client/conn.go Outdated
@codecov-commenter

codecov-commenter commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.20833% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.60%. Comparing base (2b26f76) to head (e0bbff2).

Files with missing lines Patch % Lines
tcp/client/session.go 70.68% 9 Missing and 8 partials ⚠️
udp/client/conn.go 90.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master     #674   +/-   ##
=======================================
  Coverage   76.60%   76.60%           
=======================================
  Files          77       78    +1     
  Lines        6095     6172   +77     
=======================================
+ Hits         4669     4728   +59     
- Misses       1042     1053   +11     
- Partials      384      391    +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

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

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
udp/client/conn_test.go (1)

944-959: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider documenting the raw hex payloads.

The crafted rawRequestHex values encode specific option layouts (Content-Format then option 99 / option 13) that are easy to get wrong when edited. A short comment breaking down the byte layout (header, token, URI-Path, Content-Format, the injected option) would help future maintainers avoid needing to hand-decode CoAP wire bytes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@udp/client/conn_test.go` around lines 944 - 959, Add a brief comment near the
test cases in conn_test.go explaining how each rawRequestHex is structured at
the CoAP wire level, including the header, token, URI-Path, Content-Format, and
the injected unknown option (99 or 13). Keep the existing test data, but
document the byte layout around the testCases definition so future edits can
verify the intended option ordering in the unknown critical option cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@udp/client/conn.go`:
- Around line 938-945: The unknown critical option rejection in
cc.respondUnknownCriticalOptions is only applied in the req.Type() ==
message.Confirmable branch, so NonConfirmable requests can still reach dispatch.
Update the request handling in udp/client/conn.go to check
client.GetUnknownCriticalOptions(req.Options()) for both Confirmable and
NonConfirmable messages before any handler dispatch, and keep the existing
ReleaseMessage/return flow when rejecting.

---

Nitpick comments:
In `@udp/client/conn_test.go`:
- Around line 944-959: Add a brief comment near the test cases in conn_test.go
explaining how each rawRequestHex is structured at the CoAP wire level,
including the header, token, URI-Path, Content-Format, and the injected unknown
option (99 or 13). Keep the existing test data, but document the byte layout
around the testCases definition so future edits can verify the intended option
ordering in the unknown critical option cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 495ff772-52b7-4f63-b57f-df5a00035cc5

📥 Commits

Reviewing files that changed from the base of the PR and between 2b26f76 and 644f52e.

📒 Files selected for processing (6)
  • net/client/criticalOptions.go
  • net/client/criticalOptions_test.go
  • tcp/client/session.go
  • tcp/client_test.go
  • udp/client/conn.go
  • udp/client/conn_test.go

Comment thread udp/client/conn.go Outdated
Fixes #666

Enforce RFC 7252 behavior for unrecognized critical options by
returning 4.02 Bad Option before application handlers are invoked,
preventing unintended resource mutation.t

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (2)
tcp/client/session.go (2)

230-262: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for the error branches flagged by coverage.

Codecov reports 2 missing and 2 partial lines in this file. Likely candidates are the header-decode error path, the max-message-size-exceeded path in decodeMessageFromBuffer (Lines 172-177), and/or the WriteMessage failure path in respondUnknownCriticalOptions (Line 261-263). Adding targeted unit tests for these branches would close the coverage gap on this newly refactored, security-relevant code path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tcp/client/session.go` around lines 230 - 262, Add targeted tests for the
uncovered error branches in Session.processBuffer, decodeMessageFromBuffer, and
respondUnknownCriticalOptions. Cover the header-decode failure path and the
max-message-size-exceeded branch in decodeMessageFromBuffer, and also force
WriteMessage to fail in respondUnknownCriticalOptions so the wrapped error path
is exercised. Use the existing Session, decodeMessageFromBuffer, processBuffer,
and respondUnknownCriticalOptions symbols to locate the code and assert the
returned errors and cleanup behavior.

194-206: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Critical-option check excludes RFC 8132 extended methods.

The check only runs for codes in [codes.GET, codes.DELETE] (1–4), so FETCH/PATCH/iPATCH (RFC 8132 extended methods, codes 5–7) bypass unknown-critical-option rejection and would still reach the handler. Since RFC 7252 §5.4.1 requires this behavior for any request with a critical option it doesn't recognize/handle, not just the base four methods, consider widening the guard if these extended methods are supported by this server.

♻️ Possible widening (verify extended method support first)
-	if req.Code() < codes.GET || req.Code() > codes.DELETE {
+	if req.Code() < codes.GET || req.Code() > codes.IPATCH {
 		return false, nil
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tcp/client/session.go` around lines 194 - 206, The critical-option gate in
shouldDropRequest only covers the base CoAP methods and skips RFC 8132 extended
methods, so requests like FETCH, PATCH, and iPATCH can bypass
unknown-critical-option rejection. Update the method-range guard in
Session.shouldDropRequest to include any supported extended methods as well,
while still preserving the existing unknown-critical-option response path via
respondUnknownCriticalOptions and GetUnknownCriticalOptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tcp/client/session.go`:
- Around line 230-262: Add targeted tests for the uncovered error branches in
Session.processBuffer, decodeMessageFromBuffer, and
respondUnknownCriticalOptions. Cover the header-decode failure path and the
max-message-size-exceeded branch in decodeMessageFromBuffer, and also force
WriteMessage to fail in respondUnknownCriticalOptions so the wrapped error path
is exercised. Use the existing Session, decodeMessageFromBuffer, processBuffer,
and respondUnknownCriticalOptions symbols to locate the code and assert the
returned errors and cleanup behavior.
- Around line 194-206: The critical-option gate in shouldDropRequest only covers
the base CoAP methods and skips RFC 8132 extended methods, so requests like
FETCH, PATCH, and iPATCH can bypass unknown-critical-option rejection. Update
the method-range guard in Session.shouldDropRequest to include any supported
extended methods as well, while still preserving the existing
unknown-critical-option response path via respondUnknownCriticalOptions and
GetUnknownCriticalOptions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8992432-23fa-4605-8faf-8c3f93db0146

📥 Commits

Reviewing files that changed from the base of the PR and between bd87118 and e0bbff2.

📒 Files selected for processing (6)
  • net/client/criticalOptions.go
  • net/client/criticalOptions_test.go
  • tcp/client/session.go
  • tcp/client_test.go
  • udp/client/conn.go
  • udp/client/conn_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • tcp/client_test.go
  • net/client/criticalOptions_test.go
  • net/client/criticalOptions.go
  • udp/client/conn_test.go
  • udp/client/conn.go

@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PUT with unknown critical options #99/#13 updates /store instead of returning 4.02 Bad Option

3 participants