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