UDP broadcast not working on Thunderbolt Interface

I am using UDP broadcast ( using broadcasting IP 255.255.255.255) to search my NAS devices, so i broadcast through each available Network Interface present on my MAC enumerated using getifaddrs() .


I have a problem since i have updated my OS to 10.11 (OS X EI Captain) i.e if only Thunderbolt cable is connect to my MAC, i am not able to broadcast my UDP packets through the Thunderbolt interface. I get Error Domain=NSPOSIXErrorDomain Code=65 "No route to host" UserInfo={NSLocalizedDescription=No route to host }. I was able to broadcast and receive the response before < 10.11.

I need to make this work because its one of the important and core feature of my project.


Any help is appreciated. Thanks in advance.

Replies

Wow, it’s UDP broadcast day here on DevForums!

I haven’t tried this myself but I suspect that the code from this post will work in your context as well.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello Quinn,


many thanks for the information about using the IP_BOUND_IF.

In our application software we have the same issue for the UDP broadcast as described by prashant_telangi
We use an UDP broadcast message to a dedicated IP port to detect a specific device type in the network. This was working so far from MacOS 10.5 up to MacOS 10.10. With MacOS 10.11 it does no longer work.


To analyze the issue I have created a small test program which I compile on MacOS 10.10 and run it on MacOS 10.11

I start the test program with

./testUdpBroadcast 10.0.0.88 255.255.255.255

then the setsockopt for IP_BOUND_IF will not be used and if I start the test program with

./testUdpBroadcast 10.0.0.88 255.255.255.255 en2

then the setsockopt for IP_BOUND_IF will be used.


For MacOS 10.10 both variants result in an UDP broadcast message being sent.

For MacOS 10.11 both variants result in an error message "sendto() failed: No route to host"


/*
* Test program to test the UDP broadcast on MacOS 10.11.
* build:
* gcc -Wall testUdpBroadcast.c -o testUdpBroadcast
*/

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <netdb.h>         // gethostbyname

// ---------------
// constants
// ---------------
#define TEST_UDP_MSG_SIZE    32

void usage(const char* progName)
{
    printf("usage: %s bind-IP destination-IP [IF-Name]\n", progName);
    printf("   e.g. destinationIP could be broadcast 255.255.255.255 or subnet broadcast (e.g. 10.0.0.255)\n");
    printf("   if the optional parameter IF-Name is given then the socket option IP_BOUND_IF will be set.\n");
}

int main(int argc, char*argv[])
{
    int broadcastSocket = -1;
    struct sockaddr_in sockAddr;
    struct sockaddr_in destAddr;
    int err, sentBytes;
    unsigned int ifIndex;
    int optBroadcast;
    unsigned short bindPortNum=0; // next free port
    unsigned char msg[TEST_UDP_MSG_SIZE];

    if(argc < 3)
    {
        usage(argv[0]);
        return -1;
    }

    sockAddr.sin_family = AF_INET;
    sockAddr.sin_port = htons(bindPortNum);

    err = inet_pton(AF_INET, argv[1], (struct in_addr *)&sockAddr.sin_addr);
    if(err == 0)
    {
        printf("ERROR: no valid bindIp='%s' passed to inet_pton!\n", argv[1]);
        return -1;
    }

    broadcastSocket = socket(AF_INET, SOCK_DGRAM, 0);  // use SOCK_DGRAM for UDP
    if (broadcastSocket < 0)
    {
        printf("ERROR: creating socket: %s\n", strerror(errno));
        return -1;
    }

    err = setsockopt(broadcastSocket, SOL_SOCKET, SO_BROADCAST, &optBroadcast, sizeof optBroadcast);
    if(err < 0)
    {
        printf("setsockopt() failed for SO_BROADCAST: %s\n", strerror(errno));
        return -1;
    }

    if(argc >= 4)
    {
        ifIndex = if_nametoindex(argv[3]);
        printf("ifIndex=%d for %s\n", ifIndex, argv[3]);
        // there was given an interfacen name we can translate this to ifIndex
        err = setsockopt(broadcastSocket, IPPROTO_IP, IP_BOUND_IF, &ifIndex, sizeof(ifIndex));
        if(err < 0)
        {
            printf("setsockopt() failed for IF_BOUND_IF: %s\n", strerror(errno));
            return -1;
        }
    }

    err = bind(broadcastSocket, (struct sockaddr *) &sockAddr, sizeof(sockAddr));
    if(err < 0)
    {
        printf("bind() failed: %s\n", strerror(errno));
        return -1;
    }
    else
    {
        printf("bind() successful for %s\n", inet_ntoa(sockAddr.sin_addr));
    }

    destAddr.sin_family = AF_INET;
    destAddr.sin_port = htons(33333); // the destination port
    //destAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    err = inet_pton(AF_INET, argv[2], (struct in_addr *)&destAddr.sin_addr);
    if(err == 0)
    {
        printf("ERROR: no valid destinationIP='%s' passed to inet_pton!\n", argv[2]);
        return -1;
    }


    // prepare the message to send
    memset(msg, 0x00, (size_t)TEST_UDP_MSG_SIZE);
    strncpy((char *)msg, "MacOS Test msg", (size_t)TEST_UDP_MSG_SIZE);

    sentBytes = sendto(broadcastSocket, msg, (size_t)TEST_UDP_MSG_SIZE, 0, (struct sockaddr *) &destAddr, sizeof(destAddr));
    if(sentBytes < 0)
    {
        printf("sendto() failed: %s\n", strerror(errno));
        return -1;
    }
    else if(sentBytes != TEST_UDP_MSG_SIZE)
    {
        printf("sendto(): not all bytes are sent: requested to send %d, but sendTo indicated %d\n", TEST_UDP_MSG_SIZE, sentBytes);
    }
    close(broadcastSocket);
    return 0;
}


A very long time back to MacOS 10.3 I found that I could not sent broadcasts to 255.255.255.255 in MacOS 10.3, but I have to use subnet broadcasts instead e.g. 10.0.0.255, I had found somehwere an explanation that the broadcast address 255.255.255.255 is ambiguous for the multi-homed BSD network stack. But with MacOS 10.4 and newer the broadcast address 255.255.255.255 was working I and I was using it.


Is there any security reason (firewall, ...) to maybe block such kind of UDP broadcasts?


Many thanks

Andreas

Hi Quinn,

Thanks for your swift reply. I have tested your sample code but i cannot broadcast through my Thunderbolt Interface. I get Error no: 51 after sending the udp message using sendto().


The below mentioned code works on Mac OS X version before 10.11 but does not work on OS X 10.11 EI Captain.


- (void) UDPBroadcast

{

unsigned int wifiInterface;

int fd;

BOOL success;

struct sockaddr_in destAddr;

NSData * payloadData;

ssize_t bytesSent;


wifiInterface = if_nametoindex("bridge0"); // Thunderbolt Interface name assert(wifiInterface != 0);


fd = socket(AF_INET, SOCK_DGRAM, 0);

assert(fd >= 0);


static const int kOne = 1;

success = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &kOne, sizeof(kOne)) == 0; // Success value is Yes

assert(success);


success = setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &wifiInterface, sizeof(wifiInterface)) == 0; // Success value is Yes

assert(success);


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

destAddr.sin_family = AF_INET;

destAddr.sin_len = sizeof(destAddr);

destAddr.sin_addr.s_addr = INADDR_BROADCAST;

destAddr.sin_port = htons(1234); // We use specific UDP port to broadcast


payloadData = [[NSString stringWithFormat:@"%@\r\n", [NSDate date]] dataUsingEncoding:NSUTF8StringEncoding];


bytesSent = sendto(fd, payloadData.bytes, payloadData.length, 0, (const struct sockaddr *) &destAddr, sizeof(destAddr));


if(bytesSent >= 0)

{

NSLog(@“Success");

}

else

{

NSLog(@“Error No: %d”,errno); // The output on the console is Error No: 51

}

success = close(fd) == 0;

assert(success);

}


Can you suggest me any other way to fix this issue.


Thanks in advance.

AndreasR wrote:

A very long time back to MacOS 10.3 I found that I could not sent broadcasts to 255.255.255.255 in MacOS 10.3, but I have to use subnet broadcasts instead e.g. 10.0.0.255, I had found somehwere an explanation that the broadcast address 255.255.255.255 is ambiguous for the multi-homed BSD network stack.

Right. Which is why

IP_BOUND_IF
is your friend.

Is there any security reason (firewall, ...) to maybe block such kind of UDP broadcasts?

That’s very unlikely. Problems like this are almost always related to the intricate dance between the many options provided by BSD Sockets API and the kernel’s core routing functionality.

prashant_telangi wrote:

I get Error no: 51 after sending the udp message using sendto().

This seems like the same problem that the person on the other thread is having. My guess is that it’s related to the lack of a gateway for the target network interface but I won’t know for sure until his responds to my latest questions.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello Quinn,

many thanks for your answer.

Indeed I was using a manual/static IP configuration where I set IP address 10.0.0.88 and network mask 255.255.255.0 and left the field for the Gateway/Router blank.

Now I have filled the Gateway/Router field with 10.0.0.1 and using IP_BOUND_IF then I do no longer get the "No route to host" error message and I can see the UDP broadcast message with the Wireshark tracing arriving on the other test system.

Furthermore I have checked to use the original code without IP_BOUND_IF but using a gateway/router configuration 10.0.0.1 and it also worked to send the UDP broadcast.


I am a bit confused as I always told our customers that a gateway configuraiton is only necessary if you want to send messages to be routed to another network. In case of having a very simple network, e.g. 5 nodes all with static/manual IP configuration, all within the same subnet and where there is no connection to another network and no router, I always thought there is no need for specifying an address for a gateway/router, because there is no dedicated router device in such a simple network.


I am not sure if all our customers are filling in the gateway/router field. If they are using a DHCP then I think the gateway/router address will be typically assigned by the DHCP, but for manually configured networks it could be a pitfall to forget specifying the gateway.

Might it be better to use the subnet broadcast (e.g. 10.0.0.255) instead of the complete broadcast (255.255.255.255) to avoid the pitfall with the missing gateway configuration, or are there siginificant disadvantages using a subnet broadcast compared to using the full broadcast address?


Just as additional information:

first tests I have done with Thunderbolt-to-Ethernet adapter and a USB-to-Ethernet adapter because I was using a MacBook Pro Retina which has no built-in standard Gigabit/s Ethernet interface. Meanwhile I have checked with a MacBook Pro (early 2011) which has a built-in standard Gigabit/s Ethernet.

The behavior using MacOS 10.11 was the same for all types of tested interfaces.


Many thanks

Andreas

I am a bit confused as I always told our customers that a gateway configuraiton is only necessary if you want to send messages to be routed to another network.

I agree.

It seems to me that the 10.11 behaviour is a bug and I encourage you to file it as such. Please post your bug number, just for the record.

If you don’t assign static IP addresses but instead let the interface use IPv4 link local, what happens?

Did you try binding the source address (as I suggested in the other thread)?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello Quinn,


many thanks for your answer.


I have created a bug report in the "Apple Bug Reporter", the number of the bug ticket is 23010312.


Test IPv4 link local:

I have set the network interface to DHCP and waited until the OS has automatically assigned IP address and network mask:

address: 169.254.50.26

mask: 255.255.0.0

The filed for the router will be empty.

Now started the test program (complete code see my previous post) to send the UDP broadcast message on 169.254.50.26 on en5.

Result: sendto() fails with "No route to host".

I have created a bug report in the "Apple Bug Reporter", the number of the bug ticket is 23010312.

Thanks. Using your bug report I was able to determine that this is very likely to be a known issue (r. 22149738) in current systems. The investigation is still ongoing so I have no other details to share right now.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello Quinn,


just as an additional information from the "Apple Developer bug reporting":

Engineering has determined that your bug report (23010312) is a duplicate of another issue (22149738).

Today I noticed that there is an update for OS X El Capitan.

I have downloaded and installed the 10.11.2 update and tested the issue with the UDP broadcasts and the issue seems to be solved with the 10.11.2 update.