5 #include <sys/socket.h>
6 #include <netinet/in.h>
12 #include <sys/ioctl.h>
18 static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
21 memset(ret_sa, 0, sizeof(struct sockaddr_in));
23 ret_sa->sin_family = AF_INET;
24 ret_sa->sin_port = htons(FLX_MDNS_PORT);
25 inet_pton(AF_INET, "224.0.0.251", &ret_sa->sin_addr);
28 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
32 memset(ret_sa, 0, sizeof(struct sockaddr_in6));
34 ret_sa->sin6_family = AF_INET6;
35 ret_sa->sin6_port = htons(FLX_MDNS_PORT);
36 inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
39 int flx_mdns_mcast_join_ipv4 (int index, int fd)
42 struct sockaddr_in sa;
44 mdns_mcast_group_ipv4 (&sa);
46 memset(&mreq, 0, sizeof(mreq));
47 mreq.imr_multiaddr = sa.sin_addr;
48 mreq.imr_ifindex = index;
50 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
51 g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
58 int flx_mdns_mcast_join_ipv6 (int index, int fd)
60 struct ipv6_mreq mreq6;
61 struct sockaddr_in6 sa6;
63 mdns_mcast_group_ipv6 (&sa6);
65 memset(&mreq6, 0, sizeof(mreq6));
66 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
67 mreq6.ipv6mr_interface = index;
69 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
70 g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
77 int flx_mdns_mcast_leave_ipv4 (int index, int fd)
80 struct sockaddr_in sa;
82 mdns_mcast_group_ipv4 (&sa);
84 memset(&mreq, 0, sizeof(mreq));
85 mreq.imr_multiaddr = sa.sin_addr;
86 mreq.imr_ifindex = index;
88 if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
89 g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
96 int flx_mdns_mcast_leave_ipv6 (int index, int fd)
98 struct ipv6_mreq mreq6;
99 struct sockaddr_in6 sa6;
101 mdns_mcast_group_ipv6 (&sa6);
103 memset(&mreq6, 0, sizeof(mreq6));
104 mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
105 mreq6.ipv6mr_interface = index;
107 if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
108 g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
115 gint flx_open_socket_ipv4(void) {
116 struct sockaddr_in sa, local;
117 int fd = -1, ttl, yes;
119 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
120 g_warning("socket() failed: %s\n", strerror(errno));
125 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
126 g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
131 if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
132 g_warning("IP_TTL failed: %s\n", strerror(errno));
137 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
138 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
143 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
144 g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
149 memset(&local, 0, sizeof(local));
150 local.sin_family = AF_INET;
151 local.sin_port = htons(FLX_MDNS_PORT);
153 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
154 g_warning("bind() failed: %s\n", strerror(errno));
159 if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
160 g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
165 if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
166 g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
170 if (flx_set_cloexec(fd) < 0) {
171 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
175 if (flx_set_nonblock(fd) < 0) {
176 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
189 gint flx_open_socket_ipv6(void) {
190 struct sockaddr_in6 sa, local;
191 int fd = -1, ttl, yes;
193 mdns_mcast_group_ipv6(&sa);
195 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
196 g_warning("socket() failed: %s\n", strerror(errno));
201 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
202 g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
207 if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
208 g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
213 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
214 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
219 if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
220 g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
225 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
226 g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
230 memset(&local, 0, sizeof(local));
231 local.sin6_family = AF_INET6;
232 local.sin6_port = htons(FLX_MDNS_PORT);
234 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
235 g_warning("bind() failed: %s\n", strerror(errno));
240 if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
241 g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
246 if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
247 g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
251 if (flx_set_cloexec(fd) < 0) {
252 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
256 if (flx_set_nonblock(fd) < 0) {
257 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
270 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
276 if (sendmsg(fd, msg, flags) >= 0)
279 if (errno != EAGAIN) {
280 g_message("sendmsg() failed: %s\n", strerror(errno));
284 if (flx_wait_for_write(fd) < 0)
291 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
292 struct sockaddr_in sa;
295 struct cmsghdr *cmsg;
296 struct in_pktinfo *pkti;
297 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
302 g_assert(flx_dns_packet_check_valid(p) >= 0);
304 mdns_mcast_group_ipv4(&sa);
306 memset(&io, 0, sizeof(io));
307 io.iov_base = FLX_DNS_PACKET_DATA(p);
308 io.iov_len = p->size;
310 memset(cmsg_data, 0, sizeof(cmsg_data));
311 cmsg = (struct cmsghdr*) cmsg_data;
312 cmsg->cmsg_len = sizeof(cmsg_data);
313 cmsg->cmsg_level = IPPROTO_IP;
314 cmsg->cmsg_type = IP_PKTINFO;
316 pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
317 pkti->ipi_ifindex = interface;
319 memset(&msg, 0, sizeof(msg));
321 msg.msg_namelen = sizeof(sa);
324 msg.msg_control = cmsg_data;
325 msg.msg_controllen = sizeof(cmsg_data);
328 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
331 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
332 struct sockaddr_in6 sa;
335 struct cmsghdr *cmsg;
336 struct in6_pktinfo *pkti;
337 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
342 g_assert(flx_dns_packet_check_valid(p) >= 0);
344 mdns_mcast_group_ipv6(&sa);
346 memset(&io, 0, sizeof(io));
347 io.iov_base = FLX_DNS_PACKET_DATA(p);
348 io.iov_len = p->size;
350 memset(cmsg_data, 0, sizeof(cmsg_data));
351 cmsg = (struct cmsghdr*) cmsg_data;
352 cmsg->cmsg_len = sizeof(cmsg_data);
353 cmsg->cmsg_level = IPPROTO_IPV6;
354 cmsg->cmsg_type = IPV6_PKTINFO;
356 pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
357 pkti->ipi6_ifindex = interface;
359 memset(&msg, 0, sizeof(msg));
361 msg.msg_namelen = sizeof(sa);
364 msg.msg_control = cmsg_data;
365 msg.msg_controllen = sizeof(cmsg_data);
368 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
371 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
372 flxDnsPacket *p= NULL;
377 struct cmsghdr *cmsg;
378 gboolean found_ttl = FALSE, found_iface = FALSE;
385 p = flx_dns_packet_new(0);
387 io.iov_base = FLX_DNS_PACKET_DATA(p);
388 io.iov_len = p->max_size;
390 memset(&msg, 0, sizeof(msg));
391 msg.msg_name = ret_sa;
392 msg.msg_namelen = sizeof(struct sockaddr_in);
395 msg.msg_control = aux;
396 msg.msg_controllen = sizeof(aux);
399 if ((l = recvmsg(fd, &msg, 0)) < 0)
402 p->size = (size_t) l;
406 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
407 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
408 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
412 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
413 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
418 g_assert(found_iface);
425 flx_dns_packet_free(p);
430 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
431 flxDnsPacket *p = NULL;
436 struct cmsghdr *cmsg;
437 gboolean found_ttl = FALSE, found_iface = FALSE;
444 p = flx_dns_packet_new(0);
446 io.iov_base = FLX_DNS_PACKET_DATA(p);
447 io.iov_len = p->max_size;
449 memset(&msg, 0, sizeof(msg));
450 msg.msg_name = ret_sa;
451 msg.msg_namelen = sizeof(struct sockaddr_in6);
454 msg.msg_control = aux;
455 msg.msg_controllen = sizeof(aux);
458 if ((l = recvmsg(fd, &msg, 0)) < 0)
461 p->size = (size_t) l;
465 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
466 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
467 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
471 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
472 *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
477 g_assert(found_iface);
484 flx_dns_packet_free(p);