Server sessions are keyed on (remote address, local port) only, and
session->addr_info.local is overwritten by the destination of every
received packet. When a unicast CON request is parked in a coap_async_t
for a separate response and a multicast packet from the same peer
arrives before the async fires, the re-invoked handle_request() sees a
multicast local address, drops the CON per RFC7252 8.1 ("Invalid
multicast packet received"), and coap_check_async() frees the async:
the response is silently never sent.
Snapshot the local address in coap_register_async() and restore it on
the session before the async fires, so the deferred request is handled
(and its response source selected) against the address it actually
arrived on.
Seen in the field with a CoAP remote control whose GET /endpoint was
answered via the async path while it also multicast periodic
announcements from the same source port: the device received the empty
ACK and then never got the response.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Support matching multiple, space separated, values, not limited to if=, rt= and rel=.
Fix OOB read if the last space separated value is shorter than the query.
Support matching against multiple queries.
Do not sent back empty 2.05 response if multicast.
CBOR array and map counts can exceed UINT16_MAX. The uint16_t loop counters
then wrap and never reach the advertised count, causing a CWE-835 denial of
service.
Use size_t loop counters and reject counts that cannot fit in the remaining
buffer at the minimum encoding size of one byte per array element or two
bytes per map pair. Propagate malformed-value errors and cover large
malformed containers and valid values over 64 KiB with regression tests.
In the "match attribute" branch of coap_print_wellknown_lkd(), an
attribute value shorter than 2 bytes (e.g. a lone " registered via
coap_add_attr()) causes attr->value->s[0] == '"' to read past the
value, and unquoted_val.length -= 2 to underflow the size_t length
to SIZE_MAX. The resulting bogus coap_str_const_t is then passed to
match(), which dereferences memory far outside the original buffer.
Guard the quote-check on length >= 2 before reading s[0], mirroring
the length && ... guard already used a few lines above for
query_pattern (added in #1977) and the trailing-'*' guard next to
it.
Reproduced with a standalone harness placing a 1-byte attribute
value at the end of a guard-paged region: pre-fix, unquoted_val.length
becomes SIZE_MAX and match() crashes on the guard page; post-fix,
length stays at the original value (no underflow) and match() safely
short-circuits. A normal quoted value ("foo", 5 bytes) still strips
to foo (3 bytes) unchanged, confirming no regression.
Clean up duplicate MID handling, and just send back last response if MID
matches.
Removed COAP_BLOCK_CACHE_RESPONSE as no longer required for duplicate MID
handling, and so no need to send an Empty ACK response for a subsequent
Separate response as a referenced copy of the last PDU respponse is now kept
for a session.
Note that if a request is sent by a proxy to an upstream server, this always
converts the upstream server's response into a Separate response back to the
client as the upstream server may take time to respond, do any error recovery
etc.
This allows (D)TLS1.3 to be negotiated when using PSK.
If '-i match_identity_file' is being used, the hint is taken from the first
entry if not otherwise defined by '-h hint'.