Skip to content

gcoap: Forego IP address comparison in memo finding of multicasts#17978

Merged
chrysn merged 1 commit intoRIOT-OS:masterfrom
chrysn-pull-requests:gcoap-match-response-from-multicast
Aug 10, 2022
Merged

gcoap: Forego IP address comparison in memo finding of multicasts#17978
chrysn merged 1 commit intoRIOT-OS:masterfrom
chrysn-pull-requests:gcoap-match-response-from-multicast

Conversation

@chrysn
Copy link
Copy Markdown
Member

@chrysn chrysn commented Apr 21, 2022

Contribution description

gcoap's _find_req_memo compares tokens and IP addresses. That's generally a good thing, but when requests are sent to a multicast address, it is not right (RFC7252 has an explicit exception there).

There may be other areas of multicast support that are lacking, but this is a small enhancement step.

Testing procedure

Have a local CoAP server that responds to multicasts (aiocoap-fileserver will do, even though that might be a bug there, gotta check out whether it's supposed to do that by default).

$ make -C examples/gcoap
> coap get ff01::2 5683 /.well-known/core
</>;ct=40

Previously, the request timed out.

Note that good multicast behavior would be to accept several servers' responses, and (in the command line client) to show the address of the server where the response came from, both is left for further work.

Issues/PRs references

Brought up by ad6sh in https://forum.riot-os.org/t/coap-resource-discovery/3599; the testing instructions are his.

@chrysn chrysn added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Area: CoAP Area: Constrained Application Protocol implementations labels Apr 21, 2022
@github-actions github-actions bot added Area: network Area: Networking Area: sys Area: System labels Apr 21, 2022
@chrysn
Copy link
Copy Markdown
Member Author

chrysn commented Apr 21, 2022

I should also point out that this only detects IPv6 multicast addresses; IPv4 multicast (broadcast) is harder to detect, and out of scope here. (I prefer not to sink time into a protocol that should long have been sunset).

/* Multicast addresses are not considered in matching responses */
(
memo->remote_ep.family == AF_INET6 &&
ipv6_addr_is_multicast((const ipv6_addr_t *)&memo->remote_ep.addr.ipv6)
Copy link
Copy Markdown
Contributor

@benpicco benpicco Apr 21, 2022

Choose a reason for hiding this comment

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

Want to move that to a helper function? sock_udp_ep_is_multicast()
(Or just a local one - _ep_is_multicast())

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, that'd be a good idea; will update when I get back to it.

@benpicco
Copy link
Copy Markdown
Contributor

This just needs a tiny helper function to avoid cluttering the code like that

@benpicco
Copy link
Copy Markdown
Contributor

benpicco commented Aug 9, 2022

How about this patch

diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c
index e21f22211f..6c57929ebc 100644
--- a/sys/net/application_layer/gcoap/gcoap.c
+++ b/sys/net/application_layer/gcoap/gcoap.c
@@ -764,6 +764,12 @@ static int _find_resource(gcoap_socket_type_t tl_type,
     return ret;
 }
 
+static bool _memo_ep_is_multicast(const gcoap_request_memo_t *memo)
+{
+    return memo->remote_ep.family == AF_INET6 &&
+           ipv6_addr_is_multicast((const ipv6_addr_t *)&memo->remote_ep.addr.ipv6);
+}
+
 /*
  * Finds the memo for an outstanding request within the _coap_state.open_reqs
  * array. Matches on remote endpoint and token.
@@ -803,15 +809,10 @@ static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *src_pdu,
             }
         } else if (coap_get_token_len(memo_pdu) == cmplen) {
             memo_pdu->token = coap_hdr_data_ptr(memo_pdu->hdr);
-            if ((memcmp(src_pdu->token, memo_pdu->token, cmplen) == 0)
-                    && (
-                     sock_udp_ep_equal(&memo->remote_ep, remote) ||
-                     /* Multicast addresses are not considered in matching responses */
-                     (
-                      memo->remote_ep.family == AF_INET6 &&
-                      ipv6_addr_is_multicast((const ipv6_addr_t *)&memo->remote_ep.addr.ipv6)
-                     )
-                     )) {
+            if ((memcmp(src_pdu->token, memo_pdu->token, cmplen) == 0) &&
+                (sock_udp_ep_equal(&memo->remote_ep, remote) ||
+                 /* Multicast addresses are not considered in matching responses */
+                 _memo_ep_is_multicast(memo))) {
                 *memo_ptr = memo;
                 break;
             }

@chrysn chrysn force-pushed the gcoap-match-response-from-multicast branch from 6b09c84 to ab6bec6 Compare August 9, 2022 17:09
@chrysn
Copy link
Copy Markdown
Member Author

chrysn commented Aug 9, 2022

Thanks, I lost track of this one. Added your patch, and squashed onto current master to get rid of a merge conflict due to get_token now being an accessor.

@chrysn chrysn enabled auto-merge August 9, 2022 17:36
@chrysn chrysn merged commit 9ca149f into RIOT-OS:master Aug 10, 2022
@chrysn chrysn deleted the gcoap-match-response-from-multicast branch August 18, 2022 15:49
@maribu maribu added this to the Release 2022.10 milestone Oct 14, 2022
bors bot added a commit that referenced this pull request Feb 13, 2023
18257: drivers/wdt: add periph_wdt_auto_start for early watchdog r=benpicco a=benpicco



19272: gcoap: Do not send responses from multicast addresses r=chrysn a=chrysn

### Contribution description

Since #18026, CoAP requests to multicast addresses (eg. `ff02::1`) came back from that exact address, which Linux rightfully just drops.

The fix uses the existing multicast check from #17978 (thanks `@benpicco` for making me write this as dedicated function, I just had to generalize it removing one struct layer), and foregoes setting the source address when responding to multicasts.

### Testing procedure

* Run the gcoap example
* Send a CoAP request to a multicast address RIOT listens to, eg. `./aiocoap-client coap://'[ff02::1%tapbr0]'/.well-known/core --non`

Before, this got no response (while you see it arrive on wireshark). After, you get a correct response with two lines of note:

```
WARNING:coap:Sending request to multicast via unicast request method
Response arrived from different address; base URI is coap://[fe80::3c63:beff:fe85:ca96%tapbr0]/.well-known/core
```

(The former is aiocoap telling us that we're not using the nonexistent multicast API so it's really more of an anycast, the latter is useful factual information).

Co-authored-by: Benjamin Valentin <[email protected]>
Co-authored-by: chrysn <[email protected]>
bors bot added a commit that referenced this pull request Feb 14, 2023
19272: gcoap: Do not send responses from multicast addresses r=benpicco a=chrysn

### Contribution description

Since #18026, CoAP requests to multicast addresses (eg. `ff02::1`) came back from that exact address, which Linux rightfully just drops.

The fix uses the existing multicast check from #17978 (thanks `@benpicco` for making me write this as dedicated function, I just had to generalize it removing one struct layer), and foregoes setting the source address when responding to multicasts.

### Testing procedure

* Run the gcoap example
* Send a CoAP request to a multicast address RIOT listens to, eg. `./aiocoap-client coap://'[ff02::1%tapbr0]'/.well-known/core --non`

Before, this got no response (while you see it arrive on wireshark). After, you get a correct response with two lines of note:

```
WARNING:coap:Sending request to multicast via unicast request method
Response arrived from different address; base URI is coap://[fe80::3c63:beff:fe85:ca96%tapbr0]/.well-known/core
```

(The former is aiocoap telling us that we're not using the nonexistent multicast API so it's really more of an anycast, the latter is useful factual information).

Co-authored-by: chrysn <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: CoAP Area: Constrained Application Protocol implementations Area: network Area: Networking Area: sys Area: System CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants