aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2026-06-09 14:16:25 +1000
committerDavid Gibson <david@gibson.dropbear.id.au>2026-06-09 14:16:25 +1000
commit2c69b4b7b19420a32bf169c4a1082e5fccfa976d (patch)
treede73ac47980ed582f2b470b8ca85a2463c4203ca
parentdd8923b8adb9ab1e1ad79727ee0a912131f6e2cb (diff)
downloadpasst-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/.gitignore1
-rw-r--r--doc/platform-requirements/Makefile4
-rw-r--r--doc/platform-requirements/common.h2
-rw-r--r--doc/platform-requirements/multicast-local-addr.c135
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);
+}