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 gint flx_open_socket_ipv4(void) {
31 struct sockaddr_in sa, local;
32 int fd = -1, ttl, yes;
34 mdns_mcast_group_ipv4(&sa);
36 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
37 g_warning("socket() failed: %s\n", strerror(errno));
42 if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
43 g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
48 if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
49 g_warning("IP_TTL failed: %s\n", strerror(errno));
54 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
55 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
60 if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
61 g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
66 memset(&local, 0, sizeof(local));
67 local.sin_family = AF_INET;
68 local.sin_port = htons(MDNS_PORT);
70 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
71 g_warning("bind() failed: %s\n", strerror(errno));
75 memset(&mreq, 0, sizeof(mreq));
76 mreq.imr_multiaddr = sa.sin_addr;
77 mreq.imr_address.s_addr = htonl(INADDR_ANY);
80 if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
81 g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
86 if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
87 g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
92 if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
93 g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
97 if (flx_set_cloexec(fd) < 0) {
98 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
102 if (flx_set_nonblock(fd) < 0) {
103 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
116 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
119 memset(ret_sa, 0, sizeof(struct sockaddr_in6));
121 ret_sa->sin6_family = AF_INET6;
122 ret_sa->sin6_port = htons(MDNS_PORT);
123 inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
127 gint flx_open_socket_ipv6(void) {
128 struct ipv6_mreq mreq;
129 struct sockaddr_in6 sa, local;
130 int fd = -1, ttl, yes;
132 mdns_mcast_group_ipv6(&sa);
134 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
135 g_warning("socket() failed: %s\n", strerror(errno));
140 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
141 g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
146 if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
147 g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
152 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
153 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
158 if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
159 g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
164 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
165 g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
169 memset(&local, 0, sizeof(local));
170 local.sin6_family = AF_INET6;
171 local.sin6_port = htons(MDNS_PORT);
173 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
174 g_warning("bind() failed: %s\n", strerror(errno));
178 memset(&mreq, 0, sizeof(mreq));
179 mreq.ipv6mr_multiaddr = sa.sin6_addr;
180 mreq.ipv6mr_interface = 0;
182 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
183 g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
188 if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
189 g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
194 if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
195 g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
199 if (flx_set_cloexec(fd) < 0) {
200 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
204 if (flx_set_nonblock(fd) < 0) {
205 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
218 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
224 if (sendmsg(fd, msg, flags) >= 0)
227 if (errno != EAGAIN) {
228 g_message("sendmsg() failed: %s\n", strerror(errno));
232 if (flx_wait_for_write(fd) < 0)
239 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
240 struct sockaddr_in sa;
243 struct cmsghdr *cmsg;
244 struct in_pktinfo *pkti;
245 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
250 g_assert(flx_dns_packet_check_valid(p) >= 0);
252 mdns_mcast_group_ipv4(&sa);
254 memset(&io, 0, sizeof(io));
255 io.iov_base = p->data;
256 io.iov_len = p->size;
258 memset(cmsg_data, 0, sizeof(cmsg_data));
259 cmsg = (struct cmsghdr*) cmsg_data;
260 cmsg->cmsg_len = sizeof(cmsg_data);
261 cmsg->cmsg_level = IPPROTO_IP;
262 cmsg->cmsg_type = IP_PKTINFO;
264 pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
265 pkti->ipi_ifindex = interface;
267 memset(&msg, 0, sizeof(msg));
269 msg.msg_namelen = sizeof(sa);
272 msg.msg_control = cmsg_data;
273 msg.msg_controllen = sizeof(cmsg_data);
276 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
279 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
280 struct sockaddr_in6 sa;
283 struct cmsghdr *cmsg;
284 struct in6_pktinfo *pkti;
285 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
290 g_assert(flx_dns_packet_check_valid(p) >= 0);
292 mdns_mcast_group_ipv6(&sa);
294 memset(&io, 0, sizeof(io));
295 io.iov_base = p->data;
296 io.iov_len = p->size;
298 memset(cmsg_data, 0, sizeof(cmsg_data));
299 cmsg = (struct cmsghdr*) cmsg_data;
300 cmsg->cmsg_len = sizeof(cmsg_data);
301 cmsg->cmsg_level = IPPROTO_IPV6;
302 cmsg->cmsg_type = IPV6_PKTINFO;
304 pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
305 pkti->ipi6_ifindex = interface;
307 memset(&msg, 0, sizeof(msg));
309 msg.msg_namelen = sizeof(sa);
312 msg.msg_control = cmsg_data;
313 msg.msg_controllen = sizeof(cmsg_data);
316 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
319 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
320 flxDnsPacket *p= NULL;
325 struct cmsghdr *cmsg;
326 gboolean found_ttl = FALSE, found_iface = FALSE;
333 p = flx_dns_packet_new();
335 io.iov_base = p->data;
336 io.iov_len = sizeof(p->data);
338 memset(&msg, 0, sizeof(msg));
339 msg.msg_name = ret_sa;
340 msg.msg_namelen = sizeof(struct sockaddr_in);
343 msg.msg_control = aux;
344 msg.msg_controllen = sizeof(aux);
347 if ((l = recvmsg(fd, &msg, 0)) < 0)
350 p->size = (size_t) l;
354 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
355 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
356 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
360 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
361 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
366 g_assert(found_iface);
373 flx_dns_packet_free(p);
378 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
379 flxDnsPacket *p= NULL;
384 struct cmsghdr *cmsg;
385 gboolean found_ttl = FALSE, found_iface = FALSE;
392 p = flx_dns_packet_new();
394 io.iov_base = p->data;
395 io.iov_len = sizeof(p->data);
397 memset(&msg, 0, sizeof(msg));
398 msg.msg_name = ret_sa;
399 msg.msg_namelen = sizeof(struct sockaddr_in6);
402 msg.msg_control = aux;
403 msg.msg_controllen = sizeof(aux);
406 if ((l = recvmsg(fd, &msg, 0)) < 0)
409 p->size = (size_t) l;
415 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
416 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
417 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
421 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
422 *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
426 g_message("-- %u -- %u\n", cmsg->cmsg_level, cmsg->cmsg_type);
432 g_assert(found_iface);
439 flx_dns_packet_free(p);