11 #include <linux/version.h>
13 #include <netinet/in.h>
17 #include <sys/socket.h>
26 #if defined BSD || defined __APPLE__
27 #define CHECK_KERNEL_VERSION(...) TRUE
29 #define CHECK_KERNEL_VERSION(...) LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
33 struct timeval stimeout;
34 stimeout.tv_sec = timeout;
37 PRINT_DEBUG(
"Setting send-timeout to %d", (
int)stimeout.tv_sec);
39 if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (
char *)&stimeout,
40 sizeof(stimeout)) < 0) {
41 PRINT_ERROR(
"Failed to set send-timeout: %s", strerror(errno));
49 struct timeval rtimeout;
50 rtimeout.tv_sec = timeout;
53 PRINT_DEBUG(
"Setting receive-timeout to %d", (
int)rtimeout.tv_sec);
55 if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (
char *)&rtimeout,
56 sizeof(rtimeout)) < 0) {
57 PRINT_ERROR(
"Failed to set receive-timeout: %s", strerror(errno));
66 PRINT_DEBUG(
"Setting reuseaddr");
67 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
68 PRINT_ERROR(
"Failed setting resuseaddr: %s", strerror(errno));
77 PRINT_DEBUG(
"Setting reuseport");
78 #if (defined(linux) && CHECK_KERNEL_VERSION()) || \
79 defined BSD || defined __APPLE__
80 if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse,
sizeof(reuse)) == -1) {
81 PRINT_ERROR(
"Failed setting resuseport: %s", strerror(errno));
85 PRINT_WARN(
"Not supported, falling back to reuseaddr.");
94 PRINT_DEBUG(
"Setting keepalive to %d", keepalive);
95 if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (
char *)&keepalive,
sizeof(
BOOL)) < 0) {
96 PRINT_ERROR(
"(%d) %s", errno, strerror(errno));
104 PRINT_DEBUG(
"Setting TTL to %d", ttl);
106 (family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6),
107 (family == AF_INET ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS),
110 PRINT_ERROR(
"(%d) %s", errno, strerror(errno));
119 unsigned char loop =
FALSE;
120 PRINT_DEBUG(
"Disabling loopback multicast traffic");
122 family == AF_INET ? IPPROTO_IP :
124 family == AF_INET ? IP_MULTICAST_LOOP :
128 PRINT_ERROR(
"(%d) %s", errno, strerror(errno));
136 struct ifaddrs *ifa, *interfaces = NULL;
140 struct sockaddr_storage sa_interface;
142 PRINT_DEBUG(
"join_multicast_group(%d, \"%s\", \"%s\")", sock,
143 multicast_group, interface_ip);
146 if (inet_pton(AF_INET6, interface_ip,
147 (
void *)&((
struct sockaddr_in6 *)&sa_interface)->sin6_addr) > 0) {
154 if ((res = inet_pton(AF_INET, interface_ip,
155 (
void *)&((
struct sockaddr_in *)&sa_interface)->sin_addr)) < 1) {
157 PRINT_ERROR(
"interface_ip is NULL");
159 PRINT_ERROR(
"Given multicast group address '%s' is neither an IPv4 nor"
160 " IPv6, cannot continue (%d)", interface_ip);
166 PRINT_DEBUG(
"Multicast group address is IPv%d", (is_mc_ipv6 ? 6 : 4));
169 if(interface_ip != NULL && strlen(interface_ip) == 0) {
176 PRINT_DEBUG(
"interface_ip was empty, set to '%s'", interface_ip);
180 if (inet_pton(AF_INET6, interface_ip,
181 (
void *)&((
struct sockaddr_in6 *)&sa_interface)->sin6_addr) > 0) {
188 if ((res = inet_pton(AF_INET, interface_ip,
189 (
void *)&((
struct sockaddr_in *)&sa_interface)->sin_addr)) < 1) {
191 PRINT_ERROR(
"interface_ip is NULL");
193 PRINT_ERROR(
"Given interface address '%s' is neither an IPv4 nor IPv6,"
194 " cannot continue", interface_ip);
200 PRINT_DEBUG(
"Interface address is IPv%d", (is_mc_ipv6 ? 6 : 4));
203 if(strcmp(
"0.0.0.0", interface_ip) == 0 ||
204 strcmp(
"::", interface_ip) == 0) {
208 PRINT_DEBUG(
"Interface address is %s", (is_bindall ?
"a bind-all address" :
212 if(getifaddrs(&interfaces) < 0) {
213 PRINT_ERROR(
"Could not find any interfaces: (%d) %s\n", errno,
219 PRINT_DEBUG(
"List of available interfaces and IPs:");
220 PRINT_DEBUG(
"********************");
221 for (ifa = interfaces; ifa != NULL; ifa = ifa->ifa_next) {
222 struct in_addr *ifaddr4 =
223 (
struct in_addr *)&((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
224 struct in6_addr *ifaddr6 =
225 (
struct in6_addr *)&((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
227 if(ifa->ifa_addr->sa_family != AF_INET &&
228 ifa->ifa_addr->sa_family != AF_INET6) {
229 PRINT_DEBUG(
"Not an internet address, skipping interface.");
232 if(inet_ntop(ifa->ifa_addr->sa_family,
233 ifa->ifa_addr->sa_family == AF_INET ? (
void *)ifaddr4 :
237 PRINT_ERROR(
"Failed to extract address, skipping interface: (%d) %s",
242 PRINT_DEBUG(
"IF: %s; IP: %s", ifa->ifa_name, ip);
244 PRINT_DEBUG(
"********************");
247 PRINT_DEBUG(
"Start looping through available interfaces and IPs");
250 for (ifa = interfaces; ifa != NULL; ifa = ifa->ifa_next) {
253 if(ifa->ifa_flags & IFF_LOOPBACK) {
254 PRINT_DEBUG(
"Loopback address detected, skipping");
259 struct in_addr *ifaddr4 =
260 (
struct in_addr *)&((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
261 struct in6_addr *ifaddr6 =
262 (
struct in6_addr *)&((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
263 int ss_family = ifa->ifa_addr->sa_family;
266 if((!is_ipv6 && ss_family != AF_INET) ||
267 (is_ipv6 && ss_family != AF_INET6)) {
268 PRINT_DEBUG(
"Skipping interface (%s) address, wrong type (%d)",
276 if(inet_ntop(ss_family,
277 ss_family == AF_INET ? (
void *)ifaddr4 :
281 PRINT_ERROR(
"Failed to extract address, will skip current interface:"
282 " (%d) %s", errno, strerror(errno));
288 if(!is_bindall && strcmp(ip, interface_ip) != 0) {
289 PRINT_DEBUG(
"Skipping interface (%s) address, wrong IP (%s != %s)",
296 PRINT_DEBUG(
"Found candidate interface %s, type %d, IP %s", ifa->ifa_name,
300 struct ipv6_mreq mreq6;
303 memset(&mreq, 0,
sizeof(
struct ip_mreq));
304 mreq.imr_interface.s_addr = ifaddr4->s_addr;
307 memset(&mreq6, 0,
sizeof(
struct ipv6_mreq));
308 mreq6.ipv6mr_interface = if_nametoindex(ifa->ifa_name);
312 if((res = inet_pton(ss_family,
314 (is_ipv6 ? (
void *)&mreq6.ipv6mr_multiaddr :
315 (
void *)&mreq.imr_multiaddr))) < 1) {
317 PRINT_ERROR(
"interface_ip is NULL");
319 PRINT_ERROR(
"Incompatible multicast group");
326 PRINT_DEBUG(
"%s", (is_ipv6 ?
"IPV6_ADD_MEMBERSHIP" :
327 "IP_ADD_MEMBERSHIP"));
330 PRINT_DEBUG(
"mreq6.ipv6mr_interface: %d", mreq6.ipv6mr_interface);
334 PRINT_DEBUG(
"mreq.imr_interface: %s", a);
337 is_ipv6 ? (
void *)&mreq6.ipv6mr_multiaddr :
338 (
void *)&mreq.imr_multiaddr,
341 PRINT_DEBUG(
"mreq%smr_multiaddr: %s", (is_ipv6 ?
"6.ipv6" :
".i"), a);
345 PRINT_DEBUG(
"Joining multicast group '%s' on interface IP '%s'",
346 multicast_group, ip);
349 is_ipv6 ? IPPROTO_IPV6 :
351 is_ipv6 ? IPV6_ADD_MEMBERSHIP :
353 is_ipv6 ? (
void *)&mreq6 :
355 is_ipv6 ?
sizeof(
struct ipv6_mreq) :
356 sizeof(
struct ip_mreq)) < 0) {
357 PRINT_ERROR(
"(%d) %s", errno, strerror(errno));
359 freeifaddrs(interfaces);
364 PRINT_DEBUG(
"Finished looping through interfaces and IPs");
367 if(interfaces != NULL) {
368 freeifaddrs(interfaces);
380 struct ipv6_mreq mreq6;
381 struct sockaddr_storage *saddr;
383 saddr = (
struct sockaddr_storage *)malloc(
sizeof(
struct sockaddr_storage));
384 memset(saddr, 0,
sizeof(
struct sockaddr_storage));
385 memset(&mreq, 0,
sizeof(mreq));
386 memset(&mreq6, 0,
sizeof(mreq6));
390 if(conf->
sa != NULL) {
392 if (conf->
sa->ss_family == AF_INET) {
393 sock_addr = (
void *)&((
struct sockaddr_in *)conf->
sa)->sin_addr;
395 sock_addr = (
void *)&((
struct sockaddr_in6 *)conf->
sa)->sin6_addr;
403 PRINT_ERROR(
"The requested interface '%s' could not be found",
412 memset(a,
'\0', 100);
413 if(!inet_ntop(saddr->ss_family, (saddr->ss_family == AF_INET ?
414 (
void *)&((
struct sockaddr_in *)saddr)->sin_addr :
415 (
void *)&((
struct sockaddr_in6 *)saddr)->sin6_addr), a, 100)) {
416 PRINT_ERROR(
"setup_socket(); inet_ntop(): (%d) %s", errno,
419 PRINT_DEBUG(
"find_interface() returned: saddr->sin_addr: %s", a);
426 PRINT_ERROR(
"The specified IP (%s) is not a multicast address\n",
429 if(conf->
sa != NULL) {
438 saddr->ss_family = AF_INET6;
439 protocol = IPPROTO_IPV6;
442 saddr->ss_family = AF_INET;
443 protocol = IPPROTO_IP;
447 sock = socket(saddr->ss_family, conf->
is_udp ? SOCK_DGRAM : SOCK_STREAM,
451 PRINT_ERROR(
"Failed to create socket. (%d) %s", errno, strerror(errno));
453 if (conf->
sa != NULL) {
462 if(conf->
sa != NULL) {
471 if(conf->
sa != NULL) {
480 if (conf->
sa != NULL) {
490 if (conf->
sa != NULL) {
501 if (conf->
sa != NULL) {
511 if (conf->
sa != NULL) {
519 PRINT_DEBUG(
"is_ipv6 == TRUE");
520 struct sockaddr_in6 * saddr6 = (
struct sockaddr_in6 *)saddr;
521 saddr6->sin6_port = htons(conf->
port);
523 PRINT_DEBUG(
" is_udp == TRUE && is_multicast == TRUE");
524 if (conf->
ip == NULL || strlen(conf->
ip) < 1) {
525 inet_pton(saddr->ss_family,
SSDP_ADDR6_LL, &mreq6.ipv6mr_multiaddr);
528 inet_pton(saddr->ss_family, conf->
ip, &mreq6.ipv6mr_multiaddr);
531 mreq6.ipv6mr_interface = (
unsigned int)ifindex;
534 mreq6.ipv6mr_interface = (
unsigned int)0;
541 PRINT_DEBUG(
" IPV6_MULTICAST_IF");
544 PRINT_DEBUG(
" mreq6->ipv6mr_interface: %d", ifindex);
545 inet_ntop(saddr->ss_family, (
void *)&mreq6.ipv6mr_multiaddr, a, 100);
546 PRINT_DEBUG(
" mreq6->ipv6mr_multiaddr: %s", a);
553 &mreq6.ipv6mr_interface,
554 sizeof(mreq6.ipv6mr_interface)) < 0) {
555 PRINT_ERROR(
"setsockopt() IPV6_MULTICAST_IF: (%d) %s", errno,
558 if(conf->
sa != NULL) {
566 PRINT_DEBUG(
"is_ipv6 == FALSE");
567 struct sockaddr_in *saddr4 = (
struct sockaddr_in *)saddr;
568 saddr4->sin_port = htons(conf->
port);
570 PRINT_DEBUG(
" is_udp == TRUE && is_multicast == TRUE");
571 if (conf->
ip == NULL || strlen(conf->
ip) < 1) {
572 inet_pton(saddr->ss_family,
SSDP_ADDR, &mreq.imr_multiaddr);
575 inet_pton(saddr->ss_family, conf->
ip, &mreq.imr_multiaddr);
577 if ((conf->
if_ip != NULL && strlen(conf->
if_ip) > 0) ||
579 mreq.imr_interface.s_addr = saddr4->sin_addr.s_addr;
582 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
588 PRINT_DEBUG(
" IP_MULTICAST_IF");
591 inet_ntop(saddr->ss_family, (
void *)&mreq.imr_interface, a, 100);
592 PRINT_DEBUG(
" mreq->imr_interface: %s", a);
593 inet_ntop(saddr->ss_family, (
void *)&mreq.imr_multiaddr, a, 100);
594 PRINT_DEBUG(
" mreq->imr_multiaddr: %s", a);
597 if (!conf->
is_server && setsockopt(sock, protocol, IP_MULTICAST_IF,
598 &mreq.imr_interface,
sizeof(mreq.imr_interface)) < 0) {
599 PRINT_ERROR(
"setsockopt() IP_MULTICAST_IF: (%d) %s", errno,
602 if (conf->
sa != NULL) {
614 if (conf->
sa != NULL) {
624 struct sockaddr_in bindaddr;
625 bindaddr.sin_family = saddr->ss_family;
626 bindaddr.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
627 bindaddr.sin_port = ((
struct sockaddr_in *)saddr)->sin_port;
630 PRINT_DEBUG(
"is_server == TRUE");
632 inet_ntop(bindaddr.sin_family,
633 (
void *)&((
struct sockaddr_in *)&bindaddr)->sin_addr, a, 100);
634 PRINT_DEBUG(
" bind() to: saddr->sin_family: %d(%d)",
635 ((
struct sockaddr_in *)&bindaddr)->sin_family, AF_INET);
636 PRINT_DEBUG(
" bind() to: saddr->sin_addr: %s (port %d)", a,
637 ntohs(((
struct sockaddr_in *)&bindaddr)->sin_port));
640 if (bind(sock, (
struct sockaddr *)&bindaddr,
641 (bindaddr.sin_family == AF_INET ?
sizeof(
struct sockaddr_in) :
642 sizeof(
struct sockaddr_in6))) < 0) {
643 PRINT_ERROR(
"setup_socket(); bind(): (%d) %s", errno, strerror(errno));
645 if(conf->
sa != NULL) {
651 PRINT_DEBUG(
" is_udp == FALSE");
653 PRINT_ERROR(
"setup_socket(); listen(): (%d) %s", errno,
657 if(conf->
sa != NULL) {
668 if (conf->
if_ip == NULL || strlen(conf->
if_ip) < 1) {
672 sock_addr = (
void *)&((
struct sockaddr_in6 *)saddr)->sin6_addr;
674 sock_addr = (
void *)&((
struct sockaddr_in *)saddr)->sin_addr;
677 if (inet_ntop(conf->
is_ipv6 ? AF_INET6 : AF_INET, sock_addr, iface_ip,
679 PRINT_ERROR(
"Failed to get string representation of the interface "
680 "IP address: (%d) %s", errno, strerror(errno));
686 strcpy(iface_ip, conf->
if_ip);
692 PRINT_ERROR(
"Failed to join required multicast group");
#define IPv6_STR_MAX_SIZE
int set_receive_timeout(SOCKET sock, int timeout)
int join_multicast_group(SOCKET sock, char *multicast_group, char *interface_ip)
int set_keepalive(SOCKET sock, BOOL keepalive)
int set_reuseport(SOCKET sock)
int find_interface(struct sockaddr_storage *saddr, const char *interface, const char *address)
int set_reuseaddr(SOCKET sock)
BOOL is_address_multicast(const char *address)
int set_send_timeout(SOCKET sock, int timeout)
int set_ttl(SOCKET sock, int family, int ttl)
SOCKET setup_socket(socket_conf_s *conf)
struct sockaddr_storage * sa
int disable_multicast_loopback(SOCKET sock, int family)
static configuration_s conf