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;
65 mdns_mcast_group_ipv6 (&sa6);
67 memset(&mreq6, 0, sizeof(mreq6));
68 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
69 mreq6.ipv6mr_interface = index;
71 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
72 g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
79 int flx_mdns_mcast_leave_ipv4 (int index, int fd)
82 struct sockaddr_in sa;
84 mdns_mcast_group_ipv4 (&sa);
86 memset(&mreq, 0, sizeof(mreq));
87 mreq.imr_multiaddr = sa.sin_addr;
88 mreq.imr_ifindex = index;
90 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
91 g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
98 int flx_mdns_mcast_leave_ipv6 (int index, int fd)
100 struct ipv6_mreq mreq6;
101 struct sockaddr_in6 sa6;
103 mdns_mcast_group_ipv6 (&sa6);
105 memset(&mreq6, 0, sizeof(mreq6));
106 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
107 mreq6.ipv6mr_interface = index;
109 if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
110 g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
117 gint flx_open_socket_ipv4(void) {
118 struct sockaddr_in sa, local;
119 int fd = -1, ttl, yes;
121 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
122 g_warning("socket() failed: %s\n", strerror(errno));
127 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
128 g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
133 if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
134 g_warning("IP_TTL failed: %s\n", strerror(errno));
139 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
140 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
145 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
146 g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
151 memset(&local, 0, sizeof(local));
152 local.sin_family = AF_INET;
153 local.sin_port = htons(MDNS_PORT);
155 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
156 g_warning("bind() failed: %s\n", strerror(errno));
161 if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
162 g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
167 if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
168 g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
172 if (flx_set_cloexec(fd) < 0) {
173 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
177 if (flx_set_nonblock(fd) < 0) {
178 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
191 gint flx_open_socket_ipv6(void) {
192 struct sockaddr_in6 sa, local;
193 int fd = -1, ttl, yes;
195 mdns_mcast_group_ipv6(&sa);
197 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
198 g_warning("socket() failed: %s\n", strerror(errno));
203 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
204 g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
209 if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
210 g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
215 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
216 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
221 if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
222 g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
227 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
228 g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
232 memset(&local, 0, sizeof(local));
233 local.sin6_family = AF_INET6;
234 local.sin6_port = htons(MDNS_PORT);
236 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
237 g_warning("bind() failed: %s\n", strerror(errno));
242 if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
243 g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
248 if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
249 g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
253 if (flx_set_cloexec(fd) < 0) {
254 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
258 if (flx_set_nonblock(fd) < 0) {
259 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
272 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
278 if (sendmsg(fd, msg, flags) >= 0)
281 if (errno != EAGAIN) {
282 g_message("sendmsg() failed: %s\n", strerror(errno));
286 if (flx_wait_for_write(fd) < 0)
293 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
294 struct sockaddr_in sa;
297 struct cmsghdr *cmsg;
298 struct in_pktinfo *pkti;
299 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
304 g_assert(flx_dns_packet_check_valid(p) >= 0);
306 mdns_mcast_group_ipv4(&sa);
308 memset(&io, 0, sizeof(io));
309 io.iov_base = FLX_DNS_PACKET_DATA(p);
310 io.iov_len = p->size;
312 memset(cmsg_data, 0, sizeof(cmsg_data));
313 cmsg = (struct cmsghdr*) cmsg_data;
314 cmsg->cmsg_len = sizeof(cmsg_data);
315 cmsg->cmsg_level = IPPROTO_IP;
316 cmsg->cmsg_type = IP_PKTINFO;
318 pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
319 pkti->ipi_ifindex = interface;
321 memset(&msg, 0, sizeof(msg));
323 msg.msg_namelen = sizeof(sa);
326 msg.msg_control = cmsg_data;
327 msg.msg_controllen = sizeof(cmsg_data);
330 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
333 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
334 struct sockaddr_in6 sa;
337 struct cmsghdr *cmsg;
338 struct in6_pktinfo *pkti;
339 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
344 g_assert(flx_dns_packet_check_valid(p) >= 0);
346 mdns_mcast_group_ipv6(&sa);
348 memset(&io, 0, sizeof(io));
349 io.iov_base = FLX_DNS_PACKET_DATA(p);
350 io.iov_len = p->size;
352 memset(cmsg_data, 0, sizeof(cmsg_data));
353 cmsg = (struct cmsghdr*) cmsg_data;
354 cmsg->cmsg_len = sizeof(cmsg_data);
355 cmsg->cmsg_level = IPPROTO_IPV6;
356 cmsg->cmsg_type = IPV6_PKTINFO;
358 pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
359 pkti->ipi6_ifindex = interface;
361 memset(&msg, 0, sizeof(msg));
363 msg.msg_namelen = sizeof(sa);
366 msg.msg_control = cmsg_data;
367 msg.msg_controllen = sizeof(cmsg_data);
370 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
373 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
374 flxDnsPacket *p= NULL;
379 struct cmsghdr *cmsg;
380 gboolean found_ttl = FALSE, found_iface = FALSE;
387 p = flx_dns_packet_new(0);
389 io.iov_base = FLX_DNS_PACKET_DATA(p);
390 io.iov_len = p->max_size;
392 memset(&msg, 0, sizeof(msg));
393 msg.msg_name = ret_sa;
394 msg.msg_namelen = sizeof(struct sockaddr_in);
397 msg.msg_control = aux;
398 msg.msg_controllen = sizeof(aux);
401 if ((l = recvmsg(fd, &msg, 0)) < 0)
404 p->size = (size_t) l;
408 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
409 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
410 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
414 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
415 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
420 g_assert(found_iface);
427 flx_dns_packet_free(p);
432 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
433 flxDnsPacket *p = NULL;
438 struct cmsghdr *cmsg;
439 gboolean found_ttl = FALSE, found_iface = FALSE;
446 p = flx_dns_packet_new(0);
448 io.iov_base = FLX_DNS_PACKET_DATA(p);
449 io.iov_len = p->max_size;
451 memset(&msg, 0, sizeof(msg));
452 msg.msg_name = ret_sa;
453 msg.msg_namelen = sizeof(struct sockaddr_in6);
456 msg.msg_control = aux;
457 msg.msg_controllen = sizeof(aux);
460 if ((l = recvmsg(fd, &msg, 0)) < 0)
463 p->size = (size_t) l;
467 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
468 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
469 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
473 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
474 *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
479 g_assert(found_iface);
486 flx_dns_packet_free(p);