Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Conversation

chrysn
Copy link
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
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
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
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
Contributor

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

@benpicco
Copy link
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;
             }

Co-Authored-By: Benjamin Valentin <benjamin.valentin@ml-pa.com>
@chrysn chrysn force-pushed the gcoap-match-response-from-multicast branch from 6b09c84 to ab6bec6 Compare August 9, 2022 17:09
@chrysn
Copy link
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 <benjamin.valentin@ml-pa.com>
Co-authored-by: chrysn <chrysn@fsfe.org>
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 <chrysn@fsfe.org>
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