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

gnrc_sock_udp: accept response from any address if remote is multicast #18854

Merged
merged 3 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion sys/include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ extern "C" {
* @anchor net_sock_flags
* @{
*/
#define SOCK_FLAGS_REUSE_EP (0x0001) /**< allow to reuse end point on bind */
#define SOCK_FLAGS_REUSE_EP (0x0001) /**< allow to reuse end point on bind */
#define SOCK_FLAGS_CONNECT_REMOTE (0x0002) /**< restrict responses to remote address */
/** @} */

/**
Expand Down
48 changes: 41 additions & 7 deletions sys/net/gnrc/sock/udp/gnrc_sock_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@

#include "gnrc_sock_internal.h"

#define ENABLE_DEBUG 0
#include "debug.h"

#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
static sock_udp_t *_udp_socks = NULL;
#endif
Expand Down Expand Up @@ -133,6 +136,12 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
}
gnrc_ep_set((sock_ip_ep_t *)&sock->remote,
(sock_ip_ep_t *)remote, sizeof(sock_udp_ep_t));

/* only accept responses from the set remote */
if (!ipv6_addr_is_multicast((ipv6_addr_t *)&remote->addr) &&
!ipv6_addr_is_unspecified((ipv6_addr_t *)&remote->addr)) {
flags |= SOCK_FLAGS_CONNECT_REMOTE;
}
}
if (local != NULL) {
/* listen only with local given */
Expand Down Expand Up @@ -197,6 +206,37 @@ ssize_t sock_udp_recv_aux(sock_udp_t *sock, void *data, size_t max_len,
return (nobufs) ? -ENOBUFS : ((res < 0) ? res : ret);
}

static bool _remote_accept(const sock_udp_t *sock, const udp_hdr_t *hdr,
const sock_ip_ep_t *remote)
{
if ((sock->flags & SOCK_FLAGS_CONNECT_REMOTE) == 0) {
/* socket is not bound to a remote */
return true;
}

if (sock->remote.family == AF_UNSPEC) {
/* socket accepts any remote */
return true;
}

if (sock->remote.port != byteorder_ntohs(hdr->src_port)) {
DEBUG("gnrc_sock_udp: port mismatch (%u != %u)\n",
sock->remote.port, byteorder_ntohs(hdr->src_port));
return false;
}

if (memcmp(&sock->remote.addr, &remote->addr, sizeof(ipv6_addr_t)) != 0) {
char addr_str[IPV6_ADDR_MAX_STR_LEN];
DEBUG("gnrc_sock_udp: socket bound to address %s",
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)&sock->remote.addr, sizeof(addr_str)));
DEBUG(", source (%s) does not match\n",
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)&remote->addr, sizeof(addr_str)));
return false;
}

return true;
}

ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
uint32_t timeout, sock_udp_ep_t *remote,
sock_udp_aux_rx_t *aux)
Expand Down Expand Up @@ -246,13 +286,7 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
memcpy(remote, &tmp, sizeof(tmp));
remote->port = byteorder_ntohs(hdr->src_port);
}
if ((sock->remote.family != AF_UNSPEC) && /* check remote end-point if set */
((sock->remote.port != byteorder_ntohs(hdr->src_port)) ||
/* We only have IPv6 for now, so just comparing the whole end point
* should suffice */
((memcmp(&sock->remote.addr, &ipv6_addr_unspecified,
sizeof(ipv6_addr_t)) != 0) &&
(memcmp(&sock->remote.addr, &tmp.addr, sizeof(ipv6_addr_t)) != 0)))) {
if (!_remote_accept(sock, hdr, &tmp)) {
gnrc_pktbuf_release(pkt);
return -EPROTO;
}
Expand Down
20 changes: 20 additions & 0 deletions tests/gnrc_sock_udp/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,25 @@ static void test_sock_udp_recv__EPROTO(void)
expect(_check_net());
}

static void test_sock_udp_recv__multicast(void)
{
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_WRONG };
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
static const sock_udp_ep_t local = { .family = AF_INET6,
.port = _TEST_PORT_LOCAL };
static const sock_udp_ep_t remote = { .addr = IPV6_ADDR_ALL_NODES_LINK_LOCAL,
.family = AF_INET6,
.port = _TEST_PORT_REMOTE };

expect(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
expect(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
_TEST_NETIF));
expect(5 == sock_udp_recv(&_sock, _test_buffer, sizeof(_test_buffer),
SOCK_NO_TIMEOUT, NULL));
expect(_check_net());
}

static void test_sock_udp_recv__ETIMEDOUT(void)
{
static const sock_udp_ep_t local = { .family = AF_INET6, .netif = _TEST_NETIF,
Expand Down Expand Up @@ -819,6 +838,7 @@ int main(void)
CALL(test_sock_udp_recv__EAGAIN());
CALL(test_sock_udp_recv__ENOBUFS());
CALL(test_sock_udp_recv__EPROTO());
CALL(test_sock_udp_recv__multicast());
CALL(test_sock_udp_recv__ETIMEDOUT());
CALL(test_sock_udp_recv__socketed());
CALL(test_sock_udp_recv__socketed_with_remote());
Expand Down