Coverage Report

Created: 2026-08-14 07:31

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
270k
#define SPRIME 109    /* Size of query/publish hashes */
41
1.96M
#define LPRIME 1009    /* Size of cache hash */
42
43
1.91k
#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, local;
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
64.0k
{
120
64.0k
  const unsigned char *name = (const unsigned char *)s;
121
64.0k
  unsigned long h = 0, g;
122
123
279k
  while (*name) {   /* do some fancy bitwanking on the string */
124
215k
    h = (h << 4) + (unsigned long)(*name++);
125
215k
    if ((g = (h & 0xF0000000UL)) != 0)
126
151k
      h ^= (g >> 24);
127
215k
    h &= ~g;
128
215k
  }
129
130
64.0k
  return (int)h;
131
64.0k
}
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
6.86k
{
136
6.86k
  if (!q)
137
6.86k
    q = d->queries[_namehash(host) % SPRIME];
138
0
  else
139
0
    q = q->next;
140
141
6.86k
  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
6.86k
  return NULL;
147
6.86k
}
148
149
static struct cached *_c_next(mdns_daemon_t *d, struct cached *c,const char *host, int type)
150
34.1k
{
151
34.1k
  if (!c)
152
18.4k
    c = d->cache[_namehash(host) % LPRIME];
153
15.7k
  else
154
15.7k
    c = c->next;
155
156
69.5k
  for (; c != 0; c = c->next) {
157
56.7k
    if ((type == c->rr.type || type == QTYPE_ANY) && strcmp(c->rr.name, host) == 0)
158
21.3k
      return c;
159
56.7k
  }
160
161
12.8k
  return NULL;
162
34.1k
}
163
164
static mdns_record_t *_r_next(mdns_daemon_t *d, mdns_record_t *r, const char *host, int type)
165
18.3k
{
166
18.3k
  if (!r)
167
18.3k
    r = d->published[_namehash(host) % SPRIME];
168
0
  else
169
0
    r = r->next;
170
171
18.3k
  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
18.3k
  return NULL;
177
18.3k
}
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
20.5k
{
200
20.5k
  if (!a->name)
201
0
    return 0;
202
20.5k
  if (strcmp(r->name, a->name) || r->type != a->type)
203
612
    return 0;
204
205
19.9k
  switch (r->type) {
206
2.54k
    case QTYPE_SRV:
207
2.54k
      return r->known.srv.name && a->rdname && strcmp(r->known.srv.name, a->rdname) == 0
208
2.15k
        && a->srv.port == r->known.srv.port
209
678
        && a->srv.weight == r->known.srv.weight
210
239
        && a->srv.priority == r->known.srv.priority;
211
212
213
1.10k
    case QTYPE_PTR:
214
1.41k
    case QTYPE_NS:
215
3.94k
    case QTYPE_CNAME:
216
3.94k
      return r->known.ns.name && a->rdname &&
217
3.87k
        strcmp(r->known.ns.name, a->rdname) == 0;
218
219
3.02k
    case QTYPE_A:
220
3.02k
      return memcmp(&r->known.a.ip, &a->ip, 4) == 0;
221
222
2.81k
    case QTYPE_AAAA:
223
2.81k
      return memcmp(&r->known.aaaa.ip6, &a->ip6, 16) == 0;
224
225
7.64k
    default:
226
7.64k
      return r->rdlength == a->rdlen &&
227
3.13k
        (r->rdlength == 0 || memcmp(r->rdata, a->rdata, r->rdlength) == 0);
228
19.9k
  }
229
230
0
  return 0;
231
19.9k
}
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
6.62k
{
423
6.62k
  if (!c)
424
0
    return;
425
426
6.62k
  if (c->rr.name) {
427
6.62k
    free(c->rr.name);
428
6.62k
    c->rr.name = NULL;
429
6.62k
  }
430
6.62k
  if (c->rr.rdata) {
431
2.29k
    free(c->rr.rdata);
432
2.29k
    c->rr.rdata = NULL;
433
2.29k
  }
434
6.62k
  if (c->rr.rdname) {
435
1.82k
    free(c->rr.rdname);
436
1.82k
    c->rr.rdname = NULL;
437
1.82k
  }
438
6.62k
  free(c);
439
6.62k
}
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
1.13k
{
504
1.13k
  struct cached *cur  = *list;
505
1.13k
  struct cached *last = NULL;
506
1.13k
  struct cached *next;
507
508
6.13k
  while (cur) {
509
4.99k
    next = cur->next;
510
511
4.99k
    if ((unsigned long)d->now.tv_sec >= cur->rr.ttl) {
512
1.49k
      if (last)
513
433
        last->next = next;
514
515
      /* Update list pointer if the first one expired */
516
1.49k
      if (*list == cur)
517
1.06k
        *list = next;
518
519
1.49k
      if (cur->q)
520
0
        _q_answer(d, cur);
521
522
1.49k
      _free_cached(cur);
523
3.49k
    } else {
524
3.49k
      last = cur;
525
3.49k
    }
526
4.99k
    cur = next;
527
4.99k
  }
528
1.13k
}
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
9.12k
{
545
9.12k
  unsigned long int ttl;
546
9.12k
  struct cached *c = 0;
547
9.12k
  int i = _namehash(r->name) % LPRIME;
548
549
  /* Cache flush for unique entries */
550
9.12k
  if (r->clazz == 32768 + d->clazz) {
551
691
    while ((c = _c_next(d, c, r->name, r->type)))
552
467
      c->rr.ttl = 0;
553
224
    _c_expire(d, &d->cache[i]);
554
224
  }
555
556
  /* Process deletes */
557
9.12k
  if (r->ttl == 0) {
558
5.88k
    while ((c = _c_next(d, c, r->name, r->type))) {
559
2.77k
      if (_a_match(r, &c->rr)) {
560
437
        c->rr.ttl = 0;
561
437
        _c_expire(d, &d->cache[i]);
562
437
        c = NULL;
563
437
      }
564
2.77k
    }
565
566
3.10k
    return 0;
567
3.10k
  }
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
6.02k
  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
6.02k
  c = NULL;
581
11.5k
  while ((c = _c_next(d, c, r->name, r->type))) {
582
7.84k
    if (!_a_match(r, &c->rr))
583
5.53k
      continue;
584
2.30k
    c->rr.ttl = ttl;
585
2.30k
    return 0;
586
7.84k
  }
587
588
  /* New entry, cache it */
589
3.71k
  c = calloc(1, sizeof(struct cached));
590
3.71k
  if (!c)
591
0
    return 1;
592
593
3.71k
  c->rr.name = strdup(r->name);
594
3.71k
  if (!c->rr.name) {
595
0
    free(c);
596
0
    return 1;
597
0
  }
598
3.71k
  c->rr.type = r->type;
599
3.71k
  c->rr.ttl = ttl;
600
3.71k
  c->rr.rdlen = r->rdlength;
601
3.71k
  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
1
    free(c->rr.name);
604
1
    free(c);
605
1
    return 1;
606
1
  }
607
3.71k
  if (r->rdlength) {
608
1.56k
    c->rr.rdata = malloc(r->rdlength);
609
1.56k
    if (!c->rr.rdata) {
610
0
      free(c->rr.name);
611
0
      free(c);
612
0
      return 1;
613
0
    }
614
1.56k
    memcpy(c->rr.rdata, r->rdata, r->rdlength);
615
2.14k
  } else {
616
2.14k
    c->rr.rdata = NULL;
617
2.14k
  }
618
619
3.71k
  switch (r->type) {
620
724
  case QTYPE_A:
621
724
    c->rr.ip = r->known.a.ip;
622
724
    break;
623
624
143
  case QTYPE_AAAA:
625
143
    c->rr.ip6 = r->known.aaaa.ip6;
626
143
    break;
627
628
97
  case QTYPE_NS:
629
234
  case QTYPE_CNAME:
630
563
  case QTYPE_PTR:
631
563
    if (!r->known.ns.name) {
632
25
      free(c->rr.rdata);
633
25
      free(c->rr.name);
634
25
      free(c);
635
25
      return 1;
636
25
    }
637
538
    c->rr.rdname = strdup(r->known.ns.name);
638
    /* Stash the responder address for mquery's device view */
639
#ifdef ENABLE_IPV6
640
    if (inet_family(from) == AF_INET6)
641
      c->rr.ip6 = ((const struct sockaddr_in6 *)from)->sin6_addr;
642
    else
643
#endif
644
538
      c->rr.ip = ((const struct sockaddr_in *)from)->sin_addr;
645
538
    break;
646
647
259
  case QTYPE_SRV:
648
259
    if (!r->known.srv.name) {
649
15
      free(c->rr.rdata);
650
15
      free(c->rr.name);
651
15
      free(c);
652
15
      return 1;
653
15
    }
654
244
    c->rr.rdname = strdup(r->known.srv.name);
655
244
    c->rr.srv.port = r->known.srv.port;
656
244
    c->rr.srv.weight = r->known.srv.weight;
657
244
    c->rr.srv.priority = r->known.srv.priority;
658
244
    break;
659
3.71k
  }
660
661
3.67k
  c->next = d->cache[i];
662
3.67k
  d->cache[i] = c;
663
664
3.67k
  if ((c->q = _q_next(d, 0, r->name, r->type)))
665
0
    _q_answer(d, c);
666
667
3.67k
  return 0;
668
3.71k
}
669
670
/* Copy the data bits only */
671
static void _a_copy(struct message *m, mdns_answer_t *a)
672
0
{
673
  /*
674
   * Re-encode name rdata from rdname so compression is computed for
675
   * this packet.  The raw cached rdata holds pointers into the packet
676
   * it arrived in and cannot be replayed verbatim.  See issue #79.
677
   */
678
0
  if (a->type == QTYPE_SRV) {
679
0
    message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
680
0
    return;
681
0
  }
682
0
  if (a->rdname) {
683
0
    message_rdata_name(m, a->rdname);
684
0
    return;
685
0
  }
686
687
0
  if (a->rdata) {
688
0
    message_rdata_raw(m, a->rdata, a->rdlen);
689
0
    return;
690
0
  }
691
692
0
  if (a->ip.s_addr)
693
0
    message_rdata_ipv4(m, a->ip);
694
0
  else if (!IN6_IS_ADDR_UNSPECIFIED(&(a->ip6)))
695
0
    message_rdata_ipv6(m, a->ip6);
696
0
}
697
698
/*
699
 * RFC 6763 §12: when answering a PTR or SRV query, add the related SRV,
700
 * TXT and address records to the additional section so a client need not
701
 * query again.  See issue #76.  Records answered this round are tracked so
702
 * we never repeat one of them as an additional record.
703
 */
704
0
#define ADDITIONAL_MAX 64
705
struct answered {
706
  mdns_record_t *rec[ADDITIONAL_MAX];
707
  int n;
708
};
709
710
static void _answered_add(struct answered *a, mdns_record_t *r)
711
0
{
712
0
  if (a->n < ADDITIONAL_MAX)
713
0
    a->rec[a->n++] = r;
714
0
}
715
716
static int _answered(const struct answered *a, const mdns_record_t *r)
717
0
{
718
0
  int i;
719
720
0
  for (i = 0; i < a->n; i++) {
721
0
    if (a->rec[i] == r)
722
0
      return 1;
723
0
  }
724
725
0
  return 0;
726
0
}
727
728
/* Append one additional record, unless already in the packet or out of room */
729
static void _ar(mdns_daemon_t *d, struct message *m, mdns_record_t *r, struct answered *seen)
730
0
{
731
0
  if (_answered(seen, r))
732
0
    return;
733
0
  if (message_packet_len(m) + (int)_rr_len(&r->rr) >= d->frame)
734
0
    return;
735
736
0
  message_ar(m, r->rr.name, r->rr.type, d->clazz + (r->unique ? 32768 : 0), r->rr.ttl);
737
0
  _a_copy(m, &r->rr);
738
0
  _answered_add(seen, r);
739
0
}
740
741
/* Append the A/AAAA records for host to the additional section */
742
static void _ar_addr(mdns_daemon_t *d, struct message *m, char *host, struct answered *seen)
743
0
{
744
0
  mdns_record_t *r;
745
746
0
  if (!host)
747
0
    return;
748
749
0
  for (r = mdnsd_get_published(d, host); r; r = r->next) {
750
0
    if (strcmp(r->rr.name, host))
751
0
      continue;
752
0
    if (r->rr.type == QTYPE_A || r->rr.type == QTYPE_AAAA)
753
0
      _ar(d, m, r, seen);
754
0
  }
755
0
}
756
757
/* RFC 6763 §12 additional records for an answered PTR or SRV record */
758
static void _additional(mdns_daemon_t *d, struct message *m, mdns_record_t *ans, struct answered *seen)
759
0
{
760
0
  mdns_record_t *r;
761
762
0
  if (ans->rr.type == QTYPE_SRV) {
763
0
    _ar_addr(d, m, ans->rr.rdname, seen);
764
0
    return;
765
0
  }
766
767
0
  if (ans->rr.type != QTYPE_PTR || !ans->rr.rdname || !strcmp(ans->rr.name, DISCO_NAME))
768
0
    return;
769
770
0
  for (r = mdnsd_get_published(d, ans->rr.rdname); r; r = r->next) {
771
0
    if (strcmp(r->rr.name, ans->rr.rdname))
772
0
      continue;
773
774
0
    if (r->rr.type == QTYPE_SRV) {
775
0
      _ar(d, m, r, seen);
776
0
      _ar_addr(d, m, r->rr.rdname, seen);
777
0
    } else if (r->rr.type == QTYPE_TXT) {
778
0
      _ar(d, m, r, seen);
779
0
    }
780
0
  }
781
0
}
782
783
/* Copy a published record into an outgoing message */
784
static int _r_out(mdns_daemon_t *d, struct message *m, mdns_record_t **list, struct answered *seen)
785
0
{
786
0
  mdns_record_t *r;
787
0
  int ret = 0;
788
789
0
  while ((r = *list) != NULL && message_packet_len(m) + (int)_rr_len(&r->rr) < d->frame) {
790
0
    if (r != r->list)
791
0
      *list = r->list;
792
0
    else
793
0
      *list = NULL;
794
795
    /* Service enumeration/discovery, drop non-PTR replies */
796
0
    if (d->disco) {
797
0
      if (r->rr.type != QTYPE_PTR)
798
0
        continue;
799
800
0
      if (strcmp(r->rr.name, DISCO_NAME))
801
0
        continue;
802
0
    }
803
804
0
    INFO("Appending name: %s, type %d to outbound message ...", r->rr.name, r->rr.type);
805
0
    ret++;
806
807
0
    if (r->unique)
808
0
      message_an(m, r->rr.name, r->rr.type, d->clazz + 32768, r->rr.ttl);
809
0
    else
810
0
      message_an(m, r->rr.name, r->rr.type, d->clazz, r->rr.ttl);
811
0
    r->last_sent = d->now;
812
813
0
    _a_copy(m, &r->rr);
814
815
0
    r->modified = 0; /* If updated we've now sent the update. */
816
0
    if (r->rr.ttl == 0) {
817
      /*
818
       * also remove from other lists, because record
819
       * may be in multiple lists at the same time
820
       */
821
0
      _r_remove_lists(d, r, list);
822
0
      _r_done(d, r);
823
0
    } else {
824
0
      _answered_add(seen, r);
825
0
    }
826
0
  }
827
828
0
  return ret;
829
0
}
830
831
/* Refresh the cached local interface addresses if needed (every ~5s) */
832
static void _refresh_local_addrs(mdns_daemon_t *d, bool force)
833
0
{
834
0
  struct ifaddrs *ifa = NULL;
835
836
  /* Refresh at most every 5 seconds */
837
0
  if (d->local_addrs_refreshed && (d->now.tv_sec - d->local_addrs_refreshed) < LOCAL_ADDR_REFRESH_INTERVAL && !force)
838
0
    return;
839
840
0
  if (getifaddrs(&ifa) != 0)
841
0
    return;
842
843
  /* Swap in the latest snapshot */
844
0
  if (d->local_ifaddrs)
845
0
    freeifaddrs(d->local_ifaddrs);
846
0
  d->local_ifaddrs = ifa;
847
0
  d->local_addrs_refreshed = d->now.tv_sec ? d->now.tv_sec : time(NULL);
848
0
}
849
850
/* Check if an IPv4 address belongs to this host (any interface) */
851
static bool _is_local_ipv4(mdns_daemon_t *d, struct in_addr ip)
852
0
{
853
0
  struct ifaddrs *it;
854
855
  /* Always consider the primary configured address as local */
856
0
  if (ip.s_addr == d->addr.s_addr)
857
0
    return true;
858
859
0
  _refresh_local_addrs(d, false);
860
861
0
  for (it = d->local_ifaddrs; it; it = it->ifa_next) {
862
0
    struct sockaddr_in *sin;
863
0
    if (!it->ifa_addr)
864
0
      continue;
865
0
    if (it->ifa_addr->sa_family != AF_INET)
866
0
      continue;
867
0
    sin = (struct sockaddr_in *)it->ifa_addr;
868
0
    if (sin->sin_addr.s_addr == ip.s_addr)
869
0
      return true;
870
0
  }
871
872
0
  return false;
873
0
}
874
875
#ifdef ENABLE_IPV6
876
/* Check if an IPv6 address belongs to this host (any interface) */
877
static bool _is_local_ipv6(mdns_daemon_t *d, struct in6_addr ip)
878
{
879
  struct ifaddrs *it;
880
881
  if (IN6_ARE_ADDR_EQUAL(&ip, &d->addr_v6))
882
    return true;
883
884
  _refresh_local_addrs(d, false);
885
886
  for (it = d->local_ifaddrs; it; it = it->ifa_next) {
887
    struct sockaddr_in6 *sin6;
888
889
    if (!it->ifa_addr || it->ifa_addr->sa_family != AF_INET6)
890
      continue;
891
    sin6 = (struct sockaddr_in6 *)it->ifa_addr;
892
    if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip))
893
      return true;
894
  }
895
896
  return false;
897
}
898
#endif
899
900
/* Ignore packets we sent ourselves, regardless of address family */
901
static bool _is_local(mdns_daemon_t *d, const inet_addr_t *from)
902
0
{
903
#ifdef ENABLE_IPV6
904
  if (inet_family(from) == AF_INET6)
905
    return _is_local_ipv6(d, ((const struct sockaddr_in6 *)from)->sin6_addr);
906
#endif
907
0
  return _is_local_ipv4(d, ((const struct sockaddr_in *)from)->sin_addr);
908
0
}
909
910
/* mDNS multicast destination for the daemon's transport family */
911
static void mdns_mcast(inet_addr_t *to, sa_family_t family)
912
0
{
913
0
  memset(to, 0, sizeof(*to));
914
0
  to->ss_family = family;
915
916
#ifdef ENABLE_IPV6
917
  if (family == AF_INET6) {
918
    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)to;
919
920
    inet_pton(AF_INET6, "ff02::fb", &sin6->sin6_addr);
921
    sin6->sin6_port = htons(5353);
922
    return;
923
  }
924
#endif
925
0
  ((struct sockaddr_in *)to)->sin_addr.s_addr = inet_addr("224.0.0.251");
926
0
  ((struct sockaddr_in *)to)->sin_port        = htons(5353);
927
0
}
928
929
mdns_daemon_t *mdnsd_new(int clazz, int frame)
930
1.91k
{
931
1.91k
  mdns_daemon_t *d;
932
933
1.91k
  d = calloc(1, sizeof(struct mdns_daemon));
934
1.91k
  if (!d)
935
0
    return NULL;
936
937
1.91k
  gettimeofday(&d->now, 0);
938
1.91k
  d->expireall = (unsigned long)d->now.tv_sec + GC;
939
1.91k
  d->clazz = clazz;
940
1.91k
  d->frame = frame;
941
1.91k
  d->family = AF_INET;
942
1.91k
  d->local = 1;   /* process replies from our own host by default */
943
1.91k
  d->received_callback = NULL;
944
1.91k
  d->local_ifaddrs = NULL;
945
1.91k
  d->local_addrs_refreshed = 0;
946
947
1.91k
  return d;
948
1.91k
}
949
950
void mdnsd_set_family(mdns_daemon_t *d, sa_family_t family)
951
0
{
952
0
  d->family = family;
953
0
}
954
955
/* Process replies from our own host, or ignore them like avahi-browse(1) -l */
956
void mdnsd_set_local(mdns_daemon_t *d, int enable)
957
0
{
958
0
  d->local = enable ? 1 : 0;
959
0
}
960
961
int mdnsd_get_local(mdns_daemon_t *d)
962
0
{
963
0
  return d->local;
964
0
}
965
966
void mdnsd_set_address(mdns_daemon_t *d, struct in_addr addr)
967
0
{
968
0
  int i;
969
970
0
  if (!memcmp(&d->addr, &addr, sizeof(d->addr)))
971
0
    return;   /* No change */
972
973
0
  for (i = 0; i < SPRIME; i++) {
974
0
    mdns_record_t *r, *next;
975
976
0
    r = d->published[i];
977
0
    while (r) {
978
0
      next = r->next;
979
980
0
      if (r->rr.type == QTYPE_A) {
981
0
        if (addr.s_addr == 0) {
982
0
          r->rr.ttl = 0;
983
0
          r->list = d->a_now;
984
0
          d->a_now = r;
985
0
        } else {
986
0
          mdnsd_set_ip(d, r, addr);
987
0
        }
988
0
      }
989
990
0
      r = next;
991
0
    }
992
0
  }
993
994
0
  d->addr = addr;
995
0
}
996
997
struct in_addr mdnsd_get_address(mdns_daemon_t *d)
998
0
{
999
0
  return d->addr;
1000
0
}
1001
1002
void mdnsd_set_ipv6_address(mdns_daemon_t *d, struct in6_addr addr)
1003
0
{
1004
0
  int i;
1005
1006
0
  if (!memcmp(&d->addr_v6, &addr, sizeof(d->addr_v6)))
1007
0
    return;   /* No change */
1008
1009
0
  for (i = 0; i < SPRIME; i++) {
1010
0
    mdns_record_t *r, *next;
1011
1012
0
    r = d->published[i];
1013
0
    while (r) {
1014
0
      next = r->next;
1015
1016
0
      if (r->rr.type == QTYPE_AAAA) {
1017
0
        if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
1018
0
          r->rr.ttl = 0;
1019
0
          r->list = d->a_now;
1020
0
          d->a_now = r;
1021
0
        } else {
1022
0
          mdnsd_set_ipv6(d, r, addr);
1023
0
        }
1024
0
      }
1025
1026
0
      r = next;
1027
0
    }
1028
0
  }
1029
1030
0
  d->addr_v6 = addr;
1031
0
}
1032
1033
struct in6_addr mdnsd_get_ipv6_address(mdns_daemon_t *d)
1034
0
{
1035
0
  return d->addr_v6;
1036
0
}
1037
1038
/* Shutting down, zero out ttl and push out all records */
1039
void mdnsd_shutdown(mdns_daemon_t *d)
1040
279
{
1041
279
  int i;
1042
279
  mdns_record_t *cur, *next;
1043
1044
279
  if (!d)
1045
0
    return;
1046
1047
279
  d->a_now = 0;
1048
30.6k
  for (i = 0; i < SPRIME; i++) {
1049
31.5k
    for (cur = d->published[i]; cur != 0;) {
1050
1.11k
      next = cur->next;
1051
1.11k
      cur->rr.ttl = 0;
1052
1.11k
      cur->list = d->a_now;
1053
1.11k
      d->a_now = cur;
1054
1.11k
      cur = next;
1055
1.11k
    }
1056
30.4k
  }
1057
1058
279
  d->shutdown = 1;
1059
279
}
1060
1061
void mdnsd_flush(mdns_daemon_t *d)
1062
0
{
1063
0
  (void)d;
1064
  /* - Set all querys to 0 tries
1065
   * - Free whole cache
1066
   * - Set all mdns_record_t *to probing
1067
   * - Reset all answer lists
1068
   */
1069
0
}
1070
1071
void mdnsd_free(mdns_daemon_t *d)
1072
1.91k
{
1073
1.91k
  struct unicast *u;
1074
1075
1.91k
  if (!d)
1076
0
    return;
1077
1078
1.93M
  for (size_t i = 0; i< LPRIME; i++) {
1079
1.93M
    struct cached *cur = d->cache[i];
1080
1081
1.93M
    while (cur) {
1082
5.08k
      struct cached *next = cur->next;
1083
1084
5.08k
      cur->next = NULL;
1085
5.08k
      _free_cached(cur);
1086
5.08k
      cur = next;
1087
5.08k
    }
1088
1.93M
  }
1089
1090
210k
  for (size_t i = 0; i< SPRIME; i++) {
1091
208k
    struct mdns_record *cur = d->published[i];
1092
208k
    struct query *curq;
1093
1094
209k
    while (cur) {
1095
1.11k
      struct mdns_record *next = cur->next;
1096
1097
1.11k
      cur->next = NULL;
1098
1.11k
      _free_record(cur);
1099
1.11k
      cur = next;
1100
1.11k
    }
1101
1102
208k
    curq = d->queries[i];
1103
209k
    while (curq) {
1104
279
      struct query *next = curq->next;
1105
1106
279
      curq->next = NULL;
1107
279
      free(curq->name);
1108
279
      free(curq);
1109
279
      curq = next;
1110
279
    }
1111
208k
  }
1112
1113
1.91k
  u = d->uanswers;
1114
1.91k
  while (u) {
1115
0
    struct unicast *next = u->next;
1116
1117
0
    u->next = NULL;
1118
0
    free(u);
1119
0
    u = next;
1120
0
  }
1121
1122
1.91k
  if (d->local_ifaddrs)
1123
0
    freeifaddrs(d->local_ifaddrs);
1124
1125
1.91k
  free(d);
1126
1.91k
}
1127
1128
1129
void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_callback cb, void* data)
1130
279
{
1131
279
  d->received_callback = cb;
1132
279
  d->received_callback_data = data;
1133
279
}
1134
1135
int mdnsd_in(mdns_daemon_t *d, struct message *m, const inet_addr_t *from)
1136
1.63k
{
1137
1.63k
  mdns_record_t *r = NULL;
1138
1.63k
  int i, j;
1139
1.63k
  bool did_addr_refresh = false;
1140
1141
1.63k
  if (d->shutdown)
1142
0
    return 1;
1143
1144
1.63k
  gettimeofday(&d->now, 0);
1145
1146
  /* Skip replies from our own host when local processing is off, cf. mquery -L */
1147
1.63k
  if (!d->local && _is_local(d, from))
1148
0
    return 0;
1149
1150
1.63k
  if (m->header.qr == 0) {
1151
    /* Process each query */
1152
282k
    for (i = 0; i < m->qdcount; i++) {
1153
281k
      mdns_record_t *r_start, *r_next;
1154
281k
      bool has_conflict = false;
1155
1156
281k
      if (!m->qd || m->qd[i].clazz != d->clazz)
1157
280k
        continue;
1158
1159
1.67k
      INFO("Query for %s of type %d ...", m->qd[i].name, m->qd[i].type);
1160
1.67k
      r = _r_next(d, NULL, m->qd[i].name, m->qd[i].type);
1161
1.67k
      if (!r)
1162
1.67k
        continue;
1163
1164
      /* Service enumeration/discovery prepare to send all matching records */
1165
0
      if (!strcmp(m->qd[i].name, DISCO_NAME)) {
1166
0
        d->disco = 1;
1167
0
        while (r) {
1168
0
          if (!strcmp(r->rr.name, DISCO_NAME))
1169
0
            _r_send(d, r);
1170
0
          r = _r_next(d, r, m->qd[i].name, m->qd[i].type);
1171
0
        }
1172
1173
0
        continue;
1174
0
      }
1175
1176
      /* Check all of our potential answers */
1177
0
      for (r_start = r; r != NULL; r = r_next) {
1178
0
        INFO("Local record: %s, type: %d, rdname: %s", r->rr.name, r->rr.type, r->rr.rdname);
1179
1180
        /* Fetch next here, because _conflict() might delete r, invalidating next */
1181
0
        r_next = _r_next(d, r, m->qd[i].name, m->qd[i].type);
1182
1183
        /* probing state, check for conflicts */
1184
0
        if (r->unique && r->unique < 5 && !r->modified) {
1185
          /* Check all to-be answers against our own */
1186
0
          for (j = 0; j < m->ancount; j++) {
1187
0
            if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
1188
0
              continue;
1189
1190
            /* This answer isn't ours, conflict! */
1191
0
            if (!_a_match(&m->an[j], &r->rr)) {
1192
              /* Before flagging conflict, force a local address refresh and re-check */
1193
0
              if (!did_addr_refresh) {
1194
0
                did_addr_refresh = true;
1195
0
                _refresh_local_addrs(d, true);
1196
0
              }
1197
0
              if (_is_local(d, from))
1198
0
                continue;
1199
0
              _conflict(d, r);
1200
0
              has_conflict = true;
1201
0
              break;
1202
0
            }
1203
0
          }
1204
0
          continue;
1205
0
        }
1206
1207
        /* Check the known answers for this question */
1208
0
        for (j = 0; j < m->ancount; j++) {
1209
0
          if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
1210
0
            continue;
1211
1212
0
          if (d->received_callback)
1213
0
            d->received_callback(&m->an[j], d->received_callback_data);
1214
1215
          /* Do they already have this answer? */
1216
0
          if (_a_match(&m->an[j], &r->rr))
1217
0
            break;
1218
0
        }
1219
1220
0
        INFO("Should we send answer? j: %d, m->ancount: %d", j, m->ancount);
1221
0
        if (j == m->ancount) {
1222
0
          INFO("Yes we should, enquing %s for outbound", r->rr.name);
1223
0
          _r_send(d, r);
1224
0
        }
1225
0
      }
1226
1227
      /* Send the matching unicast reply */
1228
0
      if (!has_conflict && inet_port(from) != 5353)
1229
0
        _u_push(d, r_start, m->id, from);
1230
0
    }
1231
1232
362
    return 0;
1233
362
  }
1234
1235
  /* Process each answer, check for a conflict, and cache */
1236
176k
  for (i = 0; i < m->ancount; i++) {
1237
175k
    if (!m->an)
1238
11.9k
      continue;
1239
1240
163k
    if (!m->an[i].name) {
1241
146k
      ERR("Got answer with NULL name at %p. Type: %d, TTL: %ld, skipping",
1242
146k
          (void*)&m->an[i], m->an[i].type, m->an[i].ttl);
1243
146k
      continue;
1244
146k
    }
1245
1246
16.7k
    INFO("Got Answer: Name: %s, Type: %d", m->an[i].name, m->an[i].type);
1247
16.7k
    r = _r_next(d, NULL, m->an[i].name, m->an[i].type);
1248
16.7k
    if (r && r->unique && r->modified && _a_match(&m->an[i], &r->rr)) {
1249
      /* double check, is this actually from us, looped back? */
1250
0
      if (!did_addr_refresh) {
1251
0
        did_addr_refresh = true;
1252
0
        _refresh_local_addrs(d, true);
1253
0
      }
1254
0
      if (_is_local(d, from))
1255
0
        continue;
1256
0
      _conflict(d, r);
1257
0
    }
1258
1259
16.7k
    if (d->received_callback)
1260
0
      d->received_callback(&m->an[i], d->received_callback_data);
1261
1262
16.7k
    if (_cache(d, &m->an[i], from) != 0) {
1263
83
      ERR("Failed caching answer, possibly too long packet, skipping.");
1264
83
      continue;
1265
83
    }
1266
16.7k
  }
1267
1268
1.27k
  return 0;
1269
1.63k
}
1270
1271
int mdnsd_out(mdns_daemon_t *d, struct message *m, inet_addr_t *to)
1272
0
{
1273
0
  mdns_record_t *r;
1274
0
  struct answered seen = { 0 };
1275
0
  int ret = 0;
1276
1277
0
  gettimeofday(&d->now, 0);
1278
0
  memset(m, 0, sizeof(struct message));
1279
1280
  /* Defaults, multicast */
1281
0
  mdns_mcast(to, d->family);
1282
0
  m->header.qr = 1;
1283
0
  m->header.aa = 1;
1284
1285
  /* Send out individual unicast answers */
1286
0
  if (d->uanswers) {
1287
0
    struct unicast *u = d->uanswers;
1288
1289
0
    INFO("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type);
1290
1291
0
    d->uanswers = u->next;
1292
0
    *to = u->to;
1293
0
    m->id = u->id;
1294
0
    message_qd(m, u->r->rr.name, u->r->rr.type, d->clazz);
1295
0
    message_an(m, u->r->rr.name, u->r->rr.type, d->clazz, u->r->rr.ttl);
1296
0
    u->r->last_sent = d->now;
1297
0
    _a_copy(m, &u->r->rr);
1298
1299
    /* RFC 6763 §12 additional records for the unicast answer */
1300
0
    _answered_add(&seen, u->r);
1301
0
    _additional(d, m, u->r, &seen);
1302
0
    free(u);
1303
1304
0
    return 1;
1305
0
  }
1306
1307
  /* Accumulate any immediate responses */
1308
0
  if (d->a_now)
1309
0
    ret += _r_out(d, m, &d->a_now, &seen);
1310
1311
  /* Check if it's time to send the publish retries (unlink if done) */
1312
0
  if (!d->probing && d->a_publish && _tvdiff(d->now, d->publish) <= 0) {
1313
0
    mdns_record_t *cur = d->a_publish;
1314
0
    mdns_record_t *last = NULL;
1315
0
    mdns_record_t *next;
1316
1317
0
    while (cur && message_packet_len(m) + (int)_rr_len(&cur->rr) < d->frame) {
1318
0
      if (cur->rr.type == QTYPE_PTR) {
1319
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);
1320
0
      } else if (cur->rr.type == QTYPE_SRV) {
1321
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);
1322
0
      } else {
1323
0
        INFO("Send Publish: Name: %s, Type: %d, rdname: %s", cur->rr.name, cur->rr.type, cur->rr.rdname);
1324
0
      }
1325
1326
0
      next = cur->list;
1327
0
      ret++;
1328
0
      cur->tries++;
1329
1330
0
      if (cur->unique)
1331
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz + 32768, cur->rr.ttl);
1332
0
      else
1333
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz, cur->rr.ttl);
1334
0
      _a_copy(m, &cur->rr);
1335
0
      cur->last_sent = d->now;
1336
0
      if (cur->rr.ttl != 0)
1337
0
        _answered_add(&seen, cur);
1338
1339
0
      if (cur->rr.ttl != 0 && cur->tries < 4) {
1340
0
        last = cur;
1341
0
        cur = next;
1342
0
        continue;
1343
0
      }
1344
1345
0
      cur->list = NULL;
1346
0
      if (d->a_publish == cur)
1347
0
        d->a_publish = next;
1348
0
      if (last)
1349
0
        last->list = next;
1350
0
      if (cur->rr.ttl == 0)
1351
0
        _r_done(d, cur);
1352
0
      cur = next;
1353
0
    }
1354
1355
0
    if (d->a_publish) {
1356
0
      d->publish.tv_sec = d->now.tv_sec + 2;
1357
0
      d->publish.tv_usec = d->now.tv_usec;
1358
0
    }
1359
0
  }
1360
1361
  /* If we're in shutdown, we're done */
1362
0
  if (d->shutdown)
1363
0
    return ret;
1364
1365
  /* Check if a_pause is ready */
1366
0
  if (d->a_pause && _tvdiff(d->now, d->pause) <= 0)
1367
0
    ret += _r_out(d, m, &d->a_pause, &seen);
1368
1369
  /* RFC 6763 §12: expand the answers, not the additionals _ar() appends */
1370
0
  for (int i = 0, n = seen.n; i < n; i++)
1371
0
    _additional(d, m, seen.rec[i], &seen);
1372
1373
  /* Now process questions */
1374
0
  if (ret)
1375
0
    return ret;
1376
1377
0
  m->header.qr = 0;
1378
0
  m->header.aa = 0;
1379
1380
0
  if (d->probing && _tvdiff(d->now, d->probe) <= 0) {
1381
0
    mdns_record_t *last = 0;
1382
1383
    /* Scan probe list to ask questions and process published */
1384
0
    for (r = d->probing; r != NULL;) {
1385
      /* Done probing, publish */
1386
0
      if (r->unique == 4) {
1387
0
        mdns_record_t *next = r->list;
1388
1389
0
        if (d->probing == r)
1390
0
          d->probing = r->list;
1391
0
        else if (last)
1392
0
          last->list = r->list;
1393
1394
0
        r->list = 0;
1395
0
        r->unique = 5;
1396
0
        _r_publish(d, r);
1397
0
        r = next;
1398
0
        continue;
1399
0
      }
1400
1401
0
      INFO("Send Probing: Name: %s, Type: %d", r->rr.name, r->rr.type);
1402
1403
0
      message_qd(m, r->rr.name, r->rr.type, (unsigned short)d->clazz);
1404
0
      r->last_sent = d->now;
1405
0
      last = r;
1406
0
      r = r->list;
1407
0
    }
1408
1409
    /* Scan probe list again to append our to-be answers */
1410
0
    for (r = d->probing; r != 0; r = r->list) {
1411
0
      r->unique++;
1412
1413
0
      INFO("Send Answer in Probe: Name: %s, Type: %d", r->rr.name, r->rr.type);
1414
0
      message_ns(m, r->rr.name, r->rr.type, (unsigned short)d->clazz, r->rr.ttl);
1415
0
      _a_copy(m, &r->rr);
1416
0
      r->last_sent = d->now;
1417
0
      ret++;
1418
0
    }
1419
1420
    /* Process probes again in the future */
1421
0
    if (ret) {
1422
0
      d->probe.tv_sec = d->now.tv_sec;
1423
0
      d->probe.tv_usec = d->now.tv_usec + 250000;
1424
0
      return ret;
1425
0
    }
1426
0
  }
1427
1428
  /* Process qlist for retries or expirations */
1429
0
  if (d->checkqlist && (unsigned long)d->now.tv_sec >= d->checkqlist) {
1430
0
    struct query *q;
1431
0
    struct cached *c;
1432
0
    unsigned long int nextbest = 0;
1433
1434
    /* Ask questions first, track nextbest time */
1435
0
    for (q = d->qlist; q != 0; q = q->list) {
1436
0
      if (q->nexttry > 0 && q->nexttry <= (unsigned long)d->now.tv_sec && q->tries < 3)
1437
0
        message_qd(m, q->name, q->type, d->clazz);
1438
0
      else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
1439
0
        nextbest = q->nexttry;
1440
0
    }
1441
1442
    /* Include known answers, update questions */
1443
0
    for (q = d->qlist; q != 0; q = q->list) {
1444
0
      if (q->nexttry == 0 || q->nexttry > (unsigned long)d->now.tv_sec)
1445
0
        continue;
1446
1447
      /* Done retrying, expire and reset */
1448
0
      if (q->tries == 3) {
1449
0
        _c_expire(d, &d->cache[_namehash(q->name) % LPRIME]);
1450
0
        _q_reset(d, q);
1451
0
        continue;
1452
0
      }
1453
1454
0
      ret++;
1455
0
      q->nexttry = d->now.tv_sec + ++q->tries;
1456
0
      if (nextbest == 0 || q->nexttry < nextbest)
1457
0
        nextbest = q->nexttry;
1458
1459
      /* If room, add all known good entries */
1460
0
      c = 0;
1461
0
      while ((c = _c_next(d, c, q->name, q->type)) != 0 && c->rr.ttl > (unsigned long)d->now.tv_sec + 8 &&
1462
0
        message_packet_len(m) + (int)_rr_len(&c->rr) < d->frame) {
1463
1464
0
        INFO("Add known answer: Name: %s, Type: %d", c->rr.name, c->rr.type);
1465
0
        message_an(m, q->name, (unsigned short)q->type, (unsigned short)d->clazz, c->rr.ttl - (unsigned long)d->now.tv_sec);
1466
0
        _a_copy(m, &c->rr);
1467
0
      }
1468
0
    }
1469
0
    d->checkqlist = nextbest;
1470
0
  }
1471
1472
0
  if ((unsigned long)d->now.tv_sec > d->expireall)
1473
0
    _gc(d);
1474
1475
0
  return ret;
1476
0
}
1477
1478
1479
0
#define RET do {       \
1480
0
  while (d->sleep.tv_usec > 1000000) { \
1481
0
    d->sleep.tv_sec++;    \
1482
0
    d->sleep.tv_usec -= 1000000;  \
1483
0
  }          \
1484
0
  return &d->sleep;     \
1485
0
} while (0)
1486
1487
struct timeval *mdnsd_sleep(mdns_daemon_t *d)
1488
0
{
1489
0
  time_t expire;
1490
0
  long usec;
1491
1492
0
  d->sleep.tv_sec = d->sleep.tv_usec = 0;
1493
1494
  /* First check for any immediate items to handle */
1495
0
  if (d->uanswers || d->a_now)
1496
0
    return &d->sleep;
1497
1498
0
  gettimeofday(&d->now, 0);
1499
1500
  /* Then check for paused answers or nearly expired records */
1501
0
  if (d->a_pause) {
1502
0
    if ((usec = _tvdiff(d->now, d->pause)) > 0)
1503
0
      d->sleep.tv_usec = usec;
1504
0
    RET;
1505
0
  }
1506
1507
  /* Now check for probe retries */
1508
0
  if (d->probing) {
1509
0
    if ((usec = _tvdiff(d->now, d->probe)) > 0)
1510
0
      d->sleep.tv_usec = usec;
1511
0
    RET;
1512
0
  }
1513
1514
  /* Now check for publish retries */
1515
0
  if (d->a_publish) {
1516
0
    if ((usec = _tvdiff(d->now, d->publish)) > 0)
1517
0
      d->sleep.tv_usec = usec;
1518
0
    RET;
1519
0
  }
1520
1521
  /* Also check for queries with known answer expiration/retry */
1522
0
  if (d->checkqlist) {
1523
0
    long sec;
1524
0
    if ((sec = (long)d->checkqlist - d->now.tv_sec) > 0)
1525
0
      d->sleep.tv_sec = sec;
1526
0
    RET;
1527
0
  }
1528
1529
  /* Resend published records before TTL expires */
1530
0
  expire = (long)d->expireall - d->now.tv_sec;
1531
0
  if (expire < 0)
1532
0
    RET;
1533
1534
0
  for (size_t i = 0; i < SPRIME; i++) {
1535
0
    mdns_record_t *r;
1536
0
    time_t next;
1537
1538
0
    r = d->published[i];
1539
0
    if (!r)
1540
0
      continue;
1541
1542
    /* Publish 2 seconds before expiration */
1543
0
    next = r->last_sent.tv_sec + (long)r->rr.ttl - d->now.tv_sec;
1544
0
    if (next <= 2) {
1545
0
      INFO("Republish %s before TTL expires ...", r->rr.name);
1546
0
      _r_push(&d->a_pause, r);
1547
0
    }
1548
1549
0
    if (next < expire)
1550
0
      expire = next;
1551
0
  }
1552
1553
0
  d->sleep.tv_sec = expire > 2 ? expire - 2 : 0;
1554
0
  d->pause.tv_sec = d->now.tv_sec + d->sleep.tv_sec;
1555
1556
0
  RET;
1557
0
}
1558
1559
void mdnsd_query(mdns_daemon_t *d, const char *host, int type, int (*answer)(mdns_answer_t *a, void *arg), void *arg)
1560
279
{
1561
279
  struct query *q;
1562
279
  struct cached *cur = 0;
1563
279
  int i = _namehash(host) % SPRIME;
1564
1565
279
  if (!(q = _q_next(d, 0, host, type))) {
1566
279
    if (!answer)
1567
0
      return;
1568
1569
279
    q = calloc(1, sizeof(struct query));
1570
279
    if (!q)
1571
0
      return;
1572
279
    q->name = strdup(host);
1573
279
    if (!q->name) {
1574
0
      free(q);
1575
0
      return;
1576
0
    }
1577
279
    q->type = type;
1578
279
    q->next = d->queries[i];
1579
279
    q->list = d->qlist;
1580
279
    d->qlist = d->queries[i] = q;
1581
1582
    /* Any cached entries should be associated */
1583
279
    while ((cur = _c_next(d, cur, q->name, q->type)))
1584
0
      cur->q = q;
1585
279
    _q_reset(d, q);
1586
1587
    /* New question, immediately send out */
1588
279
    q->nexttry = d->checkqlist = d->now.tv_sec;
1589
279
  }
1590
1591
  /* No answer means we don't care anymore */
1592
279
  if (!answer) {
1593
0
    _q_done(d, q);
1594
0
    return;
1595
0
  }
1596
1597
279
  q->answer = answer;
1598
279
  q->arg = arg;
1599
279
}
1600
1601
mdns_answer_t *mdnsd_list(mdns_daemon_t *d,const char *host, int type, mdns_answer_t *last)
1602
0
{
1603
0
  return (mdns_answer_t *)_c_next(d, (struct cached *)last, host, type);
1604
0
}
1605
1606
mdns_record_t *mdnsd_record_next(const mdns_record_t* r)
1607
837
{
1608
837
  return r ? r->next : NULL;
1609
837
}
1610
1611
const mdns_answer_t *mdnsd_record_data(const mdns_record_t* r)
1612
1.11k
{
1613
1.11k
  return &r->rr;
1614
1.11k
}
1615
1616
mdns_record_t *mdnsd_shared(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl)
1617
1.67k
{
1618
1.67k
  int i = _namehash(host) % SPRIME;
1619
1.67k
  mdns_record_t *r;
1620
1621
1.67k
  r = calloc(1, sizeof(struct mdns_record));
1622
1.67k
  if (!r)
1623
0
    return NULL;
1624
1625
1.67k
  r->rr.name = strdup(host);
1626
1.67k
  if (!r->rr.name) {
1627
0
    free(r);
1628
0
    return NULL;
1629
0
  }
1630
1631
1.67k
  r->rr.type = type;
1632
1.67k
  r->rr.ttl = ttl;
1633
1.67k
  r->next = d->published[i];
1634
1.67k
  d->published[i] = r;
1635
1636
1.67k
  return r;
1637
1.67k
}
1638
1639
mdns_record_t *mdnsd_unique(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl,
1640
          void (*conflict)(char *host, int type, void *arg), void *arg)
1641
558
{
1642
558
  mdns_record_t *r;
1643
1644
558
  r = mdnsd_shared(d, host, type, ttl);
1645
558
  if (!r)
1646
0
    return NULL;
1647
1648
558
  r->conflict = conflict;
1649
558
  r->arg = arg;
1650
558
  r->unique = 1;
1651
1652
  /* check if r already in other lists. If yes, remove it from there */
1653
558
  _r_remove_lists(d, r, &d->probing);
1654
558
  _r_push(&d->probing, r);
1655
1656
558
  d->probe.tv_sec = d->now.tv_sec;
1657
558
  d->probe.tv_usec = d->now.tv_usec;
1658
1659
558
  return r;
1660
558
}
1661
1662
mdns_record_t *mdnsd_get_published(mdns_daemon_t *d, const char *host)
1663
1.11k
{
1664
1.11k
  return d->published[_namehash(host) % SPRIME];
1665
1.11k
}
1666
1667
int mdnsd_has_query(mdns_daemon_t *d, const char *host)
1668
0
{
1669
0
  return d->queries[_namehash(host) % SPRIME] != NULL;
1670
0
}
1671
1672
mdns_record_t *mdnsd_find(mdns_daemon_t *d, const char *name, unsigned short type)
1673
0
{
1674
0
  mdns_record_t *r;
1675
1676
0
  r = mdnsd_get_published(d, name);
1677
0
  while (r) {
1678
0
    const mdns_answer_t *data;
1679
1680
    /*
1681
     * Search for a record with the same type and name.
1682
     * Records with different names might be in the same
1683
     * linked list when the hash functions % SPRIME assigns
1684
     * them the same index (hash collision)
1685
     */
1686
0
    data = mdnsd_record_data(r);
1687
0
    if (data->type == type && strcmp(data->name, name) == 0)
1688
0
      return r;
1689
1690
0
    r = mdnsd_record_next(r);
1691
0
  }
1692
1693
0
  return NULL;
1694
0
}
1695
1696
void mdnsd_done(mdns_daemon_t *d, mdns_record_t *r)
1697
1.11k
{
1698
1.11k
  mdns_record_t *cur;
1699
1700
1.11k
  if (r->unique && r->unique < 5) {
1701
    /* Probing yet, zap from that list first! */
1702
558
    if (d->probing == r) {
1703
558
      d->probing = r->list;
1704
558
    } else {
1705
0
      for (cur = d->probing; cur->list != r; cur = cur->list)
1706
0
        ;
1707
0
      cur->list = r->list;
1708
0
    }
1709
1710
558
    _r_done(d, r);
1711
558
    return;
1712
558
  }
1713
1714
558
  r->rr.ttl = 0;
1715
558
  _r_send(d, r);
1716
558
}
1717
1718
void mdnsd_set_raw(mdns_daemon_t *d, mdns_record_t *r, const char *data, unsigned short len)
1719
837
{
1720
837
  if (r->rr.rdata)
1721
0
    free(r->rr.rdata);
1722
1723
837
  r->rr.rdata = malloc(len);
1724
837
  if (r->rr.rdata) {
1725
837
    memcpy(r->rr.rdata, data, len);
1726
837
    r->rr.rdlen = len;
1727
837
  }
1728
837
  _r_publish(d, r);
1729
837
}
1730
1731
void mdnsd_set_host(mdns_daemon_t *d, mdns_record_t *r, const char *name)
1732
837
{
1733
837
  if (!r)
1734
0
    return;
1735
1736
837
  if (r->rr.rdname)
1737
0
    free(r->rr.rdname);
1738
837
  r->rr.rdname = strdup(name);
1739
837
  _r_publish(d, r);
1740
837
}
1741
1742
void mdnsd_set_ip(mdns_daemon_t *d, mdns_record_t *r, struct in_addr ip)
1743
0
{
1744
0
  r->rr.ip = ip;
1745
0
  _r_publish(d, r);
1746
0
}
1747
1748
void mdnsd_set_ipv6(mdns_daemon_t *d, mdns_record_t *r, struct in6_addr ip6)
1749
0
{
1750
0
  r->rr.ip6 = ip6;
1751
0
  _r_publish(d, r);
1752
0
}
1753
1754
void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short priority, unsigned short weight, unsigned short port, char *name)
1755
279
{
1756
279
  r->rr.srv.priority = priority;
1757
279
  r->rr.srv.weight = weight;
1758
279
  r->rr.srv.port = port;
1759
279
  mdnsd_set_host(d, r, name);
1760
279
}
1761
1762
/* Internal helper: update set of addresses for given host & type (A/AAAA) */
1763
static int _update_addresses_for_host(mdns_daemon_t *d, const char *host, unsigned short type, const void *addrs, size_t count)
1764
0
{
1765
0
  mdns_record_t *r;
1766
0
  mdns_record_t *cur;
1767
0
  unsigned long ttl = 120; /* default TTL if none exists */
1768
0
  char buf6[INET6_ADDRSTRLEN];
1769
1770
0
  if (!d || !host)
1771
0
    return -1;
1772
1773
  /* Determine TTL from any existing record of this type */
1774
0
  r = mdnsd_find(d, host, type);
1775
0
  if (r) {
1776
0
    const mdns_answer_t *data = mdnsd_record_data(r);
1777
0
    if (data && data->ttl)
1778
0
      ttl = data->ttl;
1779
0
  }
1780
1781
  /* For each desired address, check if there's a matching existing record */
1782
0
  for (size_t i = 0; i < count; i++) {
1783
0
    bool found = false;
1784
0
    cur = mdnsd_get_published(d, host);
1785
0
    while (cur) {
1786
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1787
0
      if (data->type == type && strcmp(data->name, host) == 0) {
1788
0
        if (type == QTYPE_A) {
1789
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1790
0
          if (data->ip.s_addr == a[i].s_addr) {
1791
0
            found = true;
1792
0
            INFO("Found A record for %s addr %s", host, inet_ntoa(a[i]));
1793
0
            break;
1794
0
          }
1795
0
        } else if (type == QTYPE_AAAA) {
1796
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1797
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) {
1798
0
            found = true;
1799
0
            INFO("Found AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1800
0
            break;
1801
0
          }
1802
0
        }
1803
0
      }
1804
0
      cur = mdnsd_record_next(cur);
1805
0
    }
1806
0
    if (!found) {
1807
      /* Create new_ record for this address */
1808
0
      mdns_record_t *nr = mdnsd_shared(d, host, type, ttl);
1809
0
      if (!nr)
1810
0
        continue;
1811
0
      if (type == QTYPE_A) {
1812
0
        const struct in_addr *a = (const struct in_addr *)addrs;
1813
0
        mdnsd_set_ip(d, nr, a[i]);
1814
0
        INFO("Created A record for %s addr %s", host, inet_ntoa(a[i]));
1815
0
      } else {
1816
0
        const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1817
0
        mdnsd_set_ipv6(d, nr, a6[i]);
1818
0
        INFO("Created AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1819
0
      }
1820
0
    }
1821
0
  }
1822
1823
  /* Remove stale records (present but not in desired set) */
1824
0
  cur = mdnsd_get_published(d, host);
1825
0
  while (cur) {
1826
0
    mdns_record_t *next = mdnsd_record_next(cur);
1827
0
    const mdns_answer_t *data = mdnsd_record_data(cur);
1828
0
    if (data->type == type && strcmp(data->name, host) == 0) {
1829
0
      bool still_present = false;
1830
0
      for (size_t i = 0; i < count; i++) {
1831
0
        if (type == QTYPE_A) {
1832
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1833
0
          if (data->ip.s_addr == a[i].s_addr) { still_present = true; break; }
1834
0
        } else {
1835
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1836
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) { still_present = true; break; }
1837
0
        }
1838
0
      }
1839
0
      if (!still_present)
1840
0
        mdnsd_done(d, cur);
1841
0
    }
1842
0
    cur = next;
1843
0
  }
1844
1845
0
  return 0;
1846
0
}
1847
1848
int mdnsd_set_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in_addr *addrs, size_t count)
1849
0
{
1850
0
  return _update_addresses_for_host(d, host, QTYPE_A, addrs, count);
1851
0
}
1852
1853
int mdnsd_set_ipv6_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in6_addr *addrs, size_t count)
1854
0
{
1855
0
  return _update_addresses_for_host(d, host, QTYPE_AAAA, addrs, count);
1856
0
}
1857
1858
int mdnsd_set_interface_addresses(mdns_daemon_t *d, const char *ifname)
1859
0
{
1860
0
  struct ifaddrs *ifa = NULL;
1861
0
  struct ifaddrs *it;
1862
0
  struct in_addr *v4 = NULL; size_t v4c = 0;
1863
0
  struct in6_addr *v6 = NULL; size_t v6c = 0;
1864
0
  char buf[INET_ADDRSTRLEN];
1865
0
  char buf6[INET6_ADDRSTRLEN];
1866
1867
0
  if (getifaddrs(&ifa) != 0)
1868
0
    return -1;
1869
1870
  /* Collect all v4/v6 addresses for the interface */
1871
0
  for (it = ifa; it; it = it->ifa_next) {
1872
0
    if (!it->ifa_addr || !it->ifa_name || strcmp(it->ifa_name, ifname))
1873
0
      continue;
1874
0
    if (it->ifa_addr->sa_family == AF_INET) {
1875
0
      v4 = realloc(v4, (v4c + 1) * sizeof(*v4));
1876
0
      if (v4) {
1877
0
        struct sockaddr_in *sin = (struct sockaddr_in *)it->ifa_addr;
1878
0
        v4[v4c++] = sin->sin_addr;
1879
0
        if(inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)))
1880
0
            INFO("Adding address %s for interface %s", buf, ifname);
1881
0
      }
1882
0
    } else if (it->ifa_addr->sa_family == AF_INET6) {
1883
0
      v6 = realloc(v6, (v6c + 1) * sizeof(*v6));
1884
0
      if (v6) {
1885
0
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)it->ifa_addr;
1886
0
        v6[v6c++] = sin6->sin6_addr;
1887
0
        if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf6, sizeof(buf6)))
1888
0
            INFO("Adding address %s for interface %s", buf6, ifname);
1889
0
      }
1890
0
    }
1891
0
  }
1892
0
  freeifaddrs(ifa);
1893
1894
  /*
1895
   * Reconcile per host name, not per record pointer: the calls below
1896
   * free stale records, which would dangle a record iterator.  See #92.
1897
   */
1898
0
  char **hosts = NULL;
1899
0
  size_t hostc = 0;
1900
1901
0
  for (size_t idx = 0; idx < SPRIME; idx++) {
1902
0
    for (mdns_record_t *cur = d->published[idx]; cur; cur = mdnsd_record_next(cur)) {
1903
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1904
0
      bool seen = false;
1905
0
      char **tmp;
1906
1907
0
      if (data->type != QTYPE_A && data->type != QTYPE_AAAA)
1908
0
        continue;
1909
1910
0
      for (size_t i = 0; i < hostc; i++) {
1911
0
        if (!strcmp(hosts[i], data->name)) {
1912
0
          seen = true;
1913
0
          break;
1914
0
        }
1915
0
      }
1916
0
      if (seen)
1917
0
        continue;
1918
1919
0
      tmp = realloc(hosts, (hostc + 1) * sizeof(*hosts));
1920
0
      if (!tmp)
1921
0
        continue;
1922
0
      hosts = tmp;
1923
0
      hosts[hostc] = strdup(data->name);
1924
0
      if (hosts[hostc])
1925
0
        hostc++;
1926
0
    }
1927
0
  }
1928
1929
0
  for (size_t i = 0; i < hostc; i++) {
1930
0
    INFO("Updating addresses for host %s", hosts[i]);
1931
    /* A count of 0 is intentional: it withdraws that whole family. */
1932
0
    mdnsd_set_addresses_for_host(d, hosts[i], v4, v4c);
1933
0
    mdnsd_set_ipv6_addresses_for_host(d, hosts[i], v6, v6c);
1934
0
    free(hosts[i]);
1935
0
  }
1936
0
  free(hosts);
1937
1938
0
  free(v4);
1939
0
  free(v6);
1940
0
  return 0;
1941
0
}
1942
1943
static int process_in(mdns_daemon_t *d, int sd)
1944
0
{
1945
0
  static unsigned char buf[MAX_PACKET_LEN + 1];
1946
0
  inet_addr_t from;
1947
0
  socklen_t ssize = sizeof(from);
1948
0
  ssize_t bsize;
1949
1950
0
  memset(buf, 0, sizeof(buf));
1951
1952
0
  while ((bsize = recvfrom(sd, buf, MAX_PACKET_LEN, MSG_DONTWAIT, (struct sockaddr *)&from, &ssize)) > 0) {
1953
0
    struct message m = { 0 };
1954
0
    int rc;
1955
1956
0
    buf[MAX_PACKET_LEN] = 0;
1957
0
    mdnsd_log_hex("Got Data:", buf, bsize);
1958
1959
0
    rc = message_parse(&m, buf);
1960
0
    if (rc)
1961
0
      continue;
1962
0
    rc = mdnsd_in(d, &m, &from);
1963
0
    if (rc)
1964
0
      continue;
1965
0
  }
1966
1967
0
  if (bsize < 0 && errno != EAGAIN)
1968
0
    return 1;
1969
1970
0
  return 0;
1971
0
}
1972
1973
static int process_out(mdns_daemon_t *d, int sd)
1974
0
{
1975
0
  inet_addr_t to;
1976
0
  struct message m;
1977
1978
0
  while (mdnsd_out(d, &m, &to)) {
1979
0
    unsigned char *buf;
1980
0
    ssize_t len;
1981
1982
0
    len = message_packet_len(&m);
1983
0
    buf = message_packet(&m);
1984
0
    mdnsd_log_hex("Send Data:", buf, len);
1985
1986
0
    if (sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, inet_len(&to)) != len)
1987
0
      return 2;
1988
0
  }
1989
1990
0
  return 0;
1991
0
}
1992
1993
int mdnsd_step(mdns_daemon_t *d, int sd, bool in, bool out, struct timeval *tv)
1994
0
{
1995
0
  int rc = 0;
1996
1997
0
  if (in)
1998
0
    rc = process_in(d, sd);
1999
0
  if (!rc && out)
2000
0
    rc = process_out(d, sd);
2001
2002
0
  if (!rc && tv) {
2003
0
    struct timeval *delay;
2004
2005
0
    delay = mdnsd_sleep(d);
2006
0
    memcpy(tv, delay, sizeof(*tv));
2007
0
  }
2008
2009
  /* Service Enumeration/Discovery completed */
2010
0
  if (d && d->disco)
2011
0
    d->disco = 0;
2012
2013
0
  return rc;
2014
0
}
2015
2016
void records_clear(mdns_daemon_t *d)
2017
0
{
2018
0
  for (int i = 0; i < SPRIME; i++)
2019
0
  {
2020
0
    mdns_record_t *r = d->published[i];
2021
0
    while (r)
2022
0
    {
2023
0
      mdns_record_t *const next = r->next;
2024
0
      _r_remove_lists(d, r, NULL);
2025
0
      _u_remove(d, r);
2026
0
      _free_record(r);
2027
0
      r = next;
2028
0
    }
2029
    d->published[i] = NULL;
2030
0
  }
2031
0
}