Coverage Report

Created: 2026-05-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/open62541/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-2022  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
169k
#define SPRIME 109    /* Size of query/publish hashes */
41
948k
#define LPRIME 1009    /* Size of cache hash */
42
43
938
#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
  struct in_addr to;
75
  unsigned short port;
76
  mdns_record_t *r;
77
  struct unicast *next;
78
};
79
80
struct cached {
81
  struct mdns_answer rr;
82
  struct query *q;
83
  struct cached *next;
84
};
85
86
struct mdns_record {
87
  struct mdns_answer rr;
88
  char unique;    /* # of checks performed to ensure */
89
  int modified;   /* Ignore conflicts after update at runtime */
90
  int tries;
91
  void (*conflict)(char *, int, void *);
92
  void *arg;
93
  struct timeval last_sent;
94
  struct mdns_record *next, *list;
95
};
96
97
struct mdns_daemon {
98
  char shutdown, disco;
99
  unsigned long int expireall, checkqlist;
100
  struct timeval now, sleep, pause, probe, publish;
101
  int clazz, frame;
102
  struct cached *cache[LPRIME];
103
  struct mdns_record *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
104
  struct unicast *uanswers;
105
  struct query *queries[SPRIME], *qlist;
106
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
8.59k
{
120
8.59k
  const unsigned char *name = (const unsigned char *)s;
121
8.59k
  unsigned long h = 0, g;
122
123
338k
  while (*name) {   /* do some fancy bitwanking on the string */
124
330k
    h = (h << 4) + (unsigned long)(*name++);
125
330k
    if ((g = (h & 0xF0000000UL)) != 0)
126
263k
      h ^= (g >> 24);
127
330k
    h &= ~g;
128
330k
  }
129
130
8.59k
  return (int)h;
131
8.59k
}
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
537
{
136
537
  if (!q)
137
537
    q = d->queries[_namehash(host) % SPRIME];
138
0
  else
139
0
    q = q->next;
140
141
537
  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
537
  return NULL;
147
537
}
148
149
static struct cached *_c_next(mdns_daemon_t *d, struct cached *c,const char *host, int type)
150
1.07k
{
151
1.07k
  if (!c)
152
1.07k
    c = d->cache[_namehash(host) % LPRIME];
153
0
  else
154
0
    c = c->next;
155
156
1.07k
  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
1.07k
  return NULL;
162
1.07k
}
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 strcmp(a->rdname, r->known.ns.name) == 0;
217
218
0
    case QTYPE_A:
219
0
      return memcmp(&r->known.a.ip, &a->ip, 4) == 0;
220
221
0
    case QTYPE_AAAA:
222
0
      return memcmp(&r->known.aaaa.ip6, &a->ip6, 16) == 0;
223
224
0
    default:
225
0
      return r->rdlength == a->rdlen && memcmp(r->rdata, a->rdata, r->rdlength) == 0;
226
0
  }
227
228
0
  return 0;
229
0
}
230
231
/* Compare time values easily */
232
static long _tvdiff(struct timeval old, struct timeval new_)
233
0
{
234
0
  long udiff = 0;
235
236
0
  if (old.tv_sec != new_.tv_sec)
237
0
    udiff = (new_.tv_sec - old.tv_sec) * 1000000;
238
239
0
  return (new_.tv_usec - old.tv_usec) + udiff;
240
0
}
241
242
static void _r_remove_list(mdns_record_t **list, mdns_record_t *r)
243
2.14k
{
244
2.14k
  mdns_record_t *tmp;
245
246
2.14k
  if (*list == r) {
247
0
    *list = r->list;
248
0
    r->list = NULL;
249
0
    return;
250
0
  }
251
252
6.44k
  for (tmp = *list; tmp; tmp = tmp->list) {
253
4.29k
    if (tmp->list == r) {
254
0
      tmp->list = r->list;
255
0
      r->list = NULL;
256
0
      break;
257
0
    }
258
4.29k
    if (tmp == tmp->list)
259
0
      break;
260
4.29k
  }
261
2.14k
}
262
263
static void _r_remove_lists(mdns_daemon_t *d, mdns_record_t *r, mdns_record_t **skip)
264
3.22k
{
265
3.22k
  if (d->probing && &d->probing != skip)
266
1.07k
    _r_remove_list(&d->probing, r);
267
268
3.22k
  if (d->a_now && &d->a_now != skip)
269
0
    _r_remove_list(&d->a_now, r);
270
271
3.22k
  if (d->a_pause && &d->a_pause != skip)
272
0
    _r_remove_list(&d->a_pause, r);
273
274
3.22k
  if (d->a_publish && &d->a_publish != skip)
275
1.07k
    _r_remove_list(&d->a_publish, r);
276
3.22k
}
277
278
/* Make sure not already on the list, then insert */
279
static void _r_push(mdns_record_t **list, mdns_record_t *r)
280
3.22k
{
281
3.22k
  mdns_record_t *cur;
282
283
6.98k
  for (cur = *list; cur != 0; cur = cur->list) {
284
3.75k
    if (cur == r)
285
0
      return;
286
3.75k
  }
287
288
3.22k
  r->list = *list;
289
3.22k
  *list = r;
290
3.22k
}
291
292
/* Force any r out right away, if valid */
293
static void _r_publish(mdns_daemon_t *d, mdns_record_t *r)
294
3.22k
{
295
3.22k
  r->modified = 1;
296
297
3.22k
  if (r->unique && r->unique < 5)
298
1.07k
    return;    /* Probing already */
299
300
2.14k
  r->tries = 0;
301
2.14k
  d->publish.tv_sec = d->now.tv_sec;
302
2.14k
  d->publish.tv_usec = d->now.tv_usec;
303
304
  /* check if r already in other lists. If yes, remove it from there */
305
2.14k
  _r_remove_lists(d, r, &d->a_publish);
306
2.14k
  _r_push(&d->a_publish, r);
307
2.14k
}
308
309
/* send r out asap */
310
static void _r_send(mdns_daemon_t *d, mdns_record_t *r)
311
1.07k
{
312
  /* Being published, make sure that happens soon */
313
1.07k
  if (r->tries < 4) {
314
1.07k
    d->publish.tv_sec = d->now.tv_sec;
315
1.07k
    d->publish.tv_usec = d->now.tv_usec;
316
1.07k
    return;
317
1.07k
  }
318
319
  /* Known unique ones can be sent asap */
320
0
  if (r->unique) {
321
    /* check if r already in other lists. If yes, remove it from there */
322
0
    _r_remove_lists(d, r, &d->a_now);
323
0
    _r_push(&d->a_now, r);
324
0
    return;
325
0
  }
326
327
  /* Set d->pause.tv_usec to random 20-120 msec */
328
0
  d->pause.tv_sec = d->now.tv_sec;
329
0
  d->pause.tv_usec = d->now.tv_usec + (d->now.tv_usec % 100) + 20;
330
331
  /* check if r already in other lists. If yes, remove it from there */
332
0
  _r_remove_lists(d, r, &d->a_pause);
333
0
  _r_push(&d->a_pause, r);
334
0
}
335
336
/* Create generic unicast response struct */
337
static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, struct in_addr to, unsigned short port)
338
0
{
339
0
  struct unicast *u;
340
341
0
  u = calloc(1, sizeof(struct unicast));
342
0
  if (!u)
343
0
    return;
344
345
0
  u->r = r;
346
0
  u->id = id;
347
0
  u->to = to;
348
0
  u->port = port;
349
0
  u->next = d->uanswers;
350
0
  d->uanswers = u;
351
0
}
352
353
static void _q_reset(mdns_daemon_t *d, struct query *q)
354
537
{
355
537
  struct cached *cur = 0;
356
357
537
  q->nexttry = 0;
358
537
  q->tries = 0;
359
360
537
  while ((cur = _c_next(d, cur, q->name, q->type))) {
361
0
    if (q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry)
362
0
      q->nexttry = cur->rr.ttl - 7;
363
0
  }
364
365
537
  if (q->nexttry != 0 && q->nexttry < d->checkqlist)
366
0
    d->checkqlist = q->nexttry;
367
537
}
368
369
/* No more queries, update all its cached entries, remove from lists */
370
static void _q_done(mdns_daemon_t *d, struct query *q)
371
0
{
372
0
  struct cached *c = 0;
373
0
  struct query *cur;
374
0
  int i = _namehash(q->name) % SPRIME;
375
376
0
  while ((c = _c_next(d, c, q->name, q->type)))
377
0
    c->q = 0;
378
379
0
  if (d->qlist == q) {
380
0
    d->qlist = q->list;
381
0
  } else {
382
0
    for (cur = d->qlist; cur->list != q; cur = cur->list)
383
0
      ;
384
0
    cur->list = q->list;
385
0
  }
386
387
0
  if (d->queries[i] == q) {
388
0
    d->queries[i] = q->next;
389
0
  } else {
390
0
    for (cur = d->queries[i]; cur->next != q; cur = cur->next)
391
0
      ;
392
0
    cur->next = q->next;
393
0
  }
394
395
0
  free(q->name);
396
0
  free(q);
397
0
}
398
399
static void _free_cached(struct cached *c)
400
0
{
401
0
  if (!c)
402
0
    return;
403
404
0
  if (c->rr.name) {
405
0
    free(c->rr.name);
406
0
    c->rr.name = NULL;
407
0
  }
408
0
  if (c->rr.rdata) {
409
0
    free(c->rr.rdata);
410
0
    c->rr.rdata = NULL;
411
0
  }
412
0
  if (c->rr.rdname) {
413
0
    free(c->rr.rdname);
414
0
    c->rr.rdname = NULL;
415
0
  }
416
0
  free(c);
417
0
}
418
419
static void _free_record(mdns_record_t *r)
420
3.22k
{
421
3.22k
  if (!r)
422
0
    return;
423
424
3.22k
  if (r->rr.name) {
425
3.22k
    free(r->rr.name);
426
3.22k
    r->rr.name = NULL;
427
3.22k
  }
428
3.22k
  if (r->rr.rdata) {
429
1.61k
    free(r->rr.rdata);
430
1.61k
    r->rr.rdata = NULL;
431
1.61k
  }
432
3.22k
  if (r->rr.rdname) {
433
1.61k
    free(r->rr.rdname);
434
1.61k
    r->rr.rdname = NULL;
435
1.61k
  }
436
3.22k
  free(r);
437
3.22k
}
438
439
/* buh-bye, remove from hash and free */
440
static void _r_done(mdns_daemon_t *d, mdns_record_t *r)
441
1.07k
{
442
1.07k
  mdns_record_t *cur = 0;
443
1.07k
  int i;
444
445
1.07k
  if (!r || !r->rr.name)
446
0
    return;
447
448
1.07k
  i = _namehash(r->rr.name) % SPRIME;
449
1.07k
  if (d->published[i] == r) {
450
537
    d->published[i] = r->next;
451
537
  } else {
452
537
    for (cur = d->published[i]; cur && cur->next != r; cur = cur->next)
453
0
      ;
454
537
    if (cur)
455
537
      cur->next = r->next;
456
537
  }
457
458
1.07k
  _free_record(r);
459
1.07k
}
460
461
/* Call the answer function with this cached entry */
462
static void _q_answer(mdns_daemon_t *d, struct cached *c)
463
0
{
464
0
  if (c->rr.ttl <= (unsigned long)d->now.tv_sec)
465
0
    c->rr.ttl = 0;
466
0
  if (c->q->answer(&c->rr, c->q->arg) == -1)
467
0
    _q_done(d, c->q);
468
0
}
469
470
static void _conflict(mdns_daemon_t *d, mdns_record_t *r)
471
0
{
472
0
  r->conflict(r->rr.name, r->rr.type, r->arg);
473
0
  mdnsd_done(d, r);
474
0
}
475
476
/* Expire any old entries in this list */
477
static void _c_expire(mdns_daemon_t *d, struct cached **list)
478
0
{
479
0
  struct cached *cur  = *list;
480
0
  struct cached *last = NULL;
481
0
  struct cached *next;
482
483
0
  while (cur) {
484
0
    next = cur->next;
485
486
0
    if ((unsigned long)d->now.tv_sec >= cur->rr.ttl) {
487
0
      if (last)
488
0
        last->next = next;
489
490
      /* Update list pointer if the first one expired */
491
0
      if (*list == cur)
492
0
        *list = next;
493
494
0
      if (cur->q)
495
0
        _q_answer(d, cur);
496
497
0
      _free_cached(cur);
498
0
    } else {
499
0
      last = cur;
500
0
    }
501
0
    cur = next;
502
0
  }
503
0
}
504
505
/* Brute force expire any old cached records */
506
static void _gc(mdns_daemon_t *d)
507
0
{
508
0
  int i;
509
510
0
  for (i = 0; i < LPRIME; i++) {
511
0
    if (d->cache[i])
512
0
      _c_expire(d, &d->cache[i]);
513
0
  }
514
515
0
  d->expireall = (unsigned long)(d->now.tv_sec + GC);
516
0
}
517
518
static int _cache(mdns_daemon_t *d, struct resource *r, struct in_addr ip)
519
0
{
520
0
  unsigned long int ttl;
521
0
  struct cached *c = 0;
522
0
  int i = _namehash(r->name) % LPRIME;
523
524
  /* Cache flush for unique entries */
525
0
  if (r->clazz == 32768 + d->clazz) {
526
0
    while ((c = _c_next(d, c, r->name, r->type)))
527
0
      c->rr.ttl = 0;
528
0
    _c_expire(d, &d->cache[i]);
529
0
  }
530
531
  /* Process deletes */
532
0
  if (r->ttl == 0) {
533
0
    while ((c = _c_next(d, c, r->name, r->type))) {
534
0
      if (_a_match(r, &c->rr)) {
535
0
        c->rr.ttl = 0;
536
0
        _c_expire(d, &d->cache[i]);
537
0
        c = NULL;
538
0
      }
539
0
    }
540
541
0
    return 0;
542
0
  }
543
544
  /*
545
   * XXX: The c->rr.ttl is a hack for now, BAD SPEC, start
546
   *      retrying just after half-waypoint, then expire
547
   */
548
0
  ttl = (unsigned long)d->now.tv_sec + (r->ttl / 2) + 8;
549
550
  /* If entry already exists, only udpate TTL value */
551
0
  c = NULL;
552
0
  while ((c = _c_next(d, c, r->name, r->type))) {
553
0
    if (r->type == QTYPE_PTR && strcmp(c->rr.rdname, r->known.ns.name)) {
554
0
      continue;
555
0
    }
556
0
    c->rr.ttl = ttl;
557
0
    return 0;
558
0
  }
559
560
  /* New entry, cache it */
561
0
  c = calloc(1, sizeof(struct cached));
562
0
  if (!c)
563
0
    return 1;
564
565
0
  c->rr.name = strdup(r->name);
566
0
  if (!c->rr.name) {
567
0
    free(c);
568
0
    return 1;
569
0
  }
570
0
  c->rr.type = r->type;
571
0
  c->rr.ttl = ttl;
572
0
  c->rr.rdlen = r->rdlength;
573
0
  if (r->rdlength && !r->rdata) {
574
//    ERR("rdlength is %d but rdata is NULL for domain name %s, type: %d, ttl: %ld", r->rdlength, r->name, r->type, r->ttl);
575
0
    free(c->rr.name);
576
0
    free(c);
577
0
    return 1;
578
0
  }
579
0
  if (r->rdlength) {
580
0
    c->rr.rdata = malloc(r->rdlength);
581
0
    if (!c->rr.rdata) {
582
0
      free(c->rr.name);
583
0
      free(c);
584
0
      return 1;
585
0
    }
586
0
    memcpy(c->rr.rdata, r->rdata, r->rdlength);
587
0
  } else {
588
0
    c->rr.rdata = NULL;
589
0
  }
590
591
0
  switch (r->type) {
592
0
  case QTYPE_A:
593
0
    c->rr.ip = r->known.a.ip;
594
0
    break;
595
596
0
  case QTYPE_AAAA:
597
0
    c->rr.ip6 = r->known.aaaa.ip6;
598
0
    break;
599
600
0
  case QTYPE_NS:
601
0
  case QTYPE_CNAME:
602
0
  case QTYPE_PTR:
603
0
    c->rr.rdname = strdup(r->known.ns.name);
604
0
    c->rr.ip = ip;
605
0
    break;
606
607
0
  case QTYPE_SRV:
608
0
    c->rr.rdname = strdup(r->known.srv.name);
609
0
    c->rr.srv.port = r->known.srv.port;
610
0
    c->rr.srv.weight = r->known.srv.weight;
611
0
    c->rr.srv.priority = r->known.srv.priority;
612
0
    break;
613
0
  }
614
615
0
  c->next = d->cache[i];
616
0
  d->cache[i] = c;
617
618
0
  if ((c->q = _q_next(d, 0, r->name, r->type)))
619
0
    _q_answer(d, c);
620
621
0
  return 0;
622
0
}
623
624
/* Copy the data bits only */
625
static void _a_copy(struct message *m, mdns_answer_t *a)
626
0
{
627
0
  if (a->rdata) {
628
0
    message_rdata_raw(m, a->rdata, a->rdlen);
629
0
    return;
630
0
  }
631
632
0
  if (a->ip.s_addr)
633
0
    message_rdata_ipv4(m, a->ip);
634
0
  else if (!IN6_IS_ADDR_UNSPECIFIED(&(a->ip6)))
635
0
    message_rdata_ipv6(m, a->ip6);
636
0
  if (a->type == QTYPE_SRV)
637
0
    message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
638
0
  else if (a->rdname)
639
0
    message_rdata_name(m, a->rdname);
640
0
}
641
642
/* Copy a published record into an outgoing message */
643
static int _r_out(mdns_daemon_t *d, struct message *m, mdns_record_t **list)
644
0
{
645
0
  mdns_record_t *r;
646
0
  int ret = 0;
647
648
0
  while ((r = *list) != NULL && message_packet_len(m) + (int)_rr_len(&r->rr) < d->frame) {
649
0
    if (r != r->list)
650
0
      *list = r->list;
651
0
    else
652
0
      *list = NULL;
653
654
    /* Service enumeration/discovery, drop non-PTR replies */
655
0
    if (d->disco) {
656
0
      if (r->rr.type != QTYPE_PTR)
657
0
        continue;
658
659
0
      if (strcmp(r->rr.name, DISCO_NAME))
660
0
        continue;
661
0
    }
662
663
0
    INFO("Appending name: %s, type %d to outbound message ...", r->rr.name, r->rr.type);
664
0
    ret++;
665
666
0
    if (r->unique)
667
0
      message_an(m, r->rr.name, r->rr.type, d->clazz + 32768, r->rr.ttl);
668
0
    else
669
0
      message_an(m, r->rr.name, r->rr.type, d->clazz, r->rr.ttl);
670
0
    r->last_sent = d->now;
671
672
0
    _a_copy(m, &r->rr);
673
674
0
    r->modified = 0; /* If updated we've now sent the update. */
675
0
    if (r->rr.ttl == 0) {
676
      /*
677
       * also remove from other lists, because record
678
       * may be in multiple lists at the same time
679
       */
680
0
      _r_remove_lists(d, r, list);
681
0
      _r_done(d, r);
682
0
    }
683
0
  }
684
685
0
  return ret;
686
0
}
687
688
/* Refresh cached local IPv4 addresses if needed (every ~5s) */
689
static void _refresh_local_ipv4(mdns_daemon_t *d, bool force)
690
0
{
691
0
  struct ifaddrs *ifa = NULL;
692
693
  /* Refresh at most every 5 seconds */
694
0
  if (d->local_addrs_refreshed && (d->now.tv_sec - d->local_addrs_refreshed) < LOCAL_ADDR_REFRESH_INTERVAL && !force)
695
0
    return;
696
697
0
  if (getifaddrs(&ifa) != 0)
698
0
    return;
699
700
  /* Swap in the latest snapshot */
701
0
  if (d->local_ifaddrs)
702
0
    freeifaddrs(d->local_ifaddrs);
703
0
  d->local_ifaddrs = ifa;
704
0
  d->local_addrs_refreshed = d->now.tv_sec ? d->now.tv_sec : time(NULL);
705
0
}
706
707
/* Check if an IPv4 address belongs to this host (any interface) */
708
static bool _is_local_ipv4(mdns_daemon_t *d, struct in_addr ip)
709
401
{
710
401
  struct ifaddrs *it;
711
712
  /* Always consider the primary configured address as local */
713
401
  if (ip.s_addr == d->addr.s_addr)
714
401
    return true;
715
716
0
  _refresh_local_ipv4(d, false);
717
718
0
  for (it = d->local_ifaddrs; it; it = it->ifa_next) {
719
0
    struct sockaddr_in *sin;
720
0
    if (!it->ifa_addr)
721
0
      continue;
722
0
    if (it->ifa_addr->sa_family != AF_INET)
723
0
      continue;
724
0
    sin = (struct sockaddr_in *)it->ifa_addr;
725
0
    if (sin->sin_addr.s_addr == ip.s_addr)
726
0
      return true;
727
0
  }
728
729
0
  return false;
730
0
}
731
732
mdns_daemon_t *mdnsd_new(int clazz, int frame)
733
938
{
734
938
  mdns_daemon_t *d;
735
736
938
  d = calloc(1, sizeof(struct mdns_daemon));
737
938
  if (!d)
738
0
    return NULL;
739
740
938
  gettimeofday(&d->now, 0);
741
938
  d->expireall = (unsigned long)d->now.tv_sec + GC;
742
938
  d->clazz = clazz;
743
938
  d->frame = frame;
744
938
  d->received_callback = NULL;
745
938
  d->local_ifaddrs = NULL;
746
938
  d->local_addrs_refreshed = 0;
747
748
938
  return d;
749
938
}
750
751
void mdnsd_set_address(mdns_daemon_t *d, struct in_addr addr)
752
0
{
753
0
  int i;
754
755
0
  if (!memcmp(&d->addr, &addr, sizeof(d->addr)))
756
0
    return;   /* No change */
757
758
0
  for (i = 0; i < SPRIME; i++) {
759
0
    mdns_record_t *r, *next;
760
761
0
    r = d->published[i];
762
0
    while (r) {
763
0
      next = r->next;
764
765
0
      if (r->rr.type == QTYPE_A) {
766
0
        if (addr.s_addr == 0) {
767
0
          r->rr.ttl = 0;
768
0
          r->list = d->a_now;
769
0
          d->a_now = r;
770
0
        } else {
771
0
          mdnsd_set_ip(d, r, addr);
772
0
        }
773
0
      }
774
775
0
      r = next;
776
0
    }
777
0
  }
778
779
0
  d->addr = addr;
780
0
}
781
782
struct in_addr mdnsd_get_address(mdns_daemon_t *d)
783
0
{
784
0
  return d->addr;
785
0
}
786
787
void mdnsd_set_ipv6_address(mdns_daemon_t *d, struct in6_addr addr)
788
0
{
789
0
  int i;
790
791
0
  if (!memcmp(&d->addr_v6, &addr, sizeof(d->addr_v6)))
792
0
    return;   /* No change */
793
794
0
  for (i = 0; i < SPRIME; i++) {
795
0
    mdns_record_t *r, *next;
796
797
0
    r = d->published[i];
798
0
    while (r) {
799
0
      next = r->next;
800
801
0
      if (r->rr.type == QTYPE_AAAA) {
802
0
        if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
803
0
          r->rr.ttl = 0;
804
0
          r->list = d->a_now;
805
0
          d->a_now = r;
806
0
        } else {
807
0
          mdnsd_set_ipv6(d, r, addr);
808
0
        }
809
0
      }
810
811
0
      r = next;
812
0
    }
813
0
  }
814
815
0
  d->addr_v6 = addr;
816
0
}
817
818
struct in6_addr mdnsd_get_ipv6_address(mdns_daemon_t *d)
819
0
{
820
0
  return d->addr_v6;
821
0
}
822
823
/* Shutting down, zero out ttl and push out all records */
824
void mdnsd_shutdown(mdns_daemon_t *d)
825
537
{
826
537
  int i;
827
537
  mdns_record_t *cur, *next;
828
829
537
  if (!d)
830
0
    return;
831
832
537
  d->a_now = 0;
833
59.0k
  for (i = 0; i < SPRIME; i++) {
834
60.6k
    for (cur = d->published[i]; cur != 0;) {
835
2.14k
      next = cur->next;
836
2.14k
      cur->rr.ttl = 0;
837
2.14k
      cur->list = d->a_now;
838
2.14k
      d->a_now = cur;
839
2.14k
      cur = next;
840
2.14k
    }
841
58.5k
  }
842
843
537
  d->shutdown = 1;
844
537
}
845
846
void mdnsd_flush(mdns_daemon_t *d)
847
0
{
848
0
  (void)d;
849
  /* - Set all querys to 0 tries
850
   * - Free whole cache
851
   * - Set all mdns_record_t *to probing
852
   * - Reset all answer lists
853
   */
854
0
}
855
856
void mdnsd_free(mdns_daemon_t *d)
857
938
{
858
938
  struct unicast *u;
859
860
938
  if (!d)
861
0
    return;
862
863
947k
  for (size_t i = 0; i< LPRIME; i++) {
864
946k
    struct cached *cur = d->cache[i];
865
866
946k
    while (cur) {
867
0
      struct cached *next = cur->next;
868
869
0
      cur->next = NULL;
870
0
      _free_cached(cur);
871
0
      cur = next;
872
0
    }
873
946k
  }
874
875
103k
  for (size_t i = 0; i< SPRIME; i++) {
876
102k
    struct mdns_record *cur = d->published[i];
877
102k
    struct query *curq;
878
879
104k
    while (cur) {
880
2.14k
      struct mdns_record *next = cur->next;
881
882
2.14k
      cur->next = NULL;
883
2.14k
      _free_record(cur);
884
2.14k
      cur = next;
885
2.14k
    }
886
887
102k
    curq = d->queries[i];
888
102k
    while (curq) {
889
537
      struct query *next = curq->next;
890
891
537
      curq->next = NULL;
892
537
      free(curq->name);
893
537
      free(curq);
894
537
      curq = next;
895
537
    }
896
102k
  }
897
898
938
  u = d->uanswers;
899
938
  while (u) {
900
0
    struct unicast *next = u->next;
901
902
0
    u->next = NULL;
903
0
    free(u);
904
0
    u = next;
905
0
  }
906
907
938
  if (d->local_ifaddrs)
908
0
    freeifaddrs(d->local_ifaddrs);
909
910
938
  free(d);
911
938
}
912
913
914
void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_callback cb, void* data)
915
537
{
916
537
  d->received_callback = cb;
917
537
  d->received_callback_data = data;
918
537
}
919
920
int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned short port)
921
401
{
922
401
  mdns_record_t *r = NULL;
923
401
  int i, j;
924
401
  bool did_addr_refresh = false;
925
926
401
  if (d->shutdown)
927
0
    return 1;
928
929
401
  gettimeofday(&d->now, 0);
930
931
  /* Ignore packets originated from any of our local IPv4 addresses */
932
401
  if (_is_local_ipv4(d, ip))
933
401
    return 0;
934
935
0
  if (m->header.qr == 0) {
936
    /* Process each query */
937
0
    for (i = 0; i < m->qdcount; i++) {
938
0
      mdns_record_t *r_start, *r_next;
939
0
      bool has_conflict = false;
940
941
0
      if (!m->qd || m->qd[i].clazz != d->clazz)
942
0
        continue;
943
944
0
      INFO("Query for %s of type %d ...", m->qd[i].name, m->qd[i].type);
945
0
      r = _r_next(d, NULL, m->qd[i].name, m->qd[i].type);
946
0
      if (!r)
947
0
        continue;
948
949
      /* Service enumeration/discovery prepare to send all matching records */
950
0
      if (!strcmp(m->qd[i].name, DISCO_NAME)) {
951
0
        d->disco = 1;
952
0
        while (r) {
953
0
          if (!strcmp(r->rr.name, DISCO_NAME))
954
0
            _r_send(d, r);
955
0
          r = _r_next(d, r, m->qd[i].name, m->qd[i].type);
956
0
        }
957
958
0
        continue;
959
0
      }
960
961
      /* Check all of our potential answers */
962
0
      for (r_start = r; r != NULL; r = r_next) {
963
0
        INFO("Local record: %s, type: %d, rdname: %s", r->rr.name, r->rr.type, r->rr.rdname);
964
965
        /* Fetch next here, because _conflict() might delete r, invalidating next */
966
0
        r_next = _r_next(d, r, m->qd[i].name, m->qd[i].type);
967
968
        /* probing state, check for conflicts */
969
0
        if (r->unique && r->unique < 5 && !r->modified) {
970
          /* Check all to-be answers against our own */
971
0
          for (j = 0; j < m->ancount; j++) {
972
0
            if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
973
0
              continue;
974
975
            /* This answer isn't ours, conflict! */
976
0
            if (!_a_match(&m->an[j], &r->rr)) {
977
              /* Before flagging conflict, force a local address refresh and re-check */
978
0
              if (!did_addr_refresh) {
979
0
                did_addr_refresh = true;
980
0
                _refresh_local_ipv4(d, true);
981
0
              }
982
0
              if (_is_local_ipv4(d, ip))
983
0
                continue;
984
0
              _conflict(d, r);
985
0
              has_conflict = true;
986
0
              break;
987
0
            }
988
0
          }
989
0
          continue;
990
0
        }
991
992
        /* Check the known answers for this question */
993
0
        for (j = 0; j < m->ancount; j++) {
994
0
          if (!m->an || m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
995
0
            continue;
996
997
0
          if (d->received_callback)
998
0
            d->received_callback(&m->an[j], d->received_callback_data);
999
1000
          /* Do they already have this answer? */
1001
0
          if (_a_match(&m->an[j], &r->rr))
1002
0
            break;
1003
0
        }
1004
1005
0
        INFO("Should we send answer? j: %d, m->ancount: %d", j, m->ancount);
1006
0
        if (j == m->ancount) {
1007
0
          INFO("Yes we should, enquing %s for outbound", r->rr.name);
1008
0
          _r_send(d, r);
1009
0
        }
1010
0
      }
1011
1012
      /* Send the matching unicast reply */
1013
0
      if (!has_conflict && port != 5353)
1014
0
        _u_push(d, r_start, m->id, ip, port);
1015
0
    }
1016
1017
0
    return 0;
1018
0
  }
1019
1020
  /* Process each answer, check for a conflict, and cache */
1021
0
  for (i = 0; i < m->ancount; i++) {
1022
0
    if (!m->an)
1023
0
      continue;
1024
1025
0
    if (!m->an[i].name) {
1026
0
      ERR("Got answer with NULL name at %p. Type: %d, TTL: %ld, skipping",
1027
0
          (void*)&m->an[i], m->an[i].type, m->an[i].ttl);
1028
0
      continue;
1029
0
    }
1030
1031
0
    INFO("Got Answer: Name: %s, Type: %d", m->an[i].name, m->an[i].type);
1032
0
    r = _r_next(d, NULL, m->an[i].name, m->an[i].type);
1033
0
    if (r && r->unique && r->modified && _a_match(&m->an[i], &r->rr)) {
1034
      /* double check, is this actually from us, looped back? */
1035
0
      if (!did_addr_refresh) {
1036
0
        did_addr_refresh = true;
1037
0
        _refresh_local_ipv4(d, true);
1038
0
      }
1039
0
      if (_is_local_ipv4(d, ip))
1040
0
        continue;
1041
0
      _conflict(d, r);
1042
0
    }
1043
1044
0
    if (d->received_callback)
1045
0
      d->received_callback(&m->an[i], d->received_callback_data);
1046
1047
0
    if (_cache(d, &m->an[i], ip) != 0) {
1048
0
      ERR("Failed caching answer, possibly too long packet, skipping.");
1049
0
      continue;
1050
0
    }
1051
0
  }
1052
1053
0
  return 0;
1054
0
}
1055
1056
int mdnsd_out(mdns_daemon_t *d, struct message *m, struct in_addr *ip, unsigned short *port)
1057
0
{
1058
0
  mdns_record_t *r;
1059
0
  int ret = 0;
1060
1061
0
  gettimeofday(&d->now, 0);
1062
0
  memset(m, 0, sizeof(struct message));
1063
1064
  /* Defaults, multicast */
1065
0
  *port = htons(5353);
1066
0
  ip->s_addr = inet_addr("224.0.0.251");
1067
0
  m->header.qr = 1;
1068
0
  m->header.aa = 1;
1069
1070
  /* Send out individual unicast answers */
1071
0
  if (d->uanswers) {
1072
0
    struct unicast *u = d->uanswers;
1073
1074
0
    INFO("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type);
1075
1076
0
    d->uanswers = u->next;
1077
0
    *port = htons(u->port);
1078
0
    *ip = u->to;
1079
0
    m->id = u->id;
1080
0
    message_qd(m, u->r->rr.name, u->r->rr.type, d->clazz);
1081
0
    message_an(m, u->r->rr.name, u->r->rr.type, d->clazz, u->r->rr.ttl);
1082
0
    u->r->last_sent = d->now;
1083
0
    _a_copy(m, &u->r->rr);
1084
0
    free(u);
1085
1086
0
    return 1;
1087
0
  }
1088
1089
  /* Accumulate any immediate responses */
1090
0
  if (d->a_now)
1091
0
    ret += _r_out(d, m, &d->a_now);
1092
1093
  /* Check if it's time to send the publish retries (unlink if done) */
1094
0
  if (!d->probing && d->a_publish && _tvdiff(d->now, d->publish) <= 0) {
1095
0
    mdns_record_t *cur = d->a_publish;
1096
0
    mdns_record_t *last = NULL;
1097
0
    mdns_record_t *next;
1098
1099
0
    while (cur && message_packet_len(m) + (int)_rr_len(&cur->rr) < d->frame) {
1100
0
      if (cur->rr.type == QTYPE_PTR) {
1101
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);
1102
0
      } else if (cur->rr.type == QTYPE_SRV) {
1103
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);
1104
0
      } else {
1105
0
        INFO("Send Publish: Name: %s, Type: %d, rdname: %s", cur->rr.name, cur->rr.type, cur->rr.rdname);
1106
0
      }
1107
1108
0
      next = cur->list;
1109
0
      ret++;
1110
0
      cur->tries++;
1111
1112
0
      if (cur->unique)
1113
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz + 32768, cur->rr.ttl);
1114
0
      else
1115
0
        message_an(m, cur->rr.name, cur->rr.type, d->clazz, cur->rr.ttl);
1116
0
      _a_copy(m, &cur->rr);
1117
0
      cur->last_sent = d->now;
1118
1119
0
      if (cur->rr.ttl != 0 && cur->tries < 4) {
1120
0
        last = cur;
1121
0
        cur = next;
1122
0
        continue;
1123
0
      }
1124
1125
0
      cur->list = NULL;
1126
0
      if (d->a_publish == cur)
1127
0
        d->a_publish = next;
1128
0
      if (last)
1129
0
        last->list = next;
1130
0
      if (cur->rr.ttl == 0)
1131
0
        _r_done(d, cur);
1132
0
      cur = next;
1133
0
    }
1134
1135
0
    if (d->a_publish) {
1136
0
      d->publish.tv_sec = d->now.tv_sec + 2;
1137
0
      d->publish.tv_usec = d->now.tv_usec;
1138
0
    }
1139
0
  }
1140
1141
  /* If we're in shutdown, we're done */
1142
0
  if (d->shutdown)
1143
0
    return ret;
1144
1145
  /* Check if a_pause is ready */
1146
0
  if (d->a_pause && _tvdiff(d->now, d->pause) <= 0)
1147
0
    ret += _r_out(d, m, &d->a_pause);
1148
1149
  /* Now process questions */
1150
0
  if (ret)
1151
0
    return ret;
1152
1153
0
  m->header.qr = 0;
1154
0
  m->header.aa = 0;
1155
1156
0
  if (d->probing && _tvdiff(d->now, d->probe) <= 0) {
1157
0
    mdns_record_t *last = 0;
1158
1159
    /* Scan probe list to ask questions and process published */
1160
0
    for (r = d->probing; r != NULL;) {
1161
      /* Done probing, publish */
1162
0
      if (r->unique == 4) {
1163
0
        mdns_record_t *next = r->list;
1164
1165
0
        if (d->probing == r)
1166
0
          d->probing = r->list;
1167
0
        else if (last)
1168
0
          last->list = r->list;
1169
1170
0
        r->list = 0;
1171
0
        r->unique = 5;
1172
0
        _r_publish(d, r);
1173
0
        r = next;
1174
0
        continue;
1175
0
      }
1176
1177
0
      INFO("Send Probing: Name: %s, Type: %d", r->rr.name, r->rr.type);
1178
1179
0
      message_qd(m, r->rr.name, r->rr.type, (unsigned short)d->clazz);
1180
0
      r->last_sent = d->now;
1181
0
      last = r;
1182
0
      r = r->list;
1183
0
    }
1184
1185
    /* Scan probe list again to append our to-be answers */
1186
0
    for (r = d->probing; r != 0; r = r->list) {
1187
0
      r->unique++;
1188
1189
0
      INFO("Send Answer in Probe: Name: %s, Type: %d", r->rr.name, r->rr.type);
1190
0
      message_ns(m, r->rr.name, r->rr.type, (unsigned short)d->clazz, r->rr.ttl);
1191
0
      _a_copy(m, &r->rr);
1192
0
      r->last_sent = d->now;
1193
0
      ret++;
1194
0
    }
1195
1196
    /* Process probes again in the future */
1197
0
    if (ret) {
1198
0
      d->probe.tv_sec = d->now.tv_sec;
1199
0
      d->probe.tv_usec = d->now.tv_usec + 250000;
1200
0
      return ret;
1201
0
    }
1202
0
  }
1203
1204
  /* Process qlist for retries or expirations */
1205
0
  if (d->checkqlist && (unsigned long)d->now.tv_sec >= d->checkqlist) {
1206
0
    struct query *q;
1207
0
    struct cached *c;
1208
0
    unsigned long int nextbest = 0;
1209
1210
    /* Ask questions first, track nextbest time */
1211
0
    for (q = d->qlist; q != 0; q = q->list) {
1212
0
      if (q->nexttry > 0 && q->nexttry <= (unsigned long)d->now.tv_sec && q->tries < 3)
1213
0
        message_qd(m, q->name, q->type, d->clazz);
1214
0
      else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
1215
0
        nextbest = q->nexttry;
1216
0
    }
1217
1218
    /* Include known answers, update questions */
1219
0
    for (q = d->qlist; q != 0; q = q->list) {
1220
0
      if (q->nexttry == 0 || q->nexttry > (unsigned long)d->now.tv_sec)
1221
0
        continue;
1222
1223
      /* Done retrying, expire and reset */
1224
0
      if (q->tries == 3) {
1225
0
        _c_expire(d, &d->cache[_namehash(q->name) % LPRIME]);
1226
0
        _q_reset(d, q);
1227
0
        continue;
1228
0
      }
1229
1230
0
      ret++;
1231
0
      q->nexttry = d->now.tv_sec + ++q->tries;
1232
0
      if (nextbest == 0 || q->nexttry < nextbest)
1233
0
        nextbest = q->nexttry;
1234
1235
      /* If room, add all known good entries */
1236
0
      c = 0;
1237
0
      while ((c = _c_next(d, c, q->name, q->type)) != 0 && c->rr.ttl > (unsigned long)d->now.tv_sec + 8 &&
1238
0
        message_packet_len(m) + (int)_rr_len(&c->rr) < d->frame) {
1239
1240
0
        INFO("Add known answer: Name: %s, Type: %d", c->rr.name, c->rr.type);
1241
0
        message_an(m, q->name, (unsigned short)q->type, (unsigned short)d->clazz, c->rr.ttl - (unsigned long)d->now.tv_sec);
1242
0
        _a_copy(m, &c->rr);
1243
0
      }
1244
0
    }
1245
0
    d->checkqlist = nextbest;
1246
0
  }
1247
1248
0
  if ((unsigned long)d->now.tv_sec > d->expireall)
1249
0
    _gc(d);
1250
1251
0
  return ret;
1252
0
}
1253
1254
1255
0
#define RET do {       \
1256
0
  while (d->sleep.tv_usec > 1000000) { \
1257
0
    d->sleep.tv_sec++;    \
1258
0
    d->sleep.tv_usec -= 1000000;  \
1259
0
  }          \
1260
0
  return &d->sleep;     \
1261
0
} while (0)
1262
1263
struct timeval *mdnsd_sleep(mdns_daemon_t *d)
1264
0
{
1265
0
  time_t expire;
1266
0
  long usec;
1267
1268
0
  d->sleep.tv_sec = d->sleep.tv_usec = 0;
1269
1270
  /* First check for any immediate items to handle */
1271
0
  if (d->uanswers || d->a_now)
1272
0
    return &d->sleep;
1273
1274
0
  gettimeofday(&d->now, 0);
1275
1276
  /* Then check for paused answers or nearly expired records */
1277
0
  if (d->a_pause) {
1278
0
    if ((usec = _tvdiff(d->now, d->pause)) > 0)
1279
0
      d->sleep.tv_usec = usec;
1280
0
    RET;
1281
0
  }
1282
1283
  /* Now check for probe retries */
1284
0
  if (d->probing) {
1285
0
    if ((usec = _tvdiff(d->now, d->probe)) > 0)
1286
0
      d->sleep.tv_usec = usec;
1287
0
    RET;
1288
0
  }
1289
1290
  /* Now check for publish retries */
1291
0
  if (d->a_publish) {
1292
0
    if ((usec = _tvdiff(d->now, d->publish)) > 0)
1293
0
      d->sleep.tv_usec = usec;
1294
0
    RET;
1295
0
  }
1296
1297
  /* Also check for queries with known answer expiration/retry */
1298
0
  if (d->checkqlist) {
1299
0
    long sec;
1300
0
    if ((sec = (long)d->checkqlist - d->now.tv_sec) > 0)
1301
0
      d->sleep.tv_sec = sec;
1302
0
    RET;
1303
0
  }
1304
1305
  /* Resend published records before TTL expires */
1306
0
  expire = (long)d->expireall - d->now.tv_sec;
1307
0
  if (expire < 0)
1308
0
    RET;
1309
1310
0
  for (size_t i = 0; i < SPRIME; i++) {
1311
0
    mdns_record_t *r;
1312
0
    time_t next;
1313
1314
0
    r = d->published[i];
1315
0
    if (!r)
1316
0
      continue;
1317
1318
    /* Publish 2 seconds before expiration */
1319
0
    next = r->last_sent.tv_sec + (long)r->rr.ttl - d->now.tv_sec;
1320
0
    if (next <= 2) {
1321
0
      INFO("Republish %s before TTL expires ...", r->rr.name);
1322
0
      _r_push(&d->a_pause, r);
1323
0
    }
1324
1325
0
    if (next < expire)
1326
0
      expire = next;
1327
0
  }
1328
1329
0
  d->sleep.tv_sec = expire > 2 ? expire - 2 : 0;
1330
0
  d->pause.tv_sec = d->now.tv_sec + d->sleep.tv_sec;
1331
1332
0
  RET;
1333
0
}
1334
1335
void mdnsd_query(mdns_daemon_t *d, const char *host, int type, int (*answer)(mdns_answer_t *a, void *arg), void *arg)
1336
537
{
1337
537
  struct query *q;
1338
537
  struct cached *cur = 0;
1339
537
  int i = _namehash(host) % SPRIME;
1340
1341
537
  if (!(q = _q_next(d, 0, host, type))) {
1342
537
    if (!answer)
1343
0
      return;
1344
1345
537
    q = calloc(1, sizeof(struct query));
1346
537
    if (!q)
1347
0
      return;
1348
537
    q->name = strdup(host);
1349
537
    if (!q->name) {
1350
0
      free(q);
1351
0
      return;
1352
0
    }
1353
537
    q->type = type;
1354
537
    q->next = d->queries[i];
1355
537
    q->list = d->qlist;
1356
537
    d->qlist = d->queries[i] = q;
1357
1358
    /* Any cached entries should be associated */
1359
537
    while ((cur = _c_next(d, cur, q->name, q->type)))
1360
0
      cur->q = q;
1361
537
    _q_reset(d, q);
1362
1363
    /* New question, immediately send out */
1364
537
    q->nexttry = d->checkqlist = d->now.tv_sec;
1365
537
  }
1366
1367
  /* No answer means we don't care anymore */
1368
537
  if (!answer) {
1369
0
    _q_done(d, q);
1370
0
    return;
1371
0
  }
1372
1373
537
  q->answer = answer;
1374
537
  q->arg = arg;
1375
537
}
1376
1377
mdns_answer_t *mdnsd_list(mdns_daemon_t *d,const char *host, int type, mdns_answer_t *last)
1378
0
{
1379
0
  return (mdns_answer_t *)_c_next(d, (struct cached *)last, host, type);
1380
0
}
1381
1382
mdns_record_t *mdnsd_record_next(const mdns_record_t* r)
1383
2.14k
{
1384
2.14k
  return r ? r->next : NULL;
1385
2.14k
}
1386
1387
const mdns_answer_t *mdnsd_record_data(const mdns_record_t* r)
1388
2.68k
{
1389
2.68k
  return &r->rr;
1390
2.68k
}
1391
1392
mdns_record_t *mdnsd_shared(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl)
1393
3.22k
{
1394
3.22k
  int i = _namehash(host) % SPRIME;
1395
3.22k
  mdns_record_t *r;
1396
1397
3.22k
  r = calloc(1, sizeof(struct mdns_record));
1398
3.22k
  if (!r)
1399
0
    return NULL;
1400
1401
3.22k
  r->rr.name = strdup(host);
1402
3.22k
  if (!r->rr.name) {
1403
0
    free(r);
1404
0
    return NULL;
1405
0
  }
1406
1407
3.22k
  r->rr.type = type;
1408
3.22k
  r->rr.ttl = ttl;
1409
3.22k
  r->next = d->published[i];
1410
3.22k
  d->published[i] = r;
1411
1412
3.22k
  return r;
1413
3.22k
}
1414
1415
mdns_record_t *mdnsd_unique(mdns_daemon_t *d, const char *host, unsigned short type, unsigned long ttl,
1416
          void (*conflict)(char *host, int type, void *arg), void *arg)
1417
1.07k
{
1418
1.07k
  mdns_record_t *r;
1419
1420
1.07k
  r = mdnsd_shared(d, host, type, ttl);
1421
1.07k
  if (!r)
1422
0
    return NULL;
1423
1424
1.07k
  r->conflict = conflict;
1425
1.07k
  r->arg = arg;
1426
1.07k
  r->unique = 1;
1427
1428
  /* check if r already in other lists. If yes, remove it from there */
1429
1.07k
  _r_remove_lists(d, r, &d->probing);
1430
1.07k
  _r_push(&d->probing, r);
1431
1432
1.07k
  d->probe.tv_sec = d->now.tv_sec;
1433
1.07k
  d->probe.tv_usec = d->now.tv_usec;
1434
1435
1.07k
  return r;
1436
1.07k
}
1437
1438
mdns_record_t *mdnsd_get_published(mdns_daemon_t *d, const char *host)
1439
2.14k
{
1440
2.14k
  return d->published[_namehash(host) % SPRIME];
1441
2.14k
}
1442
1443
int mdnsd_has_query(mdns_daemon_t *d, const char *host)
1444
0
{
1445
0
  return d->queries[_namehash(host) % SPRIME] != NULL;
1446
0
}
1447
1448
mdns_record_t *mdnsd_find(mdns_daemon_t *d, const char *name, unsigned short type)
1449
0
{
1450
0
  mdns_record_t *r;
1451
1452
0
  r = mdnsd_get_published(d, name);
1453
0
  while (r) {
1454
0
    const mdns_answer_t *data;
1455
1456
    /*
1457
     * Search for a record with the same type and name.
1458
     * Records with different names might be in the same
1459
     * linked list when the hash functions % SPRIME assigns
1460
     * them the same index (hash collision)
1461
     */
1462
0
    data = mdnsd_record_data(r);
1463
0
    if (data->type == type && strcmp(data->name, name) == 0)
1464
0
      return r;
1465
1466
0
    r = mdnsd_record_next(r);
1467
0
  }
1468
1469
0
  return NULL;
1470
0
}
1471
1472
void mdnsd_done(mdns_daemon_t *d, mdns_record_t *r)
1473
2.14k
{
1474
2.14k
  mdns_record_t *cur;
1475
1476
2.14k
  if (r->unique && r->unique < 5) {
1477
    /* Probing yet, zap from that list first! */
1478
1.07k
    if (d->probing == r) {
1479
1.07k
      d->probing = r->list;
1480
1.07k
    } else {
1481
0
      for (cur = d->probing; cur->list != r; cur = cur->list)
1482
0
        ;
1483
0
      cur->list = r->list;
1484
0
    }
1485
1486
1.07k
    _r_done(d, r);
1487
1.07k
    return;
1488
1.07k
  }
1489
1490
1.07k
  r->rr.ttl = 0;
1491
1.07k
  _r_send(d, r);
1492
1.07k
}
1493
1494
void mdnsd_set_raw(mdns_daemon_t *d, mdns_record_t *r, const char *data, unsigned short len)
1495
1.61k
{
1496
1.61k
  if (r->rr.rdata)
1497
0
    free(r->rr.rdata);
1498
1499
1.61k
  r->rr.rdata = malloc(len);
1500
1.61k
  if (r->rr.rdata) {
1501
1.61k
    memcpy(r->rr.rdata, data, len);
1502
1.61k
    r->rr.rdlen = len;
1503
1.61k
  }
1504
1.61k
  _r_publish(d, r);
1505
1.61k
}
1506
1507
void mdnsd_set_host(mdns_daemon_t *d, mdns_record_t *r, const char *name)
1508
1.61k
{
1509
1.61k
  if (!r)
1510
0
    return;
1511
1512
1.61k
  if (r->rr.rdname)
1513
0
    free(r->rr.rdname);
1514
1.61k
  r->rr.rdname = strdup(name);
1515
1.61k
  _r_publish(d, r);
1516
1.61k
}
1517
1518
void mdnsd_set_ip(mdns_daemon_t *d, mdns_record_t *r, struct in_addr ip)
1519
0
{
1520
0
  r->rr.ip = ip;
1521
0
  _r_publish(d, r);
1522
0
}
1523
1524
void mdnsd_set_ipv6(mdns_daemon_t *d, mdns_record_t *r, struct in6_addr ip6)
1525
0
{
1526
0
  r->rr.ip6 = ip6;
1527
0
  _r_publish(d, r);
1528
0
}
1529
1530
void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short priority, unsigned short weight, unsigned short port, char *name)
1531
537
{
1532
537
  r->rr.srv.priority = priority;
1533
537
  r->rr.srv.weight = weight;
1534
537
  r->rr.srv.port = port;
1535
537
  mdnsd_set_host(d, r, name);
1536
537
}
1537
1538
/* Internal helper: update set of addresses for given host & type (A/AAAA) */
1539
static int _update_addresses_for_host(mdns_daemon_t *d, const char *host, unsigned short type, const void *addrs, size_t count)
1540
0
{
1541
0
  mdns_record_t *r;
1542
0
  mdns_record_t *cur;
1543
0
  unsigned long ttl = 120; /* default TTL if none exists */
1544
0
  char buf6[INET6_ADDRSTRLEN];
1545
1546
0
  if (!d || !host)
1547
0
    return -1;
1548
1549
  /* Determine TTL from any existing record of this type */
1550
0
  r = mdnsd_find(d, host, type);
1551
0
  if (r) {
1552
0
    const mdns_answer_t *data = mdnsd_record_data(r);
1553
0
    if (data && data->ttl)
1554
0
      ttl = data->ttl;
1555
0
  }
1556
1557
  /* For each desired address, check if there's a matching existing record */
1558
0
  for (size_t i = 0; i < count; i++) {
1559
0
    bool found = false;
1560
0
    cur = mdnsd_get_published(d, host);
1561
0
    while (cur) {
1562
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1563
0
      if (data->type == type && strcmp(data->name, host) == 0) {
1564
0
        if (type == QTYPE_A) {
1565
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1566
0
          if (data->ip.s_addr == a[i].s_addr) {
1567
0
            found = true;
1568
0
            INFO("Found A record for %s addr %s", host, inet_ntoa(a[i]));
1569
0
            break;
1570
0
          }
1571
0
        } else if (type == QTYPE_AAAA) {
1572
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1573
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) {
1574
0
            found = true;
1575
0
            INFO("Found AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1576
0
            break;
1577
0
          }
1578
0
        }
1579
0
      }
1580
0
      cur = mdnsd_record_next(cur);
1581
0
    }
1582
0
    if (!found) {
1583
      /* Create new_ record for this address */
1584
0
      mdns_record_t *nr = mdnsd_shared(d, host, type, ttl);
1585
0
      if (!nr)
1586
0
        continue;
1587
0
      if (type == QTYPE_A) {
1588
0
        const struct in_addr *a = (const struct in_addr *)addrs;
1589
0
        mdnsd_set_ip(d, nr, a[i]);
1590
0
        INFO("Created A record for %s addr %s", host, inet_ntoa(a[i]));
1591
0
      } else {
1592
0
        const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1593
0
        mdnsd_set_ipv6(d, nr, a6[i]);
1594
0
        INFO("Created AAAA record for %s addr %s", host, inet_ntop(AF_INET6, &a6[i], buf6, sizeof(buf6)));
1595
0
      }
1596
0
    }
1597
0
  }
1598
1599
  /* Remove stale records (present but not in desired set) */
1600
0
  cur = mdnsd_get_published(d, host);
1601
0
  while (cur) {
1602
0
    mdns_record_t *next = mdnsd_record_next(cur);
1603
0
    const mdns_answer_t *data = mdnsd_record_data(cur);
1604
0
    if (data->type == type && strcmp(data->name, host) == 0) {
1605
0
      bool still_present = false;
1606
0
      for (size_t i = 0; i < count; i++) {
1607
0
        if (type == QTYPE_A) {
1608
0
          const struct in_addr *a = (const struct in_addr *)addrs;
1609
0
          if (data->ip.s_addr == a[i].s_addr) { still_present = true; break; }
1610
0
        } else {
1611
0
          const struct in6_addr *a6 = (const struct in6_addr *)addrs;
1612
0
          if (memcmp(&data->ip6, &a6[i], sizeof(struct in6_addr)) == 0) { still_present = true; break; }
1613
0
        }
1614
0
      }
1615
0
      if (!still_present)
1616
0
        mdnsd_done(d, cur);
1617
0
    }
1618
0
    cur = next;
1619
0
  }
1620
1621
0
  return 0;
1622
0
}
1623
1624
int mdnsd_set_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in_addr *addrs, size_t count)
1625
0
{
1626
0
  return _update_addresses_for_host(d, host, QTYPE_A, addrs, count);
1627
0
}
1628
1629
int mdnsd_set_ipv6_addresses_for_host(mdns_daemon_t *d, const char *host, const struct in6_addr *addrs, size_t count)
1630
0
{
1631
0
  return _update_addresses_for_host(d, host, QTYPE_AAAA, addrs, count);
1632
0
}
1633
1634
int mdnsd_set_interface_addresses(mdns_daemon_t *d, const char *ifname)
1635
0
{
1636
0
  struct ifaddrs *ifa = NULL;
1637
0
  struct ifaddrs *it;
1638
0
  struct in_addr *v4 = NULL; size_t v4c = 0;
1639
0
  struct in6_addr *v6 = NULL; size_t v6c = 0;
1640
0
  char buf[INET_ADDRSTRLEN];
1641
0
  char buf6[INET6_ADDRSTRLEN];
1642
1643
0
  if (getifaddrs(&ifa) != 0)
1644
0
    return -1;
1645
1646
  /* Collect all v4/v6 addresses for the interface */
1647
0
  for (it = ifa; it; it = it->ifa_next) {
1648
0
    if (!it->ifa_addr || !it->ifa_name || strcmp(it->ifa_name, ifname))
1649
0
      continue;
1650
0
    if (it->ifa_addr->sa_family == AF_INET) {
1651
0
      v4 = realloc(v4, (v4c + 1) * sizeof(*v4));
1652
0
      if (v4) {
1653
0
        struct sockaddr_in *sin = (struct sockaddr_in *)it->ifa_addr;
1654
0
        v4[v4c++] = sin->sin_addr;
1655
0
        if(inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)))
1656
0
            INFO("Adding address %s for interface %s", buf, ifname);
1657
0
      }
1658
0
    } else if (it->ifa_addr->sa_family == AF_INET6) {
1659
0
      v6 = realloc(v6, (v6c + 1) * sizeof(*v6));
1660
0
      if (v6) {
1661
0
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)it->ifa_addr;
1662
0
        v6[v6c++] = sin6->sin6_addr;
1663
0
        if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf6, sizeof(buf6)))
1664
0
            INFO("Adding address %s for interface %s", buf6, ifname);
1665
0
      }
1666
0
    }
1667
0
  }
1668
0
  freeifaddrs(ifa);
1669
1670
  /* Find all host names currently published as A/AAAA and update each */
1671
0
  for (size_t idx = 0; idx < SPRIME; idx++) {
1672
0
    mdns_record_t *cur = d->published[idx];
1673
0
    while (cur) {
1674
0
      const mdns_answer_t *data = mdnsd_record_data(cur);
1675
0
      if (data->type == QTYPE_A || data->type == QTYPE_AAAA) {
1676
0
        INFO("Updating addresses for host %s type %d", data->name, data->type);
1677
0
        const char *host = data->name;
1678
0
        if (v4c)
1679
0
          mdnsd_set_addresses_for_host(d, host, v4, v4c);
1680
0
        if (v6c)
1681
0
          mdnsd_set_ipv6_addresses_for_host(d, host, v6, v6c);
1682
0
      }
1683
0
      cur = mdnsd_record_next(cur);
1684
0
    }
1685
0
  }
1686
1687
0
  free(v4);
1688
0
  free(v6);
1689
0
  return 0;
1690
0
}
1691
1692
static int process_in(mdns_daemon_t *d, int sd)
1693
0
{
1694
0
  static unsigned char buf[MAX_PACKET_LEN + 1];
1695
0
  struct sockaddr_in from;
1696
0
  socklen_t ssize = sizeof(struct sockaddr_in);
1697
0
  ssize_t bsize;
1698
1699
0
  memset(buf, 0, sizeof(buf));
1700
1701
0
  while ((bsize = recvfrom(sd, buf, MAX_PACKET_LEN, MSG_DONTWAIT, (struct sockaddr *)&from, &ssize)) > 0) {
1702
0
    struct message m = { 0 };
1703
0
    int rc;
1704
1705
0
    buf[MAX_PACKET_LEN] = 0;
1706
0
    mdnsd_log_hex("Got Data:", buf, bsize);
1707
1708
0
    rc = message_parse(&m, buf);
1709
0
    if (rc)
1710
0
      continue;
1711
0
    rc = mdnsd_in(d, &m, from.sin_addr, ntohs(from.sin_port));
1712
0
    if (rc)
1713
0
      continue;
1714
0
  }
1715
1716
0
  if (bsize < 0 && errno != EAGAIN)
1717
0
    return 1;
1718
1719
0
  return 0;
1720
0
}
1721
1722
static int process_out(mdns_daemon_t *d, int sd)
1723
0
{
1724
0
  unsigned short int port;
1725
0
  struct sockaddr_in to;
1726
0
  struct in_addr ip;
1727
0
  struct message m;
1728
1729
0
  while (mdnsd_out(d, &m, &ip, &port)) {
1730
0
    unsigned char *buf;
1731
0
    ssize_t len;
1732
1733
0
    memset(&to, 0, sizeof(to));
1734
0
    to.sin_family = AF_INET;
1735
0
    to.sin_port = port;
1736
0
    to.sin_addr = ip;
1737
1738
0
    len = message_packet_len(&m);
1739
0
    buf = message_packet(&m);
1740
0
    mdnsd_log_hex("Send Data:", buf, len);
1741
1742
0
    if (sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, sizeof(struct sockaddr_in)) != len)
1743
0
      return 2;
1744
0
  }
1745
1746
0
  return 0;
1747
0
}
1748
1749
int mdnsd_step(mdns_daemon_t *d, int sd, bool in, bool out, struct timeval *tv)
1750
0
{
1751
0
  int rc = 0;
1752
1753
0
  if (in)
1754
0
    rc = process_in(d, sd);
1755
0
  if (!rc && out)
1756
0
    rc = process_out(d, sd);
1757
1758
0
  if (!rc && tv) {
1759
0
    struct timeval *delay;
1760
1761
0
    delay = mdnsd_sleep(d);
1762
0
    memcpy(tv, delay, sizeof(*tv));
1763
0
  }
1764
1765
  /* Service Enumeration/Discovery completed */
1766
0
  if (d && d->disco)
1767
0
    d->disco = 0;
1768
1769
0
  return rc;
1770
0
}
1771
1772
void records_clear(mdns_daemon_t *d)
1773
0
{
1774
0
  for (int i = 0; i < SPRIME; i++)
1775
0
  {
1776
0
    mdns_record_t *r = d->published[i];
1777
0
    while (r)
1778
0
    {
1779
0
      mdns_record_t *const next = r->next;
1780
0
      _r_remove_lists(d, r, NULL);
1781
0
      r = next;
1782
0
    }
1783
    d->published[i] = NULL;
1784
0
  }
1785
0
}