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