Search code examples
crustjvmipv6mdns

UDP mDNS on MacOS using C, Rust, JVM - Packets not being received


I'll do my best to keep it short.

  • While implementing multicast DNS protocols, I'm unable to listen to multicast DNS in either C or rust (However in JVM it works perfectly fine)
  • I am watching network using Wireshark
  • I've tried disabling firewall, disabling certain features of the firewall, none work.
  • Network has IPv6 enabled

Question is: What could be the cause of being unable to receive multicast packets on non virtualised code (Non JVM)

OS:

  • MacOS 14.4 (ARM)
  • Windows 11 (ARM ~ VM on Mac)

Rust code: (Does not work)

use std::net::UdpSocket;

fn main() {
    let udp = UdpSocket::bind("[::]:0").expect("Unable to bind!");
    println!("{}", udp.local_addr().unwrap());
    udp.connect("ff02::fb%en0:5353").unwrap();
    let mut buffer = [0; 65000];
    let size = udp.recv(&mut buffer).unwrap();
    println!("Data received: {}", size);
}

Kotlin (JVM) code: Works

import java.net.DatagramPacket
import java.net.MulticastSocket

fun main() {
    val port = 5353 // Multicast port
    val socket = MulticastSocket(port)
    val buffer = ByteArray(1024)
    val packet = DatagramPacket(buffer, buffer.size)
    println("UDP server listening for multicast packets on ${socket.localSocketAddress}")
    while (true) {
        socket.receive(packet)
        val receivedData = packet.data.copyOf(packet.length)
        val receivedMessage = String(receivedData)
        println("Received message: $receivedMessage")
    }
}

C code: (Does not work)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define MAX_LEN 1024 // Maximum message length

int main() {
    int sockfd;
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    char buffer[MAX_LEN + 1];
    int bytes_received;

    // Create a UDP socket
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));

    // Fill in the address structure
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // Listen on any interface
    addr.sin_port = htons(12345); // Choose any port number you like

    // Bind the socket to the address
    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // Specify the multicast group to join
    mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.251"); // Multicast group address
    mreq.imr_interface.s_addr = htonl(INADDR_ANY); // Listen on any interface

    // Join the multicast group
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    // Receive multicast messages
    while (1) {
        bytes_received = recvfrom(sockfd, buffer, MAX_LEN, 0, NULL, NULL);
        if (bytes_received < 0) {
            perror("recvfrom failed");
            exit(EXIT_FAILURE);
        }
        buffer[bytes_received] = '\0'; // Null-terminate the received data
        printf("Received message: %s\n", buffer);
    }

    // Close the socket
    close(sockfd);

    return 0;
}

Solution

  • I answered on a similar question (also posted by me trying to clarify things more): mDNS / Bonjour / UDP 5353 Port reusability