+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+#ifndef IPV6_ADD_MEMBERSHIP
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+
+#ifndef IPV6_DROP_MEMBERSHIP
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+
+static const sockaddr_t mdns_address_ipv4 = {
+ .in.sin_family = AF_INET,
+ .in.sin_addr.s_addr = 0xfb0000e0,
+ .in.sin_port = 0xe914,
+};
+
+static const sockaddr_t mdns_address_ipv6 = {
+ .in6.sin6_family = AF_INET6,
+ .in6.sin6_addr.s6_addr[0x0] = 0xff,
+ .in6.sin6_addr.s6_addr[0x1] = 0x02,
+ .in6.sin6_addr.s6_addr[0xf] = 0xfb,
+ .in6.sin6_port = 0xe914,
+};
+
+typedef struct discovery_address {
+ int index;
+ bool up;
+ sockaddr_t address;
+ time_t last_response_sent;
+} discovery_address_t;
+
+static int iface_compare(const void *va, const void *vb) {
+ const int *a = va;
+ const int *b = vb;
+ return *a - *b;
+}
+
+static int address_compare(const void *va, const void *vb) {
+ const discovery_address_t *a = va;
+ const discovery_address_t *b = vb;
+
+ if(a->index != b->index) {
+ return a->index - b->index;
+ }
+
+ return sockaddrcmp_noport(&a->address, &b->address);
+}
+
+static void send_mdns_packet_ipv4(meshlink_handle_t *mesh, int fd, int index, const sockaddr_t *src, const sockaddr_t *dest, void *data, size_t len) {
+#ifdef IP_MULTICAST_IF
+ struct ip_mreqn mreq = {
+ .imr_address = src->in.sin_addr,
+ .imr_ifindex = index,
+ };
+
+ if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) != 0) {
+ logger(mesh, MESHLINK_ERROR, "Could not set outgoing multicast interface on IPv4 socket");
+ return;