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