]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-scope.c
nss-myhostname: don't include assert.h twice
[thirdparty/systemd.git] / src / resolve / resolved-dns-scope.c
CommitLineData
74b2466e
LP
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
ad867662
LP
22#include <netinet/tcp.h>
23
74b2466e 24#include "strv.h"
ad867662 25#include "socket-util.h"
46f08bea 26#include "af-list.h"
74b2466e
LP
27#include "resolved-dns-domain.h"
28#include "resolved-dns-scope.h"
29
30#define SEND_TIMEOUT_USEC (2*USEC_PER_SEC)
31
0dd25fb9 32int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
74b2466e
LP
33 DnsScope *s;
34
35 assert(m);
36 assert(ret);
37
38 s = new0(DnsScope, 1);
39 if (!s)
40 return -ENOMEM;
41
42 s->manager = m;
1716f6dc
LP
43 s->link = l;
44 s->protocol = protocol;
45 s->family = family;
74b2466e
LP
46
47 LIST_PREPEND(scopes, m->dns_scopes, s);
48
1716f6dc
LP
49 dns_scope_llmnr_membership(s, true);
50
46f08bea 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));
1716f6dc 52
74b2466e
LP
53 *ret = s;
54 return 0;
55}
56
57DnsScope* dns_scope_free(DnsScope *s) {
58 if (!s)
59 return NULL;
60
46f08bea 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));
1716f6dc
LP
62
63 dns_scope_llmnr_membership(s, false);
64
74b2466e
LP
65 while (s->transactions) {
66 DnsQuery *q;
67
68 q = s->transactions->query;
69 dns_query_transaction_free(s->transactions);
70
71 dns_query_finish(q);
72 }
73
322345fd
LP
74 dns_cache_flush(&s->cache);
75
74b2466e
LP
76 LIST_REMOVE(scopes, s->manager->dns_scopes, s);
77 strv_free(s->domains);
78 free(s);
79
80 return NULL;
81}
82
83DnsServer *dns_scope_get_server(DnsScope *s) {
84 assert(s);
85
1716f6dc
LP
86 if (s->protocol != DNS_PROTOCOL_DNS)
87 return NULL;
88
74b2466e
LP
89 if (s->link)
90 return link_get_dns_server(s->link);
91 else
92 return manager_get_dns_server(s->manager);
93}
94
95void dns_scope_next_dns_server(DnsScope *s) {
96 assert(s);
97
1716f6dc
LP
98 if (s->protocol != DNS_PROTOCOL_DNS)
99 return;
100
74b2466e
LP
101 if (s->link)
102 link_next_dns_server(s->link);
103 else
104 manager_next_dns_server(s->manager);
105}
106
107int dns_scope_send(DnsScope *s, DnsPacket *p) {
1716f6dc
LP
108 union in_addr_union addr;
109 int ifindex = 0, r;
0dd25fb9 110 int family;
1716f6dc
LP
111 uint16_t port;
112 uint32_t mtu;
113 int fd;
74b2466e
LP
114
115 assert(s);
116 assert(p);
1716f6dc 117 assert(p->protocol == s->protocol);
ad867662
LP
118
119 if (s->link) {
1716f6dc 120 mtu = s->link->mtu;
74b2466e 121 ifindex = s->link->ifindex;
1716f6dc 122 } else
e1c95994 123 mtu = manager_find_mtu(s->manager);
74b2466e 124
1716f6dc
LP
125 if (s->protocol == DNS_PROTOCOL_DNS) {
126 DnsServer *srv;
e1c95994 127
1716f6dc
LP
128 srv = dns_scope_get_server(s);
129 if (!srv)
130 return -ESRCH;
131
132 family = srv->family;
133 addr = srv->address;
134 port = 53;
135
136 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
137 return -EMSGSIZE;
138
139 if (p->size > mtu)
140 return -EMSGSIZE;
141
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);
146 else
147 return -EAFNOSUPPORT;
148 if (fd < 0)
149 return fd;
150
151 } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
152
153 if (DNS_PACKET_QDCOUNT(p) > 1)
154 return -ENOTSUP;
155
156 family = s->family;
157 port = 5355;
158
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); */
167 } else
168 return -EAFNOSUPPORT;
169 if (fd < 0)
170 return fd;
171 } else
74b2466e
LP
172 return -EAFNOSUPPORT;
173
1716f6dc 174 r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
74b2466e
LP
175 if (r < 0)
176 return r;
177
178 return 1;
179}
180
ad867662
LP
181int dns_scope_tcp_socket(DnsScope *s) {
182 _cleanup_close_ int fd = -1;
183 union sockaddr_union sa = {};
184 socklen_t salen;
901fd816 185 int one, ret;
ad867662
LP
186 DnsServer *srv;
187 int r;
188
189 assert(s);
190
191 srv = dns_scope_get_server(s);
192 if (!srv)
193 return -ESRCH;
194
ad867662
LP
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;
901fd816 203 sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
ad867662
LP
204 salen = sizeof(sa.in6);
205 } else
206 return -EAFNOSUPPORT;
207
208 fd = socket(srv->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
209 if (fd < 0)
210 return -errno;
211
212 one = 1;
213 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
214
215 r = connect(fd, &sa.sa, salen);
216 if (r < 0 && errno != EINPROGRESS)
217 return -errno;
218
219 ret = fd;
220 fd = -1;
221 return ret;
222}
223
1716f6dc 224DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
74b2466e
LP
225 char **i;
226
227 assert(s);
228 assert(domain);
229
230 STRV_FOREACH(i, s->domains)
231 if (dns_name_endswith(domain, *i))
232 return DNS_SCOPE_YES;
233
234 if (dns_name_root(domain))
235 return DNS_SCOPE_NO;
236
faec72d5
LP
237 if (is_localhost(domain))
238 return DNS_SCOPE_NO;
239
1716f6dc 240 if (s->protocol == DNS_PROTOCOL_DNS) {
74b2466e 241 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
1716f6dc
LP
242 dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
243 dns_name_single_label(domain))
244 return DNS_SCOPE_NO;
245
246 return DNS_SCOPE_MAYBE;
247 }
248
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"))
74b2466e
LP
253 return DNS_SCOPE_MAYBE;
254
255 return DNS_SCOPE_NO;
256 }
257
1716f6dc 258 if (s->protocol == DNS_PROTOCOL_LLMNR) {
74b2466e
LP
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))
1716f6dc 262 return DNS_SCOPE_MAYBE;
74b2466e 263
1716f6dc 264 return DNS_SCOPE_NO;
74b2466e
LP
265 }
266
1716f6dc
LP
267 assert_not_reached("Unknown scope protocol");
268}
269
270int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
271 assert(s);
272 assert(key);
273
274 if (s->protocol == DNS_PROTOCOL_DNS)
275 return true;
276
277 /* On mDNS and LLMNR, send A and AAAA queries only on the
278 * respective scopes */
279
280 if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
281 return false;
282
283 if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
284 return false;
285
286 return true;
287}
288
289int dns_scope_llmnr_membership(DnsScope *s, bool b) {
290 int fd;
291
292 if (s->family == AF_INET) {
293 struct ip_mreqn mreqn = {
294 .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
295 .imr_ifindex = s->link->ifindex,
296 };
297
298 fd = manager_llmnr_ipv4_udp_fd(s->manager);
299 if (fd < 0)
300 return fd;
301
302 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
303 return -errno;
304
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,
309 };
310
311 fd = manager_llmnr_ipv6_udp_fd(s->manager);
312 if (fd < 0)
313 return fd;
314
315 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
316 return -errno;
317 } else
318 return -EAFNOSUPPORT;
319
320 return 0;
74b2466e 321}