#include <sys/ioctl.h>
#include <assert.h>
+#ifdef IP_RECVIF
+#include <net/if_dl.h>
+#endif
+
#include "dns.h"
#include "fdutil.h"
#include "socket.h"
#include "log.h"
+/* this is a portability hack */
+#ifndef IPV6_ADD_MEMBERSHIP
+#ifdef IPV6_JOIN_GROUP
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+#endif
+
+#ifndef IPV6_DROP_MEMBERSHIP
+#ifdef IPV6_LEAVE_GROUP
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+#endif
+
static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
assert(ret_sa);
memcpy(&ret_sa->sin6_addr, a, sizeof(AvahiIPv6Address));
}
-int avahi_mdns_mcast_join_ipv4(int fd, int idx) {
- struct ip_mreqn mreq;
+#ifdef HAVE_STRUCT_IP_MREQN
+int avahi_mdns_mcast_join_ipv4(int fd, int idx, int join) {
+ struct ip_mreqn mreq;
+#else
+int avahi_mdns_mcast_join_ipv4(int fd, const AvahiAddress *a, int join) {
+ struct ip_mreq mreq;
+#endif
+
struct sockaddr_in sa;
-
- mdns_mcast_group_ipv4 (&sa);
-
memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = sa.sin_addr;
- mreq.imr_ifindex = idx;
-
- if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
- avahi_log_warn("IP_ADD_MEMBERSHIP failed: %s", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-int avahi_mdns_mcast_join_ipv6(int fd, int idx) {
- struct ipv6_mreq mreq6;
- struct sockaddr_in6 sa6;
- mdns_mcast_group_ipv6 (&sa6);
-
- memset(&mreq6, 0, sizeof(mreq6));
- mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
- mreq6.ipv6mr_interface = idx;
-
- if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
- avahi_log_warn("IPV6_ADD_MEMBERSHIP failed: %s", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-int avahi_mdns_mcast_leave_ipv4(int fd, int idx) {
- struct ip_mreqn mreq;
- struct sockaddr_in sa;
+#ifdef HAVE_STRUCT_IP_MREQN
+ mreq.imr_ifindex = idx;
+#else
+ assert(a);
+ assert(a->proto == AVAHI_PROTO_INET);
+ mreq.imr_interface.s_addr = a->data.ipv4.address;
+#endif
- mdns_mcast_group_ipv4 (&sa);
-
- memset(&mreq, 0, sizeof(mreq));
+ mdns_mcast_group_ipv4(&sa);
mreq.imr_multiaddr = sa.sin_addr;
- mreq.imr_ifindex = idx;
-
- if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
- avahi_log_warn("IP_DROP_MEMBERSHIP failed: %s", strerror(errno));
+
+ if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+ avahi_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", strerror(errno));
return -1;
- }
+ }
return 0;
}
-int avahi_mdns_mcast_leave_ipv6(int fd, int idx) {
+int avahi_mdns_mcast_join_ipv6(int fd, int idx, int join) {
struct ipv6_mreq mreq6;
struct sockaddr_in6 sa6;
mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
mreq6.ipv6mr_interface = idx;
- if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
- avahi_log_warn("IPV6_DROP_MEMBERSHIP failed: %s", strerror(errno));
+ if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
+ avahi_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", strerror(errno));
return -1;
}
return 0;
}
+static int ip_pktinfo (int fd, int yes)
+{
+ int ret = -1;
+
+#ifdef IP_PKTINFO
+ if ((ret = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes))) < 0) {
+ avahi_log_warn("IP_PKTINFO failed: %s", strerror(errno));
+ }
+#else
+#ifdef IP_RECVINTERFACE
+ if ((ret = setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, &yes, sizeof (yes))) < 0) {
+ avahi_log_warn("IP_RECVINTERFACE failed: %s", strerror(errno));
+ }
+#else
+#ifdef IP_RECVIF
+ if ((ret = setsockopt (fd, IPPROTO_IP, IP_RECVIF, &yes, sizeof (yes))) < 0) {
+ avahi_log_warn("IP_RECVIF failed: %s", strerror(errno));
+ }
+#endif /* IP_RECVIF */
+#endif /* IP_RECVINTERFACE */
+#if defined (IP_RECVDSTADDR) /* && !defined(solaris) */
+ if ((ret = setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof (yes))) < 0) {
+ avahi_log_warn("IP_RECVDSTADDR failed: %s", strerror(errno));
+ }
+#endif /* IP_RECVDSTADDR */
+#endif /* IP_PKTINFO */
+
+ return (ret);
+}
+
int avahi_open_socket_ipv4(int no_reuse) {
struct sockaddr_in local;
int fd = -1, ttl, yes, r;
}
ttl = 255;
- if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
avahi_log_warn("IP_MULTICAST_TTL failed: %s", strerror(errno));
goto fail;
}
ttl = 255;
- if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
avahi_log_warn("IP_TTL failed: %s", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IP_MULTICAST_LOOP failed: %s", strerror(errno));
goto fail;
}
goto fail;
yes = 1;
- if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IP_RECVTTL failed: %s", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
- avahi_log_warn("IP_PKTINFO failed: %s", strerror(errno));
- goto fail;
+ if (ip_pktinfo (fd, yes) < 0) {
+ goto fail;
}
-
+
if (avahi_set_cloexec(fd) < 0) {
avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
goto fail;
}
ttl = 255;
- if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
avahi_log_warn("IPV6_MULTICAST_HOPS failed: %s", strerror(errno));
goto fail;
}
ttl = 255;
- if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
avahi_log_warn("IPV6_UNICAST_HOPS failed: %s", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_MULTICAST_LOOP failed: %s", strerror(errno));
goto fail;
}
if (r < 0)
goto fail;
+#ifdef IPV6_RECVHOPS
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVHOPS failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_RECVHOPLIMIT
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVHOPLIMIT failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_HOPLIMIT
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_HOPLIMIT failed: %s", strerror(errno));
goto fail;
}
+#endif
+#ifdef IPV6_RECVPKTINFO
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVPKTINFO failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_PKTINFO
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_PKTINFO failed: %s", strerror(errno));
goto fail;
}
+#endif
if (avahi_set_cloexec(fd) < 0) {
avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
struct sockaddr_in sa;
struct msghdr msg;
struct iovec io;
+#ifdef IP_PKTINFO
struct cmsghdr *cmsg;
uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
+#endif
assert(fd >= 0);
assert(p);
msg.msg_iovlen = 1;
msg.msg_flags = 0;
+#ifdef IP_PKTINFO
if (interface >= 0) {
- struct in_pktinfo *pkti;
-
memset(cmsg_data, 0, sizeof(cmsg_data));
cmsg = (struct cmsghdr*) cmsg_data;
cmsg->cmsg_len = sizeof(cmsg_data);
cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
-
- pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
- pkti->ipi_ifindex = interface;
+ {
+ struct in_pktinfo *pkti;
+ cmsg->cmsg_type = IP_PKTINFO;
+ pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
+ pkti->ipi_ifindex = interface;
+ }
msg.msg_control = cmsg_data;
msg.msg_controllen = sizeof(cmsg_data);
} else {
msg.msg_control = NULL;
msg.msg_controllen = 0;
}
+#endif
return sendmsg_loop(fd, &msg, 0);
}
uint8_t aux[1024];
ssize_t l;
struct cmsghdr *cmsg;
- int found_ttl = 0, found_iface = 0;
+ int found_ttl = 0, found_iface = 0, found_addr = 0;
int ms;
assert(fd >= 0);
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_IP) {
-
- if (cmsg->cmsg_type == IP_TTL) {
- if (ret_ttl)
- *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
- found_ttl = 1;
- } else if (cmsg->cmsg_type == IP_PKTINFO) {
- struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
-
- if (ret_iface)
- *ret_iface = (int) i->ipi_ifindex;
-
- if (ret_dest_address)
- ret_dest_address->address = i->ipi_addr.s_addr;
- found_iface = 1;
- }
+ if (cmsg->cmsg_level == IPPROTO_IP) {
+ switch (cmsg->cmsg_type) {
+#ifdef IP_RECVTTL
+ case IP_RECVTTL:
+#endif
+ case IP_TTL:
+ if (ret_ttl)
+ *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
+ found_ttl = 1;
+ break;
+#ifdef IP_PKTINFO
+ case IP_PKTINFO:
+ {
+ struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
+
+ if (ret_iface)
+ *ret_iface = (int) i->ipi_ifindex;
+
+ if (ret_dest_address)
+ ret_dest_address->address = i->ipi_addr.s_addr;
+ found_addr = found_iface = 1;
+ }
+ break;
+#elif IP_RECVIF
+ case IP_RECVIF:
+ {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA (cmsg);
+
+ if (ret_iface)
+ *ret_iface = (int) sdl->sdl_index;
+ found_iface = 1;
+ }
+ break;
+#endif
+#ifdef IP_RECVDSTADDR
+ case IP_RECVDSTADDR:
+ if (ret_dest_address)
+ memcpy (&ret_dest_address->address, CMSG_DATA (cmsg), 4);
+ found_addr = 1;
+ break;
+#endif
+ default:
+ avahi_log_warn("Unhandled cmsg_type : %d",cmsg->cmsg_type);
+ break;
+ }
}
}
assert(found_iface);
+ assert(found_addr);
assert(found_ttl);
return p;
*ret_ttl = 0;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
if (ret_ttl)
*ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
found_ttl = 1;
}
- if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
if (ret_iface)
}
yes = 1;
- if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IP_RECVTTL failed: %s", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
- avahi_log_warn("IP_PKTINFO failed: %s", strerror(errno));
- goto fail;
+ if (ip_pktinfo (fd, yes) < 0) {
+ goto fail;
}
-
+
if (avahi_set_cloexec(fd) < 0) {
avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
goto fail;
goto fail;
}
+#ifdef IPV6_RECVHOPS
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVHOPS failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_RECVHOPLIMIT
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVHOPLIMIT failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_HOPLIMIT
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_HOPLIMIT failed: %s", strerror(errno));
goto fail;
}
+#endif
+#ifdef IPV6_RECVPKTINFO
yes = 1;
- if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) {
+ avahi_log_warn("IPV6_RECVPKTINFO failed: %s", strerror(errno));
+ goto fail;
+ }
+#elif IPV6_PKTINFO
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
avahi_log_warn("IPV6_PKTINFO failed: %s", strerror(errno));
goto fail;
}
+#endif
if (avahi_set_cloexec(fd) < 0) {
avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));