1 /*****************************************************************************
2 * This file is part of libmicrodns.
3 *
4 * Copyright © 2014-2016 VideoLabs SAS
5 *
6 * Author: Jonathan Calmels <jbjcalmels@gmail.com>
7 *
8 *****************************************************************************
9 * libmicrodns is released under LGPLv2.1 (or later) and is also available
10 * under a commercial license.
11 *****************************************************************************
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <time.h>
35 #include <stdint.h>
36
37 #include "compat.h"
38 #include "utils.h"
39 #include "microdns/microdns.h"
40 #include "mdns.h"
41
42 #define MDNS_PKT_MAXSZ 4096 // read/write buffer size
43
44 struct mdns_svc {
45 enum rr_type type;
46 union
47 {
48 mdns_announce_callback announce_callback;
49 //mdns_listen_callback listen_callback; // currently unused
50 };
51 void *p_cookie;
52 struct mdns_svc *next;
53 };
54
55 struct mdns_conn {
56 sock_t sock;
57 uint32_t intf_idx;
58 struct sockaddr_storage intf_addr; // IP address and family of the interface
59 struct sockaddr_storage mcast_addr; // The multicast address targeted by this connection
60 };
61
62 struct mdns_ctx {
63 struct mdns_conn *conns;
64 size_t nb_conns;
65 struct mdns_svc *services;
66 };
67
68 static int mdns_resolve(struct mdns_ctx *ctx, const char *addr, unsigned short port);
69 static size_t mdns_write_hdr(uint8_t *, size_t *s, const struct mdns_hdr *);
70 static int strrcmp(const char *, const char *);
71
72 extern const uint8_t *rr_read(const uint8_t *, size_t *, const uint8_t *, struct rr_entry *, int8_t ans);
73 extern ssize_t rr_write(uint8_t *, size_t *, const struct rr_entry *, int8_t ans);
74 extern void rr_print(const struct rr_entry *);
75 extern void rr_free(struct rr_entry *);
76
77 #ifndef _WIN32
78 #if HAVE_GETIFADDRS
79
80 static bool
mdns_is_interface_valuable(const struct ifaddrs * ifa,int family)81 mdns_is_interface_valuable(const struct ifaddrs* ifa, int family)
82 {
83 struct sockaddr_in6 saddr;
84
85 if (ifa->ifa_addr == NULL)
86 return false;
87
88 memcpy(&saddr, ifa->ifa_addr, sizeof(saddr));
89
90 return ifa->ifa_addr->sa_family == family &&
91 (ifa->ifa_flags & IFF_LOOPBACK) == 0 &&
92 (ifa->ifa_flags & IFF_UP) != 0 &&
93 (ifa->ifa_flags & IFF_RUNNING) != 0 &&
94 /* We only want a link local address, especially since we then
95 * can get the associated interface index */
96 ((family == AF_INET6 && saddr.sin6_scope_id != 0) ||
97 ifa->ifa_addr->sa_family == AF_INET);
98 }
99
count_interfaces(const struct ifaddrs * ifs,const struct addrinfo * addrs)100 static size_t count_interfaces(const struct ifaddrs *ifs,
101 const struct addrinfo* addrs)
102 {
103 size_t nb_if = 0;
104
105 for ( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
106 for (const struct ifaddrs *c = ifs; c != NULL; c = c->ifa_next) {
107 if (!mdns_is_interface_valuable(c, addr->ai_family)) {
108 continue;
109 }
110 nb_if++;
111 }
112 }
113 return nb_if;
114 }
115
116 static int
mdns_list_interfaces(uint32_t ** pp_intfs,struct sockaddr_storage ** pp_mdns_ips,size_t * p_nb_intf,struct sockaddr_storage ** pp_mcast_addrs,const struct addrinfo * addrs)117 mdns_list_interfaces(uint32_t** pp_intfs, struct sockaddr_storage **pp_mdns_ips,
118 size_t* p_nb_intf, struct sockaddr_storage **pp_mcast_addrs,
119 const struct addrinfo* addrs)
120 {
121 struct ifaddrs *ifs;
122 struct sockaddr_storage *mdns_ips;
123 struct ifaddrs *c;
124 struct sockaddr_storage *mcast_addrs;
125 size_t nb_if;
126 uint32_t* intfs;
127
128 *p_nb_intf = 0;
129 if (getifaddrs(&ifs) || ifs == NULL)
130 return (MDNS_NETERR);
131
132 nb_if = count_interfaces(ifs, addrs);
133
134 if (nb_if == 0) {
135 freeifaddrs(ifs);
136 return (MDNS_ERROR);
137 }
138 *pp_intfs = intfs = malloc(sizeof(*intfs) * nb_if);
139 if (intfs == NULL) {
140 freeifaddrs(ifs);
141 return (MDNS_ERROR);
142 }
143 *pp_mdns_ips = mdns_ips = malloc(sizeof(*mdns_ips) * nb_if);
144 if (mdns_ips == NULL) {
145 free(intfs);
146 *pp_intfs = NULL;
147 freeifaddrs(ifs);
148 return (MDNS_ERROR);
149 }
150 *pp_mcast_addrs = mcast_addrs = malloc(sizeof(*mcast_addrs) * nb_if);
151 if (mcast_addrs == NULL) {
152 free(mdns_ips);
153 free(intfs);
154 *pp_intfs = NULL;
155 *pp_mdns_ips = NULL;
156 freeifaddrs(ifs);
157 return (MDNS_ERROR);
158 }
159 for ( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
160 for (c = ifs; c != NULL; c = c->ifa_next) {
161 if (!mdns_is_interface_valuable(c, addr->ai_family))
162 continue;
163 if (c->ifa_addr->sa_family == AF_INET) {
164 *intfs = if_nametoindex(c->ifa_name);
165 } else {
166 memcpy(intfs, &((struct sockaddr_in6*)c->ifa_addr)->sin6_scope_id,
167 sizeof(*intfs));
168 }
169 memcpy(mdns_ips, c->ifa_addr, sa_len(c->ifa_addr));
170 memcpy(mcast_addrs, addr->ai_addr, sa_len(addr->ai_addr));
171 mdns_ips++;
172 intfs++;
173 mcast_addrs++;
174 }
175 }
176 freeifaddrs(ifs);
177 *p_nb_intf = nb_if;
178 return (0);
179 }
180 #else
181 static size_t
mdns_list_interfaces(uint32_t ** pp_intfs,struct sockaddr_storage ** pp_mdns_ips,size_t * p_nb_intf,struct sockaddr_storage ** pp_mcast_addrs,const struct addrinfo * addrs)182 mdns_list_interfaces(uint32_t** pp_intfs, struct sockaddr_storage **pp_mdns_ips,
183 size_t* p_nb_intf, struct sockaddr_storage **pp_mcast_addrs,
184 const struct addrinfo* addrs)
185 {
186 struct sockaddr_storage *mdns_ips;
187 uint32_t *intfs;
188 size_t nb_intfs = 0;
189 for( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
190 if( addr->ai_family == AF_INET || addr->ai_family == AF_INET6 )
191 ++nb_intfs;
192 }
193 *pp_intfs = intfs = malloc( nb_intfs * sizeof(*intfs) );
194 if (intfs == NULL)
195 return (MDNS_ERROR);
196 *pp_mdns_ips = mdns_ips = malloc( nb_intfs * sizeof(*mdns_ips) );
197 if (mdns_ips == NULL) {
198 free(intfs);
199 *pp_intfs = NULL;
200 return (MDNS_ERROR);
201 }
202
203 struct sockaddr_storage* mcast_addrs;
204 mcast_addrs = *pp_mcast_addrs = malloc( nb_intfs * sizeof( *mcast_addrs ) );
205 if( mcast_addrs == NULL ) {
206 free(mdns_ips);
207 free(intfs);
208 *pp_intfs = NULL;
209 *pp_mdns_ips = NULL;
210 return (MDNS_ERROR);
211 }
212 for( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
213 if( addr->ai_family == AF_INET || addr->ai_family == AF_INET6 ) {
214 *intfs = 0;
215 /* Take a shortcut assuming when we are in this case, we
216 * can use MCAST_JOIN_GROUP. Otherwise, we need the
217 * adapter IP address, which without getifaddrs is a pain
218 * in the lower back to fetch
219 */
220 #ifndef MCAST_JOIN_GROUP
221 # error We need the adapter address
222 #endif
223 mdns_ips->ss_family = addr->ai_family;
224 memcpy(mcast_addrs, addr->ai_addr, sa_len(addr->ai_addr));
225 intfs++;
226 mdns_ips++;
227 mcast_addrs++;
228 }
229 }
230
231 *p_nb_intf = nb_intfs;
232 return (0);
233 }
234 #endif // HAVE_GETIFADDRS
235
236 #else // _WIN32
237
238 static bool
mdns_is_interface_valuable(IP_ADAPTER_ADDRESSES * intf,int family)239 mdns_is_interface_valuable(IP_ADAPTER_ADDRESSES *intf, int family)
240 {
241 return (intf->IfType == IF_TYPE_IEEE80211 || intf->IfType == IF_TYPE_ETHERNET_CSMACD) &&
242 intf->OperStatus == IfOperStatusUp &&
243 ((family == AF_INET && intf->Ipv4Enabled) ||
244 (family == AF_INET6 && intf->Ipv6Enabled));
245 }
246
247 static size_t
mdns_list_interfaces(uint32_t ** pp_intfs,struct sockaddr_storage ** pp_mdns_ips,size_t * p_nb_intf,struct sockaddr_storage ** pp_mcast_addrs,const struct addrinfo * addrs)248 mdns_list_interfaces(uint32_t** pp_intfs, struct sockaddr_storage **pp_mdns_ips,
249 size_t* p_nb_intf, struct sockaddr_storage **pp_mcast_addrs,
250 const struct addrinfo* addrs)
251 {
252 uint32_t* intfs;
253 struct sockaddr_storage *mdns_ips;
254 struct sockaddr_storage *mcast_addrs;
255 IP_ADAPTER_ADDRESSES *res = NULL, *current;
256 ULONG size;
257 HRESULT hr;
258 size_t nb_intf = 0;
259
260 *p_nb_intf = 0;
261 /**
262 * https://msdn.microsoft.com/en-us/library/aa365915.aspx
263 *
264 * The recommended method of calling the GetAdaptersAddresses function is to pre-allocate a
265 * 15KB working buffer pointed to by the AdapterAddresses parameter. On typical computers,
266 * this dramatically reduces the chances that the GetAdaptersAddresses function returns
267 * ERROR_BUFFER_OVERFLOW, which would require calling GetAdaptersAddresses function multiple
268 * times. The example code illustrates this method of use.
269 */
270 size = 15 * 1024;
271 do
272 {
273 free(res);
274 res = malloc( size );
275 if (res == NULL)
276 return (MDNS_ERROR);
277 hr = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST |
278 GAA_FLAG_SKIP_DNS_SERVER,
279 NULL, res, &size);
280 } while (hr == ERROR_BUFFER_OVERFLOW);
281 if (hr != NO_ERROR) {
282 free(res);
283 return (MDNS_NETERR);
284 }
285
286 for ( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
287 for (current = res; current != NULL; current = current->Next) {
288 if (!mdns_is_interface_valuable(current, addr->ai_family))
289 continue;
290 ++nb_intf;
291 }
292 }
293 if (nb_intf == 0) {
294 // Fallback to the default interface
295 *pp_intfs = malloc(sizeof(*intfs));
296 if (*pp_intfs == NULL) {
297 free(res);
298 return (MDNS_ERROR);
299 }
300 **pp_intfs = 0;
301 *pp_mdns_ips = mdns_ips = malloc(sizeof(*mdns_ips));
302 if (*pp_mdns_ips == NULL) {
303 free(*pp_intfs);
304 free(res);
305 return (MDNS_ERROR);
306 }
307 memset(mdns_ips, 0, sizeof(*mdns_ips));
308 *pp_mcast_addrs = mcast_addrs = malloc(sizeof(*mcast_addrs));
309 if (mcast_addrs == NULL) {
310 free(mdns_ips);
311 free(*pp_intfs);
312 free(res);
313 return (MDNS_ERROR);
314 }
315 memcpy(mcast_addrs, addrs->ai_addr, sa_len(addrs->ai_addr));
316 *p_nb_intf = 1;
317 return (0);
318 }
319
320 *pp_intfs = intfs = malloc(nb_intf * sizeof(*intfs));
321 if (intfs == NULL) {
322 free(res);
323 return (MDNS_ERROR);
324 }
325 *pp_mdns_ips = mdns_ips = malloc(sizeof(*mdns_ips) * nb_intf);
326 if (mdns_ips == NULL) {
327 free(intfs);
328 free(res);
329 return (MDNS_ERROR);
330 }
331 *pp_mcast_addrs = mcast_addrs = malloc(sizeof(*mcast_addrs) * nb_intf);
332 if (mcast_addrs == NULL) {
333 free(mdns_ips);
334 free(intfs);
335 free(res);
336 return (MDNS_ERROR);
337 }
338 for ( const struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next ) {
339 for (current = res; current != NULL; current = current->Next) {
340 if (!mdns_is_interface_valuable(current, addr->ai_family))
341 continue;
342 if (addr->ai_family == AF_INET6) {
343 *intfs = current->Ipv6IfIndex;
344 }
345 else {
346 *intfs = current->IfIndex;
347 }
348 memcpy(mcast_addrs, addr->ai_addr, sa_len(addr->ai_addr));
349 PIP_ADAPTER_UNICAST_ADDRESS p_unicast = current->FirstUnicastAddress;
350 if (p_unicast == NULL) {
351 free(mdns_ips);
352 free(intfs);
353 free(res);
354 return (MDNS_ERROR);
355 }
356 // Take the first unicast address (highest priority)
357 for (; p_unicast != NULL; p_unicast = p_unicast->Next) {
358 if (p_unicast->Address.lpSockaddr->sa_family != addr->ai_family) {
359 continue;
360 }
361
362 if (addr->ai_family == AF_INET) {
363 memcpy(mdns_ips, p_unicast->Address.lpSockaddr,
364 sizeof(struct sockaddr_in));
365 }
366 else {
367 memcpy(mdns_ips, p_unicast->Address.lpSockaddr,
368 sizeof(struct sockaddr_in6));
369 }
370 }
371 ++mdns_ips;
372 ++intfs;
373 ++mcast_addrs;
374 }
375 }
376 *p_nb_intf = nb_intf;
377 free(res);
378 return (0);
379 }
380 #endif
381
382 static int
mdns_resolve(struct mdns_ctx * ctx,const char * addr,unsigned short port)383 mdns_resolve(struct mdns_ctx *ctx, const char *addr, unsigned short port)
384 {
385 char buf[6];
386 struct addrinfo hints, *res = NULL;
387 uint32_t* ifaddrs = NULL;
388 struct sockaddr_storage *mdns_ips = NULL;
389 struct sockaddr_storage *mcast_addrs = NULL;
390 size_t i;
391 int status;
392
393 sprintf(buf, "%hu", port);
394 memset(&hints, 0, sizeof(hints));
395 hints.ai_socktype = SOCK_DGRAM;
396 hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
397
398 if (addr == NULL) {
399 hints.ai_family = AF_INET;
400 /* First, get the ipv4 multicast address info */
401 errno = getaddrinfo(MDNS_ADDR_IPV4, buf, &hints, &res);
402 if (errno != 0)
403 return (MDNS_LKPERR);
404 /* Now get the ipv6 informations and link them with the ipv4 ones */
405 struct addrinfo *ipv6_res = NULL;
406 hints.ai_family = AF_INET6;
407 errno = getaddrinfo(MDNS_ADDR_IPV6, buf, &hints, &ipv6_res);
408 if (errno != 0) {
409 freeaddrinfo(res);
410 return (MDNS_LKPERR);
411 }
412 struct addrinfo* ipv4 = res;
413 for (; ipv4->ai_next != NULL; ipv4 = ipv4->ai_next)
414 ;
415 ipv4->ai_next = ipv6_res;
416 } else {
417 int family;
418 if (!strcmp(addr, MDNS_ADDR_IPV4))
419 family = AF_INET;
420 else if (!strcmp(addr, MDNS_ADDR_IPV6))
421 family = AF_INET6;
422 else
423 return (MDNS_LKPERR);
424 hints.ai_family = family;
425 errno = getaddrinfo(addr, buf, &hints, &res);
426 if (errno != 0)
427 return (MDNS_LKPERR);
428 }
429
430 status = mdns_list_interfaces(&ifaddrs, &mdns_ips, &ctx->nb_conns, &mcast_addrs, res);
431 if ( status < 0) {
432 freeaddrinfo(res);
433 return (status);
434 }
435 if (ctx->nb_conns == 0) {
436 freeaddrinfo(res);
437 return (MDNS_NETERR);
438 }
439 ctx->conns = malloc(ctx->nb_conns * sizeof(*ctx->conns));
440 if (ctx->conns == NULL) {
441 free(ifaddrs);
442 free(mdns_ips);
443 freeaddrinfo(res);
444 free(mcast_addrs);
445 return (MDNS_ERROR);
446 }
447 for (i = 0; i < ctx->nb_conns; ++i ) {
448 ctx->conns[i].sock = INVALID_SOCKET;
449 ctx->conns[i].intf_idx = ifaddrs[i];
450 ctx->conns[i].intf_addr = mdns_ips[i];
451 ctx->conns[i].mcast_addr = mcast_addrs[i];
452 }
453 free(mcast_addrs);
454 free(ifaddrs);
455 free(mdns_ips);
456 freeaddrinfo(res);
457 return (0);
458 }
459
460 int
mdns_init(struct mdns_ctx ** p_ctx,const char * addr,unsigned short port)461 mdns_init(struct mdns_ctx **p_ctx, const char *addr, unsigned short port)
462 {
463 const uint32_t on_off = 1;
464 const uint32_t ttl = 255;
465 const uint32_t loop = 1;
466 int res;
467 union {
468 struct sockaddr_storage ss;
469 struct sockaddr_in sin;
470 struct sockaddr_in6 sin6;
471 } dumb;
472 struct mdns_ctx *ctx;
473
474 if (p_ctx == NULL)
475 return (MDNS_ERROR);
476 *p_ctx = NULL;
477
478 ctx = malloc(sizeof(struct mdns_ctx));
479 if (ctx == NULL)
480 return (MDNS_ERROR);
481
482 ctx->services = NULL;
483 ctx->conns = NULL;
484 ctx->nb_conns = 0;
485 errno = os_init("2.2");
486 if (errno != 0)
487 return mdns_destroy(ctx), (MDNS_NETERR);
488 res = mdns_resolve(ctx, addr, port);
489 if (res < 0)
490 return mdns_destroy(ctx), (res);
491
492 for (size_t i = 0; i < ctx->nb_conns; ++i ) {
493 struct sockaddr_storage* ss_addr = (struct sockaddr_storage*)&ctx->conns[i].mcast_addr;
494 if ((ctx->conns[i].sock = socket(ctx->conns[i].intf_addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
495 return mdns_destroy(ctx), (MDNS_NETERR);
496 if (setsockopt(ctx->conns[i].sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &on_off, sizeof(on_off)) < 0)
497 return mdns_destroy(ctx), (MDNS_NETERR);
498 /* bind the receiver on any local address */
499 memset(&dumb, 0, sizeof(dumb));
500 dumb.ss.ss_family = ss_family(&ctx->conns[i].intf_addr);
501 if (dumb.ss.ss_family == AF_INET) {
502 dumb.sin.sin_port = htons(port);
503 dumb.sin.sin_addr.s_addr = INADDR_ANY;
504 } else {
505 dumb.sin6.sin6_port = htons(port);
506 dumb.sin6.sin6_addr = in6addr_any;
507 }
508 if (bind(ctx->conns[i].sock, (const struct sockaddr *) &dumb,
509 ss_len(&dumb.ss)) < 0)
510 return mdns_destroy(ctx), (MDNS_NETERR);
511
512 if (os_mcast_join(ctx->conns[i].sock, ss_addr, ctx->conns[i].intf_idx,
513 &ctx->conns[i].intf_addr) < 0)
514 return mdns_destroy(ctx), (MDNS_NETERR);
515 if (setsockopt(ctx->conns[i].sock, ss_level(&ctx->conns[i].intf_addr),
516 ctx->conns[i].intf_addr.ss_family == AF_INET ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS,
517 (const void *) &ttl, sizeof(ttl)) < 0) {
518 return mdns_destroy(ctx), (MDNS_NETERR);
519 }
520
521 if (setsockopt(ctx->conns[i].sock, ss_level(&ctx->conns[i].intf_addr),
522 ctx->conns[i].intf_addr.ss_family == AF_INET ? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP,
523 (const void *) &loop, sizeof(loop)) < 0) {
524 return mdns_destroy(ctx), (MDNS_NETERR);
525 }
526 }
527 *p_ctx = ctx;
528 return (0);
529 }
530
531 int
mdns_destroy(struct mdns_ctx * ctx)532 mdns_destroy(struct mdns_ctx *ctx)
533 {
534 if (ctx != NULL) {
535 for (size_t i = 0; i < ctx->nb_conns; ++i) {
536 struct mdns_conn *conn = &ctx->conns[i];
537 if (conn->sock != INVALID_SOCKET) {
538 os_close(conn->sock);
539 conn->sock = INVALID_SOCKET;
540 }
541 }
542 free(ctx->conns);
543 if (ctx->services) {
544 struct mdns_svc *svc;
545
546 while ((svc = ctx->services)) {
547 ctx->services = ctx->services->next;
548 free(svc);
549 }
550 }
551 free(ctx);
552 }
553 if (os_cleanup() < 0)
554 return (MDNS_NETERR);
555 return (0);
556 }
557
558 static size_t
mdns_write_hdr(uint8_t * ptr,size_t * s,const struct mdns_hdr * hdr)559 mdns_write_hdr(uint8_t *ptr, size_t* s, const struct mdns_hdr *hdr)
560 {
561 uint8_t *p = ptr;
562
563 if (*s < 12)
564 return (-1);
565
566 p = write_u16(p, s, hdr->id);
567 p = write_u16(p, s, hdr->flags);
568 p = write_u16(p, s, hdr->num_qn);
569 p = write_u16(p, s, hdr->num_ans_rr);
570 p = write_u16(p, s, hdr->num_auth_rr);
571 p = write_u16(p, s, hdr->num_add_rr);
572 return (p - ptr);
573 }
574
575 int
mdns_write(const struct mdns_hdr * hdr,const struct rr_entry * entries,uint8_t * buf,size_t bufSize,size_t * length)576 mdns_write(const struct mdns_hdr *hdr, const struct rr_entry *entries,
577 uint8_t *buf, size_t bufSize, size_t* length)
578 {
579 *length = 0;
580 if (!entries) return (MDNS_ERROR);
581 const struct rr_entry *entry = entries;
582 ssize_t l;
583
584 l = mdns_write_hdr(buf, &bufSize, hdr);
585 if (l < 0)
586 return (MDNS_ERROR);
587 *length += l;
588
589 for (entry = entries; entry; entry = entry->next) {
590 l = rr_write(buf + *length, &bufSize, entry, (hdr->flags & FLAG_QR) > 0);
591 if (l < 0) {
592 return (MDNS_STDERR);
593 }
594 *length += l;
595 }
596 return (0);
597 }
598
599 int
mdns_entries_send(const struct mdns_ctx * ctx,const struct mdns_hdr * hdr,const struct rr_entry * entries)600 mdns_entries_send(const struct mdns_ctx *ctx, const struct mdns_hdr *hdr, const struct rr_entry *entries)
601 {
602 uint8_t buf[MDNS_PKT_MAXSZ] = {0};
603 size_t l;
604
605 if (mdns_write(hdr, entries, buf, sizeof(buf), &l) < 0)
606 return (MDNS_ERROR);
607
608 for (size_t i = 0; i < ctx->nb_conns; ++i) {
609 ssize_t r = sendto(ctx->conns[i].sock, (const char *) buf, l, 0,
610 (const struct sockaddr *) &ctx->conns[i].mcast_addr,
611 ss_len((struct sockaddr_storage*)&ctx->conns[i].mcast_addr));
612 if (r < 0)
613 return (MDNS_NETERR);
614 }
615
616 return (0);
617 }
618
619 void
mdns_free(struct rr_entry * entries)620 mdns_free(struct rr_entry *entries)
621 {
622 struct rr_entry *entry;
623
624 while ((entry = entries)) {
625 entries = entries->next;
626 rr_free(entry);
627 free(entry);
628 }
629 }
630
631 static const uint8_t *
mdns_read_header(const uint8_t * ptr,size_t * n,struct mdns_hdr * hdr)632 mdns_read_header(const uint8_t *ptr, size_t *n, struct mdns_hdr *hdr)
633 {
634 if (*n <= sizeof(struct mdns_hdr)) {
635 errno = ENOSPC;
636 return NULL;
637 }
638 ptr = read_u16(ptr, n, &hdr->id);
639 ptr = read_u16(ptr, n, &hdr->flags);
640 ptr = read_u16(ptr, n, &hdr->num_qn);
641 ptr = read_u16(ptr, n, &hdr->num_ans_rr);
642 ptr = read_u16(ptr, n, &hdr->num_auth_rr);
643 ptr = read_u16(ptr, n, &hdr->num_add_rr);
644 return ptr;
645 }
646
647 int
mdns_parse(struct mdns_hdr * hdr,struct rr_entry ** entries,const uint8_t * buf,size_t length)648 mdns_parse(struct mdns_hdr *hdr, struct rr_entry **entries, const uint8_t *buf,
649 size_t length)
650 {
651 size_t num_entry;
652 struct rr_entry *entry;
653
654 *entries = NULL;
655
656 const uint8_t *ptr = mdns_read_header(buf, &length, hdr);
657 if (ptr == NULL)
658 return (MDNS_ERROR);
659
660 num_entry = hdr->num_qn + hdr->num_ans_rr + hdr->num_add_rr;
661 for (size_t i = 0; i < num_entry; ++i) {
662 entry = calloc(1, sizeof(struct rr_entry));
663 if (!entry)
664 goto err;
665 ptr = rr_read(ptr, &length, buf, entry, i >= hdr->num_qn);
666 if (!ptr) {
667 mdns_free(entry);
668 errno = ENOSPC;
669 goto err;
670 }
671 entry->next = *entries;
672 *entries = entry;
673 }
674 if (*entries == NULL) {
675 return (MDNS_ERROR);
676 }
677 return (0);
678 err:
679 mdns_free(*entries);
680 *entries = NULL;
681 return (MDNS_ERROR);
682 }
683
684 static int
mdns_recv(const struct mdns_conn * conn,struct mdns_hdr * hdr,struct rr_entry ** entries)685 mdns_recv(const struct mdns_conn* conn, struct mdns_hdr *hdr, struct rr_entry **entries)
686 {
687 uint8_t buf[MDNS_PKT_MAXSZ];
688 ssize_t length;
689
690 *entries = NULL;
691 if ((length = recv(conn->sock, (char *) buf, sizeof(buf), 0)) < 0)
692 return (MDNS_NETERR);
693
694 return mdns_parse(hdr, entries, buf, (size_t)length);
695 }
696
697 void
mdns_entries_print(const struct rr_entry * entry)698 mdns_entries_print(const struct rr_entry *entry)
699 {
700 printf("[");
701 while (entry) {
702 rr_print(entry);
703 if (entry->next)
704 printf(",");
705 entry = entry->next;
706 }
707 printf("]\n");
708 }
709
710 int
mdns_strerror(int r,char * buf,size_t n)711 mdns_strerror(int r, char *buf, size_t n)
712 {
713 return os_strerror(r, buf, n);
714 }
715
716 static int
strrcmp(const char * s1,const char * s2)717 strrcmp(const char *s1, const char *s2)
718 {
719 size_t m, n;
720
721 if (!s1 || !s2)
722 return (1);
723 m = strlen(s1);
724 n = strlen(s2);
725 if (n > m)
726 return (1);
727 return (strncmp(s1 + m - n, s2, n));
728 }
729
730 static int
mdns_listen_probe_network(const struct mdns_ctx * ctx,const char * const names[],unsigned int nb_names,mdns_listen_callback callback,void * p_cookie)731 mdns_listen_probe_network(const struct mdns_ctx *ctx, const char *const names[],
732 unsigned int nb_names, mdns_listen_callback callback,
733 void *p_cookie)
734 {
735 struct mdns_hdr ahdr = {0};
736 struct rr_entry *entries;
737 struct pollfd *pfd = alloca( sizeof(*pfd) * ctx->nb_conns );
738 int r;
739
740 for (size_t i = 0; i < ctx->nb_conns; ++i) {
741 pfd[i].fd = ctx->conns[i].sock;
742 pfd[i].events = POLLIN;
743 }
744
745 r = poll(pfd, ctx->nb_conns, 1000);
746 if (r <= 0) {
747 return r;
748 }
749 for (size_t i = 0; i < ctx->nb_conns; ++i) {
750 if ((pfd[i].revents & POLLIN) == 0)
751 continue;
752 r = mdns_recv(&ctx->conns[i], &ahdr, &entries);
753 if (r == MDNS_NETERR && os_wouldblock())
754 {
755 mdns_free(entries);
756 continue;
757 }
758
759 if (ahdr.num_ans_rr + ahdr.num_add_rr == 0)
760 {
761 mdns_free(entries);
762 continue;
763 }
764
765 for (struct rr_entry *entry = entries; entry; entry = entry->next) {
766 for (unsigned int i = 0; i < nb_names; ++i) {
767 if (!strrcmp(entry->name, names[i])) {
768 callback(p_cookie, r, entries);
769 break;
770 }
771 }
772 }
773 mdns_free(entries);
774 }
775 return 0;
776 }
777
778 int
mdns_listen(const struct mdns_ctx * ctx,const char * const names[],unsigned int nb_names,enum rr_type type,unsigned int interval,mdns_stop_func stop,mdns_listen_callback callback,void * p_cookie)779 mdns_listen(const struct mdns_ctx *ctx, const char *const names[],
780 unsigned int nb_names, enum rr_type type, unsigned int interval,
781 mdns_stop_func stop, mdns_listen_callback callback, void *p_cookie)
782 {
783 if (ctx->nb_conns == 0)
784 return (MDNS_ERROR);
785 int r;
786 time_t t1, t2;
787 struct mdns_hdr hdr = {0};
788 struct rr_entry *qns = malloc(nb_names * sizeof(struct rr_entry));
789 if (qns == NULL)
790 return (MDNS_ERROR);
791 memset(qns, 0, nb_names * sizeof(struct rr_entry));
792
793 hdr.num_qn = nb_names;
794 for (unsigned int i = 0; i < nb_names; ++i)
795 {
796 qns[i].name = (char *)names[i];
797 qns[i].type = type;
798 qns[i].rr_class = RR_IN;
799 if (i + 1 < nb_names)
800 qns[i].next = &qns[i+1];
801 }
802
803 for (size_t i = 0; i < ctx->nb_conns; ++i) {
804 if (setsockopt(ctx->conns[i].sock, SOL_SOCKET, SO_SNDTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
805 {
806 free(qns);
807 return (MDNS_NETERR);
808 }
809 }
810
811 if ((r = mdns_entries_send(ctx, &hdr, qns)) < 0) // send a first probe request
812 callback(p_cookie, r, NULL);
813 for (t1 = t2 = time(NULL); stop(p_cookie) == false; t2 = time(NULL)) {
814 if (difftime(t2, t1) >= (double) interval) {
815 if ((r = mdns_entries_send(ctx, &hdr, qns)) < 0) {
816 callback(p_cookie, r, NULL);
817 }
818 t1 = t2;
819 }
820 mdns_listen_probe_network(ctx, names, nb_names, callback, p_cookie);
821 }
822 free(qns);
823 return (0);
824 }
825
826 int
mdns_announce(struct mdns_ctx * ctx,enum rr_type type,mdns_announce_callback callback,void * p_cookie)827 mdns_announce(struct mdns_ctx *ctx, enum rr_type type,
828 mdns_announce_callback callback, void *p_cookie)
829 {
830 if (!callback)
831 return (MDNS_ERROR);
832
833 struct mdns_svc *svc = (struct mdns_svc *) calloc(1, sizeof(struct mdns_svc));
834 if (!svc)
835 return (MDNS_ERROR);
836
837 svc->type = type;
838 svc->announce_callback = callback;
839 svc->p_cookie = p_cookie;
840 svc->next = ctx->services;
841
842 ctx->services = svc;
843 return (0);
844 }
845
846 void
mdns_request_initial_announce(struct mdns_ctx * ctx,const char * service)847 mdns_request_initial_announce(struct mdns_ctx *ctx, const char* service)
848 {
849 /* Send the initial announce (RFC 6762 §8.3) */
850 for (struct mdns_svc* svc = ctx->services; svc; svc = svc->next) {
851 for ( size_t i = 0; i < ctx->nb_conns; ++i ) {
852 svc->announce_callback(svc->p_cookie,
853 (struct sockaddr*)&ctx->conns[i].intf_addr,
854 service, MDNS_ANNOUNCE_INITIAL);
855 }
856 }
857 }
858
859 int
mdns_serve(struct mdns_ctx * ctx,mdns_stop_func stop,void * p_cookie)860 mdns_serve(struct mdns_ctx *ctx, mdns_stop_func stop, void *p_cookie)
861 {
862 int r;
863 struct mdns_svc *svc;
864 struct mdns_hdr qhdr = {0};
865 struct rr_entry *question = NULL;
866
867 for (size_t i = 0; i < ctx->nb_conns; ++i) {
868 if (setsockopt(ctx->conns[i].sock, SOL_SOCKET, SO_SNDTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
869 return (MDNS_NETERR);
870 }
871
872 /* Send the initial announce (RFC 6762 §8.3) */
873 for (svc = ctx->services; svc; svc = svc->next) {
874 for ( size_t i = 0; i < ctx->nb_conns; ++i ) {
875 svc->announce_callback(svc->p_cookie,
876 (struct sockaddr*)&ctx->conns[i].intf_addr,
877 NULL, MDNS_ANNOUNCE_INITIAL);
878 }
879 }
880
881 for (; stop(p_cookie) == false;) {
882 struct pollfd *pfd = alloca( sizeof(*pfd) * ctx->nb_conns );
883
884 for (size_t i = 0; i < ctx->nb_conns; ++i) {
885 pfd[i].fd = ctx->conns[i].sock;
886 pfd[i].events = POLLIN;
887 }
888 if (poll(pfd, ctx->nb_conns, 1000) <= 0) {
889 continue;
890 }
891 for (size_t i = 0; i < ctx->nb_conns; ++i) {
892 if ((pfd[i].revents & POLLIN) == 0)
893 continue;
894 r = mdns_recv(&ctx->conns[i], &qhdr, &question);
895 if (r < 0)
896 continue;
897 if (qhdr.num_qn == 0)
898 goto again;
899
900 for (svc = ctx->services; svc; svc = svc->next) {
901 if (question->type == svc->type) {
902 svc->announce_callback(svc->p_cookie,
903 (struct sockaddr*)&ctx->conns[i].intf_addr,
904 question->name, MDNS_ANNOUNCE_RESPONSE);
905 goto again;
906 }
907 }
908 mdns_free(question);
909 question = NULL;
910 }
911 again:
912 mdns_free(question);
913 question = NULL;
914 }
915 /* Send the goodbye packets (RFC 6762 §10.1) */
916 for (svc = ctx->services; svc; svc = svc->next) {
917 for ( size_t i = 0; i < ctx->nb_conns; ++i ) {
918 svc->announce_callback(svc->p_cookie,
919 (struct sockaddr*)&ctx->conns[i].intf_addr, NULL,
920 MDNS_ANNOUNCE_GOODBYE);
921 }
922 }
923 return (0);
924 }
925