1 #include "mdnsd_config.h"
2 #include "mdnsd.h"
3 #include <string.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8
9 #define SPRIME 108 /* Size of query/publish hashes */
10 #define LPRIME 1009 /* Size of cache hash */
11
12 #define GC 86400 /* Brute force garbage cleanup
13 * frequency, rarely needed (daily
14 * default) */
15
16 #ifdef _MSC_VER
17 #include "ms_stdint.h" /* Includes stdint.h or workaround for older Visual Studios */
18
gettimeofday(struct timeval * tp,struct timezone * tzp)19 int gettimeofday(struct timeval * tp, struct timezone * tzp)
20 {
21 // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
22 static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
23
24 SYSTEMTIME system_time;
25 FILETIME file_time;
26 uint64_t time;
27
28 GetSystemTime( &system_time );
29 SystemTimeToFileTime( &system_time, &file_time );
30 time = ((uint64_t)file_time.dwLowDateTime ) ;
31 time += ((uint64_t)file_time.dwHighDateTime) << 32;
32
33 tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
34 tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
35 return 0;
36 }
37 #else
38 #include <sys/time.h>
39 #endif
40
41 #if defined(__MINGW32__)
my_strdup(const char * s)42 static char *my_strdup(const char *s) {
43 char *p = (char *)MDNSD_malloc(strlen(s) + 1);
44 if(p) { strcpy(p, s); }
45 return p;
46 }
47 #define STRDUP my_strdup
48 #elif defined(_WIN32)
49 #define STRDUP _strdup
50 #else
51 #define STRDUP strdup
52 #endif
53
54 #ifndef _WIN32
55 # include <netdb.h>
56 #endif
57
58 /**
59 * Messy, but it's the best/simplest balance I can find at the moment
60 *
61 * Some internal data types, and a few hashes: querys, answers, cached,
62 * and records (published, unique and shared). Each type has different
63 * semantics for processing, both for timeouts, incoming, and outgoing
64 * I/O. They inter-relate too, like records affect the querys they are
65 * relevant to. Nice things about MDNS: we only publish once (and then
66 * ask asked), and only query once, then just expire records we've got
67 * cached
68 */
69
70 struct query {
71 char *name;
72 int type;
73 unsigned long int nexttry;
74 int tries;
75 int (*answer)(mdns_answer_t *, void *);
76 void *arg;
77 struct query *next, *list;
78 };
79
80 struct unicast {
81 int id;
82 unsigned long int to;
83 unsigned short int port;
84 mdns_record_t *r;
85 struct unicast *next;
86 };
87
88 struct cached {
89 struct mdns_answer rr;
90 struct query *q;
91 struct cached *next;
92 };
93
94 struct mdns_record {
95 struct mdns_answer rr;
96 char unique; /* # of checks performed to ensure */
97 int tries;
98 void (*conflict)(char *, int, void *);
99 void *arg;
100 struct timeval last_sent;
101 struct mdns_record *next, *list;
102 };
103
104 struct mdns_daemon {
105 char shutdown;
106 unsigned long int expireall, checkqlist;
107 struct timeval now, sleep, pause, probe, publish;
108 int clazz, frame;
109 struct cached *cache[LPRIME];
110 struct mdns_record *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
111 struct unicast *uanswers;
112 struct query *queries[SPRIME], *qlist;
113 mdnsd_record_received_callback received_callback;
114 void *received_callback_data;
115 };
116
_namehash(const char * s)117 static int _namehash(const char *s)
118 {
119 const unsigned char *name = (const unsigned char *)s;
120 unsigned long h = 0;
121
122 while (*name) { /* do some fancy bitwanking on the string */
123 unsigned long int g;
124 h = (h << 4) + (unsigned long int)(*name++);
125 if ((g = (h & 0xF0000000UL)) != 0)
126 h ^= (g >> 24);
127 h &= ~g;
128 }
129
130 return (int)h;
131 }
132
133 /* Basic linked list and hash primitives */
_q_next(mdns_daemon_t * d,struct query * q,const char * host,int type)134 static struct query *_q_next(mdns_daemon_t *d, struct query *q, const char *host, int type)
135 {
136 if (q == 0)
137 q = d->queries[_namehash(host) % SPRIME];
138 else
139 q = q->next;
140
141 for (; q != 0; q = q->next) {
142 if (q->type == type && strcmp(q->name, host) == 0)
143 return q;
144 }
145
146 return 0;
147 }
148
_c_next(mdns_daemon_t * d,struct cached * c,const char * host,int type)149 static struct cached *_c_next(mdns_daemon_t *d, struct cached *c,const char *host, int type)
150 {
151 if (c == 0)
152 c = d->cache[_namehash(host) % LPRIME];
153 else
154 c = c->next;
155
156 for (; c != 0; c = c->next) {
157 if ((type == c->rr.type || type == 255) && strcmp(c->rr.name, host) == 0)
158 return c;
159 }
160
161 return 0;
162 }
163
_r_next(mdns_daemon_t * d,mdns_record_t * r,const char * host,int type)164 static mdns_record_t *_r_next(mdns_daemon_t *d, mdns_record_t *r, const char *host, int type)
165 {
166 if (r == 0)
167 r = d->published[_namehash(host) % SPRIME];
168 else
169 r = r->next;
170
171 for (; r != 0; r = r->next) {
172 if (type == r->rr.type && strcmp(r->rr.name, host) == 0)
173 return r;
174 }
175
176 return 0;
177 }
178
_rr_len(mdns_answer_t * rr)179 static int _rr_len(mdns_answer_t *rr)
180 {
181 int len = 12; /* name is always compressed (dup of earlier), plus normal stuff */
182
183 if (rr->rdata)
184 len += rr->rdlen;
185 if (rr->rdname)
186 len += (int)strlen(rr->rdname); /* worst case */
187 if (rr->ip.s_addr)
188 len += 4;
189 if (rr->type == QTYPE_PTR)
190 len += 6; /* srv record stuff */
191
192 return len;
193 }
194
195 /* Compares new rdata with known a, painfully */
_a_match(struct resource * r,mdns_answer_t * a)196 static int _a_match(struct resource *r, mdns_answer_t *a)
197 {
198 if (!a->name)
199 return 0;
200 if (strcmp(r->name, a->name) || r->type != a->type)
201 return 0;
202
203 if (r->type == QTYPE_SRV && !strcmp(r->known.srv.name, a->rdname) && a->srv.port == r->known.srv.port &&
204 a->srv.weight == r->known.srv.weight && a->srv.priority == r->known.srv.priority)
205 return 1;
206
207 if ((r->type == QTYPE_PTR || r->type == QTYPE_NS || r->type == QTYPE_CNAME) && !strcmp(a->rdname, r->known.ns.name))
208 return 1;
209
210 if (r->rdlength == a->rdlen && !memcmp(r->rdata, a->rdata, r->rdlength))
211 return 1;
212
213 return 0;
214 }
215
216 /* Compare time values easily */
_tvdiff(struct timeval old_time,struct timeval new_time)217 static int _tvdiff(struct timeval old_time, struct timeval new_time)
218 {
219 int udiff = 0;
220
221 if (old_time.tv_sec != new_time.tv_sec)
222 udiff = (int)((new_time.tv_sec - old_time.tv_sec) * 1000000);
223
224 return (int)((new_time.tv_usec - old_time.tv_usec) + udiff);
225 }
226
_r_remove_list(mdns_record_t ** list,mdns_record_t * r)227 static void _r_remove_list(mdns_record_t **list, mdns_record_t *r) {
228 if (*list == r) {
229 *list = r->list;
230 } else {
231 mdns_record_t *tmp = *list;
232 while (tmp) {
233 if (tmp->list == r) {
234 tmp->list = r->list;
235 break;
236 }
237 if (tmp == tmp->list)
238 break;
239 tmp = tmp->list;
240 }
241 }
242 }
243
_r_remove_lists(mdns_daemon_t * d,mdns_record_t * r,mdns_record_t ** skip)244 static void _r_remove_lists(mdns_daemon_t *d, mdns_record_t *r, mdns_record_t **skip) {
245 if (d->probing && &d->probing != skip) {
246 _r_remove_list(&d->probing, r);
247 }
248 if (d->a_now && &d->a_now != skip) {
249 _r_remove_list(&d->a_now, r);
250 }
251 if (d->a_pause && &d->a_pause != skip) {
252 _r_remove_list(&d->a_pause, r);
253 }
254 if (d->a_publish && &d->a_publish != skip) {
255 _r_remove_list(&d->a_publish, r);
256 }
257 }
258
259 /* Make sure not already on the list, then insert */
_r_push(mdns_record_t ** list,mdns_record_t * r)260 static void _r_push(mdns_record_t **list, mdns_record_t *r)
261 {
262 mdns_record_t *cur;
263
264 for (cur = *list; cur != 0; cur = cur->list) {
265 if (cur == r)
266 return;
267 }
268
269 r->list = *list;
270 *list = r;
271 }
272
273 /* Force any r out right away, if valid */
_r_publish(mdns_daemon_t * d,mdns_record_t * r)274 static void _r_publish(mdns_daemon_t *d, mdns_record_t *r)
275 {
276 if (r->unique && r->unique < 5)
277 return; /* Probing already */
278
279 r->tries = 0;
280 d->publish.tv_sec = d->now.tv_sec;
281 d->publish.tv_usec = d->now.tv_usec;
282 _r_push(&d->a_publish, r);
283 }
284
285 /* send r out asap */
_r_send(mdns_daemon_t * d,mdns_record_t * r)286 static void _r_send(mdns_daemon_t *d, mdns_record_t *r)
287 {
288 /* Being published, make sure that happens soon */
289 if (r->tries < 4) {
290 d->publish.tv_sec = d->now.tv_sec;
291 d->publish.tv_usec = d->now.tv_usec;
292 return;
293 }
294
295 /* Known unique ones can be sent asap */
296 if (r->unique) {
297
298 // check if r already in other lists. If yes, remove it from there
299 _r_remove_lists(d,r, &d->a_now);
300 _r_push(&d->a_now, r);
301 return;
302 }
303
304 /* Set d->pause.tv_usec to random 20-120 msec */
305 d->pause.tv_sec = d->now.tv_sec;
306 d->pause.tv_usec = d->now.tv_usec + (d->now.tv_usec % 100) + 20;
307 _r_push(&d->a_pause, r);
308 }
309
310 /* Create generic unicast response struct */
_u_push(mdns_daemon_t * d,mdns_record_t * r,int id,unsigned long int to,unsigned short int port)311 static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, unsigned long int to, unsigned short int port)
312 {
313 struct unicast *u;
314
315 u = (struct unicast *)MDNSD_calloc(1, sizeof(struct unicast));
316 u->r = r;
317 u->id = id;
318 u->to = to;
319 u->port = port;
320 u->next = d->uanswers;
321 d->uanswers = u;
322 }
323
_q_reset(mdns_daemon_t * d,struct query * q)324 static void _q_reset(mdns_daemon_t *d, struct query *q)
325 {
326 struct cached *cur = 0;
327
328 q->nexttry = 0;
329 q->tries = 0;
330
331 while ((cur = _c_next(d, cur, q->name, q->type))) {
332 if (q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry)
333 q->nexttry = cur->rr.ttl - 7;
334 }
335
336 if (q->nexttry != 0 && q->nexttry < d->checkqlist)
337 d->checkqlist = q->nexttry;
338 }
339
340 /* No more query, update all it's cached entries, remove from lists */
_q_done(mdns_daemon_t * d,struct query * q)341 static void _q_done(mdns_daemon_t *d, struct query *q)
342 {
343 struct cached *c = 0;
344 struct query *cur;
345 int i = _namehash(q->name) % LPRIME;
346
347 while ((c = _c_next(d, c, q->name, q->type)))
348 c->q = 0;
349
350 if (d->qlist == q) {
351 d->qlist = q->list;
352 } else {
353 for (cur = d->qlist; cur->list != q; cur = cur->list)
354 ;
355 cur->list = q->list;
356 }
357
358 if (d->queries[i] == q) {
359 d->queries[i] = q->next;
360 } else {
361 for (cur = d->queries[i]; cur->next != q; cur = cur->next)
362 ;
363 cur->next = q->next;
364 }
365
366 MDNSD_free(q->name);
367 MDNSD_free(q);
368 }
369
370 /* buh-bye, remove from hash and free */
_r_done(mdns_daemon_t * d,mdns_record_t * r)371 static void _r_done(mdns_daemon_t *d, mdns_record_t *r)
372 {
373 mdns_record_t *cur = 0;
374 int i = _namehash(r->rr.name) % SPRIME;
375
376 if (d->published[i] == r)
377 d->published[i] = r->next;
378 else {
379 for (cur = d->published[i]; cur && cur->next != r; cur = cur->next) ;
380 if (cur)
381 cur->next = r->next;
382 }
383 MDNSD_free(r->rr.name);
384 MDNSD_free(r->rr.rdata);
385 MDNSD_free(r->rr.rdname);
386 MDNSD_free(r);
387 }
388
389 /* Call the answer function with this cached entry */
_q_answer(mdns_daemon_t * d,struct cached * c)390 static void _q_answer(mdns_daemon_t *d, struct cached *c)
391 {
392 if (c->rr.ttl <= (unsigned long int)d->now.tv_sec)
393 c->rr.ttl = 0;
394 if (c->q->answer(&c->rr, c->q->arg) == -1)
395 _q_done(d, c->q);
396 }
397
_conflict(mdns_daemon_t * d,mdns_record_t * r)398 static void _conflict(mdns_daemon_t *d, mdns_record_t *r)
399 {
400 r->conflict(r->rr.name, r->rr.type, r->arg);
401 mdnsd_done(d, r);
402 }
403
404 /* Expire any old entries in this list */
_c_expire(mdns_daemon_t * d,struct cached ** list)405 static void _c_expire(mdns_daemon_t *d, struct cached **list)
406 {
407 struct cached *next, *cur = *list, *last = 0;
408
409 while (cur != 0) {
410 next = cur->next;
411 if ((unsigned long int)d->now.tv_sec >= cur->rr.ttl) {
412 if (last)
413 last->next = next;
414
415 /* Update list pointer if the first one expired */
416 if (*list == cur)
417 *list = next;
418
419 if (cur->q)
420 _q_answer(d, cur);
421
422 MDNSD_free(cur->rr.name);
423 MDNSD_free(cur->rr.rdata);
424 MDNSD_free(cur->rr.rdname);
425 MDNSD_free(cur);
426 } else {
427 last = cur;
428 }
429 cur = next;
430 }
431 }
432
433 /* Brute force expire any old cached records */
_gc(mdns_daemon_t * d)434 static void _gc(mdns_daemon_t *d)
435 {
436 int i;
437
438 for (i = 0; i < LPRIME; i++) {
439 if (d->cache[i])
440 _c_expire(d, &d->cache[i]);
441 }
442
443 d->expireall = (unsigned long int)(d->now.tv_sec + GC);
444 }
445
_cache(mdns_daemon_t * d,struct resource * r)446 static int _cache(mdns_daemon_t *d, struct resource *r)
447 {
448 struct cached *c = 0;
449 int i = _namehash(r->name) % LPRIME;
450
451 /* Cache flush for unique entries */
452 if (r->clazz == 32768 + d->clazz) {
453 while ((c = _c_next(d, c, r->name, r->type)))
454 c->rr.ttl = 0;
455 _c_expire(d, &d->cache[i]);
456 }
457
458 /* Process deletes */
459 if (r->ttl == 0) {
460 while ((c = _c_next(d, c, r->name, r->type))) {
461 if (_a_match(r, &c->rr)) {
462 c->rr.ttl = 0;
463 _c_expire(d, &d->cache[i]);
464 c = NULL;
465 }
466 }
467
468 return 0;
469 }
470
471 /*
472 * XXX: The c->rr.ttl is a hack for now, BAD SPEC, start
473 * retrying just after half-waypoint, then expire
474 */
475 c = (struct cached *)MDNSD_calloc(1, sizeof(struct cached));
476 c->rr.name = STRDUP(r->name);
477 c->rr.type = r->type;
478 c->rr.ttl = (unsigned long int)d->now.tv_sec + (r->ttl / 2) + 8;
479 c->rr.rdlen = r->rdlength;
480 if (r->rdlength && !r->rdata) {
481 MDNSD_LOG_ERROR("rdlength is %d but rdata is NULL for domain name %s, type: %d, ttl: %ld", r->rdlength, r->name, r->type, r->ttl);
482 MDNSD_free(c->rr.name);
483 MDNSD_free(c);
484 return 1;
485 }
486 if (r->rdlength) {
487 c->rr.rdata = (unsigned char *)MDNSD_malloc(r->rdlength);
488 memcpy(c->rr.rdata, r->rdata, r->rdlength);
489 } else {
490 c->rr.rdata = NULL;
491 }
492
493 switch (r->type) {
494 case QTYPE_A:
495 c->rr.ip = r->known.a.ip;
496 break;
497
498 case QTYPE_NS:
499 case QTYPE_CNAME:
500 case QTYPE_PTR:
501 c->rr.rdname = STRDUP(r->known.ns.name);
502 break;
503
504 case QTYPE_SRV:
505 c->rr.rdname = STRDUP(r->known.srv.name);
506 c->rr.srv.port = r->known.srv.port;
507 c->rr.srv.weight = r->known.srv.weight;
508 c->rr.srv.priority = r->known.srv.priority;
509 break;
510 }
511
512 c->next = d->cache[i];
513 d->cache[i] = c;
514
515 if ((c->q = _q_next(d, 0, r->name, r->type)))
516 _q_answer(d, c);
517
518 return 0;
519 }
520
521 /* Copy the data bits only */
_a_copy(struct message * m,mdns_answer_t * a)522 static void _a_copy(struct message *m, mdns_answer_t *a)
523 {
524 if (a->rdata) {
525 message_rdata_raw(m, a->rdata, a->rdlen);
526 return;
527 }
528
529 if (a->ip.s_addr)
530 message_rdata_long(m, a->ip);
531 if (a->type == QTYPE_SRV)
532 message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
533 else if (a->rdname)
534 message_rdata_name(m, a->rdname);
535 }
536
537 /* Copy a published record into an outgoing message */
_r_out(mdns_daemon_t * d,struct message * m,mdns_record_t ** list)538 static int _r_out(mdns_daemon_t *d, struct message *m, mdns_record_t **list)
539 {
540 mdns_record_t *r;
541 int ret = 0;
542
543 while ((r = *list) != 0 && message_packet_len(m) + _rr_len(&r->rr) < d->frame) {
544 if (r != r->list)
545 *list = r->list;
546 else
547 *list = NULL;
548 ret++;
549
550 if (r->unique)
551 message_an(m, r->rr.name, r->rr.type, (unsigned short int)(d->clazz + 32768), r->rr.ttl);
552 else
553 message_an(m, r->rr.name, r->rr.type, (unsigned short int)d->clazz, r->rr.ttl);
554 r->last_sent = d->now;
555
556 _a_copy(m, &r->rr);
557 if (r->rr.ttl == 0) {
558
559 // also remove from other lists, because record may be in multiple lists at the same time
560 _r_remove_lists(d, r, list);
561
562 _r_done(d, r);
563
564 }
565 }
566
567 return ret;
568 }
569
570
mdnsd_new(int clazz,int frame)571 mdns_daemon_t *mdnsd_new(int clazz, int frame)
572 {
573 mdns_daemon_t *d;
574
575 d = (mdns_daemon_t *)MDNSD_calloc(1, sizeof(struct mdns_daemon));
576 gettimeofday(&d->now, 0);
577 d->expireall = (unsigned long int)(d->now.tv_sec + GC);
578 d->clazz = clazz;
579 d->frame = frame;
580 d->received_callback = NULL;
581
582 return d;
583 }
584
585 /* Shutting down, zero out ttl and push out all records */
mdnsd_shutdown(mdns_daemon_t * d)586 void mdnsd_shutdown(mdns_daemon_t *d)
587 {
588 int i;
589 mdns_record_t *cur, *next;
590
591 d->a_now = 0;
592 for (i = 0; i < SPRIME; i++) {
593 for (cur = d->published[i]; cur != 0;) {
594 next = cur->next;
595 cur->rr.ttl = 0;
596 cur->list = d->a_now;
597 d->a_now = cur;
598 cur = next;
599 }
600 }
601
602 d->shutdown = 1;
603 }
604
mdnsd_flush(mdns_daemon_t * d)605 void mdnsd_flush(mdns_daemon_t *d)
606 {
607 (void)d;
608 /* - Set all querys to 0 tries
609 * - Free whole cache
610 * - Set all mdns_record_t *to probing
611 * - Reset all answer lists
612 */
613 }
614
mdnsd_free(mdns_daemon_t * d)615 void mdnsd_free(mdns_daemon_t *d)
616 {
617 size_t i;
618 for (i = 0; i< LPRIME; i++) {
619 struct cached* cur = d->cache[i];
620 while (cur) {
621 struct cached* next = cur->next;
622 MDNSD_free(cur->rr.name);
623 MDNSD_free(cur->rr.rdata);
624 MDNSD_free(cur->rr.rdname);
625 MDNSD_free(cur);
626 cur = next;
627 }
628 }
629
630 for (i = 0; i< SPRIME; i++) {
631 struct mdns_record* cur = d->published[i];
632 struct query* curq = NULL;
633 while (cur) {
634 struct mdns_record* next = cur->next;
635 MDNSD_free(cur->rr.name);
636 MDNSD_free(cur->rr.rdata);
637 MDNSD_free(cur->rr.rdname);
638 MDNSD_free(cur);
639 cur = next;
640 }
641
642
643 curq = d->queries[i];
644 while (curq) {
645 struct query* next = curq->next;
646 MDNSD_free(curq->name);
647 MDNSD_free(curq);
648 curq = next;
649 }
650
651 }
652
653 {
654 struct unicast *u = d->uanswers;
655 while (u) {
656 struct unicast *next = u->next;
657 MDNSD_free(u);
658 u=next;
659 }
660 }
661
662 MDNSD_free(d);
663 }
664
665
mdnsd_register_receive_callback(mdns_daemon_t * d,mdnsd_record_received_callback cb,void * data)666 void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_callback cb, void* data) {
667 d->received_callback = cb;
668 d->received_callback_data = data;
669 }
670
mdnsd_in(mdns_daemon_t * d,struct message * m,unsigned long int ip,unsigned short int port)671 int mdnsd_in(mdns_daemon_t *d, struct message *m, unsigned long int ip, unsigned short int port)
672 {
673 int i;
674 mdns_record_t *r = 0;
675
676 if (d->shutdown)
677 return 1;
678
679 gettimeofday(&d->now, 0);
680
681 if (m->header.qr == 0) {
682 /* Process each query */
683 for (i = 0; i < m->qdcount; i++) {
684 mdns_record_t *r_start, *r_next = NULL;
685 bool hasConflict = false;
686 if (m->qd[i].clazz != d->clazz || (r = _r_next(d, 0, m->qd[i].name, m->qd[i].type)) == 0)
687 continue;
688 r_start = r;
689
690
691 /* Check all of our potential answers */
692 for (; r != 0; r = r_next) {
693
694 MDNSD_LOG_TRACE("Got Query: Name: %s, Type: %d", r->rr.name, r->rr.type);
695
696 // do this here, because _conflict deletes r and thus next is not valid anymore
697 r_next = _r_next(d, r, m->qd[i].name, m->qd[i].type);
698 /* probing state, check for conflicts */
699 if (r->unique && r->unique < 5) {
700 /* Check all to-be answers against our own */
701 int j;
702 for (j = 0; j < m->nscount; j++) {
703 if (m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
704 continue;
705
706 /* This answer isn't ours, conflict! */
707 if (!_a_match(&m->an[j], &r->rr)) {
708 _conflict(d, r);
709 hasConflict = true;
710 break;
711 }
712 }
713 continue;
714 }
715
716 /* Check the known answers for this question */
717 {
718 int j;
719 for (j = 0; j < m->ancount; j++) {
720 if (m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
721 continue;
722
723 if (d->received_callback) {
724 d->received_callback(&m->an[j], d->received_callback_data);
725 }
726
727 /* Do they already have this answer? */
728 if (_a_match(&m->an[j], &r->rr))
729 break;
730 }
731 if (j == m->ancount)
732 _r_send(d, r);
733 }
734
735 }
736
737 /* Send the matching unicast reply */
738 if (!hasConflict && port != 5353)
739 _u_push(d, r_start, m->id, ip, port);
740 }
741
742 return 0;
743 }
744
745 /* Process each answer, check for a conflict, and cache */
746 for (i = 0; i < m->ancount; i++) {
747 if (m->an[i].name == NULL) {
748 MDNSD_LOG_ERROR("Got answer with NULL name at %p. Type: %d, TTL: %ld\n", (void*)&m->an[i], m->an[i].type, m->an[i].ttl);
749 return 3;
750 }
751
752 MDNSD_LOG_TRACE("Got Answer: Name: %s, Type: %d", m->an[i].name, m->an[i].type);
753 if ((r = _r_next(d, 0, m->an[i].name, m->an[i].type)) != 0 &&
754 r->unique && _a_match(&m->an[i], &r->rr) == 0)
755 _conflict(d, r);
756
757 if (d->received_callback) {
758 d->received_callback(&m->an[i], d->received_callback_data);
759 }
760 if (_cache(d, &m->an[i]) != 0)
761 return 2;
762 }
763 return 0;
764 }
765
mdnsd_out(mdns_daemon_t * d,struct message * m,unsigned long int * ip,unsigned short int * port)766 int mdnsd_out(mdns_daemon_t *d, struct message *m, unsigned long int *ip, unsigned short int *port)
767 {
768 mdns_record_t *r;
769 int ret = 0;
770
771 gettimeofday(&d->now, 0);
772 memset(m, 0, sizeof(struct message));
773
774 /* Defaults, multicast */
775 *port = htons(5353);
776 *ip = inet_addr("224.0.0.251");
777 m->header.qr = 1;
778 m->header.aa = 1;
779
780 /* Send out individual unicast answers */
781 if (d->uanswers) {
782 struct unicast *u = d->uanswers;
783
784 MDNSD_LOG_TRACE("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type);
785
786 d->uanswers = u->next;
787 *port = u->port;
788 *ip = u->to;
789 m->id = (unsigned short int)u->id;
790 message_qd(m, u->r->rr.name, u->r->rr.type, (unsigned short int)d->clazz);
791 message_an(m, u->r->rr.name, u->r->rr.type, (unsigned short int)d->clazz, u->r->rr.ttl);
792 u->r->last_sent = d->now;
793 _a_copy(m, &u->r->rr);
794 MDNSD_free(u);
795
796 return 1;
797 }
798
799 // printf("OUT: probing %X now %X pause %X publish %X\n",d->probing,d->a_now,d->a_pause,d->a_publish);
800
801 /* Accumulate any immediate responses */
802 if (d->a_now)
803 ret += _r_out(d, m, &d->a_now);
804
805 /* Check if it's time to send the publish retries (unlink if done) */
806 if (d->a_publish && _tvdiff(d->now, d->publish) <= 0) {
807
808 mdns_record_t *next, *cur = d->a_publish, *last = NULL;
809
810 while (cur && message_packet_len(m) + _rr_len(&cur->rr) < d->frame) {
811
812 if (cur->rr.type == QTYPE_PTR) {
813 MDNSD_LOG_TRACE("Send Publish PTR: Name: %s, rdlen: %d, rdata: %s, rdname: %s", cur->rr.name,cur->rr.rdlen, cur->rr.rdata, cur->rr.rdname);
814 } else if (cur->rr.type == QTYPE_SRV) {
815 MDNSD_LOG_TRACE("Send Publish SRV: Name: %s, rdlen: %d, rdata: %s, rdname: %s, port: %d, prio: %d, weight: %d", cur->rr.name,cur->rr.rdlen, cur->rr.rdname, cur->rr.rdata, cur->rr.srv.port, cur->rr.srv.priority, cur->rr.srv.weight);
816 } else {
817 MDNSD_LOG_TRACE("Send Publish: Name: %s, Type: %d, rdname: %s", cur->rr.name, cur->rr.type, cur->rr.rdname);
818 }
819 next = cur->list;
820 ret++;
821 cur->tries++;
822
823 if (cur->unique)
824 message_an(m, cur->rr.name, cur->rr.type, (unsigned short int)(d->clazz + 32768), cur->rr.ttl);
825 else
826 message_an(m, cur->rr.name, cur->rr.type, (unsigned short int)d->clazz, cur->rr.ttl);
827 _a_copy(m, &cur->rr);
828 cur->last_sent = d->now;
829
830 if (cur->rr.ttl != 0 && cur->tries < 4) {
831 last = cur;
832 cur = next;
833 continue;
834 }
835
836 if (d->a_publish == cur)
837 d->a_publish = next;
838 if (last)
839 last->list = next;
840 if (cur->rr.ttl == 0)
841 _r_done(d, cur);
842 cur = next;
843 }
844
845 if (d->a_publish) {
846 d->publish.tv_sec = d->now.tv_sec + 2;
847 d->publish.tv_usec = d->now.tv_usec;
848 }
849 }
850
851 /* If we're in shutdown, we're done */
852 if (d->shutdown)
853 return ret;
854
855 /* Check if a_pause is ready */
856 if (d->a_pause && _tvdiff(d->now, d->pause) <= 0)
857 ret += _r_out(d, m, &d->a_pause);
858
859 /* Now process questions */
860 if (ret > 0)
861 return ret;
862
863 m->header.qr = 0;
864 m->header.aa = 0;
865
866 if (d->probing && _tvdiff(d->now, d->probe) <= 0) {
867 mdns_record_t *last = 0;
868
869 /* Scan probe list to ask questions and process published */
870 for (r = d->probing; r != 0;) {
871 /* Done probing, publish */
872 if (r->unique == 4) {
873 mdns_record_t *next = r->list;
874
875 if (d->probing == r)
876 d->probing = r->list;
877 else
878 last->list = r->list;
879
880 r->list = 0;
881 r->unique = 5;
882 _r_publish(d, r);
883 r = next;
884 continue;
885 }
886
887 MDNSD_LOG_TRACE("Send Probing: Name: %s, Type: %d", r->rr.name, r->rr.type);
888
889 message_qd(m, r->rr.name, r->rr.type, (unsigned short int)d->clazz);
890 r->last_sent = d->now;
891 last = r;
892 r = r->list;
893 }
894
895 /* Scan probe list again to append our to-be answers */
896 for (r = d->probing; r != 0; r = r->list) {
897 r->unique++;
898
899 MDNSD_LOG_TRACE("Send Answer in Probe: Name: %s, Type: %d", r->rr.name, r->rr.type);
900 message_ns(m, r->rr.name, r->rr.type, (unsigned short int)d->clazz, r->rr.ttl);
901 _a_copy(m, &r->rr);
902 r->last_sent = d->now;
903 ret++;
904 }
905
906 /* Process probes again in the future */
907 if (ret) {
908 d->probe.tv_sec = d->now.tv_sec;
909 d->probe.tv_usec = d->now.tv_usec + 250000;
910 return ret;
911 }
912 }
913
914 /* Process qlist for retries or expirations */
915 if (d->checkqlist && (unsigned long int)d->now.tv_sec >= d->checkqlist) {
916 struct query *q;
917 struct cached *c;
918 unsigned long int nextbest = 0;
919
920 /* Ask questions first, track nextbest time */
921 for (q = d->qlist; q != 0; q = q->list) {
922 if (q->nexttry > 0 && q->nexttry <= (unsigned long int)d->now.tv_sec && q->tries < 3)
923 message_qd(m, q->name, (unsigned short int)q->type, (unsigned short int)d->clazz);
924 else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
925 nextbest = q->nexttry;
926 }
927
928 /* Include known answers, update questions */
929 for (q = d->qlist; q != 0; q = q->list) {
930 if (q->nexttry == 0 || q->nexttry > (unsigned long int)d->now.tv_sec)
931 continue;
932
933 /* Done retrying, expire and reset */
934 if (q->tries == 3) {
935 _c_expire(d, &d->cache[_namehash(q->name) % LPRIME]);
936 _q_reset(d, q);
937 continue;
938 }
939
940 ret++;
941 q->nexttry = (unsigned long int)(d->now.tv_sec + ++q->tries);
942 if (nextbest == 0 || q->nexttry < nextbest)
943 nextbest = q->nexttry;
944
945 /* If room, add all known good entries */
946 c = 0;
947 while ((c = _c_next(d, c, q->name, q->type)) != 0 && c->rr.ttl > (unsigned long int)d->now.tv_sec + 8 &&
948 message_packet_len(m) + _rr_len(&c->rr) < d->frame) {
949
950 MDNSD_LOG_TRACE("Add known answer: Name: %s, Type: %d", c->rr.name, c->rr.type);
951 message_an(m, q->name, (unsigned short int)q->type, (unsigned short int)d->clazz, c->rr.ttl - (unsigned long int)d->now.tv_sec);
952 _a_copy(m, &c->rr);
953 }
954 }
955 d->checkqlist = nextbest;
956 }
957
958 if ((unsigned long int)d->now.tv_sec > d->expireall)
959 _gc(d);
960
961 return ret;
962 }
963
964
965 #define RET \
966 while (d->sleep.tv_usec > 1000000) { \
967 d->sleep.tv_sec++; \
968 d->sleep.tv_usec -= 1000000; \
969 } \
970 return &d->sleep;
971
mdnsd_sleep(mdns_daemon_t * d)972 struct timeval *mdnsd_sleep(mdns_daemon_t *d)
973 {
974 int usec, minExpire;
975
976 d->sleep.tv_sec = d->sleep.tv_usec = 0;
977
978 /* First check for any immediate items to handle */
979 if (d->uanswers || d->a_now)
980 return &d->sleep;
981
982 gettimeofday(&d->now, 0);
983
984 /* Then check for paused answers or nearly expired records */
985 if (d->a_pause) {
986 if ((usec = _tvdiff(d->now, d->pause)) > 0)
987 d->sleep.tv_usec = usec;
988 RET;
989 }
990
991 /* Now check for probe retries */
992 if (d->probing) {
993 if ((usec = _tvdiff(d->now, d->probe)) > 0)
994 d->sleep.tv_usec = usec;
995 RET;
996 }
997
998 /* Now check for publish retries */
999 if (d->a_publish) {
1000 if ((usec = _tvdiff(d->now, d->publish)) > 0)
1001 d->sleep.tv_usec = usec;
1002 RET;
1003 }
1004
1005 /* Also check for queries with known answer expiration/retry */
1006 if (d->checkqlist) {
1007 int sec;
1008 if ((sec = (int)(d->checkqlist - (unsigned long int)d->now.tv_sec)) > 0)
1009 d->sleep.tv_sec = sec;
1010 RET;
1011 }
1012
1013 /* Resend published records before TTL expires */
1014 // latest expire is garbage collection
1015 minExpire = (int)(d->expireall - (unsigned long int)d->now.tv_sec);
1016 if (minExpire < 0)
1017 return &d->sleep;
1018
1019 {
1020 size_t i;
1021 for (i=0; i<SPRIME; i++) {
1022 int expire;
1023 if (!d->published[i])
1024 continue;
1025 expire = (int)((d->published[i]->last_sent.tv_sec + (long int)d->published[i]->rr.ttl) - d->now.tv_sec);
1026 if (expire < minExpire)
1027 d->a_pause = NULL;
1028 minExpire = expire < minExpire ? expire : minExpire;
1029 _r_push(&d->a_pause, d->published[i]);
1030 }
1031 }
1032 // publish 2 seconds before expire.
1033 d->sleep.tv_sec = minExpire > 2 ? minExpire-2 : 0;
1034 d->pause.tv_sec = d->now.tv_sec + d->sleep.tv_sec;
1035 RET;
1036 }
1037
mdnsd_query(mdns_daemon_t * d,const char * host,int type,int (* answer)(mdns_answer_t * a,void * arg),void * arg)1038 void mdnsd_query(mdns_daemon_t *d, const char *host, int type, int (*answer)(mdns_answer_t *a, void *arg), void *arg)
1039 {
1040 struct query *q;
1041 int i = _namehash(host) % SPRIME;
1042
1043 if (!(q = _q_next(d, 0, host, type))) {
1044 if (!answer)
1045 return;
1046
1047 q = (struct query *)MDNSD_calloc(1, sizeof(struct query));
1048 q->name = STRDUP(host);
1049 q->type = type;
1050 q->next = d->queries[i];
1051 q->list = d->qlist;
1052 d->qlist = d->queries[i] = q;
1053
1054 /* Any cached entries should be associated */
1055 {
1056 struct cached *cur = 0;
1057 while ((cur = _c_next(d, cur, q->name, q->type)))
1058 cur->q = q;
1059 }
1060 _q_reset(d, q);
1061
1062 /* New question, immediately send out */
1063 q->nexttry = d->checkqlist = (unsigned long int)d->now.tv_sec;
1064 }
1065
1066 /* No answer means we don't care anymore */
1067 if (!answer) {
1068 _q_done(d, q);
1069 return;
1070 }
1071
1072 q->answer = answer;
1073 q->arg = arg;
1074 }
1075
mdnsd_list(mdns_daemon_t * d,const char * host,int type,mdns_answer_t * last)1076 mdns_answer_t *mdnsd_list(mdns_daemon_t *d,const char *host, int type, mdns_answer_t *last)
1077 {
1078 return (mdns_answer_t *)_c_next(d, (struct cached *)last, host, type);
1079 }
1080
mdnsd_record_next(const mdns_record_t * r)1081 mdns_record_t *mdnsd_record_next(const mdns_record_t* r) {
1082 return r ? r->next : NULL;
1083 }
1084
mdnsd_record_data(const mdns_record_t * r)1085 const mdns_answer_t *mdnsd_record_data(const mdns_record_t* r) {
1086 return &r->rr;
1087 }
1088
mdnsd_shared(mdns_daemon_t * d,const char * host,unsigned short int type,unsigned long int ttl)1089 mdns_record_t *mdnsd_shared(mdns_daemon_t *d, const char *host, unsigned short int type, unsigned long int ttl)
1090 {
1091 int i = _namehash(host) % SPRIME;
1092 mdns_record_t *r;
1093
1094 r = (struct mdns_record *)MDNSD_calloc(1, sizeof(struct mdns_record));
1095 r->rr.name = STRDUP(host);
1096 r->rr.type = type;
1097 r->rr.ttl = ttl;
1098 r->next = d->published[i];
1099 d->published[i] = r;
1100
1101 return r;
1102 }
1103
mdnsd_unique(mdns_daemon_t * d,const char * host,unsigned short int type,unsigned long int ttl,void (* conflict)(char * host,int type,void * arg),void * arg)1104 mdns_record_t *mdnsd_unique(mdns_daemon_t *d, const char *host, unsigned short int type, unsigned long int ttl, void (*conflict)(char *host, int type, void *arg), void *arg)
1105 {
1106 mdns_record_t *r;
1107
1108 r = mdnsd_shared(d, host, type, ttl);
1109 r->conflict = conflict;
1110 r->arg = arg;
1111 r->unique = 1;
1112 _r_push(&d->probing, r);
1113 d->probe.tv_sec = d->now.tv_sec;
1114 d->probe.tv_usec = d->now.tv_usec;
1115
1116 return r;
1117 }
1118
mdnsd_get_published(const mdns_daemon_t * d,const char * host)1119 mdns_record_t * mdnsd_get_published(const mdns_daemon_t *d, const char *host) {
1120 return d->published[_namehash(host) % SPRIME];
1121 }
1122
mdnsd_has_query(const mdns_daemon_t * d,const char * host)1123 int mdnsd_has_query(const mdns_daemon_t *d, const char *host) {
1124 return d->queries[_namehash(host) % SPRIME]!=NULL;
1125 }
1126
mdnsd_done(mdns_daemon_t * d,mdns_record_t * r)1127 void mdnsd_done(mdns_daemon_t *d, mdns_record_t *r)
1128 {
1129 mdns_record_t *cur;
1130
1131 if (r->unique && r->unique < 5) {
1132 /* Probing yet, zap from that list first! */
1133 if (d->probing == r) {
1134 d->probing = r->list;
1135 } else {
1136 for (cur = d->probing; cur->list != r; cur = cur->list)
1137 ;
1138 cur->list = r->list;
1139 }
1140
1141 _r_done(d, r);
1142 return;
1143 }
1144
1145 r->rr.ttl = 0;
1146 _r_send(d, r);
1147 }
1148
mdnsd_set_raw(mdns_daemon_t * d,mdns_record_t * r,const char * data,unsigned short int len)1149 void mdnsd_set_raw(mdns_daemon_t *d, mdns_record_t *r, const char *data, unsigned short int len)
1150 {
1151 MDNSD_free(r->rr.rdata);
1152 r->rr.rdata = (unsigned char *)MDNSD_malloc(len);
1153 memcpy(r->rr.rdata, data, len);
1154 r->rr.rdlen = len;
1155 _r_publish(d, r);
1156 }
1157
mdnsd_set_host(mdns_daemon_t * d,mdns_record_t * r,const char * name)1158 void mdnsd_set_host(mdns_daemon_t *d, mdns_record_t *r, const char *name)
1159 {
1160 MDNSD_free(r->rr.rdname);
1161 r->rr.rdname = STRDUP(name);
1162 _r_publish(d, r);
1163 }
1164
mdnsd_set_ip(mdns_daemon_t * d,mdns_record_t * r,struct in_addr ip)1165 void mdnsd_set_ip(mdns_daemon_t *d, mdns_record_t *r, struct in_addr ip)
1166 {
1167 r->rr.ip = ip;
1168 _r_publish(d, r);
1169 }
1170
mdnsd_set_srv(mdns_daemon_t * d,mdns_record_t * r,unsigned short int priority,unsigned short int weight,unsigned short int port,char * name)1171 void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short int priority, unsigned short int weight, unsigned short int port, char *name)
1172 {
1173 r->rr.srv.priority = priority;
1174 r->rr.srv.weight = weight;
1175 r->rr.srv.port = port;
1176 mdnsd_set_host(d, r, name);
1177 }
1178
1179 #if MDNSD_LOGLEVEL <= 100
1180 #include <ctype.h>
dump_hex_pkg(char * buffer,int bufferLen)1181 static void dump_hex_pkg(char* buffer, int bufferLen) {
1182 char ascii[17];
1183 memset(ascii,0,17);
1184 for (int i = 0; i < bufferLen; i++)
1185 {
1186 if (i%16 == 0)
1187 printf("%s\n%06x ", ascii, i);
1188 if (isprint((int)(buffer[i])))
1189 ascii[i%16] = buffer[i];
1190 else
1191 ascii[i%16] = '.';
1192 printf("%02X ", (unsigned char)buffer[i]);
1193 }
1194 printf("%s\n%06x ", ascii, bufferLen);
1195 printf("\n");
1196 }
1197 #endif
1198
mdnsd_step(mdns_daemon_t * d,int mdns_socket,bool processIn,bool processOut,struct timeval * nextSleep)1199 unsigned short int mdnsd_step(mdns_daemon_t *d, int mdns_socket, bool processIn, bool processOut, struct timeval *nextSleep) {
1200
1201 struct message m;
1202
1203 if (processIn) {
1204 int bsize;
1205 socklen_t ssize = sizeof(struct sockaddr_in);
1206 unsigned char buf[MAX_PACKET_LEN];
1207 struct sockaddr_in from;
1208
1209 while ((bsize = (int)recvfrom(mdns_socket, (char*)buf, MAX_PACKET_LEN, 0, (struct sockaddr *)&from, &ssize)) > 0) {
1210 memset(&m, 0, sizeof(struct message));
1211 #if MDNSD_LOGLEVEL <= 100
1212 MDNSD_LOG_TRACE("Got Data:");
1213 dump_hex_pkg((char*)buf, bsize);
1214 #endif
1215 message_parse(&m, buf);
1216 if (mdnsd_in(d, &m, (unsigned long int)from.sin_addr.s_addr, from.sin_port)!=0)
1217 return 2;
1218 }
1219 #ifdef _WIN32
1220 if (bsize < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
1221 #else
1222 if (bsize < 0 && errno != EAGAIN)
1223 #endif
1224 {
1225 return 1;
1226 }
1227 }
1228
1229 if (processOut) {
1230 struct sockaddr_in to;
1231 struct in_addr ip;
1232 unsigned short int port;
1233 #ifdef __clang__
1234 #pragma clang diagnostic push
1235 #pragma clang diagnostic ignored "-Wcast-align"
1236 #endif
1237 while (mdnsd_out(d, &m, (long unsigned int *)&ip, &port)) {
1238 #ifdef __clang__
1239 #pragma clang diagnostic pop
1240 #endif
1241 int len = message_packet_len(&m);
1242 char* buf = (char*)message_packet(&m);
1243 memset(&to, 0, sizeof(to));
1244 to.sin_family = AF_INET;
1245 to.sin_port = port;
1246 to.sin_addr = ip;
1247 #if MDNSD_LOGLEVEL <= 100
1248 MDNSD_LOG_TRACE("Send Data:");
1249 dump_hex_pkg(buf, (int)len);
1250 #endif
1251
1252 if (sendto(mdns_socket, buf, (unsigned int)len, 0, (struct sockaddr *)&to,
1253 sizeof(struct sockaddr_in)) != len) {
1254 return 2;
1255 }
1256 }
1257 }
1258
1259 if (nextSleep) {
1260 struct timeval *tv = mdnsd_sleep(d);
1261 nextSleep->tv_sec = tv->tv_sec;
1262 nextSleep->tv_usec = tv->tv_usec;
1263 }
1264
1265 return 0;
1266 }
1267