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