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>
25 #include "socket-util.h"
27 #include "resolved-dns-domain.h"
28 #include "resolved-dns-scope.h"
30 #define SEND_TIMEOUT_USEC (2*USEC_PER_SEC)
32 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
38 s = new0(DnsScope, 1);
44 s->protocol = protocol;
47 LIST_PREPEND(scopes, m->dns_scopes, s);
49 dns_scope_llmnr_membership(s, true);
51 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));
57 DnsScope* dns_scope_free(DnsScope *s) {
61 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));
63 dns_scope_llmnr_membership(s, false);
65 while (s->transactions) {
68 q = s->transactions->query;
69 dns_query_transaction_free(s->transactions);
74 dns_cache_flush(&s->cache);
76 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
77 strv_free(s->domains);
83 DnsServer *dns_scope_get_server(DnsScope *s) {
86 if (s->protocol != DNS_PROTOCOL_DNS)
90 return link_get_dns_server(s->link);
92 return manager_get_dns_server(s->manager);
95 void dns_scope_next_dns_server(DnsScope *s) {
98 if (s->protocol != DNS_PROTOCOL_DNS)
102 link_next_dns_server(s->link);
104 manager_next_dns_server(s->manager);
107 int dns_scope_send(DnsScope *s, DnsPacket *p) {
108 union in_addr_union addr;
117 assert(p->protocol == s->protocol);
121 ifindex = s->link->ifindex;
123 mtu = manager_find_mtu(s->manager);
125 if (s->protocol == DNS_PROTOCOL_DNS) {
128 srv = dns_scope_get_server(s);
132 family = srv->family;
136 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
142 if (family == AF_INET)
143 fd = manager_dns_ipv4_fd(s->manager);
144 else if (family == AF_INET6)
145 fd = manager_dns_ipv6_fd(s->manager);
147 return -EAFNOSUPPORT;
151 } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
153 if (DNS_PACKET_QDCOUNT(p) > 1)
159 if (family == AF_INET) {
160 addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
161 /* fd = manager_dns_ipv4_fd(s->manager); */
162 fd = manager_llmnr_ipv4_udp_fd(s->manager);
163 } else if (family == AF_INET6) {
164 addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
165 fd = manager_llmnr_ipv6_udp_fd(s->manager);
166 /* fd = manager_dns_ipv6_fd(s->manager); */
168 return -EAFNOSUPPORT;
172 return -EAFNOSUPPORT;
174 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
181 int dns_scope_tcp_socket(DnsScope *s) {
182 _cleanup_close_ int fd = -1;
183 union sockaddr_union sa = {};
191 srv = dns_scope_get_server(s);
195 sa.sa.sa_family = srv->family;
196 if (srv->family == AF_INET) {
197 sa.in.sin_port = htobe16(53);
198 sa.in.sin_addr = srv->address.in;
199 salen = sizeof(sa.in);
200 } else if (srv->family == AF_INET6) {
201 sa.in6.sin6_port = htobe16(53);
202 sa.in6.sin6_addr = srv->address.in6;
203 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
204 salen = sizeof(sa.in6);
206 return -EAFNOSUPPORT;
208 fd = socket(srv->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
213 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
215 r = connect(fd, &sa.sa, salen);
216 if (r < 0 && errno != EINPROGRESS)
224 DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
230 STRV_FOREACH(i, s->domains)
231 if (dns_name_endswith(domain, *i))
232 return DNS_SCOPE_YES;
234 if (dns_name_root(domain))
237 if (is_localhost(domain))
240 if (s->protocol == DNS_PROTOCOL_DNS) {
241 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
242 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
243 dns_name_single_label(domain))
246 return DNS_SCOPE_MAYBE;
249 if (s->protocol == DNS_PROTOCOL_MDNS) {
250 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
251 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
252 dns_name_endswith(domain, "local"))
253 return DNS_SCOPE_MAYBE;
258 if (s->protocol == DNS_PROTOCOL_LLMNR) {
259 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
260 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
261 dns_name_single_label(domain))
262 return DNS_SCOPE_MAYBE;
267 assert_not_reached("Unknown scope protocol");
270 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
274 if (s->protocol == DNS_PROTOCOL_DNS)
277 /* On mDNS and LLMNR, send A and AAAA queries only on the
278 * respective scopes */
280 if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
283 if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
289 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
292 if (s->family == AF_INET) {
293 struct ip_mreqn mreqn = {
294 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
295 .imr_ifindex = s->link->ifindex,
298 fd = manager_llmnr_ipv4_udp_fd(s->manager);
302 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
305 } else if (s->family == AF_INET6) {
306 struct ipv6_mreq mreq = {
307 .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
308 .ipv6mr_interface = s->link->ifindex,
311 fd = manager_llmnr_ipv6_udp_fd(s->manager);
315 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
318 return -EAFNOSUPPORT;