Skip to content

Follow-up: Added CoAP socket #4334#5002

Open
polybassa wants to merge 8 commits into
secdev:masterfrom
polybassa:coap_socket_2
Open

Follow-up: Added CoAP socket #4334#5002
polybassa wants to merge 8 commits into
secdev:masterfrom
polybassa:coap_socket_2

Conversation

@polybassa
Copy link
Copy Markdown
Contributor

Description

This PR implements a CoAP socket, pretty similar on how ISOTPSoftSocket works.
I implemented the basic message exchange, mostly based on the RFC-7252.

  • Congestion control
  • Retransmission mechanism
  • Separate responses
  • Message duplication detection

Known-limitations

  • No POST and DELETE methods
  • No DTLS
  • No discovery via multicast/broadcast, although you can still bind to one of these interfaces
  • No observer
  • The SR/SR1 functions cannot handle separate responses.

General comments

It has a dependency for from scapy.contrib.isotp.isotp_soft_socket import TimeoutScheduler, I found nice how this is implemented, so I just used it, I didn't want to copy/paste again.

Also I added some unit tests for the basic cases.

Quick usage

Client example:
    >>> with CoAPSocket("127.0.0.1", 1234) as coap_client:
    >>>     req = CoAPSocket.make_coap_req_packet(method=GET, uri="endpoint-uri", payload=b"")
    >>>     coap_client.send("127.0.0.1", 5683, req)
    >>>     res = coap_client.recv() # Careful, this will block until the coap_client receives something

Server without specifying resources:
    >>> with CoAPSocket("127.0.0.1", 5683) as coap_server:
    >>>     while True:
    >>>         pkg = coap_server.recv()
    >>>         handle_package(pkg)

Server with custom resources:
    >>> class DummyResource(CoAPResource):
    >>>     def get(self, payload, options, token, sa_ll):
    >>>         return {"type": ACK, "code": CONTENT_205, "options": [(CONTENT_FORMAT, CF_TEXT_PLAIN)], "payload": b'dummy response'}
    >>>
    >>> class DelayedResource(CoAPResource):
    >>>     def __init__(self, url):
    >>>         CoAPResource.__init__(self, url=url)
    >>>         self.delayed_tokens = []
    >>>
    >>>     def delayed_message(self):
    >>>         token, address = self.delayed_tokens.pop(0)
    >>>         pkt = CoAPSocket.make_delayed_resp_packet(token, [(CONTENT_FORMAT, CF_TEXT_PLAIN)], b"delayed payload")
    >>>         self._send_separate_response(pkt, address)
    >>>
    >>>     def get(self, payload, options, token, sa_ll):
    >>>         # We know that this can take a while, so we return an empty ACK now and wait for whatever resource to be available.
    >>>         TimeoutScheduler.schedule(1, self.delayed_message)
    >>>         self.delayed_tokens.append((token, sa_ll))
    >>>         return CoAPSocket.empty_ack_params()
    >>>
    >>> # Doesn't matter if it starts with "/dummy" or "dummy", but it is an error if it is in the end
    >>> lst_resources = [DummyResource("dummy"), DelayedResource("/delayed")].
    >>> with CoAPSocket("127.0.0.1", 5683, lst_resources=lst_resources) as coap_socket:
    >>>     while True:
    >>>         pkg = coap_socket.recv()
    >>>         # You can handle the packages inside your resources, here will only be the "unhandled" ones.

This follow-up reintegrates master and adds additional unit tests

@polybassa
Copy link
Copy Markdown
Contributor Author

@gpotter2 How to add the "AI Trailer" the "old" commits which were created 2 years ago?

@gpotter2
Copy link
Copy Markdown
Member

You can git rebase -i and use "edit" to change the commit. It's a bit annoying sorry :/

@polybassa
Copy link
Copy Markdown
Contributor Author

Ok, that should work. I just disliked changing to much of the history.

What do you think about a start date? Like only commits from 2026 onward are filtered by the script?

@gpotter2
Copy link
Copy Markdown
Member

Ok, that should work. I just disliked changing to much of the history.

What do you think about a start date? Like only commits from 2026 onward are filtered by the script?

Sure that's a good idea.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new CoAP socket implementation to Scapy’s contrib layer, expanding CoAP support beyond packet parsing to include client/server exchanges (retransmissions, separate responses, duplicate detection), and introduces regression + interop tests (libcoap) with CI support.

Changes:

  • Introduce scapy.contrib.coap_socket implementing a CoAP-aware SuperSocket with resource handling and basic retransmission/separate-response behavior.
  • Extend scapy.contrib.coap with exported CoAP constants plus hashret() / answers() to improve request/response matching in Scapy send/recv workflows.
  • Add UTScapy regression + libcoap interoperability/stress tests and install libcoap binaries in CI.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.

File Description
scapy/contrib/coap_socket.py New CoAP socket implementation (client/server, resources, retransmission, separate responses).
scapy/contrib/coap.py Adds exported constants and response-matching helpers (hashret, answers).
test/contrib/coap_socket.uts New UTScapy regression + libcoap interoperability/stress tests for CoAPSocket.
.config/ci/install.sh Installs libcoap binaries for CI to enable interop tests.

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

Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py Outdated
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread scapy/contrib/coap_socket.py
Comment thread test/contrib/coap_socket.uts
eHonnef and others added 8 commits May 26, 2026 07:35
Fixing response payload

Some docstring and bug fixes.

Finished CoAP server logic implementation

Added client interaction

Client/Server done.

Added delayed response handling

Fixing small problems

Unit tests

Documentation

AI-Assisted: no
- Moved the defines/enumerators to coap.py
- Changed the send() function to match the SuperSocket declaration
- Updated unit tests

AI-Assisted: no
- Implemented coap.answers function
- Fixed some types
- Remove unnecessary override
- Changed sr and sr1 functions signatures.

AI-Assisted: no
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

AI-Assisted: yes (GitHub CoPilot Auto)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

AI-Assisted: yes (GitHub CoPilot Auto)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

AI-Assisted: yes (GitHub CoPilot Auto)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind((self.ip, self.port))
@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

❌ Patch coverage is 89.74943% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.03%. Comparing base (30c07a1) to head (93ce604).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
scapy/contrib/coap_socket.py 89.05% 44 Missing ⚠️
scapy/contrib/coap.py 97.29% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5002      +/-   ##
==========================================
- Coverage   80.29%   80.03%   -0.27%     
==========================================
  Files         383      384       +1     
  Lines       95163    95601     +438     
==========================================
+ Hits        76407    76510     +103     
- Misses      18756    19091     +335     
Files with missing lines Coverage Δ
scapy/contrib/coap.py 95.91% <97.29%> (+0.42%) ⬆️
scapy/contrib/coap_socket.py 89.05% <89.05%> (ø)

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

5 participants