chiark / gitweb /
resolved: provide properly named way to access SPF data in RRs
[elogind.git] / src / resolve / resolved-dns-scope.c
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
22 #include <netinet/tcp.h>
23
24 #include "missing.h"
25 #include "strv.h"
26 #include "socket-util.h"
27 #include "af-list.h"
28 #include "resolved-dns-domain.h"
29 #include "resolved-dns-scope.h"
30
31 int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
32         DnsScope *s;
33
34         assert(m);
35         assert(ret);
36
37         s = new0(DnsScope, 1);
38         if (!s)
39                 return -ENOMEM;
40
41         s->manager = m;
42         s->link = l;
43         s->protocol = protocol;
44         s->family = family;
45
46         LIST_PREPEND(scopes, m->dns_scopes, s);
47
48         dns_scope_llmnr_membership(s, true);
49
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));
51
52         *ret = s;
53         return 0;
54 }
55
56 DnsScope* dns_scope_free(DnsScope *s) {
57         DnsTransaction *t;
58
59         if (!s)
60                 return NULL;
61
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));
63
64         dns_scope_llmnr_membership(s, false);
65
66         while ((t = s->transactions)) {
67
68                 /* Abort the transaction, but make sure it is not
69                  * freed while we still look at it */
70
71                 t->block_gc++;
72                 dns_transaction_complete(t, DNS_TRANSACTION_ABORTED);
73                 t->block_gc--;
74
75                 dns_transaction_free(t);
76         }
77
78         dns_cache_flush(&s->cache);
79         dns_zone_flush(&s->zone);
80
81         LIST_REMOVE(scopes, s->manager->dns_scopes, s);
82         strv_free(s->domains);
83         free(s);
84
85         return NULL;
86 }
87
88 DnsServer *dns_scope_get_server(DnsScope *s) {
89         assert(s);
90
91         if (s->protocol != DNS_PROTOCOL_DNS)
92                 return NULL;
93
94         if (s->link)
95                 return link_get_dns_server(s->link);
96         else
97                 return manager_get_dns_server(s->manager);
98 }
99
100 void dns_scope_next_dns_server(DnsScope *s) {
101         assert(s);
102
103         if (s->protocol != DNS_PROTOCOL_DNS)
104                 return;
105
106         if (s->link)
107                 link_next_dns_server(s->link);
108         else
109                 manager_next_dns_server(s->manager);
110 }
111
112 int dns_scope_send(DnsScope *s, DnsPacket *p) {
113         union in_addr_union addr;
114         int ifindex = 0, r;
115         int family;
116         uint16_t port;
117         uint32_t mtu;
118         int fd;
119
120         assert(s);
121         assert(p);
122         assert(p->protocol == s->protocol);
123
124         if (s->link) {
125                 mtu = s->link->mtu;
126                 ifindex = s->link->ifindex;
127         } else
128                 mtu = manager_find_mtu(s->manager);
129
130         if (s->protocol == DNS_PROTOCOL_DNS) {
131                 DnsServer *srv;
132
133                 if (DNS_PACKET_QDCOUNT(p) > 1)
134                         return -ENOTSUP;
135
136                 srv = dns_scope_get_server(s);
137                 if (!srv)
138                         return -ESRCH;
139
140                 family = srv->family;
141                 addr = srv->address;
142                 port = 53;
143
144                 if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
145                         return -EMSGSIZE;
146
147                 if (p->size > mtu)
148                         return -EMSGSIZE;
149
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);
154                 else
155                         return -EAFNOSUPPORT;
156                 if (fd < 0)
157                         return fd;
158
159         } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
160
161                 if (DNS_PACKET_QDCOUNT(p) > 1)
162                         return -ENOTSUP;
163
164                 family = s->family;
165                 port = 5355;
166
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);
173                 } else
174                         return -EAFNOSUPPORT;
175                 if (fd < 0)
176                         return fd;
177         } else
178                 return -EAFNOSUPPORT;
179
180         r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
181         if (r < 0)
182                 return r;
183
184         return 1;
185 }
186
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 = {};
190         socklen_t salen;
191         static const int one = 1;
192         int ret, r;
193
194         assert(s);
195         assert((family == AF_UNSPEC) == !address);
196
197         if (family == AF_UNSPEC) {
198                 DnsServer *srv;
199
200                 srv = dns_scope_get_server(s);
201                 if (!srv)
202                         return -ESRCH;
203
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);
214                 } else
215                         return -EAFNOSUPPORT;
216         } else {
217                 sa.sa.sa_family = family;
218
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);
228                 } else
229                         return -EAFNOSUPPORT;
230         }
231
232         fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
233         if (fd < 0)
234                 return -errno;
235
236         r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
237         if (r < 0)
238                 return -errno;
239
240         if (s->link) {
241                 uint32_t ifindex = htobe32(s->link->ifindex);
242
243                 if (sa.sa.sa_family == AF_INET) {
244                         r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
245                         if (r < 0)
246                                 return -errno;
247                 } else if (sa.sa.sa_family == AF_INET6) {
248                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
249                         if (r < 0)
250                                 return -errno;
251                 }
252         }
253
254         if (s->protocol == DNS_PROTOCOL_LLMNR) {
255                 /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
256
257                 if (sa.sa.sa_family == AF_INET) {
258                         r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
259                         if (r < 0)
260                                 return -errno;
261                 } else if (sa.sa.sa_family == AF_INET6) {
262                         r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
263                         if (r < 0)
264                                 return -errno;
265                 }
266         }
267
268         r = connect(fd, &sa.sa, salen);
269         if (r < 0 && errno != EINPROGRESS)
270                 return -errno;
271
272         ret = fd;
273         fd = -1;
274
275         return ret;
276 }
277
278 DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
279         char **i;
280
281         assert(s);
282         assert(domain);
283
284         STRV_FOREACH(i, s->domains)
285                 if (dns_name_endswith(domain, *i) > 0)
286                         return DNS_SCOPE_YES;
287
288         if (dns_name_root(domain) != 0)
289                 return DNS_SCOPE_NO;
290
291         if (is_localhost(domain))
292                 return DNS_SCOPE_NO;
293
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;
299
300                 return DNS_SCOPE_NO;
301         }
302
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;
308
309                 return DNS_SCOPE_NO;
310         }
311
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;
317
318                 return DNS_SCOPE_NO;
319         }
320
321         assert_not_reached("Unknown scope protocol");
322 }
323
324 int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
325         assert(s);
326         assert(key);
327
328         if (s->protocol == DNS_PROTOCOL_DNS)
329                 return true;
330
331         /* On mDNS and LLMNR, send A and AAAA queries only on the
332          * respective scopes */
333
334         if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
335                 return false;
336
337         if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
338                 return false;
339
340         return true;
341 }
342
343 int dns_scope_llmnr_membership(DnsScope *s, bool b) {
344         int fd;
345
346         if (s->family == AF_INET) {
347                 struct ip_mreqn mreqn = {
348                         .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
349                         .imr_ifindex = s->link->ifindex,
350                 };
351
352                 fd = manager_llmnr_ipv4_udp_fd(s->manager);
353                 if (fd < 0)
354                         return fd;
355
356                 if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
357                         return -errno;
358
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,
363                 };
364
365                 fd = manager_llmnr_ipv6_udp_fd(s->manager);
366                 if (fd < 0)
367                         return fd;
368
369                 if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
370                         return -errno;
371         } else
372                 return -EAFNOSUPPORT;
373
374         return 0;
375 }
376
377 int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
378         assert(s);
379         assert(address);
380
381         if (s->protocol != DNS_PROTOCOL_DNS)
382                 return 1;
383
384         if (s->link)
385                 return !!link_find_dns_server(s->link,  family, address);
386         else
387                 return !!manager_find_dns_server(s->manager, family, address);
388 }
389
390 static int dns_scope_make_reply_packet(
391                 DnsScope *s,
392                 uint16_t id,
393                 int rcode,
394                 DnsQuestion *q,
395                 DnsAnswer *answer,
396                 DnsAnswer *soa,
397                 bool tentative,
398                 DnsPacket **ret) {
399
400         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
401         unsigned i;
402         int r;
403
404         assert(s);
405
406         if (q->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
407                 return -EINVAL;
408
409         r = dns_packet_new(&p, s->protocol, 0);
410         if (r < 0)
411                 return r;
412
413         DNS_PACKET_HEADER(p)->id = id;
414         DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
415                                                               1 /* qr */,
416                                                               0 /* opcode */,
417                                                               0 /* c */,
418                                                               0 /* tc */,
419                                                               tentative,
420                                                               0 /* (ra) */,
421                                                               0 /* (ad) */,
422                                                               0 /* (cd) */,
423                                                               rcode));
424
425         if (q) {
426                 for (i = 0; i < q->n_keys; i++) {
427                         r = dns_packet_append_key(p, q->keys[i], NULL);
428                         if (r < 0)
429                                 return r;
430                 }
431
432                 DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
433         }
434
435         if (answer) {
436                 for (i = 0; i < answer->n_rrs; i++) {
437                         r = dns_packet_append_rr(p, answer->rrs[i], NULL);
438                         if (r < 0)
439                                 return r;
440                 }
441
442                 DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
443         }
444
445         if (soa) {
446                 for (i = 0; i < soa->n_rrs; i++) {
447                         r = dns_packet_append_rr(p, soa->rrs[i], NULL);
448                         if (r < 0)
449                                 return r;
450                 }
451
452                 DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
453         }
454
455         *ret = p;
456         p = NULL;
457
458         return 0;
459 }
460
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;
465         int r, fd;
466
467         assert(s);
468         assert(p);
469
470         if (p->protocol != DNS_PROTOCOL_LLMNR)
471                 return;
472
473         if (p->ipproto == IPPROTO_UDP) {
474                 /* Don't accept UDP queries directed to anything but
475                  * the LLMNR multicast addresses. See RFC 4795,
476                  * section 2.5.*/
477
478                 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
479                         return;
480
481                 if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
482                         return;
483         }
484
485         r = dns_packet_extract(p);
486         if (r < 0) {
487                 log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
488                 return;
489         }
490
491         if (DNS_PACKET_C(p)) {
492                 /* FIXME: Somebody notified us about a likely conflict */
493                 return;
494         }
495
496         r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
497         if (r < 0) {
498                 log_debug("Failed to lookup key: %s", strerror(-r));
499                 return;
500         }
501         if (r == 0)
502                 return;
503
504         if (answer)
505                 dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
506
507         r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
508         if (r < 0) {
509                 log_debug("Failed to build reply packet: %s", strerror(-r));
510                 return;
511         }
512
513         if (stream)
514                 r = dns_stream_write_packet(stream, reply);
515         else {
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);
520                 else {
521                         log_debug("Unknown protocol");
522                         return;
523                 }
524                 if (fd < 0) {
525                         log_debug("Failed to get reply socket: %s", strerror(-fd));
526                         return;
527                 }
528
529                 r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
530         }
531
532         if (r < 0) {
533                 log_debug("Failed to send reply packet: %s", strerror(-r));
534                 return;
535         }
536 }
537
538 DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsQuestion *question) {
539         DnsTransaction *t;
540
541         assert(scope);
542         assert(question);
543
544         /* Try to find an ongoing transaction that is a equal or a
545          * superset of the specified question */
546
547         LIST_FOREACH(transactions_by_scope, t, scope->transactions)
548                 if (dns_question_is_superset(t->question, question) > 0)
549                         return t;
550
551         return NULL;
552 }