chiark / gitweb /
resolved: allow passing on which protocol, family and interface to look something up
[elogind.git] / src / resolve / resolved-dns-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/tcp.h>
23
24 #include "missing.h"
25 #include "strv.h"
26 #include "socket-util.h"
27 #include "af-list.h"
28 #include "resolved-dns-domain.h"
29 #include "resolved-dns-scope.h"
30
31 #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
32 #define MULTICAST_RATELIMIT_BURST 1000
33
34 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
35         DnsScope *s;
36
37         assert(m);
38         assert(ret);
39
40         s = new0(DnsScope, 1);
41         if (!s)
42                 return -ENOMEM;
43
44         s->manager = m;
45         s->link = l;
46         s->protocol = protocol;
47         s->family = family;
48
49         LIST_PREPEND(scopes, m->dns_scopes, s);
50
51         dns_scope_llmnr_membership(s, true);
52
53         log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
54
55         /* Enforce ratelimiting for the multicast protocols */
56         RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
57
58         *ret = s;
59         return 0;
60 }
61
62 DnsScope* dns_scope_free(DnsScope *s) {
63         DnsTransaction *t;
64         DnsResourceRecord *rr;
65
66         if (!s)
67                 return NULL;
68
69         log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
70
71         dns_scope_llmnr_membership(s, false);
72
73         while ((t = s->transactions)) {
74
75                 /* Abort the transaction, but make sure it is not
76                  * freed while we still look at it */
77
78                 t->block_gc++;
79                 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
80                 t->block_gc--;
81
82                 dns_transaction_free(t);
83         }
84
85         while ((rr = hashmap_steal_first(s->conflict_queue)))
86                 dns_resource_record_unref(rr);
87
88         hashmap_free(s->conflict_queue);
89         sd_event_source_unref(s->conflict_event_source);
90
91         dns_cache_flush(&s->cache);
92         dns_zone_flush(&s->zone);
93
94         LIST_REMOVE(scopes, s->manager->dns_scopes, s);
95         strv_free(s->domains);
96         free(s);
97
98         return NULL;
99 }
100
101 DnsServer *dns_scope_get_dns_server(DnsScope *s) {
102         assert(s);
103
104         if (s->protocol != DNS_PROTOCOL_DNS)
105                 return NULL;
106
107         if (s->link)
108                 return link_get_dns_server(s->link);
109         else
110                 return manager_get_dns_server(s->manager);
111 }
112
113 void dns_scope_next_dns_server(DnsScope *s) {
114         assert(s);
115
116         if (s->protocol != DNS_PROTOCOL_DNS)
117                 return;
118
119         if (s->link)
120                 link_next_dns_server(s->link);
121         else
122                 manager_next_dns_server(s->manager);
123 }
124
125 int dns_scope_emit(DnsScope *s, DnsPacket *p) {
126         union in_addr_union addr;
127         int ifindex = 0, r;
128         int family;
129         uint16_t port;
130         uint32_t mtu;
131         int fd;
132
133         assert(s);
134         assert(p);
135         assert(p->protocol == s->protocol);
136
137         if (s->link) {
138                 mtu = s->link->mtu;
139                 ifindex = s->link->ifindex;
140         } else
141                 mtu = manager_find_mtu(s->manager);
142
143         if (s->protocol == DNS_PROTOCOL_DNS) {
144                 DnsServer *srv;
145
146                 if (DNS_PACKET_QDCOUNT(p) > 1)
147                         return -ENOTSUP;
148
149                 srv = dns_scope_get_dns_server(s);
150                 if (!srv)
151                         return -ESRCH;
152
153                 family = srv->family;
154                 addr = srv->address;
155                 port = 53;
156
157                 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
158                         return -EMSGSIZE;
159
160                 if (p->size > mtu)
161                         return -EMSGSIZE;
162
163                 if (family == AF_INET)
164                         fd = manager_dns_ipv4_fd(s->manager);
165                 else if (family == AF_INET6)
166                         fd = manager_dns_ipv6_fd(s->manager);
167                 else
168                         return -EAFNOSUPPORT;
169                 if (fd < 0)
170                         return fd;
171
172         } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
173
174                 if (DNS_PACKET_QDCOUNT(p) > 1)
175                         return -ENOTSUP;
176
177                 if (!ratelimit_test(&s->ratelimit))
178                         return -EBUSY;
179
180                 family = s->family;
181                 port = 5355;
182
183                 if (family == AF_INET) {
184                         addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
185                         fd = manager_llmnr_ipv4_udp_fd(s->manager);
186                 } else if (family == AF_INET6) {
187                         addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
188                         fd = manager_llmnr_ipv6_udp_fd(s->manager);
189                 } else
190                         return -EAFNOSUPPORT;
191                 if (fd < 0)
192                         return fd;
193         } else
194                 return -EAFNOSUPPORT;
195
196         r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
197         if (r < 0)
198                 return r;
199
200         return 1;
201 }
202
203 int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
204         _cleanup_close_ int fd = -1;
205         union sockaddr_union sa = {};
206         socklen_t salen;
207         static const int one = 1;
208         int ret, r;
209
210         assert(s);
211         assert((family == AF_UNSPEC) == !address);
212
213         if (family == AF_UNSPEC) {
214                 DnsServer *srv;
215
216                 srv = dns_scope_get_dns_server(s);
217                 if (!srv)
218                         return -ESRCH;
219
220                 sa.sa.sa_family = srv->family;
221                 if (srv->family == AF_INET) {
222                         sa.in.sin_port = htobe16(port);
223                         sa.in.sin_addr = srv->address.in;
224                         salen = sizeof(sa.in);
225                 } else if (srv->family == AF_INET6) {
226                         sa.in6.sin6_port = htobe16(port);
227                         sa.in6.sin6_addr = srv->address.in6;
228                         sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
229                         salen = sizeof(sa.in6);
230                 } else
231                         return -EAFNOSUPPORT;
232         } else {
233                 sa.sa.sa_family = family;
234
235                 if (family == AF_INET) {
236                         sa.in.sin_port = htobe16(port);
237                         sa.in.sin_addr = address->in;
238                         salen = sizeof(sa.in);
239                 } else if (family == AF_INET6) {
240                         sa.in6.sin6_port = htobe16(port);
241                         sa.in6.sin6_addr = address->in6;
242                         sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
243                         salen = sizeof(sa.in6);
244                 } else
245                         return -EAFNOSUPPORT;
246         }
247
248         fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
249         if (fd < 0)
250                 return -errno;
251
252         r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
253         if (r < 0)
254                 return -errno;
255
256         if (s->link) {
257                 uint32_t ifindex = htobe32(s->link->ifindex);
258
259                 if (sa.sa.sa_family == AF_INET) {
260                         r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
261                         if (r < 0)
262                                 return -errno;
263                 } else if (sa.sa.sa_family == AF_INET6) {
264                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
265                         if (r < 0)
266                                 return -errno;
267                 }
268         }
269
270         if (s->protocol == DNS_PROTOCOL_LLMNR) {
271                 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
272
273                 if (sa.sa.sa_family == AF_INET) {
274                         r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
275                         if (r < 0)
276                                 return -errno;
277                 } else if (sa.sa.sa_family == AF_INET6) {
278                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
279                         if (r < 0)
280                                 return -errno;
281                 }
282         }
283
284         r = connect(fd, &sa.sa, salen);
285         if (r < 0 && errno != EINPROGRESS)
286                 return -errno;
287
288         ret = fd;
289         fd = -1;
290
291         return ret;
292 }
293
294 DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
295         char **i;
296
297         assert(s);
298         assert(domain);
299
300         if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex))
301                 return DNS_SCOPE_NO;
302
303         if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0)
304                 return DNS_SCOPE_NO;
305
306         STRV_FOREACH(i, s->domains)
307                 if (dns_name_endswith(domain, *i) > 0)
308                         return DNS_SCOPE_YES;
309
310         if (dns_name_root(domain) != 0)
311                 return DNS_SCOPE_NO;
312
313         if (is_localhost(domain))
314                 return DNS_SCOPE_NO;
315
316         if (s->protocol == DNS_PROTOCOL_DNS) {
317                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
318                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
319                     dns_name_single_label(domain) == 0)
320                         return DNS_SCOPE_MAYBE;
321
322                 return DNS_SCOPE_NO;
323         }
324
325         if (s->protocol == DNS_PROTOCOL_MDNS) {
326                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
327                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
328                     (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
329                         return DNS_SCOPE_MAYBE;
330
331                 return DNS_SCOPE_NO;
332         }
333
334         if (s->protocol == DNS_PROTOCOL_LLMNR) {
335                 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
336                     dns_name_endswith(domain, "ip6.arpa") > 0 ||
337                     dns_name_single_label(domain) > 0)
338                         return DNS_SCOPE_MAYBE;
339
340                 return DNS_SCOPE_NO;
341         }
342
343         assert_not_reached("Unknown scope protocol");
344 }
345
346 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
347         assert(s);
348         assert(key);
349
350         if (s->protocol == DNS_PROTOCOL_DNS)
351                 return true;
352
353         /* On mDNS and LLMNR, send A and AAAA queries only on the
354          * respective scopes */
355
356         if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
357                 return false;
358
359         if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
360                 return false;
361
362         return true;
363 }
364
365 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
366         int fd;
367
368         if (s->family == AF_INET) {
369                 struct ip_mreqn mreqn = {
370                         .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
371                         .imr_ifindex = s->link->ifindex,
372                 };
373
374                 fd = manager_llmnr_ipv4_udp_fd(s->manager);
375                 if (fd < 0)
376                         return fd;
377
378                 /* Always first try to drop membership before we add
379                  * one. This is necessary on some devices, such as
380                  * veth. */
381                 if (b)
382                         setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
383
384                 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
385                         return -errno;
386
387         } else if (s->family == AF_INET6) {
388                 struct ipv6_mreq mreq = {
389                         .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
390                         .ipv6mr_interface = s->link->ifindex,
391                 };
392
393                 fd = manager_llmnr_ipv6_udp_fd(s->manager);
394                 if (fd < 0)
395                         return fd;
396
397                 if (b)
398                         setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
399
400                 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
401                         return -errno;
402         } else
403                 return -EAFNOSUPPORT;
404
405         return 0;
406 }
407
408 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
409         assert(s);
410         assert(address);
411
412         if (s->protocol != DNS_PROTOCOL_DNS)
413                 return 1;
414
415         if (s->link)
416                 return !!link_find_dns_server(s->link,  family, address);
417         else
418                 return !!manager_find_dns_server(s->manager, family, address);
419 }
420
421 static int dns_scope_make_reply_packet(
422                 DnsScope *s,
423                 uint16_t id,
424                 int rcode,
425                 DnsQuestion *q,
426                 DnsAnswer *answer,
427                 DnsAnswer *soa,
428                 bool tentative,
429                 DnsPacket **ret) {
430
431         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
432         unsigned i;
433         int r;
434
435         assert(s);
436         assert(ret);
437
438         if ((!q || q->n_keys <= 0)
439             && (!answer || answer->n_rrs <= 0)
440             && (!soa || soa->n_rrs <= 0))
441                 return -EINVAL;
442
443         r = dns_packet_new(&p, s->protocol, 0);
444         if (r < 0)
445                 return r;
446
447         DNS_PACKET_HEADER(p)->id = id;
448         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
449                                                               1 /* qr */,
450                                                               0 /* opcode */,
451                                                               0 /* c */,
452                                                               0 /* tc */,
453                                                               tentative,
454                                                               0 /* (ra) */,
455                                                               0 /* (ad) */,
456                                                               0 /* (cd) */,
457                                                               rcode));
458
459         if (q) {
460                 for (i = 0; i < q->n_keys; i++) {
461                         r = dns_packet_append_key(p, q->keys[i], NULL);
462                         if (r < 0)
463                                 return r;
464                 }
465
466                 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
467         }
468
469         if (answer) {
470                 for (i = 0; i < answer->n_rrs; i++) {
471                         r = dns_packet_append_rr(p, answer->rrs[i], NULL);
472                         if (r < 0)
473                                 return r;
474                 }
475
476                 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
477         }
478
479         if (soa) {
480                 for (i = 0; i < soa->n_rrs; i++) {
481                         r = dns_packet_append_rr(p, soa->rrs[i], NULL);
482                         if (r < 0)
483                                 return r;
484                 }
485
486                 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
487         }
488
489         *ret = p;
490         p = NULL;
491
492         return 0;
493 }
494
495 static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
496         unsigned n;
497
498         assert(s);
499         assert(p);
500
501         if (p->question)
502                 for (n = 0; n < p->question->n_keys; n++)
503                         dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
504         if (p->answer)
505                 for (n = 0; n < p->answer->n_rrs; n++)
506                         dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
507 }
508
509 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
510         _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
511         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
512         bool tentative = false;
513         int r, fd;
514
515         assert(s);
516         assert(p);
517
518         if (p->protocol != DNS_PROTOCOL_LLMNR)
519                 return;
520
521         if (p->ipproto == IPPROTO_UDP) {
522                 /* Don't accept UDP queries directed to anything but
523                  * the LLMNR multicast addresses. See RFC 4795,
524                  * section 2.5.*/
525
526                 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
527                         return;
528
529                 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
530                         return;
531         }
532
533         r = dns_packet_extract(p);
534         if (r < 0) {
535                 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
536                 return;
537         }
538
539         if (DNS_PACKET_C(p)) {
540                 /* Somebody notified us about a possible conflict */
541                 dns_scope_verify_conflicts(s, p);
542                 return;
543         }
544
545         r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
546         if (r < 0) {
547                 log_debug("Failed to lookup key: %s", strerror(-r));
548                 return;
549         }
550         if (r == 0)
551                 return;
552
553         if (answer)
554                 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
555
556         r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
557         if (r < 0) {
558                 log_debug("Failed to build reply packet: %s", strerror(-r));
559                 return;
560         }
561
562         if (stream)
563                 r = dns_stream_write_packet(stream, reply);
564         else {
565                 if (!ratelimit_test(&s->ratelimit))
566                         return;
567
568                 if (p->family == AF_INET)
569                         fd = manager_llmnr_ipv4_udp_fd(s->manager);
570                 else if (p->family == AF_INET6)
571                         fd = manager_llmnr_ipv6_udp_fd(s->manager);
572                 else {
573                         log_debug("Unknown protocol");
574                         return;
575                 }
576                 if (fd < 0) {
577                         log_debug("Failed to get reply socket: %s", strerror(-fd));
578                         return;
579                 }
580
581                 /* Note that we always immediately reply to all LLMNR
582                  * requests, and do not wait any time, since we
583                  * verified uniqueness for all records. Also see RFC
584                  * 4795, Section 2.7 */
585
586                 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
587         }
588
589         if (r < 0) {
590                 log_debug("Failed to send reply packet: %s", strerror(-r));
591                 return;
592         }
593 }
594
595 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
596         DnsTransaction *t;
597
598         assert(scope);
599         assert(question);
600
601         /* Try to find an ongoing transaction that is a equal or a
602          * superset of the specified question */
603
604         LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
605
606                 /* Refuse reusing transactions that completed based on
607                  * cached data instead of a real packet, if that's
608                  * requested. */
609                 if (!cache_ok &&
610                     IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
611                     !t->received)
612                         continue;
613
614                 if (dns_question_is_superset(t->question, question) > 0)
615                         return t;
616         }
617
618         return NULL;
619 }
620
621 static int dns_scope_make_conflict_packet(
622                 DnsScope *s,
623                 DnsResourceRecord *rr,
624                 DnsPacket **ret) {
625
626         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
627         int r;
628
629         assert(s);
630         assert(rr);
631         assert(ret);
632
633         r = dns_packet_new(&p, s->protocol, 0);
634         if (r < 0)
635                 return r;
636
637         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
638                                                               0 /* qr */,
639                                                               0 /* opcode */,
640                                                               1 /* conflict */,
641                                                               0 /* tc */,
642                                                               0 /* t */,
643                                                               0 /* (ra) */,
644                                                               0 /* (ad) */,
645                                                               0 /* (cd) */,
646                                                               0));
647         random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
648         DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
649         DNS_PACKET_HEADER(p)->arcount = htobe16(1);
650
651         r = dns_packet_append_key(p, rr->key, NULL);
652         if (r < 0)
653                 return r;
654
655         r = dns_packet_append_rr(p, rr, NULL);
656         if (r < 0)
657                 return r;
658
659         *ret = p;
660         p = NULL;
661
662         return 0;
663 }
664
665 static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
666         DnsScope *scope = userdata;
667         int r;
668
669         assert(es);
670         assert(scope);
671
672         scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
673
674         for (;;) {
675                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
676                 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
677
678                 rr = hashmap_steal_first(scope->conflict_queue);
679                 if (!rr)
680                         break;
681
682                 r = dns_scope_make_conflict_packet(scope, rr, &p);
683                 if (r < 0) {
684                         log_error("Failed to make conflict packet: %s", strerror(-r));
685                         return 0;
686                 }
687
688                 r = dns_scope_emit(scope, p);
689                 if (r < 0)
690                         log_debug("Failed to send conflict packet: %s", strerror(-r));
691         }
692
693         return 0;
694 }
695
696 int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
697         usec_t jitter;
698         int r;
699
700         assert(scope);
701         assert(rr);
702
703         /* We don't send these queries immediately. Instead, we queue
704          * them, and send them after some jitter delay. */
705         r = hashmap_ensure_allocated(&scope->conflict_queue, dns_resource_key_hash_func, dns_resource_key_compare_func);
706         if (r < 0) {
707                 log_oom();
708                 return r;
709         }
710
711         /* We only place one RR per key in the conflict
712          * messages, not all of them. That should be enough to
713          * indicate where there might be a conflict */
714         r = hashmap_put(scope->conflict_queue, rr->key, rr);
715         if (r == -EEXIST || r == 0)
716                 return 0;
717         if (r < 0) {
718                 log_debug("Failed to queue conflicting RR: %s", strerror(-r));
719                 return r;
720         }
721
722         dns_resource_record_ref(rr);
723
724         if (scope->conflict_event_source)
725                 return 0;
726
727         random_bytes(&jitter, sizeof(jitter));
728         jitter %= LLMNR_JITTER_INTERVAL_USEC;
729
730         r = sd_event_add_time(scope->manager->event,
731                               &scope->conflict_event_source,
732                               clock_boottime_or_monotonic(),
733                               now(clock_boottime_or_monotonic()) + jitter,
734                               LLMNR_JITTER_INTERVAL_USEC,
735                               on_conflict_dispatch, scope);
736         if (r < 0) {
737                 log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
738                 return r;
739         }
740
741         return 0;
742 }
743
744 void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
745         unsigned i;
746         int r;
747
748         assert(scope);
749         assert(p);
750
751         if (p->protocol != DNS_PROTOCOL_LLMNR)
752                 return;
753
754         if (DNS_PACKET_RRCOUNT(p) <= 0)
755                 return;
756
757         if (DNS_PACKET_C(p) != 0)
758                 return;
759
760         if (DNS_PACKET_T(p) != 0)
761                 return;
762
763         if (manager_our_packet(scope->manager, p))
764                 return;
765
766         r = dns_packet_extract(p);
767         if (r < 0) {
768                 log_debug("Failed to extract packet: %s", strerror(-r));
769                 return;
770         }
771
772         log_debug("Checking for conflicts...");
773
774         for (i = 0; i < p->answer->n_rrs; i++) {
775
776                 /* Check for conflicts against the local zone. If we
777                  * found one, we won't check any further */
778                 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
779                 if (r != 0)
780                         continue;
781
782                 /* Check for conflicts against the local cache. If so,
783                  * send out an advisory query, to inform everybody */
784                 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
785                 if (r <= 0)
786                         continue;
787
788                 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
789         }
790 }