1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
22 #include <netinet/tcp.h>
26 #include "socket-util.h"
28 #include "resolved-dns-domain.h"
29 #include "resolved-dns-scope.h"
31 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
37 s = new0(DnsScope, 1);
43 s->protocol = protocol;
46 LIST_PREPEND(scopes, m->dns_scopes, s);
48 dns_scope_llmnr_membership(s, true);
50 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));
56 DnsScope* dns_scope_free(DnsScope *s) {
62 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));
64 dns_scope_llmnr_membership(s, false);
66 while ((t = s->transactions)) {
68 /* Abort the transaction, but make sure it is not
69 * freed while we still look at it */
72 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
75 dns_transaction_free(t);
78 dns_cache_flush(&s->cache);
79 dns_zone_flush(&s->zone);
81 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
82 strv_free(s->domains);
88 DnsServer *dns_scope_get_dns_server(DnsScope *s) {
91 if (s->protocol != DNS_PROTOCOL_DNS)
95 return link_get_dns_server(s->link);
97 return manager_get_dns_server(s->manager);
100 void dns_scope_next_dns_server(DnsScope *s) {
103 if (s->protocol != DNS_PROTOCOL_DNS)
107 link_next_dns_server(s->link);
109 manager_next_dns_server(s->manager);
112 int dns_scope_send(DnsScope *s, DnsPacket *p) {
113 union in_addr_union addr;
122 assert(p->protocol == s->protocol);
126 ifindex = s->link->ifindex;
128 mtu = manager_find_mtu(s->manager);
130 if (s->protocol == DNS_PROTOCOL_DNS) {
133 if (DNS_PACKET_QDCOUNT(p) > 1)
136 srv = dns_scope_get_dns_server(s);
140 family = srv->family;
144 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
150 if (family == AF_INET)
151 fd = manager_dns_ipv4_fd(s->manager);
152 else if (family == AF_INET6)
153 fd = manager_dns_ipv6_fd(s->manager);
155 return -EAFNOSUPPORT;
159 } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
161 if (DNS_PACKET_QDCOUNT(p) > 1)
167 if (family == AF_INET) {
168 addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
169 fd = manager_llmnr_ipv4_udp_fd(s->manager);
170 } else if (family == AF_INET6) {
171 addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
172 fd = manager_llmnr_ipv6_udp_fd(s->manager);
174 return -EAFNOSUPPORT;
178 return -EAFNOSUPPORT;
180 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
187 int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
188 _cleanup_close_ int fd = -1;
189 union sockaddr_union sa = {};
191 static const int one = 1;
195 assert((family == AF_UNSPEC) == !address);
197 if (family == AF_UNSPEC) {
200 srv = dns_scope_get_dns_server(s);
204 sa.sa.sa_family = srv->family;
205 if (srv->family == AF_INET) {
206 sa.in.sin_port = htobe16(port);
207 sa.in.sin_addr = srv->address.in;
208 salen = sizeof(sa.in);
209 } else if (srv->family == AF_INET6) {
210 sa.in6.sin6_port = htobe16(port);
211 sa.in6.sin6_addr = srv->address.in6;
212 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
213 salen = sizeof(sa.in6);
215 return -EAFNOSUPPORT;
217 sa.sa.sa_family = family;
219 if (family == AF_INET) {
220 sa.in.sin_port = htobe16(port);
221 sa.in.sin_addr = address->in;
222 salen = sizeof(sa.in);
223 } else if (family == AF_INET6) {
224 sa.in6.sin6_port = htobe16(port);
225 sa.in6.sin6_addr = address->in6;
226 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
227 salen = sizeof(sa.in6);
229 return -EAFNOSUPPORT;
232 fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
236 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
241 uint32_t ifindex = htobe32(s->link->ifindex);
243 if (sa.sa.sa_family == AF_INET) {
244 r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
247 } else if (sa.sa.sa_family == AF_INET6) {
248 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
254 if (s->protocol == DNS_PROTOCOL_LLMNR) {
255 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
257 if (sa.sa.sa_family == AF_INET) {
258 r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
261 } else if (sa.sa.sa_family == AF_INET6) {
262 r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
268 r = connect(fd, &sa.sa, salen);
269 if (r < 0 && errno != EINPROGRESS)
278 DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
284 STRV_FOREACH(i, s->domains)
285 if (dns_name_endswith(domain, *i) > 0)
286 return DNS_SCOPE_YES;
288 if (dns_name_root(domain) != 0)
291 if (is_localhost(domain))
294 if (s->protocol == DNS_PROTOCOL_DNS) {
295 if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
296 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
297 dns_name_single_label(domain) == 0)
298 return DNS_SCOPE_MAYBE;
303 if (s->protocol == DNS_PROTOCOL_MDNS) {
304 if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
305 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
306 (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
307 return DNS_SCOPE_MAYBE;
312 if (s->protocol == DNS_PROTOCOL_LLMNR) {
313 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
314 dns_name_endswith(domain, "ip6.arpa") > 0 ||
315 dns_name_single_label(domain) > 0)
316 return DNS_SCOPE_MAYBE;
321 assert_not_reached("Unknown scope protocol");
324 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
328 if (s->protocol == DNS_PROTOCOL_DNS)
331 /* On mDNS and LLMNR, send A and AAAA queries only on the
332 * respective scopes */
334 if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
337 if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
343 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
346 if (s->family == AF_INET) {
347 struct ip_mreqn mreqn = {
348 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
349 .imr_ifindex = s->link->ifindex,
352 fd = manager_llmnr_ipv4_udp_fd(s->manager);
356 /* Always first try to drop membership before we add
357 * one. This is necessary on some devices, such as
360 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
362 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
365 } else if (s->family == AF_INET6) {
366 struct ipv6_mreq mreq = {
367 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
368 .ipv6mr_interface = s->link->ifindex,
371 fd = manager_llmnr_ipv6_udp_fd(s->manager);
376 setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
378 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
381 return -EAFNOSUPPORT;
386 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
390 if (s->protocol != DNS_PROTOCOL_DNS)
394 return !!link_find_dns_server(s->link, family, address);
396 return !!manager_find_dns_server(s->manager, family, address);
399 static int dns_scope_make_reply_packet(
409 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
415 if ((!q || q->n_keys <= 0)
416 && (!answer || answer->n_rrs <= 0)
417 && (!soa || soa->n_rrs <= 0))
420 r = dns_packet_new(&p, s->protocol, 0);
424 DNS_PACKET_HEADER(p)->id = id;
425 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
437 for (i = 0; i < q->n_keys; i++) {
438 r = dns_packet_append_key(p, q->keys[i], NULL);
443 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
447 for (i = 0; i < answer->n_rrs; i++) {
448 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
453 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
457 for (i = 0; i < soa->n_rrs; i++) {
458 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
463 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
472 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
473 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
474 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
475 bool tentative = false;
481 if (p->protocol != DNS_PROTOCOL_LLMNR)
484 if (p->ipproto == IPPROTO_UDP) {
485 /* Don't accept UDP queries directed to anything but
486 * the LLMNR multicast addresses. See RFC 4795,
489 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
492 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
496 r = dns_packet_extract(p);
498 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
502 if (DNS_PACKET_C(p)) {
503 /* FIXME: Somebody notified us about a likely conflict */
507 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
509 log_debug("Failed to lookup key: %s", strerror(-r));
516 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
518 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
520 log_debug("Failed to build reply packet: %s", strerror(-r));
525 r = dns_stream_write_packet(stream, reply);
527 if (p->family == AF_INET)
528 fd = manager_llmnr_ipv4_udp_fd(s->manager);
529 else if (p->family == AF_INET6)
530 fd = manager_llmnr_ipv6_udp_fd(s->manager);
532 log_debug("Unknown protocol");
536 log_debug("Failed to get reply socket: %s", strerror(-fd));
540 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
544 log_debug("Failed to send reply packet: %s", strerror(-r));
549 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question, bool cache_ok) {
555 /* Try to find an ongoing transaction that is a equal or a
556 * superset of the specified question */
558 LIST_FOREACH(transactions_by_scope, t, scope->transactions) {
560 /* Refuse reusing transactions that completed based on
561 * cached data instead of a real packet, if that's
564 IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) &&
568 if (dns_question_is_superset(t->question, question) > 0)