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_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_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_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 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
359 } else if (s->family == AF_INET6) {
360 struct ipv6_mreq mreq = {
361 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
362 .ipv6mr_interface = s->link->ifindex,
365 fd = manager_llmnr_ipv6_udp_fd(s->manager);
369 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
372 return -EAFNOSUPPORT;
377 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
381 if (s->protocol != DNS_PROTOCOL_DNS)
385 return !!link_find_dns_server(s->link, family, address);
387 return manager_known_dns_server(s->manager, family, address);
390 static int dns_scope_make_reply_packet(
400 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
406 if (q->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
409 r = dns_packet_new(&p, s->protocol, 0);
413 DNS_PACKET_HEADER(p)->id = id;
414 DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
426 for (i = 0; i < q->n_keys; i++) {
427 r = dns_packet_append_key(p, q->keys[i], NULL);
432 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
436 for (i = 0; i < answer->n_rrs; i++) {
437 r = dns_packet_append_rr(p, answer->rrs[i], NULL);
442 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
446 for (i = 0; i < soa->n_rrs; i++) {
447 r = dns_packet_append_rr(p, soa->rrs[i], NULL);
452 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
461 void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
462 _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
463 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
464 bool tentative = false;
470 if (p->protocol != DNS_PROTOCOL_LLMNR)
473 if (p->ipproto == IPPROTO_UDP) {
474 /* Don't accept UDP queries directed to anything but
475 * the LLMNR multicast addresses. See RFC 4795,
478 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
481 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
485 r = dns_packet_extract(p);
487 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
491 if (DNS_PACKET_C(p)) {
492 /* FIXME: Somebody notified us about a likely conflict */
496 r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
498 log_debug("Failed to lookup key: %s", strerror(-r));
505 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
507 r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
509 log_debug("Failed to build reply packet: %s", strerror(-r));
514 r = dns_stream_write_packet(stream, reply);
516 if (p->family == AF_INET)
517 fd = manager_llmnr_ipv4_udp_fd(s->manager);
518 else if (p->family == AF_INET6)
519 fd = manager_llmnr_ipv6_udp_fd(s->manager);
521 log_debug("Unknown protocol");
525 log_debug("Failed to get reply socket: %s", strerror(-fd));
529 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
533 log_debug("Failed to send reply packet: %s", strerror(-r));
538 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question) {
544 /* Try to find an ongoing transaction that is a equal or a
545 * superset of the specified question */
547 LIST_FOREACH(transactions_by_scope, t, scope->transactions)
548 if (dns_question_is_superset(t->question, question) > 0)