]> git.ipfire.org Git - thirdparty/shairport-sync.git/blob - tinysvcmdns.c
Update check_classic_systemd_full.yml
[thirdparty/shairport-sync.git] / tinysvcmdns.c
1 // This file is the concatenation of mdnsd.c and mdns.c
2 // from tinysvcmdns with minor modifications
3 // The code was taken from https://bitbucket.org/geekman/tinysvcmdns at revision e34b562
4
5 /*
6 * tinysvcmdns - a tiny MDNS implementation for publishing services
7 * Copyright (C) 2011 Darell Tan
8 * All rights reserved.
9 * Updated many times by Mike Brady (c) 2014 -- 2019
10 * Includes fixes for CVE-12087 and CVE-2017-12130
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "tinysvcmdns.h"
36 #include "common.h"
37
38 #define DEBUG_PRINTF(...) debug(3, __VA_ARGS__)
39 #define log_message(level, ...) \
40 do { \
41 switch (level) { \
42 case LOG_ERR: \
43 warn(__VA_ARGS__); \
44 break; \
45 default: \
46 debug(3, __VA_ARGS__); \
47 } \
48 } while (0)
49
50 //******************************************************//
51 // mdns.c //
52 //******************************************************//
53 #include <assert.h>
54 #include <stdint.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58
59 #ifdef _WIN32
60 #include <in6addr.h>
61 #include <winsock.h>
62 #else
63 #include <netinet/in.h>
64 #endif
65
66 // See RFC 6762 Section 10 for an account of two TTLs -- 120 seconds for rrs with a host name as the
67 // record's name
68 // or a host name in the record's rdata
69 // 75 minutes for everything else.
70 // https://tools.ietf.org/html/rfc6762
71
72 #define DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME 120
73 #define DEFAULT_TTL 4500
74
75 struct name_comp {
76 uint8_t *label; // label
77 size_t pos; // position in msg
78
79 struct name_comp *next;
80 };
81
82 // ----- label functions -----
83
84 // duplicates a name
85 inline uint8_t *dup_nlabel(const uint8_t *n) {
86 if (n == NULL)
87 return NULL;
88 assert(n[0] <= 63); // prevent mis-use
89 return (uint8_t *)strdup((char *)n);
90 }
91
92 // duplicates a label
93 uint8_t *dup_label(const uint8_t *label) {
94 int len = *label + 1;
95 if (len > 63)
96 return NULL;
97 uint8_t *newlabel = malloc(len + 1);
98 if (newlabel)
99 strncpy((char *)newlabel, (char *)label, len);
100 else
101 die("could not allocate memory for \"newlabel\" in tinysvcmdns");
102 newlabel[len] = '\0';
103 return newlabel;
104 }
105
106 uint8_t *join_nlabel(const uint8_t *n1, const uint8_t *n2) {
107 int len1, len2;
108 uint8_t *s;
109
110 assert(n1[0] <= 63 && n2[0] <= 63); // detect misuse
111
112 len1 = strlen((char *)n1);
113 len2 = strlen((char *)n2);
114
115 s = malloc(len1 + len2 + 1);
116 if (s) {
117 memcpy((char *)s, (char *)n1, len1);
118 memcpy((char *)s + len1, (char *)n2, len2);
119 s[len1 + len2] = '\0';
120 } else {
121 die("can not allocate memory for \"s\" in tinysvcmdns");
122 }
123 return s;
124 }
125
126 // returns a human-readable name label in dotted form
127 char *nlabel_to_str(const uint8_t *name) {
128 char *label, *labelp;
129 const uint8_t *p;
130 size_t buf_len = 256;
131
132 if (name == NULL)
133 return NULL;
134 label = labelp = malloc(buf_len);
135
136 if (label) {
137 for (p = name; *p; p++) {
138 uint8_t label_len = *p;
139 if (buf_len <= label_len)
140 break;
141
142 strncpy(labelp, (char *)p + 1, label_len);
143 labelp += label_len;
144
145 *labelp = '.';
146 labelp++;
147
148 buf_len -= label_len + 1;
149
150 p += label_len;
151 }
152
153 // avoid writing NULL past end of buffer
154 if (buf_len == 0)
155 labelp--;
156
157 *labelp = '\0';
158 } else {
159 die("could not allocate memory for \"label\" in tinysvcmdns.c.");
160 }
161
162 return label;
163 }
164
165 // returns the length of a label field
166 // does NOT uncompress the field, so it could be as small as 2 bytes
167 // or 1 for the root
168 static size_t label_len(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
169 uint8_t *p;
170 uint8_t *e = pkt_buf + pkt_len;
171 size_t len = 0;
172
173 for (p = pkt_buf + off; p < e; p++) {
174 if (*p == 0) {
175 return len + 1;
176 } else if ((*p & 0xC0) == 0xC0) {
177 return len + 2;
178 } else {
179 len += *p + 1;
180 p += *p;
181 }
182 }
183
184 return len;
185 }
186
187 // creates a label
188 // free() after use
189 uint8_t *create_label(const char *txt) {
190 int len;
191 uint8_t *s;
192
193 // assert(txt != NULL);
194 if (txt == NULL)
195 return NULL;
196 len = strlen(txt);
197 if (len > 63)
198 return NULL;
199
200 s = malloc(len + 2);
201 if (s) {
202 s[0] = len;
203 memcpy((char *)s + 1, txt, len);
204 s[len + 1] = '\0';
205 } else {
206 die("can not allocate memory for \"s\" 2 in tinysvcmdns.");
207 }
208 return s;
209 }
210
211 // creates a uncompressed name label given a DNS name like "apple.b.com"
212 // free() after use
213 uint8_t *create_nlabel(const char *name) {
214 char *label;
215 char *p, *e, *lenpos;
216 int len = 0;
217
218 assert(name != NULL);
219
220 len = strlen(name);
221 label = malloc(len + 1 + 1);
222 if (label == NULL)
223 return NULL;
224
225 memcpy((char *)label + 1, name, len);
226 label[len + 1] = '\0';
227
228 p = label;
229 e = p + len;
230 lenpos = p;
231
232 while (p < e) {
233 *lenpos = 0;
234 char *dot = memchr(p + 1, '.', e - p - 1);
235 if (dot == NULL)
236 dot = e + 1;
237 *lenpos = dot - p - 1;
238
239 p = dot;
240 lenpos = dot;
241 }
242
243 return (uint8_t *)label;
244 }
245
246 // copies a label from the buffer into a newly-allocated string
247 // free() after use
248 static uint8_t *copy_label(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
249 int len;
250
251 if (off > pkt_len)
252 return NULL;
253
254 len = pkt_buf[off] + 1;
255 if (off + len > pkt_len) {
256 DEBUG_PRINTF("label length exceeds packet buffer\n");
257 return NULL;
258 }
259
260 return dup_label(pkt_buf + off);
261 }
262
263 // uncompresses a name
264 // free() after use
265 static uint8_t *uncompress_nlabel(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
266 uint8_t *p;
267 uint8_t *e = pkt_buf + pkt_len;
268 size_t len = 0;
269 char *str, *sp;
270 if (off >= pkt_len)
271 return NULL;
272
273 // calculate length of uncompressed label
274 for (p = pkt_buf + off; *p && p < e; p++) {
275 size_t llen = 0;
276 if ((*p & 0xC0) == 0xC0) {
277 uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
278 llen = *p2 + 1;
279 p = p2 + llen - 1;
280 } else {
281 llen = *p + 1;
282 p += llen - 1;
283 }
284 len += llen;
285 }
286
287 str = sp = malloc(len + 1);
288 if (str == NULL)
289 return NULL;
290
291 // FIXME: must merge this with above code
292 for (p = pkt_buf + off; *p && p < e; p++) {
293 size_t llen = 0;
294 if ((*p & 0xC0) == 0xC0) {
295 uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
296 llen = *p2 + 1;
297 strncpy(sp, (char *)p2, llen);
298 p = p2 + llen - 1;
299 } else {
300 llen = *p + 1;
301 strncpy(sp, (char *)p, llen);
302 p += llen - 1;
303 }
304 sp += llen;
305 }
306 *sp = '\0';
307
308 return (uint8_t *)str;
309 }
310
311 // ----- RR list & group functions -----
312
313 const char *rr_get_type_name(enum rr_type type) {
314 switch (type) {
315 case RR_A:
316 return "A";
317 case RR_PTR:
318 return "PTR";
319 case RR_TXT:
320 return "TXT";
321 case RR_AAAA:
322 return "AAAA";
323 case RR_SRV:
324 return "SRV";
325 case RR_NSEC:
326 return "NSEC";
327 case RR_ANY:
328 return "ANY";
329 }
330 return NULL;
331 }
332
333 void rr_entry_destroy(struct rr_entry *rr) {
334 struct rr_data_txt *txt_rec;
335 assert(rr);
336
337 // check rr_type and free data elements
338 switch (rr->type) {
339 case RR_PTR:
340 if (rr->data.PTR.name)
341 free(rr->data.PTR.name);
342 // don't free entry
343 break;
344
345 case RR_TXT:
346 txt_rec = &rr->data.TXT;
347 while (txt_rec) {
348 struct rr_data_txt *next = txt_rec->next;
349 if (txt_rec->txt)
350 free(txt_rec->txt);
351
352 // only free() if it wasn't part of the struct
353 if (txt_rec != &rr->data.TXT)
354 free(txt_rec);
355
356 txt_rec = next;
357 }
358 break;
359
360 case RR_SRV:
361 if (rr->data.SRV.target)
362 free(rr->data.SRV.target);
363 break;
364
365 default:
366 // nothing to free
367 break;
368 }
369
370 free(rr->name);
371 free(rr);
372 }
373
374 // destroys an RR list (and optionally, items)
375 void rr_list_destroy(struct rr_list *rr, char destroy_items) {
376 struct rr_list *rr_next;
377
378 for (; rr; rr = rr_next) {
379 rr_next = rr->next;
380 if (destroy_items)
381 rr_entry_destroy(rr->e);
382 free(rr);
383 }
384 }
385
386 int rr_list_count(struct rr_list *rr) {
387 int i = 0;
388 for (; rr; i++, rr = rr->next)
389 ;
390 return i;
391 }
392
393 struct rr_entry *rr_list_remove(struct rr_list **rr_head, struct rr_entry *rr) {
394 struct rr_list *le = *rr_head, *pe = NULL;
395 for (; le; le = le->next) {
396 if (le->e == rr) {
397 if (pe == NULL) {
398 *rr_head = le->next;
399 free(le);
400 return rr;
401 } else {
402 pe->next = le->next;
403 free(le);
404 return rr;
405 }
406 }
407 pe = le;
408 }
409 return NULL;
410 }
411
412 // appends an rr_entry to an RR list
413 // if the RR is already in the list, it will not be added
414 // RRs are compared by memory location - not its contents
415 // return value of 0 means item not added
416 int rr_list_append(struct rr_list **rr_head, struct rr_entry *rr) {
417 struct rr_list *node = malloc(sizeof(struct rr_list));
418 if (node) {
419 node->e = rr;
420 node->next = NULL;
421
422 if (*rr_head == NULL) {
423 *rr_head = node;
424 } else {
425 struct rr_list *e = *rr_head, *taile = NULL;
426 for (; e; e = e->next) {
427 // already in list - don't add
428 if (e->e == rr) {
429 free(node);
430 return 0;
431 }
432 if (e->next == NULL)
433 taile = e;
434 }
435 if (taile)
436 taile->next = node;
437 else
438 DEBUG_PRINTF("taile not given a value.\n");
439 }
440 } else {
441 die("can not allocate memory for \"node\" in tinysvcmdns.");
442 }
443 return 1;
444 }
445
446 #define FILL_RR_ENTRY(rr, _name, _type) \
447 rr->name = _name; \
448 rr->type = _type; \
449 rr->ttl = DEFAULT_TTL; \
450 rr->cache_flush = 1; \
451 rr->rr_class = 1;
452
453 struct rr_entry *rr_create_a(uint8_t *name, uint32_t addr) {
454 DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
455 if (rr) {
456 FILL_RR_ENTRY(rr, name, RR_A);
457 rr->data.A.addr = addr;
458 rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
459 } else {
460 die("could not allocate an RR data structure in tinysvcmdns.c.");
461 }
462 return rr;
463 }
464
465 struct rr_entry *rr_create_aaaa(uint8_t *name, struct in6_addr *addr) {
466 DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
467 if (rr) {
468 FILL_RR_ENTRY(rr, name, RR_AAAA);
469 rr->data.AAAA.addr = addr;
470 rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
471 } else {
472 die("could not allocate an RR 2 data structure in tinysvcmdns.c.");
473 }
474 return rr;
475 }
476
477 struct rr_entry *rr_create_srv(uint8_t *name, uint16_t port, uint8_t *target) {
478 DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
479 if (rr) {
480 FILL_RR_ENTRY(rr, name, RR_SRV);
481 rr->data.SRV.port = port;
482 rr->data.SRV.target = target;
483 } else {
484 die("could not allocate an RR 3 data structure in tinysvcmdns.c.");
485 }
486 return rr;
487 }
488
489 struct rr_entry *rr_create_ptr(uint8_t *name, struct rr_entry *d_rr) {
490 DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
491 if (rr) {
492 FILL_RR_ENTRY(rr, name, RR_PTR);
493 rr->cache_flush = 0; // PTRs shouldn't have their cache flush bit set
494 rr->data.PTR.entry = d_rr;
495 } else {
496 die("could not allocate an RR 4 data structure in tinysvcmdns.c.");
497 }
498 return rr;
499 }
500
501 struct rr_entry *rr_create(uint8_t *name, enum rr_type type) {
502 DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
503 if (rr) {
504 FILL_RR_ENTRY(rr, name, type);
505 } else {
506 die("could not allocate an RR 4 data structure in tinysvcmdns.c.");
507 }
508 return rr;
509 }
510
511 void rr_set_nsec(struct rr_entry *rr_nsec, enum rr_type type) {
512 assert((rr_nsec->type = RR_NSEC));
513 assert((type / 8) < sizeof(rr_nsec->data.NSEC.bitmap));
514
515 rr_nsec->data.NSEC.bitmap[type / 8] = 1 << (7 - (type % 8));
516 }
517
518 void rr_add_txt(struct rr_entry *rr_txt, const char *txt) {
519 struct rr_data_txt *txt_rec;
520 assert(rr_txt->type == RR_TXT);
521
522 txt_rec = &rr_txt->data.TXT;
523
524 // is current data filled?
525 if (txt_rec->txt == NULL) {
526 txt_rec->txt = create_label(txt);
527 return;
528 }
529
530 // find the last node
531 for (; txt_rec->next; txt_rec = txt_rec->next)
532 ;
533
534 // create a new empty node
535 txt_rec->next = malloc(sizeof(struct rr_data_txt));
536
537 txt_rec = txt_rec->next;
538 txt_rec->txt = create_label(txt);
539 txt_rec->next = NULL;
540 }
541
542 // adds a record to an rr_group
543 void rr_group_add(struct rr_group **group, struct rr_entry *rr) {
544 struct rr_group *g;
545
546 assert(rr != NULL);
547
548 if (*group) {
549 g = rr_group_find(*group, rr->name);
550 if (g) {
551 rr_list_append(&g->rr, rr);
552 return;
553 }
554 }
555
556 MALLOC_ZERO_STRUCT(g, rr_group);
557 if (g) {
558 g->name = dup_nlabel(rr->name);
559 rr_list_append(&g->rr, rr);
560
561 // prepend to list
562 g->next = *group;
563 *group = g;
564 } else {
565 die("can not allocate memory for \"g\" in tinysvcmdns");
566 }
567 }
568
569 // finds a rr_group matching the given name
570 struct rr_group *rr_group_find(struct rr_group *g, uint8_t *name) {
571 for (; g; g = g->next) {
572 if (cmp_nlabel(g->name, name) == 0)
573 return g;
574 }
575 return NULL;
576 }
577
578 struct rr_entry *rr_entry_find(struct rr_list *rr_list, uint8_t *name, uint16_t type) {
579 struct rr_list *rr = rr_list;
580 for (; rr; rr = rr->next) {
581 if (rr->e->type == type && cmp_nlabel(rr->e->name, name) == 0)
582 return rr->e;
583 }
584 return NULL;
585 }
586
587 // looks for a matching entry in rr_list
588 // if entry is a PTR, we need to check if the PTR target also matches
589 struct rr_entry *rr_entry_match(struct rr_list *rr_list, struct rr_entry *entry) {
590 struct rr_list *rr = rr_list;
591 for (; rr; rr = rr->next) {
592 if (rr->e->type == entry->type && cmp_nlabel(rr->e->name, entry->name) == 0) {
593 if (entry->type != RR_PTR) {
594 return rr->e;
595 } else if (cmp_nlabel(MDNS_RR_GET_PTR_NAME(entry), MDNS_RR_GET_PTR_NAME(rr->e)) == 0) {
596 // if it's a PTR, we need to make sure PTR target also matches
597 return rr->e;
598 }
599 }
600 }
601 return NULL;
602 }
603
604 void rr_group_destroy(struct rr_group *group) {
605 struct rr_group *g = group;
606
607 while (g) {
608 struct rr_group *nextg = g->next;
609 free(g->name);
610 rr_list_destroy(g->rr, 1);
611 free(g);
612 g = nextg;
613 }
614 }
615
616 uint8_t *mdns_write_u16(uint8_t *ptr, const uint16_t v) {
617 *ptr++ = (uint8_t)(v >> 8) & 0xFF;
618 *ptr++ = (uint8_t)(v >> 0) & 0xFF;
619 return ptr;
620 }
621
622 uint8_t *mdns_write_u32(uint8_t *ptr, const uint32_t v) {
623 *ptr++ = (uint8_t)(v >> 24) & 0xFF;
624 *ptr++ = (uint8_t)(v >> 16) & 0xFF;
625 *ptr++ = (uint8_t)(v >> 8) & 0xFF;
626 *ptr++ = (uint8_t)(v >> 0) & 0xFF;
627 return ptr;
628 }
629
630 uint16_t mdns_read_u16(const uint8_t *ptr) {
631 return ((ptr[0] & 0xFF) << 8) | ((ptr[1] & 0xFF) << 0);
632 }
633
634 uint32_t mdns_read_u32(const uint8_t *ptr) {
635 return ((ptr[0] & 0xFF) << 24) | ((ptr[1] & 0xFF) << 16) | ((ptr[2] & 0xFF) << 8) |
636 ((ptr[3] & 0xFF) << 0);
637 }
638
639 // initialize the packet for reply
640 // clears the packet of list structures but not its list items
641 void mdns_init_reply(struct mdns_pkt *pkt, uint16_t id) {
642 // copy transaction ID
643 pkt->id = id;
644
645 // response flags
646 pkt->flags = MDNS_FLAG_RESP | MDNS_FLAG_AA;
647
648 rr_list_destroy(pkt->rr_qn, 0);
649 rr_list_destroy(pkt->rr_ans, 0);
650 rr_list_destroy(pkt->rr_auth, 0);
651 rr_list_destroy(pkt->rr_add, 0);
652
653 pkt->rr_qn = NULL;
654 pkt->rr_ans = NULL;
655 pkt->rr_auth = NULL;
656 pkt->rr_add = NULL;
657
658 pkt->num_qn = 0;
659 pkt->num_ans_rr = 0;
660 pkt->num_auth_rr = 0;
661 pkt->num_add_rr = 0;
662 }
663
664 // destroys an mdns_pkt struct, including its contents
665 void mdns_pkt_destroy(struct mdns_pkt *p) {
666 rr_list_destroy(p->rr_qn, 1);
667 rr_list_destroy(p->rr_ans, 1);
668 rr_list_destroy(p->rr_auth, 1);
669 rr_list_destroy(p->rr_add, 1);
670
671 free(p);
672 }
673
674 // parse the MDNS questions section
675 // stores the parsed data in the given mdns_pkt struct
676 static size_t mdns_parse_qn(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct mdns_pkt *pkt) {
677 const uint8_t *p = pkt_buf + off;
678 struct rr_entry *rr;
679 uint8_t *name;
680
681 assert(pkt != NULL);
682
683 rr = malloc(sizeof(struct rr_entry));
684 if (rr)
685 memset(rr, 0, sizeof(struct rr_entry));
686 else
687 goto err;
688
689 name = uncompress_nlabel(pkt_buf, pkt_len, off);
690 if (name == NULL)
691 goto err;
692
693 p += label_len(pkt_buf, pkt_len, off);
694 rr->name = name;
695
696 rr->type = mdns_read_u16(p);
697 p += sizeof(uint16_t);
698
699 rr->unicast_query = (*p & 0x80) == 0x80;
700 rr->rr_class = mdns_read_u16(p) & ~0x80;
701 p += sizeof(uint16_t);
702
703 rr_list_append(&pkt->rr_qn, rr);
704
705 return p - (pkt_buf + off);
706
707 err:
708 free(rr);
709 return 0;
710 }
711
712 // parse the MDNS RR section
713 // stores the parsed data in the given mdns_pkt struct
714 static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct mdns_pkt *pkt) {
715 const uint8_t *p = pkt_buf + off;
716 const uint8_t *e = pkt_buf + pkt_len;
717 struct rr_entry *rr;
718 uint8_t *name;
719 size_t rr_data_len = 0;
720 struct rr_data_txt *txt_rec;
721 int parse_error = 0;
722
723 assert(pkt != NULL);
724
725 if (off > pkt_len)
726 return 0;
727
728 rr = malloc(sizeof(struct rr_entry));
729 if (rr)
730 memset(rr, 0, sizeof(struct rr_entry));
731 else
732 goto err;
733
734 name = uncompress_nlabel(pkt_buf, pkt_len, off);
735 if (name == NULL)
736 goto err;
737
738 // parse the MDNS RR section
739 p += label_len(pkt_buf, pkt_len, off);
740 rr->name = name;
741
742 rr->type = mdns_read_u16(p);
743 p += sizeof(uint16_t);
744
745 rr->cache_flush = (*p & 0x80) == 0x80;
746 rr->rr_class = mdns_read_u16(p) & ~0x80;
747 p += sizeof(uint16_t);
748
749 rr->ttl = mdns_read_u32(p);
750 p += sizeof(uint32_t);
751
752 // RR data
753 rr_data_len = mdns_read_u16(p);
754 p += sizeof(uint16_t);
755
756 if (p + rr_data_len > e) {
757 DEBUG_PRINTF("rr_data_len goes beyond packet buffer: %lu > %lu\n", rr_data_len, e - p);
758 rr_entry_destroy(rr);
759 return 0;
760 }
761
762 e = p + rr_data_len;
763
764 // see if we can parse the RR data
765 switch (rr->type) {
766 case RR_A:
767 if (rr_data_len < sizeof(uint32_t)) {
768 DEBUG_PRINTF("invalid rr_data_len=%lu for A record\n", rr_data_len);
769 parse_error = 1;
770 break;
771 }
772 rr->data.A.addr = ntohl(mdns_read_u32(p)); /* addr already in net order */
773 p += sizeof(uint32_t);
774 break;
775
776 case RR_AAAA:
777 if (rr_data_len < sizeof(struct in6_addr)) {
778 DEBUG_PRINTF("invalid rr_data_len=%lu for AAAA record\n", rr_data_len);
779 parse_error = 1;
780 break;
781 }
782 rr->data.AAAA.addr = malloc(sizeof(struct in6_addr));
783 unsigned int i;
784 for (i = 0; i < sizeof(struct in6_addr); i++)
785 rr->data.AAAA.addr->s6_addr[i] = p[i];
786 p += sizeof(struct in6_addr);
787 break;
788
789 case RR_PTR:
790 rr->data.PTR.name = uncompress_nlabel(pkt_buf, pkt_len, p - pkt_buf);
791 if (rr->data.PTR.name == NULL) {
792 DEBUG_PRINTF("unable to parse/uncompress label for PTR name\n");
793 parse_error = 1;
794 break;
795 }
796 p += rr_data_len;
797 break;
798
799 case RR_TXT:
800 txt_rec = &rr->data.TXT;
801
802 // not supposed to happen, but we should handle it
803 if (rr_data_len == 0) {
804 DEBUG_PRINTF("WARN: rr_data_len for TXT is 0\n");
805 txt_rec->txt = create_label("");
806 break;
807 }
808
809 while (1) {
810 txt_rec->txt = copy_label(pkt_buf, pkt_len, p - pkt_buf);
811 if (txt_rec->txt == NULL) {
812 DEBUG_PRINTF("unable to copy label for TXT record\n");
813 parse_error = 1;
814 break;
815 }
816 p += txt_rec->txt[0] + 1;
817
818 if (p >= e)
819 break;
820
821 // allocate another record
822 txt_rec->next = malloc(sizeof(struct rr_data_txt));
823 txt_rec = txt_rec->next;
824 txt_rec->next = NULL;
825 }
826 break;
827
828 default:
829 // skip to end of RR data
830 p = e;
831 }
832
833 // if there was a parse error, destroy partial rr_entry
834 if (parse_error) {
835 rr_entry_destroy(rr);
836 return 0;
837 }
838
839 rr_list_append(&pkt->rr_ans, rr);
840
841 return p - (pkt_buf + off);
842
843 err:
844 free(rr);
845 return 0;
846 }
847
848 // parse a MDNS packet into an mdns_pkt struct
849 struct mdns_pkt *mdns_parse_pkt(uint8_t *pkt_buf, size_t pkt_len) {
850 uint8_t *p = pkt_buf;
851 size_t off;
852 struct mdns_pkt *pkt;
853 int i;
854
855 if (pkt_len < 12)
856 return NULL;
857
858 MALLOC_ZERO_STRUCT(pkt, mdns_pkt);
859
860 if (pkt == NULL)
861 die("cannot allocate memory for \"pkt\" in tinysvcmdns.c.");
862
863 // parse header
864 pkt->id = mdns_read_u16(p);
865 p += sizeof(uint16_t);
866 pkt->flags = mdns_read_u16(p);
867 p += sizeof(uint16_t);
868 pkt->num_qn = mdns_read_u16(p);
869 p += sizeof(uint16_t);
870 pkt->num_ans_rr = mdns_read_u16(p);
871 p += sizeof(uint16_t);
872 pkt->num_auth_rr = mdns_read_u16(p);
873 p += sizeof(uint16_t);
874 pkt->num_add_rr = mdns_read_u16(p);
875 p += sizeof(uint16_t);
876
877 off = p - pkt_buf;
878
879 // parse questions
880 for (i = 0; i < pkt->num_qn; i++) {
881 size_t l = mdns_parse_qn(pkt_buf, pkt_len, off, pkt);
882 if (!l) {
883 DEBUG_PRINTF("error parsing question #%d\n", i);
884 mdns_pkt_destroy(pkt);
885 return NULL;
886 }
887
888 off += l;
889 }
890
891 // parse answer RRs
892 for (i = 0; i < pkt->num_ans_rr; i++) {
893 size_t l = mdns_parse_rr(pkt_buf, pkt_len, off, pkt);
894 if (!l) {
895 DEBUG_PRINTF("error parsing answer #%d\n", i);
896 mdns_pkt_destroy(pkt);
897 return NULL;
898 }
899
900 off += l;
901 }
902
903 // TODO: parse the authority and additional RR sections
904
905 return pkt;
906 }
907
908 // encodes a name (label) into a packet using the name compression scheme
909 // encoded names will be added to the compression list for subsequent use
910 static size_t mdns_encode_name(uint8_t *pkt_buf, __attribute__((unused)) size_t pkt_len, size_t off,
911 const uint8_t *name, struct name_comp *comp) {
912 struct name_comp *c, *c_tail = NULL;
913 uint8_t *p = pkt_buf + off;
914 size_t len = 0;
915
916 if (name) {
917 while (*name) {
918 // find match for compression
919 for (c = comp; c; c = c->next) {
920 if (cmp_nlabel(name, c->label) == 0) {
921 mdns_write_u16(p, 0xC000 | (c->pos & ~0xC000));
922 return len + sizeof(uint16_t);
923 }
924
925 if (c->next == NULL)
926 c_tail = c;
927 }
928
929 // copy this segment
930 int segment_len = *name + 1;
931 strncpy((char *)p, (char *)name, segment_len);
932
933 // cache the name for subsequent compression
934 DECL_MALLOC_ZERO_STRUCT(new_c, name_comp);
935
936 new_c->label = (uint8_t *)name;
937 new_c->pos = p - pkt_buf;
938 c_tail->next = new_c;
939
940 // advance to next name segment
941 p += segment_len;
942 len += segment_len;
943 name += segment_len;
944 }
945 }
946
947 *p = '\0'; // root "label"
948 len += 1;
949
950 return len;
951 }
952
953 // encodes an RR entry at the given offset
954 // returns the size of the entire RR entry
955 static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct rr_entry *rr,
956 struct name_comp *comp) {
957 uint8_t *p = pkt_buf + off, *p_data;
958 size_t l;
959 struct rr_data_txt *txt_rec;
960 uint8_t *label;
961 unsigned int i;
962
963 assert(off < pkt_len);
964
965 // name
966 l = mdns_encode_name(pkt_buf, pkt_len, off, rr->name, comp);
967 assert(l != 0);
968 p += l;
969
970 // type
971 p = mdns_write_u16(p, rr->type);
972
973 // class & cache flush
974 p = mdns_write_u16(p, (rr->rr_class & ~0x8000) | (rr->cache_flush << 15));
975
976 // TTL
977 p = mdns_write_u32(p, rr->ttl);
978
979 // data length (filled in later)
980 p += sizeof(uint16_t);
981
982 // start of data marker
983 p_data = p;
984
985 switch (rr->type) {
986 case RR_A:
987 /* htonl() needed coz addr already in net order */
988 p = mdns_write_u32(p, htonl(rr->data.A.addr));
989 break;
990
991 case RR_AAAA:
992 for (i = 0; i < sizeof(struct in6_addr); i++)
993 *p++ = rr->data.AAAA.addr->s6_addr[i];
994 break;
995
996 case RR_PTR:
997 label = rr->data.PTR.name ? rr->data.PTR.name : rr->data.PTR.entry->name;
998 p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, label, comp);
999 break;
1000
1001 case RR_TXT:
1002 txt_rec = &rr->data.TXT;
1003 for (; txt_rec; txt_rec = txt_rec->next) {
1004 int len = txt_rec->txt[0] + 1;
1005 strncpy((char *)p, (char *)txt_rec->txt, len);
1006 p += len;
1007 }
1008 break;
1009
1010 case RR_SRV:
1011 p = mdns_write_u16(p, rr->data.SRV.priority);
1012
1013 p = mdns_write_u16(p, rr->data.SRV.weight);
1014
1015 p = mdns_write_u16(p, rr->data.SRV.port);
1016
1017 p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, rr->data.SRV.target, comp);
1018 break;
1019
1020 case RR_NSEC:
1021 p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, rr->name, comp);
1022
1023 *p++ = 0; // bitmap window/block number
1024
1025 *p++ = sizeof(rr->data.NSEC.bitmap); // bitmap length
1026
1027 for (i = 0; i < sizeof(rr->data.NSEC.bitmap); i++)
1028 *p++ = rr->data.NSEC.bitmap[i];
1029
1030 break;
1031
1032 default:
1033 DEBUG_PRINTF("unhandled rr type 0x%02x\n", rr->type);
1034 }
1035
1036 // calculate data length based on p
1037 l = p - p_data;
1038
1039 // fill in the length
1040 mdns_write_u16(p - l - sizeof(uint16_t), l);
1041
1042 return p - pkt_buf - off;
1043 }
1044
1045 // encodes a MDNS packet from the given mdns_pkt struct into a buffer
1046 // returns the size of the entire MDNS packet
1047 size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len) {
1048 struct name_comp *comp;
1049 uint8_t *p = pkt_buf;
1050 // uint8_t *e = pkt_buf + pkt_len;
1051 size_t off;
1052 unsigned int i;
1053
1054 assert(answer != NULL);
1055 assert(pkt_len >= 12);
1056
1057 if (p == NULL)
1058 return -1;
1059
1060 // this is an Answer - number of qns should be zero
1061 assert(answer->num_qn == 0);
1062
1063 p = mdns_write_u16(p, answer->id);
1064 p = mdns_write_u16(p, answer->flags);
1065 p = mdns_write_u16(p, answer->num_qn);
1066 p = mdns_write_u16(p, answer->num_ans_rr);
1067 p = mdns_write_u16(p, answer->num_auth_rr);
1068 p = mdns_write_u16(p, answer->num_add_rr);
1069
1070 off = p - pkt_buf;
1071
1072 // allocate list for name compression
1073 comp = malloc(sizeof(struct name_comp));
1074 if (comp == NULL)
1075 return -1;
1076 memset(comp, 0, sizeof(struct name_comp));
1077
1078 // dummy entry
1079 comp->label = (uint8_t *)"";
1080 comp->pos = 0;
1081
1082 // skip encoding of qn
1083
1084 struct rr_list *rr_set[] = {answer->rr_ans, answer->rr_auth, answer->rr_add};
1085
1086 // encode answer, authority and additional RRs
1087 for (i = 0; i < sizeof(rr_set) / sizeof(rr_set[0]); i++) {
1088 struct rr_list *rr = rr_set[i];
1089 for (; rr; rr = rr->next) {
1090 size_t l = mdns_encode_rr(pkt_buf, pkt_len, off, rr->e, comp);
1091 off += l;
1092
1093 if (off >= pkt_len) {
1094 DEBUG_PRINTF("packet buffer too small\n");
1095 return -1;
1096 }
1097 }
1098 }
1099
1100 // free name compression list
1101 while (comp) {
1102 struct name_comp *c = comp->next;
1103 free(comp);
1104 comp = c;
1105 }
1106
1107 return off;
1108 }
1109
1110 //******************************************************//
1111 // mdnsd.c //
1112 //******************************************************//
1113
1114 #ifdef _WIN32
1115 #include <winsock2.h>
1116 #include <ws2tcpip.h>
1117 #define LOG_ERR 3
1118 #else
1119 #include <arpa/inet.h>
1120 #include <net/if.h>
1121 #include <netinet/in.h>
1122 #include <sys/ioctl.h>
1123 #include <sys/select.h>
1124 #include <sys/socket.h>
1125 #include <syslog.h>
1126 #endif
1127
1128 #include <assert.h>
1129 #include <fcntl.h>
1130 #include <pthread.h>
1131 #include <signal.h>
1132 #include <stdarg.h>
1133 #include <stdio.h>
1134 #include <stdlib.h>
1135 #include <string.h>
1136 #include <sys/stat.h>
1137 #include <sys/types.h>
1138 #include <unistd.h>
1139
1140 /*
1141 * Define a proper IP socket level if not already done.
1142 * Required to compile on OS X
1143 */
1144 #ifndef SOL_IP
1145 #define SOL_IP IPPROTO_IP
1146 #endif
1147
1148 #define MDNS_ADDR "224.0.0.251"
1149 #define MDNS_PORT 5353
1150
1151 #define PACKET_SIZE 65536
1152
1153 #define SERVICES_DNS_SD_NLABEL ((uint8_t *)"\x09_services\x07_dns-sd\x04_udp\x05local")
1154
1155 struct mdnsd {
1156 pthread_mutex_t data_lock;
1157 int sockfd;
1158 int notify_pipe[2];
1159 int stop_flag;
1160
1161 struct rr_group *group;
1162 struct rr_list *announce;
1163 struct rr_list *services;
1164 uint8_t *hostname;
1165 };
1166
1167 struct mdns_service {
1168 struct rr_list *entries;
1169 };
1170
1171 /////////////////////////////////
1172
1173 static int create_recv_sock() {
1174 int sd = socket(AF_INET, SOCK_DGRAM, 0);
1175 if (sd < 0) {
1176 log_message(LOG_ERR, "recv socket(): %m");
1177 return sd;
1178 }
1179
1180 int r = -1;
1181
1182 int on = 1;
1183 if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0) {
1184 log_message(LOG_ERR, "recv setsockopt(SO_REUSEADDR): %m");
1185 return r;
1186 }
1187
1188 /* bind to an address */
1189 struct sockaddr_in serveraddr;
1190 memset(&serveraddr, 0, sizeof(serveraddr));
1191 serveraddr.sin_family = AF_INET;
1192 serveraddr.sin_port = htons(MDNS_PORT);
1193 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* receive multicast */
1194 if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
1195 log_message(LOG_ERR, "recv bind(): %m");
1196 }
1197
1198 // add membership to receiving socket
1199 struct ip_mreq mreq;
1200 memset(&mreq, 0, sizeof(struct ip_mreq));
1201 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
1202 mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
1203 if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq))) < 0) {
1204 log_message(LOG_ERR, "recv setsockopt(IP_ADD_MEMBERSHIP): %m");
1205 return r;
1206 }
1207
1208 // enable loopback in case someone else needs the data
1209 if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&on, sizeof(on))) < 0) {
1210 log_message(LOG_ERR, "recv setsockopt(IP_MULTICAST_LOOP): %m");
1211 return r;
1212 }
1213
1214 #ifdef IP_PKTINFO
1215 if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *)&on, sizeof(on))) < 0) {
1216 log_message(LOG_ERR, "recv setsockopt(IP_PKTINFO): %m");
1217 return r;
1218 }
1219 #endif
1220
1221 return sd;
1222 }
1223
1224 static ssize_t send_packet(int fd, const void *data, size_t len) {
1225 static struct sockaddr_in toaddr;
1226 if (toaddr.sin_family != AF_INET) {
1227 memset(&toaddr, 0, sizeof(struct sockaddr_in));
1228 toaddr.sin_family = AF_INET;
1229 toaddr.sin_port = htons(MDNS_PORT);
1230 toaddr.sin_addr.s_addr = inet_addr(MDNS_ADDR);
1231 }
1232
1233 return sendto(fd, data, len, 0, (struct sockaddr *)&toaddr, sizeof(struct sockaddr_in));
1234 }
1235
1236 // populate the specified list which matches the RR name and type
1237 // type can be RR_ANY, which populates all entries EXCEPT RR_NSEC
1238 static int populate_answers(struct mdnsd *svr, struct rr_list **rr_head, uint8_t *name,
1239 enum rr_type type) {
1240 int num_ans = 0;
1241
1242 // check if we have the records
1243 pthread_mutex_lock(&svr->data_lock);
1244 struct rr_group *ans_grp = rr_group_find(svr->group, name);
1245 if (ans_grp == NULL) {
1246 pthread_mutex_unlock(&svr->data_lock);
1247 return num_ans;
1248 }
1249
1250 // decide which records should go into answers
1251 struct rr_list *n = ans_grp->rr;
1252 for (; n; n = n->next) {
1253 // exclude NSEC for RR_ANY
1254 if (type == RR_ANY && n->e->type == RR_NSEC)
1255 continue;
1256
1257 if ((type == n->e->type || type == RR_ANY) && cmp_nlabel(name, n->e->name) == 0) {
1258 num_ans += rr_list_append(rr_head, n->e);
1259 }
1260 }
1261
1262 pthread_mutex_unlock(&svr->data_lock);
1263
1264 return num_ans;
1265 }
1266
1267 // given a list of RRs, look up related records and add them
1268 static void add_related_rr(struct mdnsd *svr, struct rr_list *list, struct mdns_pkt *reply) {
1269 for (; list; list = list->next) {
1270 struct rr_entry *ans = list->e;
1271
1272 switch (ans->type) {
1273 case RR_PTR:
1274 // target host A, AAAA records
1275 reply->num_add_rr += populate_answers(svr, &reply->rr_add, MDNS_RR_GET_PTR_NAME(ans), RR_ANY);
1276 break;
1277
1278 case RR_SRV:
1279 // target host A, AAAA records
1280 reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->data.SRV.target, RR_ANY);
1281
1282 // perhaps TXT records of the same name?
1283 // if we use RR_ANY, we risk pulling in the same RR_SRV
1284 reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->name, RR_TXT);
1285 break;
1286
1287 case RR_A:
1288 case RR_AAAA:
1289 reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->name, RR_NSEC);
1290 break;
1291
1292 default:
1293 // nothing to add
1294 break;
1295 }
1296 }
1297 }
1298
1299 // creates an announce packet given the type name PTR
1300 static void announce_srv(struct mdnsd *svr, struct mdns_pkt *reply, uint8_t *name) {
1301 mdns_init_reply(reply, 0);
1302
1303 reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, name, RR_PTR);
1304
1305 // remember to add the services dns-sd PTR too
1306 reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, SERVICES_DNS_SD_NLABEL, RR_PTR);
1307
1308 // see if we can match additional records for answers
1309 add_related_rr(svr, reply->rr_ans, reply);
1310
1311 // additional records for additional records
1312 add_related_rr(svr, reply->rr_add, reply);
1313 }
1314
1315 // processes the incoming MDNS packet
1316 // returns >0 if processed, 0 otherwise
1317 static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns_pkt *reply) {
1318 int i;
1319
1320 assert(pkt != NULL);
1321
1322 // is it standard query?
1323 if ((pkt->flags & MDNS_FLAG_RESP) == 0 && MDNS_FLAG_GET_OPCODE(pkt->flags) == 0) {
1324 mdns_init_reply(reply, pkt->id);
1325
1326 DEBUG_PRINTF("flags = %04x, qn = %d, ans = %d, add = %d\n", pkt->flags, pkt->num_qn,
1327 pkt->num_ans_rr, pkt->num_add_rr);
1328
1329 // loop through questions
1330 struct rr_list *qnl = pkt->rr_qn;
1331 for (i = 0; i < pkt->num_qn; i++, qnl = qnl->next) {
1332 struct rr_entry *qn = qnl->e;
1333 int num_ans_added = 0;
1334
1335 char *namestr = nlabel_to_str(qn->name);
1336 DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type,
1337 namestr);
1338 free(namestr);
1339
1340 // check if it's a unicast query - we ignore those
1341 if (qn->unicast_query) {
1342 DEBUG_PRINTF("skipping unicast query\n");
1343 continue;
1344 }
1345
1346 num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type);
1347 reply->num_ans_rr += num_ans_added;
1348
1349 DEBUG_PRINTF("added %d answers\n", num_ans_added);
1350 }
1351
1352 // remove our replies if they were already in their answers
1353 struct rr_list *ans = NULL, *prev_ans = NULL;
1354 for (ans = reply->rr_ans; ans;) {
1355 struct rr_list *next_ans = ans->next;
1356 struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e);
1357
1358 // discard answers that have at least half of the actual TTL
1359 if (known_ans != NULL && known_ans->ttl >= ans->e->ttl / 2) {
1360 char *namestr = nlabel_to_str(ans->e->name);
1361 DEBUG_PRINTF("removing answer for %s\n", namestr);
1362 free(namestr);
1363
1364 // check if list item is head
1365 if (prev_ans == NULL)
1366 reply->rr_ans = ans->next;
1367 else
1368 prev_ans->next = ans->next;
1369 free(ans);
1370
1371 ans = prev_ans;
1372
1373 // adjust answer count
1374 reply->num_ans_rr--;
1375 }
1376
1377 prev_ans = ans;
1378 ans = next_ans;
1379 }
1380
1381 // see if we can match additional records for answers
1382 add_related_rr(svr, reply->rr_ans, reply);
1383
1384 // additional records for additional records
1385 add_related_rr(svr, reply->rr_add, reply);
1386
1387 DEBUG_PRINTF("\n");
1388
1389 return reply->num_ans_rr;
1390 }
1391
1392 return 0;
1393 }
1394
1395 int create_pipe(int handles[2]) {
1396 #ifdef _WIN32
1397 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
1398 if (sock == INVALID_SOCKET) {
1399 return -1;
1400 }
1401 struct sockaddr_in serv_addr;
1402 memset(&serv_addr, 0, sizeof(serv_addr));
1403 serv_addr.sin_family = AF_INET;
1404 serv_addr.sin_port = htons(0);
1405 serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1406 if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) {
1407 closesocket(sock);
1408 return -1;
1409 }
1410 if (listen(sock, 1) == SOCKET_ERROR) {
1411 closesocket(sock);
1412 return -1;
1413 }
1414 int len = sizeof(serv_addr);
1415 if (getsockname(sock, (SOCKADDR *)&serv_addr, &len) == SOCKET_ERROR) {
1416 closesocket(sock);
1417 return -1;
1418 }
1419 if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
1420 closesocket(sock);
1421 return -1;
1422 }
1423 if (connect(handles[1], (struct sockaddr *)&serv_addr, len) == SOCKET_ERROR) {
1424 closesocket(sock);
1425 return -1;
1426 }
1427 if ((handles[0] = accept(sock, (struct sockaddr *)&serv_addr, &len)) == INVALID_SOCKET) {
1428 closesocket((SOCKET)handles[1]);
1429 handles[1] = INVALID_SOCKET;
1430 closesocket(sock);
1431 return -1;
1432 }
1433 closesocket(sock);
1434 return 0;
1435 #else
1436 return pipe(handles);
1437 #endif
1438 }
1439
1440 int read_pipe(int s, char *buf, int len) {
1441 #ifdef _WIN32
1442 int ret = recv(s, buf, len, 0);
1443 if (ret < 0 && WSAGetLastError() == WSAECONNRESET) {
1444 ret = 0;
1445 }
1446 return ret;
1447 #else
1448 return read(s, buf, len);
1449 #endif
1450 }
1451
1452 int write_pipe(int s, char *buf, int len) {
1453 #ifdef _WIN32
1454 return send(s, buf, len, 0);
1455 #else
1456 return write(s, buf, len);
1457 #endif
1458 }
1459
1460 int close_pipe(int s) {
1461 #ifdef _WIN32
1462 return closesocket(s);
1463 #else
1464 return close(s);
1465 #endif
1466 }
1467
1468 // main loop to receive, process and send out MDNS replies
1469 // also handles MDNS service announces
1470 void *main_loop(struct mdnsd *svr) {
1471 fd_set sockfd_set;
1472 int max_fd = svr->sockfd;
1473 char notify_buf[2]; // buffer for reading of notify_pipe
1474
1475 void *pkt_buffer = malloc(PACKET_SIZE);
1476
1477 if (svr->notify_pipe[0] > max_fd)
1478 max_fd = svr->notify_pipe[0];
1479
1480 struct mdns_pkt *mdns_reply = malloc(sizeof(struct mdns_pkt));
1481 if (mdns_reply)
1482 memset(mdns_reply, 0, sizeof(struct mdns_pkt));
1483 else
1484 die("could not allocate memory for \"mdns_reply\" in tinysvcmdns");
1485
1486 while (!svr->stop_flag) {
1487 FD_ZERO(&sockfd_set);
1488 FD_SET(svr->sockfd, &sockfd_set);
1489 FD_SET(svr->notify_pipe[0], &sockfd_set);
1490 select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
1491
1492 if (FD_ISSET(svr->notify_pipe[0], &sockfd_set)) {
1493 // flush the notify_pipe
1494 read_pipe(svr->notify_pipe[0], (char *)&notify_buf, 1);
1495 } else if (FD_ISSET(svr->sockfd, &sockfd_set)) {
1496 struct sockaddr_in fromaddr;
1497 socklen_t sockaddr_size = sizeof(struct sockaddr_in);
1498
1499 ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
1500 (struct sockaddr *)&fromaddr, &sockaddr_size);
1501 if (recvsize < 0) {
1502 log_message(LOG_ERR, "recv(): %m");
1503 }
1504
1505 DEBUG_PRINTF("data from=%s size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long)recvsize);
1506 struct mdns_pkt *mdns = mdns_parse_pkt(pkt_buffer, recvsize);
1507 if (mdns != NULL) {
1508 if (process_mdns_pkt(svr, mdns, mdns_reply)) {
1509 size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
1510 send_packet(svr->sockfd, pkt_buffer, replylen);
1511 } else if (mdns->num_qn == 0) {
1512 DEBUG_PRINTF("(no questions in packet)\n\n");
1513 }
1514
1515 mdns_pkt_destroy(mdns);
1516 }
1517 }
1518
1519 // send out announces
1520 while (1) {
1521 struct rr_entry *ann_e = NULL;
1522
1523 // extract from head of list
1524 pthread_mutex_lock(&svr->data_lock);
1525 if (svr->announce)
1526 ann_e = rr_list_remove(&svr->announce, svr->announce->e);
1527 pthread_mutex_unlock(&svr->data_lock);
1528
1529 if (!ann_e)
1530 break;
1531
1532 char *namestr = nlabel_to_str(ann_e->name);
1533 DEBUG_PRINTF("sending announce for %s\n", namestr);
1534 free(namestr);
1535
1536 announce_srv(svr, mdns_reply, ann_e->name);
1537
1538 if (mdns_reply->num_ans_rr > 0) {
1539 size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
1540 send_packet(svr->sockfd, pkt_buffer, replylen);
1541 }
1542 }
1543 }
1544
1545 // main thread terminating. send out "goodbye packets" for services
1546 mdns_init_reply(mdns_reply, 0);
1547
1548 pthread_mutex_lock(&svr->data_lock);
1549 struct rr_list *svc_le = svr->services;
1550 for (; svc_le; svc_le = svc_le->next) {
1551 // set TTL to zero
1552 svc_le->e->ttl = 0;
1553 mdns_reply->num_ans_rr += rr_list_append(&mdns_reply->rr_ans, svc_le->e);
1554 }
1555 pthread_mutex_unlock(&svr->data_lock);
1556
1557 // send out packet
1558 if (mdns_reply->num_ans_rr > 0) {
1559 size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
1560 send_packet(svr->sockfd, pkt_buffer, replylen);
1561 }
1562
1563 // destroy packet
1564 mdns_init_reply(mdns_reply, 0);
1565 free(mdns_reply);
1566
1567 free(pkt_buffer);
1568
1569 close_pipe(svr->sockfd);
1570
1571 svr->stop_flag = 2;
1572 return NULL;
1573 }
1574
1575 /////////////////////////////////////////////////////
1576
1577 void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip) {
1578 struct rr_entry *a_e = NULL, *nsec_e = NULL;
1579
1580 // currently can't be called twice
1581 // don't ask me what happens if the IP changes
1582 assert(svr->hostname == NULL);
1583
1584 a_e = rr_create_a(create_nlabel(hostname), ip); // 120 seconds automatically
1585
1586 nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
1587 nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
1588 rr_set_nsec(nsec_e, RR_A);
1589
1590 pthread_mutex_lock(&svr->data_lock);
1591 svr->hostname = create_nlabel(hostname);
1592 rr_group_add(&svr->group, a_e);
1593 rr_group_add(&svr->group, nsec_e);
1594 pthread_mutex_unlock(&svr->data_lock);
1595 }
1596
1597 void mdnsd_set_hostname_v6(struct mdnsd *svr, const char *hostname, struct in6_addr *addr) {
1598 struct rr_entry *aaaa_e = NULL, *nsec_e = NULL;
1599
1600 // currently can't be called twice
1601 // don't ask me what happens if the IP changes
1602 assert(svr->hostname == NULL);
1603
1604 aaaa_e = rr_create_aaaa(create_nlabel(hostname), addr); // 120 seconds automatically
1605
1606 nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
1607 nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
1608 rr_set_nsec(nsec_e, RR_AAAA);
1609
1610 pthread_mutex_lock(&svr->data_lock);
1611 svr->hostname = create_nlabel(hostname);
1612 rr_group_add(&svr->group, aaaa_e);
1613 rr_group_add(&svr->group, nsec_e);
1614 pthread_mutex_unlock(&svr->data_lock);
1615 }
1616
1617 void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr) {
1618 pthread_mutex_lock(&svr->data_lock);
1619 rr_group_add(&svr->group, rr);
1620 pthread_mutex_unlock(&svr->data_lock);
1621 }
1622
1623 struct mdns_service *mdnsd_register_svc(struct mdnsd *svr, const char *instance_name,
1624 const char *type, uint16_t port, const char *hostname,
1625 const char *txt[]) {
1626 struct rr_entry *txt_e = NULL, *srv_e = NULL, *ptr_e = NULL, *bptr_e = NULL;
1627 uint8_t *target;
1628 uint8_t *inst_nlabel, *type_nlabel, *nlabel = NULL;
1629 struct mdns_service *service = malloc(sizeof(struct mdns_service));
1630 if (service)
1631 memset(service, 0, sizeof(struct mdns_service));
1632 else
1633 die("could not allocate memory for \"service\" in tinysvcmdns");
1634 // combine service name
1635 type_nlabel = create_nlabel(type);
1636 inst_nlabel = create_label(instance_name);
1637 if (inst_nlabel) {
1638 nlabel = join_nlabel(inst_nlabel, type_nlabel);
1639 } else {
1640 die("could not allocate memory for \"inst_nlabel\" in tinysvcmdns");
1641 }
1642
1643 // create TXT record
1644 if (txt && *txt) {
1645 txt_e = rr_create(dup_nlabel(nlabel), RR_TXT); // automatically 4500 seconds
1646 rr_list_append(&service->entries, txt_e);
1647
1648 // add TXTs
1649 for (; *txt; txt++)
1650 rr_add_txt(txt_e, *txt);
1651 }
1652
1653 // create SRV record
1654 assert(hostname || svr->hostname); // either one as target
1655 target = hostname ? create_nlabel(hostname) : dup_nlabel(svr->hostname);
1656
1657 srv_e = rr_create_srv(dup_nlabel(nlabel), port, target); // automatically 4500 seconds
1658 rr_list_append(&service->entries, srv_e);
1659
1660 // create PTR record for type
1661 ptr_e = rr_create_ptr(type_nlabel, srv_e); // automatically 4500 seconds
1662
1663 // create services PTR record for type
1664 // this enables the type to show up as a "service"
1665 bptr_e = rr_create_ptr(dup_nlabel(SERVICES_DNS_SD_NLABEL), ptr_e); // automatically 4500 seconds
1666
1667 // modify lists here
1668 pthread_mutex_lock(&svr->data_lock);
1669
1670 if (txt_e)
1671 rr_group_add(&svr->group, txt_e);
1672 rr_group_add(&svr->group, srv_e);
1673 rr_group_add(&svr->group, ptr_e);
1674 rr_group_add(&svr->group, bptr_e);
1675
1676 // append PTR entry to announce list
1677 rr_list_append(&svr->announce, ptr_e);
1678 rr_list_append(&svr->services, ptr_e);
1679
1680 pthread_mutex_unlock(&svr->data_lock);
1681
1682 // don't free type_nlabel - it's with the PTR record
1683 if (nlabel)
1684 free(nlabel);
1685 free(inst_nlabel);
1686
1687 // notify server
1688 write_pipe(svr->notify_pipe[1], ".", 1);
1689
1690 return service;
1691 }
1692
1693 void mdns_service_destroy(struct mdns_service *srv) {
1694 assert(srv != NULL);
1695 rr_list_destroy(srv->entries, 0);
1696 free(srv);
1697 }
1698
1699 struct mdnsd *mdnsd_start() {
1700 pthread_t tid;
1701 pthread_attr_t attr;
1702
1703 struct mdnsd *server = malloc(sizeof(struct mdnsd));
1704 if (server)
1705 memset(server, 0, sizeof(struct mdnsd));
1706 else
1707 die("could not allocate memory for \"server\" in tinysvcmdns");
1708
1709 if (create_pipe(server->notify_pipe) != 0) {
1710 log_message(LOG_ERR, "pipe(): %m\n");
1711 free(server);
1712 return NULL;
1713 }
1714
1715 server->sockfd = create_recv_sock();
1716 if (server->sockfd < 0) {
1717 log_message(LOG_ERR, "unable to create recv socket");
1718 free(server);
1719 return NULL;
1720 }
1721
1722 pthread_mutex_init(&server->data_lock, NULL);
1723
1724 // init thread
1725 pthread_attr_init(&attr);
1726 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1727
1728 if (pthread_create(&tid, &attr, (void *(*)(void *)) & main_loop, (void *)server) != 0) {
1729 pthread_mutex_destroy(&server->data_lock);
1730 free(server);
1731 return NULL;
1732 }
1733
1734 return server;
1735 }
1736
1737 void mdnsd_stop(struct mdnsd *s) {
1738 assert(s != NULL);
1739
1740 struct timeval tv = {
1741 .tv_sec = 0,
1742 .tv_usec = 500 * 1000,
1743 };
1744
1745 s->stop_flag = 1;
1746 write_pipe(s->notify_pipe[1], ".", 1);
1747
1748 while (s->stop_flag != 2)
1749 select(0, NULL, NULL, NULL, &tv);
1750
1751 close_pipe(s->notify_pipe[0]);
1752 close_pipe(s->notify_pipe[1]);
1753
1754 pthread_mutex_destroy(&s->data_lock);
1755 rr_group_destroy(s->group);
1756 rr_list_destroy(s->announce, 0);
1757 rr_list_destroy(s->services, 0);
1758
1759 if (s->hostname)
1760 free(s->hostname);
1761
1762 free(s);
1763 }