5 #include <sys/socket.h>
6 #include <netinet/in.h>
12 #include <sys/ioctl.h>
17 #define MDNS_PORT 5353
19 static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
22 memset(ret_sa, 0, sizeof(struct sockaddr_in));
24 ret_sa->sin_family = AF_INET;
25 ret_sa->sin_port = htons(MDNS_PORT);
26 inet_pton(AF_INET, "224.0.0.251", &ret_sa->sin_addr);
29 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
33 memset(ret_sa, 0, sizeof(struct sockaddr_in6));
35 ret_sa->sin6_family = AF_INET6;
36 ret_sa->sin6_port = htons(MDNS_PORT);
37 inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
40 int flx_mdns_mcast_join_ipv4 (int index, int fd)
43 struct sockaddr_in sa;
45 mdns_mcast_group_ipv4 (&sa);
47 memset(&mreq, 0, sizeof(mreq));
48 mreq.imr_multiaddr = sa.sin_addr;
49 mreq.imr_ifindex = index;
51 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
52 g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
59 int flx_mdns_mcast_join_ipv6 (int index, int fd)
61 struct ipv6_mreq mreq6;
62 struct sockaddr_in6 sa6;
64 mdns_mcast_group_ipv6 (&sa6);
66 memset(&mreq6, 0, sizeof(mreq6));
67 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
68 mreq6.ipv6mr_interface = index;
70 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
71 g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
78 int flx_mdns_mcast_leave_ipv4 (int index, int fd)
81 struct sockaddr_in sa;
83 mdns_mcast_group_ipv4 (&sa);
85 memset(&mreq, 0, sizeof(mreq));
86 mreq.imr_multiaddr = sa.sin_addr;
87 mreq.imr_ifindex = index;
89 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
90 g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
97 int flx_mdns_mcast_leave_ipv6 (int index, int fd)
99 struct ipv6_mreq mreq6;
100 struct sockaddr_in6 sa6;
102 mdns_mcast_group_ipv6 (&sa6);
104 memset(&mreq6, 0, sizeof(mreq6));
105 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
106 mreq6.ipv6mr_interface = index;
108 if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
109 g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
116 gint flx_open_socket_ipv4(void) {
117 struct sockaddr_in sa, local;
118 int fd = -1, ttl, yes;
120 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
121 g_warning("socket() failed: %s\n", strerror(errno));
126 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
127 g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
132 if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
133 g_warning("IP_TTL failed: %s\n", strerror(errno));
138 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
139 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
144 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
145 g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
150 memset(&local, 0, sizeof(local));
151 local.sin_family = AF_INET;
152 local.sin_port = htons(MDNS_PORT);
154 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
155 g_warning("bind() failed: %s\n", strerror(errno));
160 if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
161 g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
166 if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
167 g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
171 if (flx_set_cloexec(fd) < 0) {
172 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
176 if (flx_set_nonblock(fd) < 0) {
177 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
190 gint flx_open_socket_ipv6(void) {
191 struct sockaddr_in6 sa, local;
192 int fd = -1, ttl, yes;
194 mdns_mcast_group_ipv6(&sa);
196 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
197 g_warning("socket() failed: %s\n", strerror(errno));
202 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
203 g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
208 if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
209 g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
214 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
215 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
220 if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
221 g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
226 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
227 g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
231 memset(&local, 0, sizeof(local));
232 local.sin6_family = AF_INET6;
233 local.sin6_port = htons(MDNS_PORT);
235 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
236 g_warning("bind() failed: %s\n", strerror(errno));
241 if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
242 g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
247 if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
248 g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
252 if (flx_set_cloexec(fd) < 0) {
253 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
257 if (flx_set_nonblock(fd) < 0) {
258 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
271 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
277 if (sendmsg(fd, msg, flags) >= 0)
280 if (errno != EAGAIN) {
281 g_message("sendmsg() failed: %s\n", strerror(errno));
285 if (flx_wait_for_write(fd) < 0)
292 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
293 struct sockaddr_in sa;
296 struct cmsghdr *cmsg;
297 struct in_pktinfo *pkti;
298 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
303 g_assert(flx_dns_packet_check_valid(p) >= 0);
305 mdns_mcast_group_ipv4(&sa);
307 memset(&io, 0, sizeof(io));
308 io.iov_base = FLX_DNS_PACKET_DATA(p);
309 io.iov_len = p->size;
311 memset(cmsg_data, 0, sizeof(cmsg_data));
312 cmsg = (struct cmsghdr*) cmsg_data;
313 cmsg->cmsg_len = sizeof(cmsg_data);
314 cmsg->cmsg_level = IPPROTO_IP;
315 cmsg->cmsg_type = IP_PKTINFO;
317 pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
318 pkti->ipi_ifindex = interface;
320 memset(&msg, 0, sizeof(msg));
322 msg.msg_namelen = sizeof(sa);
325 msg.msg_control = cmsg_data;
326 msg.msg_controllen = sizeof(cmsg_data);
329 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
332 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
333 struct sockaddr_in6 sa;
336 struct cmsghdr *cmsg;
337 struct in6_pktinfo *pkti;
338 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
343 g_assert(flx_dns_packet_check_valid(p) >= 0);
345 mdns_mcast_group_ipv6(&sa);
347 memset(&io, 0, sizeof(io));
348 io.iov_base = FLX_DNS_PACKET_DATA(p);
349 io.iov_len = p->size;
351 memset(cmsg_data, 0, sizeof(cmsg_data));
352 cmsg = (struct cmsghdr*) cmsg_data;
353 cmsg->cmsg_len = sizeof(cmsg_data);
354 cmsg->cmsg_level = IPPROTO_IPV6;
355 cmsg->cmsg_type = IPV6_PKTINFO;
357 pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
358 pkti->ipi6_ifindex = interface;
360 memset(&msg, 0, sizeof(msg));
362 msg.msg_namelen = sizeof(sa);
365 msg.msg_control = cmsg_data;
366 msg.msg_controllen = sizeof(cmsg_data);
369 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
372 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
373 flxDnsPacket *p= NULL;
378 struct cmsghdr *cmsg;
379 gboolean found_ttl = FALSE, found_iface = FALSE;
386 p = flx_dns_packet_new(0);
388 io.iov_base = FLX_DNS_PACKET_DATA(p);
389 io.iov_len = p->max_size;
391 memset(&msg, 0, sizeof(msg));
392 msg.msg_name = ret_sa;
393 msg.msg_namelen = sizeof(struct sockaddr_in);
396 msg.msg_control = aux;
397 msg.msg_controllen = sizeof(aux);
400 if ((l = recvmsg(fd, &msg, 0)) < 0)
403 p->size = (size_t) l;
407 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
408 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
409 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
413 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
414 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
419 g_assert(found_iface);
426 flx_dns_packet_free(p);
431 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
432 flxDnsPacket *p = NULL;
437 struct cmsghdr *cmsg;
438 gboolean found_ttl = FALSE, found_iface = FALSE;
445 p = flx_dns_packet_new(0);
447 io.iov_base = FLX_DNS_PACKET_DATA(p);
448 io.iov_len = p->max_size;
450 memset(&msg, 0, sizeof(msg));
451 msg.msg_name = ret_sa;
452 msg.msg_namelen = sizeof(struct sockaddr_in6);
455 msg.msg_control = aux;
456 msg.msg_controllen = sizeof(aux);
459 if ((l = recvmsg(fd, &msg, 0)) < 0)
462 p->size = (size_t) l;
466 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
467 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
468 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
472 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
473 *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
478 g_assert(found_iface);
485 flx_dns_packet_free(p);