Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/open62541_15/src_generated/mdnsd/mdnsd.c
Line
Count
Source
1
#include "open62541/config.h"
2
/*
3
 * Copyright (c) 2003  Jeremie Miller <jer@jabber.org>
4
 * Copyright (c) 2016-2026  Joachim Wiberg <troglobit@gmail.com>
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *     * Redistributions of source code must retain the above copyright
10
 *       notice, this list of conditions and the following disclaimer.
11
 *     * Redistributions in binary form must reproduce the above copyright
12
 *       notice, this list of conditions and the following disclaimer in the
13
 *       documentation and/or other materials provided with the distribution.
14
 *     * Neither the name of the copyright holders nor the names of its
15
 *       contributors may be used to endorse or promote products derived from
16
 *       this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
 * POSSIBILITY OF SUCH DAMAGE.
29
 */
30
31
#include "mdnsd.h"
32
#include <string.h>
33
#include <stdlib.h>
34
#include <stdbool.h>
35
#include <time.h>
36
#include <errno.h>
37
#include <ifaddrs.h>
38
#include <arpa/inet.h>
39
40
108k
#define SPRIME 109    /* Size of query/publish hashes */
41
675k
#define LPRIME 1009    /* Size of cache hash */
42
43
668
#define GC 86400                /* Brute force garbage cleanup
44
         * frequency, rarely needed (daily
45
         * default) */
46
47
/* Interval for refreshing cached local interface addresses (seconds) */
48
0
#define LOCAL_ADDR_REFRESH_INTERVAL 5
49
50
/**
51
 * Messy, but it's the best/simplest balance I can find at the moment
52
 *
53
 * Some internal data types, and a few hashes: querys, answers, cached,
54
 * and records (published, unique and shared).  Each type has different
55
 * semantics for processing, both for timeouts, incoming, and outgoing
56
 * I/O.  They inter-relate too, like records affect the querys they are
57
 * relevant to.  Nice things about MDNS: we only publish once (and then
58
 * ask asked), and only query once, then just expire records we've got
59
 * cached
60
*/
61
62
struct query {
63
  char *name;
64
  int type;
65
  unsigned long int nexttry;
66
  int tries;
67
  int (*answer)(mdns_answer_t *, void *);
68
  void *arg;
69
  struct query *next, *list;
70
};
71
72
struct unicast {
73
  int id;
74
  inet_addr_t to;
75
  mdns_record_t *r;
76
  struct unicast *next;
77
};
78
79
struct cached {
80
  struct mdns_answer rr;
81
  struct query *q;
82
  struct cached *next;
83
};
84
85
struct mdns_record {
86
  struct mdns_answer rr;
87
  char unique;    /* # of checks performed to ensure */
88
  int modified;   /* Ignore conflicts after update at runtime */
89
  int tries;
90
  void (*conflict)(char *, int, void *);
91
  void *arg;
92
  struct timeval last_sent;
93
  struct mdns_record *next, *list;
94
};
95
96
struct mdns_daemon {
97
  char shutdown, disco;
98
  unsigned long int expireall, checkqlist;
99
  struct timeval now, sleep, pause, probe, publish;
100
  int clazz, frame;
101
  struct cached *cache[LPRIME];
102
  struct mdns_record *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
103
  struct unicast *uanswers;
104
  struct query *queries[SPRIME], *qlist;
105
106
  sa_family_t family;   /* transport: AF_INET or AF_INET6 */
107
  struct in_addr addr;
108
  struct in6_addr addr_v6;
109
110
  /* Cached local interface snapshot to avoid getifaddrs() per packet */
111
  struct ifaddrs *local_ifaddrs;
112
  time_t local_addrs_refreshed;
113
114
  mdnsd_record_received_callback received_callback;
115
  void *received_callback_data;
116
};
117
118
static int _namehash(const char *s)
119
4.46k
{
120
4.46k
  const unsigned char *name = (const unsigned char *)s;
121
4.46k
  unsigned long h = 0, g;
122
123
176k
  while (*name) {   /* do some fancy bitwanking on the string */
124
171k
    h = (h << 4) + (unsigned long)(*name++);
125
171k
    if ((g = (h & 0xF0000000UL)) != 0)
126
136k
      h ^= (g >> 24);
127
171k
    h &= ~g;
128
171k
  }
129
130
4.46k
  return (int)h;
131
4.46k
}
132
133
/* Basic linked list and hash primitives */
134
static struct query *_q_next(mdns_daemon_t *d, struct query *q, const char *host, int type)
135
279
{
136
279
  if (!q)
137
279
    q = d->queries[_namehash(host) % SPRIME];
138
0
  else
139
0
    q = q->next;
140
141
279
  for (; q != 0; q = q->next) {
142
0
    if (q->type == type && strcmp(q->name, host) == 0)
143
0
      return q;
144
0
  }
145
146
279
  return NULL;
147
279
}
148
149
static struct cached *_c_next(mdns_daemon_t *d, struct cached *c,const char *host, int type)
150
558
{
151
558
  if (!c)
152
558
    c = d->cache[_namehash(host) % LPRIME];
153
0
  else
154
0
    c = c->next;
155
156
558
  for (; c != 0; c = c->next) {
157
0
    if ((type == c->rr.type || type == QTYPE_ANY) && strcmp(c->rr.name, host) == 0)
158
0
      return c;
159
0
  }
160
161
558
  return NULL;
162
558
}
163
164
static mdns_record_t *_r_next(mdns_daemon_t *d, mdns_record_t *r, const char *host, int type)
165
0
{
166
0
  if (!r)
167
0
    r = d->published[_namehash(host) % SPRIME];
168
0
  else
169
0
    r = r->next;
170
171
0
  for (; r != NULL; r = r->next) {
172
0
    if ((type == r->rr.type || type == QTYPE_ANY) && strcmp(r->rr.name, host) == 0)
173
0
      return r;
174
0
  }
175
176
0
  return NULL;
177
0
}
178
179
static size_t _rr_len(mdns_answer_t *rr)
180
0
{
181
0
  size_t len = 12;    /* name is always compressed (dup of earlier), plus normal stuff */
182
183
0
  if (rr->rdata)
184
0
    len += rr->rdlen;
185
0
  if (rr->rdname)
186
0
    len += strlen(rr->rdname); /* worst case */
187
0
  if (rr->ip.s_addr)
188
0
    len += 4;
189
0
  if (! IN6_IS_ADDR_UNSPECIFIED(&(rr->ip6)))
190
0
    len += 16;
191
0
  if (rr->type == QTYPE_PTR)
192
0
    len += 6; /* srv record stuff */
193
194
0
  return len;
195
0
}
196
197
/* Compares new_ rdata with known a, painfully */
198
static bool _a_match(struct resource *r, mdns_answer_t *a)
199
0
{
200
0
  if (!a->name)
201
0
    return 0;
202
0
  if (strcmp(r->name, a->name) || r->type != a->type)
203
0
    return 0;
204
205
0
  switch (r->type) {
206
0
    case QTYPE_SRV:
207
0
      return r->known.srv.name && a->rdname && strcmp(r->known.srv.name, a->rdname) == 0
208
0
        && a->srv.port == r->known.srv.port
209
0
        && a->srv.weight == r->known.srv.weight
210
0
        && a->srv.priority == r->known.srv.priority;
211
212
213
0
    case QTYPE_PTR:
214
0
    case QTYPE_NS:
215
0
    case QTYPE_CNAME:
216
0
      return r->known.ns.name && a->rdname &&
217
0
        strcmp(r->known.ns.name, a->rdname) == 0;
218
219
0
    case QTYPE_A:
220
0
      return memcmp(&r->known.a.ip, &a->ip, 4) == 0;
221
222
0
    case QTYPE_AAAA:
223
0
      return memcmp(&r->known.aaaa.ip6, &a->ip6, 16) == 0;
224
225
0
    default:
226
0
      return r->rdlength == a->rdlen &&
227
0
        (r->rdlength == 0 || memcmp(r->rdata, a->rdata, r->rdlength) == 0);
228
0
  }
229
230
0
  return 0;
231
0
}
232
233
/* Compare time values easily */
234
static long _tvdiff(struct timeval old, struct timeval new_)
235
0
{
236
0
  long udiff = 0;
237
238
0
  if (old.tv_sec != new_.tv_sec)
239
0
    udiff = (new_.tv_sec - old.tv_sec) * 1000000;
240
241
0
  return (new_.tv_usec - old.tv_usec) + udiff;
242
0
}
243
244
static void _r_remove_list(mdns_record_t **list, mdns_record_t *r)
245
1.11k
{
246
1.11k
  mdns_record_t *tmp;
247
248
1.11k
  if (*list == r) {
249
0
    *list = r->list;
250
0
    r->list = NULL;
251
0
    return;
252
0
  }
253
254
3.34k
  for (tmp = *list; tmp; tmp = tmp->list) {
255
2.23k
    if (tmp->list == r) {
256
0
      tmp->list = r->list;
257
0
      r->list = NULL;
258
0
      break;
259
0
    }
260
2.23k
    if (tmp == tmp->list)
261
0
      break;
262
2.23k
  }
263
1.11k
}
264
265
static void _r_remove_lists(mdns_daemon_t *d, mdns_record_t *r, mdns_record_t **skip)
266
1.67k
{
267
1.67k
  if (d->probing && &d->probing != skip)
268
558
    _r_remove_list(&d->probing, r);
269
270
1.67k
  if (d->a_now && &d->a_now != skip)
271
0
    _r_remove_list(&d->a_now, r);
272
273
1.67k
  if (d->a_pause && &d->a_pause != skip)
274
0
    _r_remove_list(&d->a_pause, r);
275
276
1.67k
  if (d->a_publish && &d->a_publish != skip)
277
558
    _r_remove_list(&d->a_publish, r);
278
1.67k
}
279
280
/* Make sure not already on the list, then insert */
281
static void _r_push(mdns_record_t **list, mdns_record_t *r)
282
1.67k
{
283
1.67k
  mdns_record_t *cur;
284
285
3.62k
  for (cur = *list; cur != 0; cur = cur->list) {
286
1.95k
    if (cur == r)
287
0
      return;
288
1.95k
  }
289
290
1.67k
  r->list = *list;
291
1.67k
  *list = r;
292
1.67k
}
293
294
/* Force any r out right away, if valid */
295
static void _r_publish(mdns_daemon_t *d, mdns_record_t *r)
296
1.67k
{
297
1.67k
  r->modified = 1;
298
299
1.67k
  if (r->unique && r->unique < 5)
300
558
    return;    /* Probing already */
301
302
1.11k
  r->tries = 0;
303
1.11k
  d->publish.tv_sec = d->now.tv_sec;
304
1.11k
  d->publish.tv_usec = d->now.tv_usec;
305
306
  /* check if r already in other lists. If yes, remove it from there */
307
1.11k
  _r_remove_lists(d, r, &d->a_publish);
308
1.11k
  _r_push(&d->a_publish, r);
309
1.11k
}
310
311
/* send r out asap */
312
static void _r_send(mdns_daemon_t *d, mdns_record_t *r)
313
558
{
314
  /* Being published, make sure that happens soon */
315
558
  if (r->tries < 4) {
316
558
    d->publish.tv_sec = d->now.tv_sec;
317
558
    d->publish.tv_usec = d->now.tv_usec;
318
558
    return;
319
558
  }
320
321
  /* Known unique ones can be sent asap */
322
0
  if (r->unique) {
323
    /* check if r already in other lists. If yes, remove it from there */
324
0
    _r_remove_lists(d, r, &d->a_now);
325
0
    _r_push(&d->a_now, r);
326
0
    return;
327
0
  }
328
329
  /* Set d->pause.tv_usec to random 20-120 msec */
330
0
  d->pause.tv_sec = d->now.tv_sec;
331
0
  d->pause.tv_usec = d->now.tv_usec + (d->now.tv_usec % 100) + 20;
332
333
  /* check if r already in other lists. If yes, remove it from there */
334
0
  _r_remove_lists(d, r, &d->a_pause);
335
0
  _r_push(&d->a_pause, r);
336
0
}
337
338
/* Create generic unicast response struct */
339
static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, const inet_addr_t *to)
340
0
{
341
0
  struct unicast *u;
342
343
0
  u = calloc(1, sizeof(struct unicast));
344
0
  if (!u)
345
0
    return;
346
347
0
  u->r = r;
348
0
  u->id = id;
349
0
  u->to = *to;
350
0
  u->next = d->uanswers;
351
0
  d->uanswers = u;
352
0
}
353
354
/* Drop any pending unicast answers referring to r, which is being freed */
355
static void _u_remove(mdns_daemon_t *d, mdns_record_t *r)
356
558
{
357
558
  struct unicast *u = d->uanswers, *prev = NULL;
358
359
558
  while (u) {
360
0
    struct unicast *next = u->next;
361
362
0
    if (u->r == r) {
363
0
      if (prev)
364
0
        prev->next = next;
365
0
      else
366
0
        d->uanswers = next;
367
0
      free(u);
368
0
    } else {
369
0
      prev = u;
370
0
    }
371
0
    u = next;
372
0
  }
373
558
}
374
375
static void _q_reset(mdns_daemon_t *d, struct query *q)
376
279
{
377
279
  struct cached *cur = 0;
378
379
279
  q->nexttry = 0;
380
279
  q->tries = 0;
381
382
279
  while ((cur = _c_next(d, cur, q->name, q->type))) {
383
0
    if (q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry)
384
0
      q->nexttry = cur->rr.ttl - 7;
385
0
  }
386
387
279
  if (q->nexttry != 0 && q->nexttry < d->checkqlist)
388
0
    d->checkqlist = q->nexttry;
389
279
}
390
391
/* No more queries, update all its cached entries, remove from lists */
392
static void _q_done(mdns_daemon_t *d, struct query *q)
393
0
{
394
0
  struct cached *c = 0;
395
0
  struct query *cur;
396
0
  int i = _namehash(q->name) % SPRIME;
397
398
0
  while ((c = _c_next(d, c, q->name, q->type)))
399
0
    c->q = 0;
400
401
0
  if (d->qlist == q) {
402
0
    d->qlist = q->list;
403
0
  } else {
404
0
    for (cur = d->qlist; cur->list != q; cur = cur->list)
405
0
      ;
406
0
    cur->list = q->list;
407
0
  }
408
409
0
  if (d->queries[i] == q) {
410
0
    d->queries[i] = q->next;
411
0
  } else {
412
0
    for (cur = d->queries[i]; cur->next != q; cur = cur->next)
413
0
      ;
414
0
    cur->next = q->next;
415
0
  }
416
417
0
  free(q->name);
418
0
  free(q);
419
0
}
420
421
static void _free_cached(struct cached *c)
422
0
{
423
0
  if (!c)
424
0
    return;
425
426
0
  if (c->rr.name) {
427
0
    free(c->rr.name);
428
0
    c->rr.name = NULL;
429
0
  }
430
0
  if (c->rr.rdata) {
431
0
    free(c->rr.rdata);
432
0
    c->rr.rdata = NULL;
433
0
  }
434
0
  if (c->rr.rdname) {
435
0
    free(c->rr.rdname);
436
0
    c->rr.rdname = NULL;
437
0
  }
438
0
  free(c);
439
0
}
440
441
static void _free_record(mdns_record_t *r)
442
1.67k
{
443
1.67k
  if (!r)
444
0
    return;
445
446
1.67k
  if (r->rr.name) {
447
1.67k
    free(r->rr.name);
448
1.67k
    r->rr.name = NULL;
449
1.67k
  }
450
1.67k
  if (r->rr.rdata) {
451
837
    free(r->rr.rdata);
452
837
    r->rr.rdata = NULL;
453
837
  }
454
1.67k
  if (r->rr.rdname) {
455
837
    free(r->rr.rdname);
456
837
    r->rr.rdname = NULL;
457
837
  }
458
1.67k
  free(r);
459
1.67k
}
460
461
/* buh-bye, remove from hash and free */
462
static void _r_done(mdns_daemon_t *d, mdns_record_t *r)
463
558
{
464
558
  mdns_record_t *cur = 0;
465
558
  int i;
466
467
558
  if (!r || !r->rr.name)
468
0
    return;
469
470
558
  i = _namehash(r->rr.name) % SPRIME;
471
558
  if (d->published[i] == r) {
472
279
    d->published[i] = r->next;
473
279
  } else {
474
279
    for (cur = d->published[i]; cur && cur->next != r; cur = cur->next)
475
0
      ;
476
279
    if (cur)
477
279
      cur->next = r->next;
478
279
  }
479
480
  /* A queued unicast answer may still point at r; drop it first. */
481
558
  _u_remove(d, r);
482
483
558
  _free_record(r);
484
558
}
485
486
/* Call the answer function with this cached entry */
487
static void _q_answer(mdns_daemon_t *d, struct cached *c)
488
0
{
489
0
  if (c->rr.ttl <= (unsigned long)d->now.tv_sec)
490
0
    c->rr.ttl = 0;
491
0
  if (c->q->answer(&c->rr, c->q->arg) == -1)
492
0
    _q_done(d, c->q);
493
0
}
494
495
static void _conflict(mdns_daemon_t *d, mdns_record_t *r)
496
0
{
497
0
  r->conflict(r->rr.name, r->rr.type, r->arg);
498
0
  mdnsd_done(d, r);
499
0
}
500
501
/* Expire any old entries in this list */
502
static void _c_expire(mdns_daemon_t *d, struct cached **list)
503
0
{
504
0
  struct cached *cur  = *list;
505
0
  struct cached *last = NULL;
506
0
  struct cached *next;
507
508
0
  while (cur) {
509
0
    next = cur->next;
510
511
0
    if ((unsigned long)d->now.tv_sec >= cur->rr.ttl) {
512
0
      if (last)
513
0
        last->next = next;
514
515
      /* Update list pointer if the first one expired */
516
0
      if (*list == cur)
517
0
        *list = next;
518
519
0
      if (cur->q)
520
0
        _q_answer(d, cur);
521
522
0
      _free_cached(cur);
523
0
    } else {
524
0
      last = cur;
525
0
    }
526
0
    cur = next;
527
0
  }
528
0
}
529
530
/* Brute force expire any old cached records */
531
static void _gc(mdns_daemon_t *d)
532
0
{
533
0
  int i;
534
535
0
  for (i = 0; i < LPRIME; i++) {
536
0
    if (d->cache[i])
537
0
      _c_expire(d, &d->cache[i]);
538
0
  }
539
540
0
  d->expireall = (unsigned long)(d->now.tv_sec + GC);
541
0
}
542
543
static int _cache(mdns_daemon_t *d, struct resource *r, const inet_addr_t *from)
544
0
{
545
0
  unsigned long int ttl;
546
0
  struct cached *c = 0;
547
0
  int i = _namehash(r->name) % LPRIME;
548
549
  /* Cache flush for unique entries */
550
0
  if (r->clazz == 32768 + d->clazz) {
551
0
    while ((c = _c_next(d, c, r->name, r->type)))
552
0
      c->rr.ttl = 0;
553
0
    _c_expire(d, &d->cache[i]);
554
0
  }
555
556
  /* Process deletes */
557
0
  if (r->ttl == 0) {
558
0
    while ((c = _c_next(d, c, r->name, r->type))) {
559
0
      if (_a_match(r, &c->rr)) {
560
0
        c->rr.ttl = 0;
561
0
        _c_expire(d, &d->cache[i]);
562
0
        c = NULL;
563
0
      }
564
0
    }
565
566
0
    return 0;
567
0
  }
568
569
  /*
570
   * XXX: The c->rr.ttl is a hack for now, BAD SPEC, start
571
   *      retrying just after half-waypoint, then expire
572
   */
573
0
  ttl = (unsigned long)d->now.tv_sec + (r->ttl / 2) + 8;
574
575
  /*
576
   * If this record is already cached, just refresh its TTL.  Match on
577
   * the rdata, not only name+type: a host can have several A/AAAA
578
   * records (e.g. a link-local and a global address), each its own entry.
579
   */
580
0
  c = NULL;
581
0
  while ((c = _c_next(d, c, r->name, r->type))) {
582
0
    if (!_a_match(r, &c->rr))
583
0
      continue;
584
0
    c->rr.ttl = ttl;
585
0
    return 0;
586
0
  }
587
588
  /* New entry, cache it */
589
0
  c = calloc(1, sizeof(struct cached));
590
0
  if (!c)
591
0
    return 1;
592
593
0
  c->rr.name = strdup(r->name);
594
0
  if (!c->rr.name) {
595
0
    free(c);
596
0
    return 1;
597
0
  }
598
0
  c->rr.type = r->type;
599
0
  c->rr.ttl = ttl;
600
0
  c->rr.rdlen = r->rdlength;
601
0
  if (r->rdlength && !r->rdata) {
602
//    ERR("rdlength is %d but rdata is NULL for domain name %s, type: %d, ttl: %ld", r->rdlength, r->name, r->type, r->ttl);
603
0
    free(c->rr.name);
604
0
    free(c);
605
0
    return 1;
606
0
  }
607
0
  if (r->rdlength) {
608
0
    c->rr.rdata = malloc(r->rdlength);
609
0
    if (!c->rr.rdata) {
610
0
      free(c->rr.name);
611
0
      free(c);
612
0
      return 1;
613
0
    }
614
0
    memcpy(c->rr.rdata, r->rdata, r->rdlength);
615
0
  } else {
616
0
    c->rr.rdata = NULL;
617
0
  }
618
619
0
  switch (r->type) {
620
0
  case QTYPE_A:
621
0
    c->rr.ip = r->known.a.ip;
622
0
    break;
623
624
0
  case QTYPE_AAAA:
625
0
    c->rr.ip6 = r->known.aaaa.ip6;
626
0
    break;
627
628
0
  case QTYPE_NS:
629
0
  case QTYPE_CNAME:
630
0
  case QTYPE_PTR:
631
0
    c->rr.rdname = strdup(r->known.ns.name);
632
    /* Stash the responder address for mquery's device view */
633
#ifdef ENABLE_IPV6
634
    if (inet_family(from) == AF_INET6)
635
      c->rr.ip6 = ((const struct sockaddr_in6 *)from)->sin6_addr;
636
    else
637
#endif
638
0
      c->rr.ip = ((const struct sockaddr_in *)from)->sin_addr;
639
0
    break;
640
641
0
  case QTYPE_SRV:
642
0
    c->rr.rdname = strdup(r->known.srv.name);
643
0
    c->rr.srv.port = r->known.srv.port;
644
0
    c->rr.srv.weight = r->known.srv.weight;
645
0
    c->rr.srv.priority = r->known.srv.priority;
646
0
    break;
647
0
  }
648
649
0
  c->next = d->cache[i];
650
0
  d->cache[i] = c;
651
652
0
  if ((c->q = _q_next(d, 0, r->name, r->type)))
653
0
    _q_answer(d, c);
654
655
0
  return 0;
656
0
}
657
658
/* Copy the data bits only */
659
static void _a_copy(struct message *m, mdns_answer_t *a)
660
0
{
661
  /*
662
   * Re-encode name rdata from rdname so compression is computed for
663
   * this packet.  The raw cached rdata holds pointers into the packet
664
   * it arrived in and cannot be replayed verbatim.  See issue #79.
665
   */
666
0
  if (a->type == QTYPE_SRV) {
667
0
    message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
668
0
    return;
669
0
  }
670
0
  if (a->rdname) {
671
0
    message_rdata_name(m, a->rdname);
672
0
    return;
673
0
  }
674
675
0
  if (a->rdata) {
676
0
    message_rdata_raw(m, a->rdata, a->rdlen);
677
0
    return;
678
0
  }
679
680
0
  if (a->ip.s_addr)
681
0
    message_rdata_ipv4(m, a->ip);
682
0
  else if (!IN6_IS_ADDR_UNSPECIFIED(&(a->ip6)))
683
0
    message_rdata_ipv6(m, a->ip6);
684
0
}
685
686
/*
687
 * RFC 6763 §12: when answering a PTR or SRV query, add the related SRV,
688
 * TXT and address records to the additional section so a client need not
689
 * query again.  See issue #76.  Records answered this round are tracked so
690
 * we never repeat one of them as an additional record.
691
 */
692
0
#define ADDITIONAL_MAX 64
693
struct answered {
694
  mdns_record_t *rec[ADDITIONAL_MAX];
695
  int n;
696
};
697
698
static void _answered_add(struct answered *a, mdns_record_t *r)
699
0
{
700
0
  if (a->n < ADDITIONAL_MAX)
701
0
    a->rec[a->n++] = r;
702
0
}
703
704
static int _answered(const struct answered *a, const mdns_record_t *r)
705
0
{
706
0
  int i;
707
708
0
  for (i = 0; i < a->n; i++) {
709
0
    if (a->rec[i] == r)
710
0
      return 1;
711
0
  }
712
713
0
  return 0;
714
0
}
715
716
/* Append one additional record, unless already in the packet or out of room */
717
static void _ar(mdns_daemon_t *d, struct message *m, mdns_record_t *r, struct answered *seen)
718
0
{
719
0
  if (_answered(seen, r))
720
0
    return;
721
0
  if (message_packet_len(m) + (int)_rr_len(&r->rr) >= d->frame)
722
0
    return;
723
724
0
  message_ar(m, r->rr.name, r->rr.type, d->clazz + (r->unique ? 32768 : 0), r->rr.ttl);
725
0
  _a_copy(m, &r->rr);
726
0
  _answered_add(seen, r);
727
0
}
728
729
/* Append the A/AAAA records for host to the additional section */
730
static void _ar_addr(mdns_daemon_t *d, struct message *m, char *host, struct answered *seen)
731
0
{
732
0
  mdns_record_t *r;
733
734
0
  if (!host)
735
0
    return;
736
737
0
  for (r = mdnsd_get_published(d, host); r; r = r->next) {
738
0
    if (strcmp(r->rr.name, host))
739
0
      continue;
740
0
    if (r->rr.type == QTYPE_A || r->rr.type == QTYPE_AAAA)
741
0
      _ar(d, m, r, seen);
742
0
  }
743
0
}
744
745
/* RFC 6763 §12 additional records for an answered PTR or SRV record */
746
static void _additional(mdns_daemon_t *d, struct message *m, mdns_record_t *ans, struct answered *seen)
747
0
{
748
0
  mdns_record_t *r;
749
750
0
  if (ans->rr.type == QTYPE_SRV) {
751
0
    _ar_addr(d, m, ans->rr.rdname, seen);
752
0
    return;
753
0
  }
754
755
0
  if (ans->rr.type != QTYPE_PTR || !ans->rr.rdname || !strcmp(ans->rr.name, DISCO_NAME))
756
0
    return;
757
758
0
  for (r = mdnsd_get_published(d, ans->rr.rdname); r; r = r->next) {
759
0
    if (strcmp(r->rr.name, ans->rr.rdname))
760
0
      continue;
761
762
0
    if (r->rr.type == QTYPE_SRV) {
763
0
      _ar(d, m, r, seen);
764
0
      _ar_addr(d, m, r->rr.rdname, seen);
765
0
    } else if (r->rr.type == QTYPE_TXT) {
766
0
      _ar(d, m, r, seen);
767
0
    }
768
0
  }
769
0
}
770
771
/* Copy a published record into an outgoing message */
772
static int _r_out(mdns_daemon_t *d, struct message *m, mdns_record_t **list, struct answered *seen)
773
0
{
774
0
  mdns_record_t *r;
775
0
  int ret = 0;
776
777
0
  while ((r = *list) != NULL && message_packet_len(m) + (int)_rr_len(&r->rr) < d->frame) {
778
0
    if (r != r->list)
779
0
      *list = r->list;
780
0
    else
781
0
      *list = NULL;
782
783
    /* Service enumeration/discovery, drop non-PTR replies */
784
0
    if (d->disco) {
785
0
      if (r->rr.type != QTYPE_PTR)
786
0
        continue;
787
788
0
      if (strcmp(r->rr.name, DISCO_NAME))
789
0
        continue;
790
0
    }
791
792
0
    INFO("Appending name: %s, type %d to outbound message ...", r->rr.name, r->rr.type);
793
0
    ret++;
794
795
0
    if (r->unique)
796
0
      message_an(m, r->rr.name, r->rr.type, d->clazz + 32768, r->rr.ttl);
797
0
    else
798
0
      message_an(m, r->rr.name, r->rr.type, d->clazz, r->rr.ttl);
799
0
    r->last_sent = d->now;
800
801
0
    _a_copy(m, &r->rr);
802
803
0
    r->modified = 0; /* If updated we've now sent the update. */
804
0
    if (r->rr.ttl == 0) {
805
      /*
806
       * also remove from other lists, because record
807
       * may be in multiple lists at the same time
808
       */
809
0
      _r_remove_lists(d, r, list);
810
0
      _r_done(d, r);
811
0
    } else {
812
0
      _answered_add(seen, r);
813
0
    }
814
0
  }
815
816
0
  return ret;
817
0
}
818
819
/* Refresh the cached local interface addresses if needed (every ~5s) */
820
static void _refresh_local_addrs(mdns_daemon_t *d, bool force)
821
0
{
822
0
  struct ifaddrs *ifa = NULL;
823
824
  /* Refresh at most every 5 seconds */
825
0
  if (d->local_addrs_refreshed && (d->now.tv_sec - d->local_addrs_refreshed) < LOCAL_ADDR_REFRESH_INTERVAL && !force)
826
0
    return;
827
828
0
  if (getifaddrs(&ifa) != 0)
829
0
    return;
830
831
  /* Swap in the latest snapshot */
832
0
  if (d->local_ifaddrs)
833
0
    freeifaddrs(d->local_ifaddrs);
834
0
  d->local_ifaddrs = ifa;
835
0
  d->local_addrs_refreshed = d->now.tv_sec ? d->now.tv_sec : time(NULL);
836
0
}
837
838
/* Check if an IPv4 address belongs to this host (any interface) */
839
static bool _is_local_ipv4(mdns_daemon_t *d, struct in_addr ip)
840
389
{
841
389
  struct ifaddrs *it;
842
843
  /* Always consider the primary configured address as local */
844
389
  if (ip.s_addr == d->addr.s_addr)
845
389
    return true;
846
847
0
  _refresh_local_addrs(d, false);
848
849
0
  for (it = d->local_ifaddrs; it; it = it->ifa_next) {
850
0
    struct sockaddr_in *sin;
851
0
    if (!it->ifa_addr)
852
0
      continue;
853
0
    if (it->ifa_addr->sa_family != AF_INET)
854
0
      continue;
855
0
    sin = (struct sockaddr_in *)it->ifa_addr;
856
0
    if (sin->sin_addr.s_addr == ip.s_addr)
857
0
      return true;
858
0
  }
859
860
0
  return false;
861
0
}
862
863
#ifdef ENABLE_IPV6
864
/* Check if an IPv6 address belongs to this host (any interface) */
865
static bool _is_local_ipv6(mdns_daemon_t *d, struct in6_addr ip)
866
{
867
  struct ifaddrs *it;
868
869
  if (IN6_ARE_ADDR_EQUAL(&ip, &d->addr_v6))
870
    return true;
871
872
  _refresh_local_addrs(d, false);
873
874
  for (it = d->local_ifaddrs; it; it = it->ifa_next) {
875
    struct sockaddr_in6 *sin6;
876
877
    if (!it->ifa_addr || it->ifa_addr->sa_family != AF_INET6)
878
      continue;
879
    sin6 = (struct sockaddr_in6 *)it->ifa_addr;
880
    if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip))
881
      return true;
882
  }
883
884
  return false;
885
}
886
#endif
887
888
/* Ignore packets we sent ourselves, regardless of address family */
889
static bool _is_local(mdns_daemon_t *d, const inet_addr_t *from)
890
182
{
891
#ifdef ENABLE_IPV6
892
  if (inet_family(from) == AF_INET6)
893
    return _is_local_ipv6(d, ((const struct sockaddr_in6 *)from)->sin6_addr);
894
#endif
895
182
  return _is_local_ipv4(d, ((const struct sockaddr_in *)from)->sin_addr);
896
182
}
897
898
/* mDNS multicast destination for the daemon's transport family */
899
static void mdns_mcast(inet_addr_t *to, sa_family_t family)
900
0
{
901
0
  memset(to, 0, sizeof(*to));
902
0
  to->ss_family = family;
903
904
#ifdef ENABLE_IPV6
905
  if (family == AF_INET6) {
906
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)to;
907
908
    inet_pton(AF_INET6, "ff02::fb", &sin6->sin6_addr);
909
    sin6->sin6_port = htons(5353);
910
    return;
911
  }
912
#endif
913
0
  ((struct sockaddr_in *)to)->sin_addr.s_addr = inet_addr("224.0.0.251");
914
0
  ((struct sockaddr_in *)to)->sin_port        = htons(5353);
915
0
}
916
917
mdns_daemon_t *mdnsd_new(int clazz, int frame)
918
668
{
919
668
  mdns_daemon_t *d;
920
921
668
  d = calloc(1, sizeof(struct mdns_daemon));
922
668
  if (!d)
923
0
    return NULL;
924
925
668
  gettimeofday(&d->now, 0);
926
668
  d->expireall = (unsigned long)d->now.tv_sec + GC;
927
668
  d->clazz = clazz;
928
668
  d->frame = frame;
929
668
  d->family = AF_INET;
930
668
  d->received_callback = NULL;
931
668
  d->local_ifaddrs = NULL;
932
668
  d->local_addrs_refreshed = 0;
933
934
668
  return d;
935
668
}
936
937
void mdnsd_set_family(mdns_daemon_t *d, sa_family_t family)
938
0
{
939
0
  d->family = family;
940
0
}
941
942
void mdnsd_set_address(mdns_daemon_t *d, struct in_addr addr)
943
0
{
944
0
  int i;
945
946
0
  if (!memcmp(&d->addr, &addr, sizeof(d->addr)))
947
0
    return;   /* No change */
948
949
0
  for (i = 0; i < SPRIME; i++) {
950
0
    mdns_record_t *r, *next;
951
952
0
    r = d->published[i];
953
0
    while (r) {
954
0
      next = r->next;
955
956
0
      if (r->rr.type == QTYPE_A) {
957
0
        if (addr.s_addr == 0) {
958
0
          r->rr.ttl = 0;
959
0
          r->list = d->a_now;
960
0
          d->a_now = r;
961
0
        } else {
962
0
          mdnsd_set_ip(d, r, addr);
963
0
        }
964
0
      }
965
966
0
      r = next;
967
0
    }
968
0
  }
969
970
0
  d->addr = addr;
971
0
}
972
973
struct in_addr mdnsd_get_address(mdns_daemon_t *d)
974
0
{
975
0
  return d->addr;
976
0
}
977
978
void mdnsd_set_ipv6_address(mdns_daemon_t *d, struct in6_addr addr)
979
0
{
980
0
  int i;
981
982
0
  if (!memcmp(&d->addr_v6, &addr, sizeof(d->addr_v6)))
983
0
    return;   /* No change */
984
985
0
  for (i = 0; i < SPRIME; i++) {
986
0
    mdns_record_t *r, *next;
987
988
0
    r = d->published[i];
989
0
    while (r) {
990
0
      next = r->next;
991
992
0
      if (r->rr.type == QTYPE_AAAA) {
993
0
        if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
994
0
          r->rr.ttl = 0;
995
0
          r->list = d->a_now;
996
0
          d->a_now = r;
997
0
        } else {
998
0
          mdnsd_set_ipv6(d, r, addr);
999
0
        }
1000
0
      }
1001
1002
0
      r = next;
1003
0
    }
1004
0
  }
1005
1006
0
  d->addr_v6 = addr;
1007
0
}
1008
1009
struct in6_addr mdnsd_get_ipv6_address(mdns_daemon_t *d)
1010
0
{
1011
0
  return d->addr_v6;
1012
0
}
1013
1014
/* Shutting down, zero out ttl and push out all records */
1015
void mdnsd_shutdown(mdns_daemon_t *d)
1016
279
{
1017
279
  int i;
1018
279
  mdns_record_t *cur, *next;
1019
1020
279
  if (!d)
1021
0
    return;
1022
1023
279
  d->a_now = 0;
1024
30.6k
  for (i = 0; i < SPRIME; i++) {
1025
31.5k
    for (cur = d->published[i]; cur != 0;) {
1026
1.11k
      next = cur->next;
1027
1.11k
      cur->rr.ttl = 0;
1028
1.11k
      cur->list = d->a_now;
1029
1.11k
      d->a_now = cur;
1030
1.11k
      cur = next;
1031
1.11k
    }
1032
30.4k
  }
1033
1034
279
  d->shutdown = 1;
1035
279
}
1036
1037
void mdnsd_flush(mdns_daemon_t *d)
1038
0
{
1039
0
  (void)d;
1040
  /* - Set all querys to 0 tries
1041
   * - Free whole cache
1042
   * - Set all mdns_record_t *to probing
1043
   * - Reset all answer lists
1044
   */
1045
0
}
1046
1047
void mdnsd_free(mdns_daemon_t *d)
1048
668
{
1049
668
  struct unicast *u;
1050
1051
668
  if (!d)
1052
0
    return;
1053
1054
674k
  for (size_t i = 0; i< LPRIME; i++) {
1055
674k
    struct cached *cur = d->cache[i];
1056
1057
674k
    while (cur) {
1058
0
      struct cached *next = cur->next;
1059
1060
0
      cur->next = NULL;
1061
0
      _free_cached(cur);
1062
0
      cur = next;
1063
0
    }
1064
674k
  }
1065
1066
73.4k
  for (size_t i = 0; i< SPRIME; i++) {
1067
72.8k
    struct mdns_record *cur = d->published[i];
1068
72.8k
    struct query *curq;
1069
1070
73.9k
    while (cur) {
1071
1.11k
      struct mdns_record *next = cur->next;
1072
1073
1.11k
      cur->next = NULL;
1074
1.11k
      _free_record(cur);
1075
1.11k
      cur = next;
1076
1.11k
    }
1077
1078
72.8k
    curq = d->queries[i];
1079
73.0k
    while (curq) {
1080
279
      struct query *next = curq->next;
1081
1082
279
      curq->next = NULL;
1083
279
      free(curq->name);
1084
279
      free(curq);
1085
279
      curq = next;
1086
279
    }
1087
72.8k
  }
1088
1089
668
  u = d->uanswers;
1090
668
  while (u) {
1091
0
    struct unicast *next = u->next;
1092
1093
0
    u->next = NULL;
1094
0
    free(u);
1095
0
    u = next;
1096
0
  }
1097
1098
668
  if (d->local_ifaddrs)
1099
0
    freeifaddrs(d->local_ifaddrs);
1100
1101
668
  free(d);
1102
668
}
1103
1104
1105
void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_callback cb, void* data)
1106
279
{
1107
279
  d->received_callback = cb;
1108
279
  d->received_callback_data = data;
1109
279
}
1110
1111
int mdnsd_in(mdns_daemon_t *d, struct message *m, const inet_addr_t *from)
1112
389
{
1113
389
  mdns_record_t *r = NULL;
1114
389
  int i, j;
1115
389
  bool did_addr_refresh = false;
1116
1117
389
  if (d->shutdown)
1118
0
    return 1;
1119
1120
389
  gettimeofday(&d->now, 0);
1121
1122
  /* Ignore packets originated from any of our own local addresses */
1123
389
  if (_is_local(d, from))
1124
389
    return 0;
1125
1126
0
  if (m->header.qr == 0) {
1127
    /* Process each query */
1128
0
    for (i = 0; i < m->qdcount; i++) {
1129
0
      mdns_record_t *r_start, *r_next;
1130
0
      bool has_conflict = false;
1131
1132
0
      if (!m->qd || m->qd[i].clazz != d->clazz)
1133
0
        continue;
1134
1135
0
      INFO("Query for %s of type %d ...", m->qd[i].name, m->qd[i].type);
1136
0
      r = _r_next(d, NULL, m->qd[i].name, m->qd[i].type);
1137
0
      if (!r)
1138
0
        continue;
1139
1140
      /* Service enumeration/discovery prepare to send all matching records */
1141
0
      if (!strcmp(m->qd[i].name, DISCO_NAME)) {
1142
0
        d->disco = 1;
1143
0
        while (r) {
1144
0
          if (!strcmp(r->rr.name, DISCO_NAME))
1145
0
            _r_send(d, r);
1146
0
          r = _r_next(d, r, m->qd[i].name, m->qd[i].type);
1147
0
        }
1148
1149
0
        continue;
1150
0
      }
1151
1152
      /* Check all of our potential answers */
1153
0
      for (r_start = r; r != NULL; r = r_next) {
1154
0
        INFO("Local record: %s, type: %d, rdname: %s", r->rr.name, r->rr.type, r->rr.rdname);
1155
1156
        /* Fetch next here, because _conflict() might delete r, invalidating next */
1157
0
        r_next = _r_next(d, r, m->qd[i].name, m->qd[i].type);
1158
1159
        /* probing state, check for conflicts */
1160
0
        if (r->unique && r->unique < 5 && !r->modified) {
1161
          /* Check all to-be answers against our own */
1162
0
          for (j = 0; j < m->ancount; j++) {
1163
0
            if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
1164
0
              continue;
1165
1166
            /* This answer isn't ours, conflict! */
1167
0
            if (!_a_match(&m->an[j], &r->rr)) {
1168
              /* Before flagging conflict, force a local address refresh and re-check */
1169
0
              if (!did_addr_refresh) {
1170
0
                did_addr_refresh = true;
1171
0
                _refresh_local_addrs(d, true);
1172
0
              }
1173
0
              if (_is_local(d, from))
1174
0
                continue;
1175
0
              _conflict(d, r);
1176
0
              has_conflict = true;
1177
0
              break;
1178
0
            }
1179
0
          }
1180
0
          continue;
1181
0
        }
1182
1183
        /* Check the known answers for this question */
1184
0
        for (j = 0; j < m->ancount; j++) {
1185
0
          if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
1186
0
            continue;
1187
1188
0
          if (d->received_callback)
1189
0
            d->received_callback(&m->an[j], d->received_callback_data);
1190
1191
          /* Do they already have this answer? */
1192
0
          if (_a_match(&m->an[j], &r->rr))
1193
0
            break;
1194
0
        }
1195
1196
0
        INFO("Should we send answer? j: %d, m->ancount: %d", j, m->ancount);
1197
0
        if (j == m->ancount) {
1198
0
          INFO("Yes we should, enquing %s for outbound", r->rr.name);
1199
0
          _r_send(d, r);
1200
0
        }
1201
0
      }
1202
1203
      /* Send the matching unicast reply */
1204
0
      if (!has_conflict && inet_port(from) != 5353)
1205
0
        _u_push(d, r_start, m->id, from);
1206
0
    }
1207
1208
0
    return 0;
1209
0
  }
1210
1211
  /* Process each answer, check for a conflict, and cache */
1212
0
  for (i = 0; i < m->ancount; i++) {
1213
0
    if (!m->an)
1214
0
      continue;
1215
1216
0
    if (!m->an[i].name) {
1217
0
      ERR("Got answer with NULL name at %p. Type: %d, TTL: %ld, skipping",
1218
0
          (void*)&m->an[i], m->an[i].type, m->an[i].ttl);
1219
0
      continue;
1220
0
    }
1221
1222
0
    INFO("Got Answer: Name: %s, Type: %d", m->an[i].name, m->an[i].type);
1223
0
    r = _r_next(d, NULL, m->an[i].name, m->an[i].type);
1224
0
    if (r && r->unique && r->modified && _a_match(&m->an[i], &r->rr)) {
1225
      /* double check, is this actually from us, looped back? */
1226
0
      if (!did_addr_refresh) {
1227
0
        did_addr_refresh = true;
1228
0
        _refresh_local_addrs(d, true);
1229
0
      }
1230
0
      if (_is_local(d, from))
1231
0
        continue;
1232
0
      _conflict(d, r);
1233
0
    }
1234
1235
0
    if (d->received_callback)
1236
0
      d->received_callback(&m->an[i], d->received_callback_data);
1237
1238
0
    if (_cache(d, &m->an[i], from) != 0) {
1239
0
      ERR("Failed caching answer, possibly too long packet, skipping.");
1240
0
      continue;
1241
0
    }
1242
0
  }
1243
1244
0
  return 0;
1245
0
}
1246
1247
int mdnsd_out(mdns_daemon_t *d, struct message *m, inet_addr_t *to)
1248
0
{
1249
0
  mdns_record_t *r;
1250
0
  struct answered seen = { 0 };
1251
0
  int ret = 0;
1252
1253
0
  gettimeofday(&d->now, 0);
1254
0
  memset(m, 0, sizeof(struct message));
1255
1256
  /* Defaults, multicast */
1257
0
  mdns_mcast(to, d->family);
1258
0
  m->header.qr = 1;
1259
0
  m->header.aa = 1;
1260
1261
  /* Send out individual unicast answers */
1262
0
  if (d->uanswers) {
1263
0
    struct unicast *u = d->uanswers;
1264
1265
0
    INFO("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type);
1266
1267
0
    d->uanswers = u->next;
1268
0
    *to = u->to;
1269
0
    m->id = u->id;
1270
0
    message_qd(m, u->r->rr.name, u->r->rr.type, d->clazz);
1271
0
    message_an(m, u->r->rr.name, u->r->rr.type, d->clazz, u->r->rr.ttl);
1272
0
    u->r->last_sent = d->now;
1273
0
    _a_copy(m, &u->r->rr);
1274
1275
    /* RFC 6763 §12 additional records for the unicast answer */
1276
0
    _answered_add(&seen, u->r);
1277
0
    _additional(d, m, u->r, &seen);
1278
0
    free(u);
1279
1280
0
    return 1;
1281
0
  }
1282
1283
  /* Accumulate any immediate responses */
1284
0
  if (d->a_now)
1285
0
    ret += _r_out(d, m, &d->a_now, &seen);
1286
1287
  /* Check if it's time to send the publish retries (unlink if done) */
1288
0
  if (!d->probing && d->a_publish && _tvdiff(d->now, d->publish) <= 0) {
1289
0
    mdns_record_t *cur = d->a_publish;
1290
0
    mdns_record_t *last = NULL;
1291
0
    mdns_record_t *next;
1292
1293
0
    while (cur && message_packet_len(m) + (int)_rr_len(&cur->rr) < d->frame) {
1294
0
      if (cur->rr.type == QTYPE_PTR) {
1295
0
        INFO("Send Publish PTR: Name: %s, rdlen: %d, rdata: %s, rdname: %s", cur->rr.name,cur->rr.rdlen, cur->rr.rdata, cur->rr.rdname);
1296
0
      } else if (cur->rr.type == QTYPE_SRV) {
1297
0
        INFO("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);
1298
0
      } else {
1299
0
        INFO("Send Publish: Name: %s, Type: %d, rdname: %s", cur->rr.name, cur->rr.type, cur->rr.rdname);
1300
0
      }
1301
1302
0
      next = cur->list;
1303
0
      ret++;
1304
0
      cur->tries++;
1305
1306
0
      if (cur->unique)
1307
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz + 32768, cur->rr.ttl);
1308
0
      else
1309
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz, cur->rr.ttl);
1310
0
      _a_copy(m, &cur->rr);
1311
0
      cur->last_sent = d->now;
1312
0
      if (cur->rr.ttl != 0)
1313
0
        _answered_add(&seen, cur);
1314
1315
0
      if (cur->rr.ttl != 0 && cur->tries < 4) {
1316
0
        last = cur;
1317
0
        cur = next;
1318
0
        continue;
1319
0
      }
1320
1321
0
      cur->list = NULL;
1322
0
      if (d->a_publish == cur)
1323
0
        d->a_publish = next;
1324
0
      if (last)
1325
0
        last->list = next;
1326
0
      if (cur->rr.ttl == 0)
1327
0
        _r_done(d, cur);
1328
0
      cur = next;
1329
0
    }
1330
1331
0
    if (d->a_publish) {
1332
0
      d->publish.tv_sec = d->now.tv_sec + 2;
1333
0
      d->publish.tv_usec = d->now.tv_usec;
1334
0
    }
1335
0
  }
1336
1337
  /* If we're in shutdown, we're done */
1338
0
  if (d->shutdown)
1339
0
    return ret;
1340
1341
  /* Check if a_pause is ready */
1342
0
  if (d->a_pause && _tvdiff(d->now, d->pause) <= 0)
1343
0
    ret += _r_out(d, m, &d->a_pause, &seen);
1344
1345
  /* RFC 6763 §12: expand the answers, not the additionals _ar() appends */
1346
0
  for (int i = 0, n = seen.n; i < n; i++)
1347
0
    _additional(d, m, seen.rec[i], &seen);
1348
1349
  /* Now process questions */
1350
0
  if (ret)
1351
0
    return ret;
1352
1353
0
  m->header.qr = 0;
1354
0
  m->header.aa = 0;
1355
1356
0
  if (d->probing && _tvdiff(d->now, d->probe) <= 0) {
1357
0
    mdns_record_t *last = 0;
1358
1359
    /* Scan probe list to ask questions and process published */
1360
0
    for (r = d->probing; r != NULL;) {
1361
      /* Done probing, publish */
1362
0
      if (r->unique == 4) {
1363
0
        mdns_record_t *next = r->list;
1364
1365
0
        if (d->probing == r)
1366
0
          d->probing = r->list;
1367
0
        else if (last)
1368
0
          last->list = r->list;
1369
1370
0
        r->list = 0;
1371
0
        r->unique = 5;
1372
0
        _r_publish(d, r);
1373
0
        r = next;
1374
0
        continue;
1375
0
      }
1376
1377
0
      INFO("Send Probing: Name: %s, Type: %d", r->rr.name, r->rr.type);
1378
1379
0
      message_qd(m, r->rr.name, r->rr.type, (unsigned short)d->clazz);
1380
0
      r->last_sent = d->now;
1381
0
      last = r;
1382
0
      r = r->list;
1383
0
    }
1384
1385
    /* Scan probe list again to append our to-be answers */
1386
0
    for (r = d->probing; r != 0; r = r->list) {
1387
0
      r->unique++;
1388
1389
0
      INFO("Send Answer in Probe: Name: %s, Type: %d", r->rr.name, r->rr.type);
1390
0
      message_ns(m, r->rr.name, r->rr.type, (unsigned short)d->clazz, r->rr.ttl);
1391
0
      _a_copy(m, &r->rr);
1392
0
      r->last_sent = d->now;
1393
0
      ret++;
1394
0
    }
1395
1396
    /* Process probes again in the future */
1397
0
    if (ret) {
1398
0
      d->probe.tv_sec = d->now.tv_sec;
1399
0
      d->probe.tv_usec = d->now.tv_usec + 250000;
1400
0
      return ret;
1401
0
    }
1402
0
  }
1403
1404
  /* Process qlist for retries or expirations */
1405
0
  if (d->checkqlist && (unsigned long)d->now.tv_sec >= d->checkqlist) {
1406
0
    struct query *q;
1407
0
    struct cached *c;
1408
0
    unsigned long int nextbest = 0;
1409
1410
    /* Ask questions first, track nextbest time */
1411
0
    for (q = d->qlist; q != 0; q = q->list) {
1412
0
      if (q->nexttry > 0 && q->nexttry <= (unsigned long)d->now.tv_sec && q->tries < 3)
1413
0
        message_qd(m, q->name, q->type, d->clazz);
1414
0
      else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
1415
0
        nextbest = q->nexttry;
1416
0
    }
1417
1418
    /* Include known answers, update questions */
1419
0
    for (q = d->qlist; q != 0; q = q->list) {
1420
0
      if (q->nexttry == 0 || q->nexttry > (unsigned long)d->now.tv_sec)
1421
0
        continue;
1422
1423
      /* Done retrying, expire and reset */
1424
0
      if (q->tries == 3) {
1425
0
        _c_expire(d, &d->cache[_namehash(q->name) % LPRIME]);
1426
0
        _q_reset(d, q);
1427
0
        continue;
1428
0
      }
1429
1430
0
      ret++;
1431
0
      q->nexttry = d->now.tv_sec + ++q->tries;
1432
0
      if (nextbest == 0 || q->nexttry < nextbest)
1433
0
        nextbest = q->nexttry;
1434
1435
      /* If room, add all known good entries */
1436
0
      c = 0;
1437
0
      while ((c = _c_next(d, c, q->name, q->type)) != 0 && c->rr.ttl > (unsigned long)d->now.tv_sec + 8 &&
1438
0
        message_packet_len(m) + (int)_rr_len(&c->rr) < d->frame) {
1439
1440
0
        INFO("Add known answer: Name: %s, Type: %d", c->rr.name, c->rr.type);
1441
0
        message_an(m, q->name, (unsigned short)q->type, (unsigned short)d->clazz, c->rr.ttl - (unsigned long)d->now.tv_sec);
1442
0
        _a_copy(m, &c->rr);
1443
0
      }
1444
0
    }
1445
0
    d->checkqlist = nextbest;
1446
0
  }
1447
1448
0
  if ((unsigned long)d->now.tv_sec > d->expireall)
1449
0
    _gc(d);
1450
1451
0
  return ret;
1452
0
}
1453
1454
1455
0
#define RET do {       \
1456
0
  while (d->sleep.tv_usec > 1000000) { \
1457
0
    d->sleep.tv_sec++;    \
1458
0
    d->sleep.tv_usec -= 1000000;  \
1459
0
  }          \
1460
0
  return &d->sleep;     \
1461
0
} while (0)
1462
1463
struct timeval *mdnsd_sleep(mdns_daemon_t *d)
1464
0
{
1465
0
  time_t expire;
1466
0
  long usec;
1467
1468
0
  d->sleep.tv_sec = d->sleep.tv_usec = 0;
1469
1470
  /* First check for any immediate items to handle */
1471
0
  if (d->uanswers || d->a_now)
1472
0
    return &d->sleep;
1473
1474
0
  gettimeofday(&d->now, 0);
1475
1476
  /* Then check for paused answers or nearly expired records */
1477
0
  if (d->a_pause) {
1478
0
    if ((usec = _tvdiff(d->now, d->pause)) > 0)
1479
0
      d->sleep.tv_usec = usec;
1480
0
    RET;
1481
0
  }
1482
1483
  /* Now check for probe retries */
1484
0
  if (d->probing) {
1485
0
    if ((usec = _tvdiff(d->now, d->probe)) > 0)
1486
0
      d->sleep.tv_usec = usec;
1487
0
    RET;
1488
0
  }
1489
1490
  /* Now check for publish retries */
1491
0
  if (d->a_publish) {
1492
0
    if ((usec = _tvdiff(d->now, d->publish)) > 0)
1493
0
      d->sleep.tv_usec = usec;
1494
0
    RET;
1495
0
  }
1496
1497
  /* Also check for queries with known answer expiration/retry */
1498
0
  if (d->checkqlist) {
1499
0
    long sec;
1500
0
    if ((sec = (long)d->checkqlist - d->now.tv_sec) > 0)
1501
0
      d->sleep.tv_sec = sec;
1502
0
    RET;
1503
0
  }
1504
1505
  /* Resend published records before TTL expires */
1506
0
  expire = (long)d->expireall - d->now.tv_sec;
1507
0
  if (expire < 0)
1508
0
    RET;
1509
1510
0
  for (size_t i = 0; i < SPRIME; i++) {
1511
0
    mdns_record_t *r;
1512
0
    time_t next;
1513
1514
0
    r = d->published[i];
1515
0
    if (!r)
1516
0
      continue;
1517
1518
    /* Publish 2 seconds before expiration */
1519
0
    next = r->last_sent.tv_sec + (long)r->rr.ttl - d->now.tv_sec;
1520
0
    if (next <= 2) {
1521
0
      INFO("Republish %s before TTL expires ...", r->rr.name);
1522
0
      _r_push(&d->a_pause, r);
1523
0
    }
1524
1525
0
    if (next < expire)
1526
0
      expire = next;
1527
0
  }
1528
1529
0
  d->sleep.tv_sec = expire > 2 ? expire - 2 : 0;
1530
0
  d->pause.tv_sec = d->now.tv_sec + d->sleep.tv_sec;
1531
1532
0
  RET;
1533
0
}
1534
1535
void mdnsd_query(mdns_daemon_t *d, const char *host, int type, int (*answer)(mdns_answer_t *a, void *arg), void *arg)
1536
279
{
1537
279
  struct query *q;
1538
279
  struct cached *cur = 0;
1539
279
  int i = _namehash(host) % SPRIME;
1540
1541
279
  if (!(q = _q_next(d, 0, host, type))) {
1542
279
    if (!answer)
1543
0
      return;
1544
1545
279
    q = calloc(1, sizeof(struct query));
1546
279
    if (!q)
1547
0
      return;
1548
279
    q->name = strdup(host);
1549
279
    if (!q->name) {
1550
0
      free(q);
1551
0
      return;
1552
0
    }
1553
279
    q->type = type;
1554
279
    q->next = d->queries[i];
1555
279
    q->list = d->qlist;
1556
279
    d->qlist = d->queries[i] = q;
1557
1558
    /* Any cached entries should be associated */
1559
279
    while ((cur = _c_next(d, cur, q->name, q->type)))
1560
0
      cur->q = q;
1561
279
    _q_reset(d, q);
1562
1563
    /* New question, immediately send out */
1564
279
    q->nexttry = d->checkqlist = d->now.tv_sec;
1565
279
  }
1566
1567
  /* No answer means we don't care anymore */
1568
279
  if (!answer) {
1569
0
    _q_done(d, q);
1570
0
    return;
1571
0
  }
1572
1573
279
  q->answer = answer;
1574
279
  q->arg = arg;
1575
279
}
1576
1577
mdns_answer_t *mdnsd_list(mdns_daemon_t *d,const char *host, int type, mdns_answer_t *last)
1578
0
{
1579
0
  return (mdns_answer_t *)_c_next(d, (struct cached *)last, host, type);
1580
0
}
1581
1582
mdns_record_t *mdnsd_record_next(const mdns_record_t* r)
1583
837
{
1584
837
  return r ? r->next : NULL;
1585
837
}
1586
1587
const mdns_answer_t *mdnsd_record_data(const mdns_record_t* r)
1588
1.11k
{
1589
1.11k
  return &r->rr;
1590
1.11k
}
1591
1592
mdns_record_t *mdnsd_shared(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl)
1593
1.67k
{
1594
1.67k
  int i = _namehash(host) % SPRIME;
1595
1.67k
  mdns_record_t *r;
1596
1597
1.67k
  r = calloc(1, sizeof(struct mdns_record));
1598
1.67k
  if (!r)
1599
0
    return NULL;
1600
1601
1.67k
  r->rr.name = strdup(host);
1602
1.67k
  if (!r->rr.name) {
1603
0
    free(r);
1604
0
    return NULL;
1605
0
  }
1606
1607
1.67k
  r->rr.type = type;
1608
1.67k
  r->rr.ttl = ttl;
1609
1.67k
  r->next = d->published[i];
1610
1.67k
  d->published[i] = r;
1611
1612
1.67k
  return r;
1613
1.67k
}
1614
1615
mdns_record_t *mdnsd_unique(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl,
1616
          void (*conflict)(char *host, int type, void *arg), void *arg)
1617
558
{
1618
558
  mdns_record_t *r;
1619
1620
558
  r = mdnsd_shared(d, host, type, ttl);
1621
558
  if (!r)
1622
0
    return NULL;
1623
1624
558
  r->conflict = conflict;
1625
558
  r->arg = arg;
1626
558
  r->unique = 1;
1627
1628
  /* check if r already in other lists. If yes, remove it from there */
1629
558
  _r_remove_lists(d, r, &d->probing);
1630
558
  _r_push(&d->probing, r);
1631
1632
558
  d->probe.tv_sec = d->now.tv_sec;
1633
558
  d->probe.tv_usec = d->now.tv_usec;
1634
1635
558
  return r;
1636
558
}
1637
1638
mdns_record_t *mdnsd_get_published(mdns_daemon_t *d, const char *host)
1639
1.11k
{
1640
1.11k
  return d->published[_namehash(host) % SPRIME];
1641
1.11k
}
1642
1643
int mdnsd_has_query(mdns_daemon_t *d, const char *host)
1644
0
{
1645
0
  return d->queries[_namehash(host) % SPRIME] != NULL;
1646
0
}
1647
1648
mdns_record_t *mdnsd_find(mdns_daemon_t *d, const char *name, unsigned short type)
1649
0
{
1650
0
  mdns_record_t *r;
1651
1652
0
  r = mdnsd_get_published(d, name);
1653
0
  while (r) {
1654
0
    const mdns_answer_t *data;
1655
1656
    /*
1657
     * Search for a record with the same type and name.
1658
     * Records with different names might be in the same
1659
     * linked list when the hash functions % SPRIME assigns
1660
     * them the same index (hash collision)
1661
     */
1662
0
    data = mdnsd_record_data(r);
1663
0
    if (data->type == type && strcmp(data->name, name) == 0)
1664
0
      return r;
1665
1666
0
    r = mdnsd_record_next(r);
1667
0
  }
1668
1669
0
  return NULL;
1670
0
}
1671
1672
void mdnsd_done(mdns_daemon_t *d, mdns_record_t *r)
1673
1.11k
{
1674
1.11k
  mdns_record_t *cur;
1675
1676
1.11k
  if (r->unique && r->unique < 5) {
1677
    /* Probing yet, zap from that list first! */
1678
558
    if (d->probing == r) {
1679
558
      d->probing = r->list;
1680
558
    } else {
1681
0
      for (cur = d->probing; cur->list != r; cur = cur->list)
1682
0
        ;
1683
0
      cur->list = r->list;
1684
0
    }
1685
1686
558
    _r_done(d, r);
1687
558
    return;
1688
558
  }
1689
1690
558
  r->rr.ttl = 0;
1691
558
  _r_send(d, r);
1692
558
}
1693
1694
void mdnsd_set_raw(mdns_daemon_t *d, mdns_record_t *r, const char *data, unsigned short len)
1695
837
{
1696
837
  if (r->rr.rdata)
1697
0
    free(r->rr.rdata);
1698
1699
837
  r->rr.rdata = malloc(len);
1700
837
  if (r->rr.rdata) {
1701
837
    memcpy(r->rr.rdata, data, len);
1702
837
    r->rr.rdlen = len;
1703
837
  }
1704
837
  _r_publish(d, r);
1705
837
}
1706
1707
void mdnsd_set_host(mdns_daemon_t *d, mdns_record_t *r, const char *name)
1708
837
{
1709
837
  if (!r)
1710
0
    return;
1711
1712
837
  if (r->rr.rdname)
1713
0
    free(r->rr.rdname);
1714
837
  r->rr.rdname = strdup(name);
1715
837
  _r_publish(d, r);
1716
837
}
1717
1718
void mdnsd_set_ip(mdns_daemon_t *d, mdns_record_t *r, struct in_addr ip)
1719
0
{
1720
0
  r->rr.ip = ip;
1721
0
  _r_publish(d, r);
1722
0
}
1723
1724
void mdnsd_set_ipv6(mdns_daemon_t *d, mdns_record_t *r, struct in6_addr ip6)
1725
0
{
1726
0
  r->rr.ip6 = ip6;
1727
0
  _r_publish(d, r);
1728
0
}
1729
1730
void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short priority, unsigned short weight, unsigned short port, char *name)
1731
279
{
1732
279
  r->rr.srv.priority = priority;
1733
279
  r->rr.srv.weight = weight;
1734
279
  r->rr.srv.port = port;
1735
279
  mdnsd_set_host(d, r, name);
1736
279
}
1737
1738
/* Internal helper: update set of addresses for given host & type (A/AAAA) */
1739
static int _update_addresses_for_host(mdns_daemon_t *d, const char *host, unsigned short type, const void *addrs, size_t count)
1740
0
{
1741
0
  mdns_record_t *r;
1742
0
  mdns_record_t *cur;
1743
0
  unsigned long ttl = 120; /* default TTL if none exists */
1744
0
  char buf6[INET6_ADDRSTRLEN];
1745
1746
0
  if (!d || !host)
1747
0
    return -1;
1748
1749
  /* Determine TTL from any existing record of this type */
1750
0
  r = mdnsd_find(d, host, type);
1751
0
  if (r) {
1752
0
    const mdns_answer_t *data = mdnsd_record_data(r);
1753
0
    if (data && data->ttl)
1754
0
      ttl = data->ttl;
1755
0
  }
1756
1757
  /* For each desired address, check if there's a matching existing record */
1758
0
  for (size_t i = 0; i < count; i++) {
1759
0
    bool found = false;
1760
0
    cur = mdnsd_get_published(d, host);
1761
0
    while (cur) {
1762
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1763
0
      if (data->type == type && strcmp(data->name, host) == 0) {
1764
0
        if (type == QTYPE_A) {
1765
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1766
0
          if (data->ip.s_addr == a[i].s_addr) {
1767
0
            found = true;
1768
0
            INFO("Found A record for %s addr %s", host, inet_ntoa(a[i]));
1769
0
            break;
1770
0
          }
1771
0
        } else if (type == QTYPE_AAAA) {
1772
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1773
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) {
1774
0
            found = true;
1775
0
            INFO("Found AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1776
0
            break;
1777
0
          }
1778
0
        }
1779
0
      }
1780
0
      cur = mdnsd_record_next(cur);
1781
0
    }
1782
0
    if (!found) {
1783
      /* Create new_ record for this address */
1784
0
      mdns_record_t *nr = mdnsd_shared(d, host, type, ttl);
1785
0
      if (!nr)
1786
0
        continue;
1787
0
      if (type == QTYPE_A) {
1788
0
        const struct in_addr *a = (const struct in_addr *)addrs;
1789
0
        mdnsd_set_ip(d, nr, a[i]);
1790
0
        INFO("Created A record for %s addr %s", host, inet_ntoa(a[i]));
1791
0
      } else {
1792
0
        const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1793
0
        mdnsd_set_ipv6(d, nr, a6[i]);
1794
0
        INFO("Created AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1795
0
      }
1796
0
    }
1797
0
  }
1798
1799
  /* Remove stale records (present but not in desired set) */
1800
0
  cur = mdnsd_get_published(d, host);
1801
0
  while (cur) {
1802
0
    mdns_record_t *next = mdnsd_record_next(cur);
1803
0
    const mdns_answer_t *data = mdnsd_record_data(cur);
1804
0
    if (data->type == type && strcmp(data->name, host) == 0) {
1805
0
      bool still_present = false;
1806
0
      for (size_t i = 0; i < count; i++) {
1807
0
        if (type == QTYPE_A) {
1808
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1809
0
          if (data->ip.s_addr == a[i].s_addr) { still_present = true; break; }
1810
0
        } else {
1811
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1812
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) { still_present = true; break; }
1813
0
        }
1814
0
      }
1815
0
      if (!still_present)
1816
0
        mdnsd_done(d, cur);
1817
0
    }
1818
0
    cur = next;
1819
0
  }
1820
1821
0
  return 0;
1822
0
}
1823
1824
int mdnsd_set_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in_addr *addrs, size_t count)
1825
0
{
1826
0
  return _update_addresses_for_host(d, host, QTYPE_A, addrs, count);
1827
0
}
1828
1829
int mdnsd_set_ipv6_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in6_addr *addrs, size_t count)
1830
0
{
1831
0
  return _update_addresses_for_host(d, host, QTYPE_AAAA, addrs, count);
1832
0
}
1833
1834
int mdnsd_set_interface_addresses(mdns_daemon_t *d, const char *ifname)
1835
0
{
1836
0
  struct ifaddrs *ifa = NULL;
1837
0
  struct ifaddrs *it;
1838
0
  struct in_addr *v4 = NULL; size_t v4c = 0;
1839
0
  struct in6_addr *v6 = NULL; size_t v6c = 0;
1840
0
  char buf[INET_ADDRSTRLEN];
1841
0
  char buf6[INET6_ADDRSTRLEN];
1842
1843
0
  if (getifaddrs(&ifa) != 0)
1844
0
    return -1;
1845
1846
  /* Collect all v4/v6 addresses for the interface */
1847
0
  for (it = ifa; it; it = it->ifa_next) {
1848
0
    if (!it->ifa_addr || !it->ifa_name || strcmp(it->ifa_name, ifname))
1849
0
      continue;
1850
0
    if (it->ifa_addr->sa_family == AF_INET) {
1851
0
      v4 = realloc(v4, (v4c + 1) * sizeof(*v4));
1852
0
      if (v4) {
1853
0
        struct sockaddr_in *sin = (struct sockaddr_in *)it->ifa_addr;
1854
0
        v4[v4c++] = sin->sin_addr;
1855
0
        if(inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)))
1856
0
            INFO("Adding address %s for interface %s", buf, ifname);
1857
0
      }
1858
0
    } else if (it->ifa_addr->sa_family == AF_INET6) {
1859
0
      v6 = realloc(v6, (v6c + 1) * sizeof(*v6));
1860
0
      if (v6) {
1861
0
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)it->ifa_addr;
1862
0
        v6[v6c++] = sin6->sin6_addr;
1863
0
        if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf6, sizeof(buf6)))
1864
0
            INFO("Adding address %s for interface %s", buf6, ifname);
1865
0
      }
1866
0
    }
1867
0
  }
1868
0
  freeifaddrs(ifa);
1869
1870
  /*
1871
   * Reconcile per host name, not per record pointer: the calls below
1872
   * free stale records, which would dangle a record iterator.  See #92.
1873
   */
1874
0
  char **hosts = NULL;
1875
0
  size_t hostc = 0;
1876
1877
0
  for (size_t idx = 0; idx < SPRIME; idx++) {
1878
0
    for (mdns_record_t *cur = d->published[idx]; cur; cur = mdnsd_record_next(cur)) {
1879
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1880
0
      bool seen = false;
1881
0
      char **tmp;
1882
1883
0
      if (data->type != QTYPE_A && data->type != QTYPE_AAAA)
1884
0
        continue;
1885
1886
0
      for (size_t i = 0; i < hostc; i++) {
1887
0
        if (!strcmp(hosts[i], data->name)) {
1888
0
          seen = true;
1889
0
          break;
1890
0
        }
1891
0
      }
1892
0
      if (seen)
1893
0
        continue;
1894
1895
0
      tmp = realloc(hosts, (hostc + 1) * sizeof(*hosts));
1896
0
      if (!tmp)
1897
0
        continue;
1898
0
      hosts = tmp;
1899
0
      hosts[hostc] = strdup(data->name);
1900
0
      if (hosts[hostc])
1901
0
        hostc++;
1902
0
    }
1903
0
  }
1904
1905
0
  for (size_t i = 0; i < hostc; i++) {
1906
0
    INFO("Updating addresses for host %s", hosts[i]);
1907
    /* A count of 0 is intentional: it withdraws that whole family. */
1908
0
    mdnsd_set_addresses_for_host(d, hosts[i], v4, v4c);
1909
0
    mdnsd_set_ipv6_addresses_for_host(d, hosts[i], v6, v6c);
1910
0
    free(hosts[i]);
1911
0
  }
1912
0
  free(hosts);
1913
1914
0
  free(v4);
1915
0
  free(v6);
1916
0
  return 0;
1917
0
}
1918
1919
static int process_in(mdns_daemon_t *d, int sd)
1920
0
{
1921
0
  static unsigned char buf[MAX_PACKET_LEN + 1];
1922
0
  inet_addr_t from;
1923
0
  socklen_t ssize = sizeof(from);
1924
0
  ssize_t bsize;
1925
1926
0
  memset(buf, 0, sizeof(buf));
1927
1928
0
  while ((bsize = recvfrom(sd, buf, MAX_PACKET_LEN, MSG_DONTWAIT, (struct sockaddr *)&from, &ssize)) > 0) {
1929
0
    struct message m = { 0 };
1930
0
    int rc;
1931
1932
0
    buf[MAX_PACKET_LEN] = 0;
1933
0
    mdnsd_log_hex("Got Data:", buf, bsize);
1934
1935
0
    rc = message_parse(&m, buf);
1936
0
    if (rc)
1937
0
      continue;
1938
0
    rc = mdnsd_in(d, &m, &from);
1939
0
    if (rc)
1940
0
      continue;
1941
0
  }
1942
1943
0
  if (bsize < 0 && errno != EAGAIN)
1944
0
    return 1;
1945
1946
0
  return 0;
1947
0
}
1948
1949
static int process_out(mdns_daemon_t *d, int sd)
1950
0
{
1951
0
  inet_addr_t to;
1952
0
  struct message m;
1953
1954
0
  while (mdnsd_out(d, &m, &to)) {
1955
0
    unsigned char *buf;
1956
0
    ssize_t len;
1957
1958
0
    len = message_packet_len(&m);
1959
0
    buf = message_packet(&m);
1960
0
    mdnsd_log_hex("Send Data:", buf, len);
1961
1962
0
    if (sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, inet_len(&to)) != len)
1963
0
      return 2;
1964
0
  }
1965
1966
0
  return 0;
1967
0
}
1968
1969
int mdnsd_step(mdns_daemon_t *d, int sd, bool in, bool out, struct timeval *tv)
1970
0
{
1971
0
  int rc = 0;
1972
1973
0
  if (in)
1974
0
    rc = process_in(d, sd);
1975
0
  if (!rc && out)
1976
0
    rc = process_out(d, sd);
1977
1978
0
  if (!rc && tv) {
1979
0
    struct timeval *delay;
1980
1981
0
    delay = mdnsd_sleep(d);
1982
0
    memcpy(tv, delay, sizeof(*tv));
1983
0
  }
1984
1985
  /* Service Enumeration/Discovery completed */
1986
0
  if (d && d->disco)
1987
0
    d->disco = 0;
1988
1989
0
  return rc;
1990
0
}
1991
1992
void records_clear(mdns_daemon_t *d)
1993
0
{
1994
0
  for (int i = 0; i < SPRIME; i++)
1995
0
  {
1996
0
    mdns_record_t *r = d->published[i];
1997
0
    while (r)
1998
0
    {
1999
0
      mdns_record_t *const next = r->next;
2000
0
      _r_remove_lists(d, r, NULL);
2001
0
      _u_remove(d, r);
2002
0
      _free_record(r);
2003
0
      r = next;
2004
0
    }
2005
    d->published[i] = NULL;
2006
0
  }
2007
0
}