chiark / gitweb /
resolve: fix CID#1237549 Unchecked return value
[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 = ordered_hashmap_steal_first(s->conflict_queue)))
86                 dns_resource_record_unref(rr);
87
88         ordered_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         assert(s);
369
370         if (s->protocol != DNS_PROTOCOL_LLMNR)
371                 return 0;
372
373         assert(s->link);
374
375         if (s->family == AF_INET) {
376                 struct ip_mreqn mreqn = {
377                         .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
378                         .imr_ifindex = s->link->ifindex,
379                 };
380
381                 fd = manager_llmnr_ipv4_udp_fd(s->manager);
382                 if (fd < 0)
383                         return fd;
384
385                 /* Always first try to drop membership before we add
386                  * one. This is necessary on some devices, such as
387                  * veth. */
388                 if (b)
389                         (void)setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
390
391                 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
392                         return -errno;
393
394         } else if (s->family == AF_INET6) {
395                 struct ipv6_mreq mreq = {
396                         .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
397                         .ipv6mr_interface = s->link->ifindex,
398                 };
399
400                 fd = manager_llmnr_ipv6_udp_fd(s->manager);
401                 if (fd < 0)
402                         return fd;
403
404                 if (b)
405                         (void)setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
406
407                 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
408                         return -errno;
409         } else
410                 return -EAFNOSUPPORT;
411
412         return 0;
413 }
414
415 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
416         assert(s);
417         assert(address);
418
419         if (s->protocol != DNS_PROTOCOL_DNS)
420                 return 1;
421
422         if (s->link)
423                 return !!link_find_dns_server(s->link,  family, address);
424         else
425                 return !!manager_find_dns_server(s->manager, family, address);
426 }
427
428 static int dns_scope_make_reply_packet(
429                 DnsScope *s,
430                 uint16_t id,
431                 int rcode,
432                 DnsQuestion *q,
433                 DnsAnswer *answer,
434                 DnsAnswer *soa,
435                 bool tentative,
436                 DnsPacket **ret) {
437
438         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
439         unsigned i;
440         int r;
441
442         assert(s);
443         assert(ret);
444
445         if ((!q || q->n_keys <= 0)
446             && (!answer || answer->n_rrs <= 0)
447             && (!soa || soa->n_rrs <= 0))
448                 return -EINVAL;
449
450         r = dns_packet_new(&p, s->protocol, 0);
451         if (r < 0)
452                 return r;
453
454         DNS_PACKET_HEADER(p)->id = id;
455         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
456                                                               1 /* qr */,
457                                                               0 /* opcode */,
458                                                               0 /* c */,
459                                                               0 /* tc */,
460                                                               tentative,
461                                                               0 /* (ra) */,
462                                                               0 /* (ad) */,
463                                                               0 /* (cd) */,
464                                                               rcode));
465
466         if (q) {
467                 for (i = 0; i < q->n_keys; i++) {
468                         r = dns_packet_append_key(p, q->keys[i], NULL);
469                         if (r < 0)
470                                 return r;
471                 }
472
473                 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
474         }
475
476         if (answer) {
477                 for (i = 0; i < answer->n_rrs; i++) {
478                         r = dns_packet_append_rr(p, answer->rrs[i], NULL);
479                         if (r < 0)
480                                 return r;
481                 }
482
483                 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
484         }
485
486         if (soa) {
487                 for (i = 0; i < soa->n_rrs; i++) {
488                         r = dns_packet_append_rr(p, soa->rrs[i], NULL);
489                         if (r < 0)
490                                 return r;
491                 }
492
493                 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
494         }
495
496         *ret = p;
497         p = NULL;
498
499         return 0;
500 }
501
502 static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
503         unsigned n;
504
505         assert(s);
506         assert(p);
507
508         if (p->question)
509                 for (n = 0; n < p->question->n_keys; n++)
510                         dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
511         if (p->answer)
512                 for (n = 0; n < p->answer->n_rrs; n++)
513                         dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
514 }
515
516 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
517         _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
518         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
519         bool tentative = false;
520         int r, fd;
521
522         assert(s);
523         assert(p);
524
525         if (p->protocol != DNS_PROTOCOL_LLMNR)
526                 return;
527
528         if (p->ipproto == IPPROTO_UDP) {
529                 /* Don't accept UDP queries directed to anything but
530                  * the LLMNR multicast addresses. See RFC 4795,
531                  * section 2.5.*/
532
533                 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
534                         return;
535
536                 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
537                         return;
538         }
539
540         r = dns_packet_extract(p);
541         if (r < 0) {
542                 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
543                 return;
544         }
545
546         if (DNS_PACKET_C(p)) {
547                 /* Somebody notified us about a possible conflict */
548                 dns_scope_verify_conflicts(s, p);
549                 return;
550         }
551
552         r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
553         if (r < 0) {
554                 log_debug("Failed to lookup key: %s", strerror(-r));
555                 return;
556         }
557         if (r == 0)
558                 return;
559
560         if (answer)
561                 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
562
563         r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
564         if (r < 0) {
565                 log_debug("Failed to build reply packet: %s", strerror(-r));
566                 return;
567         }
568
569         if (stream)
570                 r = dns_stream_write_packet(stream, reply);
571         else {
572                 if (!ratelimit_test(&s->ratelimit))
573                         return;
574
575                 if (p->family == AF_INET)
576                         fd = manager_llmnr_ipv4_udp_fd(s->manager);
577                 else if (p->family == AF_INET6)
578                         fd = manager_llmnr_ipv6_udp_fd(s->manager);
579                 else {
580                         log_debug("Unknown protocol");
581                         return;
582                 }
583                 if (fd < 0) {
584                         log_debug("Failed to get reply socket: %s", strerror(-fd));
585                         return;
586                 }
587
588                 /* Note that we always immediately reply to all LLMNR
589                  * requests, and do not wait any time, since we
590                  * verified uniqueness for all records. Also see RFC
591                  * 4795, Section 2.7 */
592
593                 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
594         }
595
596         if (r < 0) {
597                 log_debug("Failed to send reply packet: %s", strerror(-r));
598                 return;
599         }
600 }
601
602 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
603         DnsTransaction *t;
604
605         assert(scope);
606         assert(question);
607
608         /* Try to find an ongoing transaction that is a equal or a
609          * superset of the specified question */
610
611         LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
612
613                 /* Refuse reusing transactions that completed based on
614                  * cached data instead of a real packet, if that's
615                  * requested. */
616                 if (!cache_ok &&
617                     IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
618                     !t->received)
619                         continue;
620
621                 if (dns_question_is_superset(t->question, question) > 0)
622                         return t;
623         }
624
625         return NULL;
626 }
627
628 static int dns_scope_make_conflict_packet(
629                 DnsScope *s,
630                 DnsResourceRecord *rr,
631                 DnsPacket **ret) {
632
633         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
634         int r;
635
636         assert(s);
637         assert(rr);
638         assert(ret);
639
640         r = dns_packet_new(&p, s->protocol, 0);
641         if (r < 0)
642                 return r;
643
644         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
645                                                               0 /* qr */,
646                                                               0 /* opcode */,
647                                                               1 /* conflict */,
648                                                               0 /* tc */,
649                                                               0 /* t */,
650                                                               0 /* (ra) */,
651                                                               0 /* (ad) */,
652                                                               0 /* (cd) */,
653                                                               0));
654         random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t));
655         DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
656         DNS_PACKET_HEADER(p)->arcount = htobe16(1);
657
658         r = dns_packet_append_key(p, rr->key, NULL);
659         if (r < 0)
660                 return r;
661
662         r = dns_packet_append_rr(p, rr, NULL);
663         if (r < 0)
664                 return r;
665
666         *ret = p;
667         p = NULL;
668
669         return 0;
670 }
671
672 static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata) {
673         DnsScope *scope = userdata;
674         int r;
675
676         assert(es);
677         assert(scope);
678
679         scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
680
681         for (;;) {
682                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
683                 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
684
685                 rr = ordered_hashmap_steal_first(scope->conflict_queue);
686                 if (!rr)
687                         break;
688
689                 r = dns_scope_make_conflict_packet(scope, rr, &p);
690                 if (r < 0) {
691                         log_error("Failed to make conflict packet: %s", strerror(-r));
692                         return 0;
693                 }
694
695                 r = dns_scope_emit(scope, p);
696                 if (r < 0)
697                         log_debug("Failed to send conflict packet: %s", strerror(-r));
698         }
699
700         return 0;
701 }
702
703 int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
704         usec_t jitter;
705         int r;
706
707         assert(scope);
708         assert(rr);
709
710         /* We don't send these queries immediately. Instead, we queue
711          * them, and send them after some jitter delay. */
712         r = ordered_hashmap_ensure_allocated(&scope->conflict_queue, &dns_resource_key_hash_ops);
713         if (r < 0) {
714                 log_oom();
715                 return r;
716         }
717
718         /* We only place one RR per key in the conflict
719          * messages, not all of them. That should be enough to
720          * indicate where there might be a conflict */
721         r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
722         if (r == -EEXIST || r == 0)
723                 return 0;
724         if (r < 0) {
725                 log_debug("Failed to queue conflicting RR: %s", strerror(-r));
726                 return r;
727         }
728
729         dns_resource_record_ref(rr);
730
731         if (scope->conflict_event_source)
732                 return 0;
733
734         random_bytes(&jitter, sizeof(jitter));
735         jitter %= LLMNR_JITTER_INTERVAL_USEC;
736
737         r = sd_event_add_time(scope->manager->event,
738                               &scope->conflict_event_source,
739                               clock_boottime_or_monotonic(),
740                               now(clock_boottime_or_monotonic()) + jitter,
741                               LLMNR_JITTER_INTERVAL_USEC,
742                               on_conflict_dispatch, scope);
743         if (r < 0) {
744                 log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
745                 return r;
746         }
747
748         return 0;
749 }
750
751 void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
752         unsigned i;
753         int r;
754
755         assert(scope);
756         assert(p);
757
758         if (p->protocol != DNS_PROTOCOL_LLMNR)
759                 return;
760
761         if (DNS_PACKET_RRCOUNT(p) <= 0)
762                 return;
763
764         if (DNS_PACKET_C(p) != 0)
765                 return;
766
767         if (DNS_PACKET_T(p) != 0)
768                 return;
769
770         if (manager_our_packet(scope->manager, p))
771                 return;
772
773         r = dns_packet_extract(p);
774         if (r < 0) {
775                 log_debug("Failed to extract packet: %s", strerror(-r));
776                 return;
777         }
778
779         log_debug("Checking for conflicts...");
780
781         for (i = 0; i < p->answer->n_rrs; i++) {
782
783                 /* Check for conflicts against the local zone. If we
784                  * found one, we won't check any further */
785                 r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
786                 if (r != 0)
787                         continue;
788
789                 /* Check for conflicts against the local cache. If so,
790                  * send out an advisory query, to inform everybody */
791                 r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
792                 if (r <= 0)
793                         continue;
794
795                 dns_scope_notify_conflict(scope, p->answer->rrs[i]);
796         }
797 }