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, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
43 g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
48 if (setsockopt(fd, IPPROTO_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));
59 memset(&local, 0, sizeof(local));
60 local.sin_family = AF_INET;
61 local.sin_port = htons(MDNS_PORT);
63 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
64 g_warning("bind() failed: %s\n", strerror(errno));
68 memset(&mreq, 0, sizeof(mreq));
69 mreq.imr_multiaddr = sa.sin_addr;
70 mreq.imr_address.s_addr = htonl(INADDR_ANY);
73 if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
74 g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
79 if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
80 g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
85 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
86 g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
90 if (flx_set_cloexec(fd) < 0) {
91 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
95 if (flx_set_nonblock(fd) < 0) {
96 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
109 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
112 memset(ret_sa, 0, sizeof(struct sockaddr_in6));
114 ret_sa->sin6_family = AF_INET6;
115 ret_sa->sin6_port = htons(MDNS_PORT);
116 inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
120 gint flx_open_socket_ipv6(void) {
121 struct ipv6_mreq mreq;
122 struct sockaddr_in6 sa, local;
123 int fd = -1, ttl, yes;
125 mdns_mcast_group_ipv6(&sa);
127 if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
128 g_warning("socket() failed: %s\n", strerror(errno));
133 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
134 g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
139 if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
140 g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
145 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
146 g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
150 memset(&local, 0, sizeof(local));
151 local.sin6_family = AF_INET6;
152 local.sin6_port = htons(MDNS_PORT);
154 if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
155 g_warning("bind() failed: %s\n", strerror(errno));
159 memset(&mreq, 0, sizeof(mreq));
160 mreq.ipv6mr_multiaddr = sa.sin6_addr;
161 mreq.ipv6mr_interface = 0;
163 if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
164 g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
169 if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
170 g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
175 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
176 g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
180 if (flx_set_cloexec(fd) < 0) {
181 g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
185 if (flx_set_nonblock(fd) < 0) {
186 g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
199 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
205 if (sendmsg(fd, msg, flags) >= 0)
208 if (errno != EAGAIN) {
209 g_message("sendmsg() failed: %s\n", strerror(errno));
213 if (flx_wait_for_write(fd) < 0)
220 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
221 struct sockaddr_in sa;
224 struct cmsghdr *cmsg;
225 struct in_pktinfo *pkti;
226 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
231 g_assert(flx_dns_packet_check_valid(p) >= 0);
233 mdns_mcast_group_ipv4(&sa);
235 memset(&io, 0, sizeof(io));
236 io.iov_base = p->data;
237 io.iov_len = p->size;
239 memset(cmsg_data, 0, sizeof(cmsg_data));
240 cmsg = (struct cmsghdr*) cmsg_data;
241 cmsg->cmsg_len = sizeof(cmsg_data);
242 cmsg->cmsg_level = IPPROTO_IP;
243 cmsg->cmsg_type = IP_PKTINFO;
245 pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
246 pkti->ipi_ifindex = interface;
248 memset(&msg, 0, sizeof(msg));
250 msg.msg_namelen = sizeof(sa);
253 msg.msg_control = cmsg_data;
254 msg.msg_controllen = sizeof(cmsg_data);
257 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
260 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
261 struct sockaddr_in6 sa;
264 struct cmsghdr *cmsg;
265 struct in6_pktinfo *pkti;
266 uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
271 g_assert(flx_dns_packet_check_valid(p) >= 0);
273 mdns_mcast_group_ipv6(&sa);
275 memset(&io, 0, sizeof(io));
276 io.iov_base = p->data;
277 io.iov_len = p->size;
279 memset(cmsg_data, 0, sizeof(cmsg_data));
280 cmsg = (struct cmsghdr*) cmsg_data;
281 cmsg->cmsg_len = sizeof(cmsg_data);
282 cmsg->cmsg_level = IPPROTO_IPV6;
283 cmsg->cmsg_type = IPV6_PKTINFO;
285 pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
286 pkti->ipi6_ifindex = interface;
288 memset(&msg, 0, sizeof(msg));
290 msg.msg_namelen = sizeof(sa);
293 msg.msg_control = cmsg_data;
294 msg.msg_controllen = sizeof(cmsg_data);
297 return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
300 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
301 flxDnsPacket *p= NULL;
306 struct cmsghdr *cmsg;
307 gboolean found_ttl = FALSE, found_iface = FALSE;
314 p = flx_dns_packet_new();
316 io.iov_base = p->data;
317 io.iov_len = sizeof(p->data);
319 memset(&msg, 0, sizeof(msg));
320 msg.msg_name = ret_sa;
321 msg.msg_namelen = sizeof(struct sockaddr_in);
324 msg.msg_control = aux;
325 msg.msg_controllen = sizeof(aux);
328 if ((l = recvmsg(fd, &msg, 0)) < 0)
331 p->size = (size_t) l;
335 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
336 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
337 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
341 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
342 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
347 g_assert(found_iface && found_ttl);
353 flx_dns_packet_free(p);
358 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
359 flxDnsPacket *p= NULL;
364 struct cmsghdr *cmsg;
365 gboolean found_ttl = FALSE, found_iface = FALSE;
372 p = flx_dns_packet_new();
374 io.iov_base = p->data;
375 io.iov_len = sizeof(p->data);
377 memset(&msg, 0, sizeof(msg));
378 msg.msg_name = ret_sa;
379 msg.msg_namelen = sizeof(struct sockaddr_in6);
382 msg.msg_control = aux;
383 msg.msg_controllen = sizeof(aux);
386 if ((l = recvmsg(fd, &msg, 0)) < 0)
389 p->size = (size_t) l;
393 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
394 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IPV6_HOPLIMIT) {
395 *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
399 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IPV6_PKTINFO) {
400 *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
405 g_assert(found_iface && found_ttl);
411 flx_dns_packet_free(p);