diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2026-06-09 14:16:25 +1000 |
|---|---|---|
| committer | David Gibson <david@gibson.dropbear.id.au> | 2026-06-09 14:16:25 +1000 |
| commit | 2c69b4b7b19420a32bf169c4a1082e5fccfa976d (patch) | |
| tree | de73ac47980ed582f2b470b8ca85a2463c4203ca | |
| parent | dd8923b8adb9ab1e1ad79727ee0a912131f6e2cb (diff) | |
| download | passt-podman23739.tar passt-podman23739.tar.gz passt-podman23739.tar.bz2 passt-podman23739.tar.lz passt-podman23739.tar.xz passt-podman23739.tar.zst passt-podman23739.zip | |
Check behaviour of connect() with multicast destinationspodman23739
Work in progress debugging patch.
| -rw-r--r-- | doc/platform-requirements/.gitignore | 1 | ||||
| -rw-r--r-- | doc/platform-requirements/Makefile | 4 | ||||
| -rw-r--r-- | doc/platform-requirements/common.h | 2 | ||||
| -rw-r--r-- | doc/platform-requirements/multicast-local-addr.c | 135 |
4 files changed, 140 insertions, 2 deletions
diff --git a/doc/platform-requirements/.gitignore b/doc/platform-requirements/.gitignore index b2a0069..e426db9 100644 --- a/doc/platform-requirements/.gitignore +++ b/doc/platform-requirements/.gitignore @@ -3,3 +3,4 @@ /recv-zero /tcp-close-rst /udp-close-dup +/multicast-local-addr diff --git a/doc/platform-requirements/Makefile b/doc/platform-requirements/Makefile index 204341b..dae7e58 100644 --- a/doc/platform-requirements/Makefile +++ b/doc/platform-requirements/Makefile @@ -4,9 +4,9 @@ # Author: David Gibson <david@gibson.dropbear.id.au> TARGETS = reuseaddr-priority recv-zero udp-close-dup listen-vs-repair \ - tcp-close-rst + tcp-close-rst multicast-local-addr SRCS = reuseaddr-priority.c recv-zero.c udp-close-dup.c listen-vs-repair.c \ - tcp-close-rst.c + tcp-close-rst.c multicast-local-addr.c CFLAGS = -Wall all: cppcheck clang-tidy $(TARGETS:%=check-%) diff --git a/doc/platform-requirements/common.h b/doc/platform-requirements/common.h index e85fc2b..016ab2e 100644 --- a/doc/platform-requirements/common.h +++ b/doc/platform-requirements/common.h @@ -15,6 +15,8 @@ #include <stdio.h> #include <stdlib.h> +#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0]))) + __attribute__((format(printf, 1, 2), noreturn)) static inline void die(const char *fmt, ...) { diff --git a/doc/platform-requirements/multicast-local-addr.c b/doc/platform-requirements/multicast-local-addr.c new file mode 100644 index 0000000..222b291 --- /dev/null +++ b/doc/platform-requirements/multicast-local-addr.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* multicast-local-addr.c + * + * Check behaviour of local address assignment when sending to multicast + * destinations. + * + * Copyright Red Hat + * Author: David Gibson <david@gibson.dropbear.id.au> + */ + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "common.h" + +static struct sockaddr_in6 sa6_from_str(const char *addr, in_port_t port) +{ + struct sockaddr_in6 sa = { + .sin6_family = AF_INET6, + .sin6_port = htons(port), + }; + + if (!inet_pton(AF_INET6, addr, &sa.sin6_addr)) + die("Couldn't parse address %s\n", addr); + + return sa; +} + +#define INET6_SADDRSTRLEN (INET6_ADDRSTRLEN + 7) + +static const char *str_from_sa6(const struct sockaddr_in6 *sa, + char *buf, size_t size) +{ + char astr[INET6_ADDRSTRLEN]; + + if (!sa) { + if (snprintf(buf, size, "[*]:?") >= size) + die("Failed to format address"); + return buf; + } + + if (!inet_ntop(AF_INET6, &sa->sin6_addr, astr, sizeof(astr))) + die("Failed to format address"); + + if (snprintf(buf, size, "[%s]:%hu", astr, ntohs(sa->sin6_port)) >= size) + die("Failed to format address"); + + return buf; +} + +/* Address used by bittorrent for local peer discovery + * This is a site-local multicast address. + */ +#define BITTORRENT_PORT 6771 +#define BITTORRENT_MC sa6_from_str("ff15::efc0:988f", BITTORRENT_PORT) + +static void test_one(const struct sockaddr_in6 local, + const struct sockaddr_in6 remote, + int do_connect) +{ + char lstr[INET6_SADDRSTRLEN], rstr[INET6_SADDRSTRLEN]; + struct sockaddr_in6 la; + socklen_t addrlen = sizeof(la); + const char data[] = "TEST"; + int s; + + printf("Testing %s -> %s %s\n", str_from_sa6(&local, lstr, sizeof(lstr)), + str_from_sa6(&remote, rstr, sizeof(rstr)), + do_connect ? "(connected)" : ""); + + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) + die("socket() failed: %s\n", strerror(errno)); + + if (bind(s, (const struct sockaddr *)&local, sizeof(local))) + die("bind() to %s failed: %s\n", lstr, strerror(errno)); + if (do_connect && + connect(s, (const struct sockaddr *)&remote, sizeof(remote))) + die("connect() to %s failed: %s\n", rstr, strerror(errno)); + + if (do_connect) { + if (send(s, data, sizeof(data), 0) < 0) + die("send() failed: %s\n", strerror(errno)); + } else { + if (sendto(s, data, sizeof(data), 0, + (const struct sockaddr *)&remote, sizeof(remote)) < 0) + die("sendto() failed: %s\n", strerror(errno)); + } + + if (getsockname(s, (struct sockaddr *)&la, &addrlen)) + die("getsockname() failed: %s\n", strerror(errno)); + + printf("Final local address: %s\n", + str_from_sa6(&la, lstr, sizeof(lstr))); + close(s); +} + +static void test_dest(const struct sockaddr_in6 remote) +{ + in_port_t rport = ntohs(remote.sin6_port); + const char *srcaddr[] = {"::", "::1"}; + const in_port_t srcport[] = {0, rport}; + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(srcaddr); i++) { + for (j = 0; j < ARRAY_SIZE(srcport); j++) { + struct sockaddr_in6 local; + + local = sa6_from_str(srcaddr[i], srcport[j]); + + for (k = 0; k <= 1; k++) + test_one(local, remote, k); + } + } +} + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + test_dest(BITTORRENT_MC); + + printf("So far so good\n"); + exit(0); +} |
