Skip to content

rpl: read option address lengths in octets - #5262

Open
bIackr0se wants to merge 1 commit into
secdev:masterfrom
bIackr0se:fix/rpl-option-address-octets
Open

bIackr0se wants to merge 1 commit into
secdev:masterfrom
bIackr0se:fix/rpl-option-address-octets

Conversation

@bIackr0se

@bIackr0se bIackr0se commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Description

RPLOptRIO, RPLOptTgt and RPLOptTIO read their address from the wrong number of bytes. They use _IP6PrefixField, which reads the option length in 8-octet units as in IPv6 ND (inet6.py#L2031), while RPL option lengths count octets (RFC 6550, 6.7.1; 6.7.5 says "unlike in IPv6 ND"). A Target with len=18 followed by a Transit option without a parent address asks for 136 address bytes, gets the 22 bytes that remain, and the dissection fails, so the options are Raw. When the bytes the field takes do convert to an address, bytes of the following options can become part of it.

The fix adds an RPL field that takes len minus the fixed fields as the address size. Build output with an unset len is unchanged.

from scapy.all import load_contrib
from scapy.layers.inet6 import ICMPv6RPL
load_contrib("rpl")
p = ICMPv6RPL(bytes.fromhex(  # DAO: /64 RPL Target, then Transit Information
    "9b0255ec1e000009050a0040fd0000000000004206040000051e"))
print(repr(p.payload.payload))

Before:

<Raw  load=b'\x05\n\x00@\xfd\x00\x00\x00\x00\x00\x00B\x06\x04\x00\x00\x05\x1e' |>

After:

<RPLOptTgt  otype=RPL Target len=10 flags=0 plen=64 prefix=fd00:0:0:42:: |<Raw  load=b'\x06\x04\x00\x00\x05\x1e' |>>

In four RPL messages built by hand from RFC 6550 (Target /128 and /64, Transit Information with and without a parent address, Route Information /64), each option dissected at the start of the option area gives the prefixes, addresses and path fields that tshark decodes.

The option after the first one is still Raw: RPL options do not select the next option class, which is a separate fix.

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

RPLOptRIO, RPLOptTgt and RPLOptTIO used the IPv6 ND prefix field,
which reads the option length in 8-octet units. RPL option lengths
count octets (RFC 6550, 6.7.1), so the address field read the wrong
bytes: a Target followed by a Transit Information option fell back to
Raw, and bytes of following options could be read as part of the
address.

Use an RPL field that takes len minus the fixed fields as the address
size. Build output with an unset len is unchanged.

AI-Assisted: yes (Claude Opus 5.5, GPT-6.1 Sol)
@codecov

codecov Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.04%. Comparing base (57dd077) to head (1533ac6).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5262      +/-   ##
==========================================
- Coverage   80.55%   80.04%   -0.51%     
==========================================
  Files         375      375              
  Lines       98399    98417      +18     
==========================================
- Hits        79261    78774     -487     
- Misses      19138    19643     +505     
Files with missing lines Coverage Δ
scapy/contrib/rpl.py 98.80% <100.00%> (+0.32%) ⬆️

... and 20 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