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->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
418 r = dns_packet_new(&p, s->protocol, 0);
422 DNS_PACKET_HEADER(p)->id = id;
423 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
435 for (i = 0; i < q->n_keys; i++) {
436 r = dns_packet_append_key(p, q->keys[i], NULL);
441 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
445 for (i = 0; i < answer->n_rrs; i++) {
446 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
451 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
455 for (i = 0; i < soa->n_rrs; i++) {
456 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
461 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
470 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
471 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
472 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
473 bool tentative = false;
479 if (p->protocol != DNS_PROTOCOL_LLMNR)
482 if (p->ipproto == IPPROTO_UDP) {
483 /* Don't accept UDP queries directed to anything but
484 * the LLMNR multicast addresses. See RFC 4795,
487 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
490 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
494 r = dns_packet_extract(p);
496 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
500 if (DNS_PACKET_C(p)) {
501 /* FIXME: Somebody notified us about a likely conflict */
505 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
507 log_debug("Failed to lookup key: %s", strerror(-r));
514 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
516 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
518 log_debug("Failed to build reply packet: %s", strerror(-r));
523 r = dns_stream_write_packet(stream, reply);
525 if (p->family == AF_INET)
526 fd = manager_llmnr_ipv4_udp_fd(s->manager);
527 else if (p->family == AF_INET6)
528 fd = manager_llmnr_ipv6_udp_fd(s->manager);
530 log_debug("Unknown protocol");
534 log_debug("Failed to get reply socket: %s", strerror(-fd));
538 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
542 log_debug("Failed to send reply packet: %s", strerror(-r));
547 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question) {
553 /* Try to find an ongoing transaction that is a equal or a
554 * superset of the specified question */
556 LIST_FOREACH(transactions_by_scope, t, scope->transactions)
557 if (dns_question_is_superset(t->question, question) > 0)