Skip to content

rpl_metrics: read an unknown metric object with its 4-octet header - #5299

Open
bIackr0se wants to merge 1 commit into
secdev:masterfrom
bIackr0se:fix/rpl-unknown-metric
Open

bIackr0se wants to merge 1 commit into
secdev:masterfrom
bIackr0se:fix/rpl-unknown-metric

Conversation

@bIackr0se

Copy link
Copy Markdown
Contributor

Description

A DAG Metric Container object of a type scapy has no class for (anything other than types 1 to 8) is read with the wrong header, and the objects after it are lost. Every routing metric or constraint object starts with Type, 16 bits of flags and a Length octet, then Length octets of body (RFC 6551, 2.1). DAGMCObjUnknown read a length octet right after Type, so it took the first flags octet as its length and the following object became part of its data or its payload.

DAGMCObjUnknown now subclasses DAGMCObj, so it has the common header, and its odata holds Length octets of body. olen is kept as a deprecated name of len. A built unknown object now writes the 4-octet header (09 00 00 02 ab cd for type 9 with body ab cd, where 09 02 ab cd was written before), and its default otype is the DAGMCObj default 0 instead of 3 (Hop Count, which has its own class).

from scapy.all import load_contrib
load_contrib("rpl")
load_contrib("rpl_metrics")
from scapy.contrib.rpl_metrics import RPLOptDAGMC
# Hop Count 3, an object of type 9 with an empty body, Link ETX 256
p = RPLOptDAGMC(bytes.fromhex("021003000002000309000000070000020100"))
print([o.name for o in p.options])

Before:

['Hop Count', 'Unknown DAGMC Object Option']

After:

['Hop Count', 'Unknown DAGMC Object Option', 'Link ETX']

tshark 4.6.9 decodes that container as the same three objects. With a non-empty unknown body, tshark reads the same 4-octet header but does not skip the body (the default branch of its metric loop does not advance), so the split there follows the RFC Length. A test is added to test/contrib/rpl.uts.

This message was written with the help of AI (Claude Opus 5.5).

Every routing metric or constraint object starts with Type, 16 bits of
flags and a Length octet, then Length octets of body (RFC 6551, 2.1).
DAGMCObjUnknown, used for types without their own class, read a
1-octet length right after Type, so it took the first flags octet as
its length: an object of type 9 with a 2-octet body ended after its
header and the Hop Count after it became part of its data. The class
now has the common header of DAGMCObj and a body of Length octets.
olen stays as a deprecated name of len.

AI-Assisted: yes (Claude Opus 5.5)
@codecov

codecov Bot commented Nov 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.14%. Comparing base (0e2f6ba) to head (6fe6526).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5299      +/-   ##
==========================================
+ Coverage   80.06%   80.14%   +0.08%     
==========================================
  Files         375      375              
  Lines       98775    98776       +1     
==========================================
+ Hits        79083    79168      +85     
+ Misses      19692    19608      -84     
Files with missing lines Coverage Δ
scapy/contrib/rpl_metrics.py 100.00% <100.00%> (+1.31%) ⬆️

... and 15 files with indirect coverage changes

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

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.

1 participant