resolved-dns-scope.c revision fcf57f9cf706ff5be2b5e6d41b2ac48e3e98467b
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/***
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2014 Lennart Poettering
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is free software; you can redistribute it and/or modify it
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen under the terms of the GNU Lesser General Public License as published by
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (at your option) any later version.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is distributed in the hope that it will be useful, but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Lesser General Public License for more details.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen You should have received a copy of the GNU Lesser General Public License
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen***/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include <netinet/tcp.h>
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "missing.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "strv.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "socket-util.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "af-list.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "resolved-dns-domain.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#include "resolved-dns-scope.h"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen#define SEND_TIMEOUT_USEC (2*USEC_PER_SEC)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DnsScope *s;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(m);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(ret);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen s = new0(DnsScope, 1);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!s)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOMEM;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen s->manager = m;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen s->link = l;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen s->protocol = protocol;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen s->family = family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen LIST_PREPEND(scopes, m->dns_scopes, s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_scope_llmnr_membership(s, true);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 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));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = s;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom GundersenDnsScope* dns_scope_free(DnsScope *s) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DnsQueryTransaction *t;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!s)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 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));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_scope_llmnr_membership(s, false);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((t = s->transactions)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Abort the transaction, but make sure it is not
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * freed while we still look at it */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen t->block_gc++;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_query_transaction_complete(t, DNS_QUERY_ABORTED);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen t->block_gc--;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_query_transaction_free(t);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_cache_flush(&s->cache);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_zone_flush(&s->zone);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen LIST_REMOVE(scopes, s->manager->dns_scopes, s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen strv_free(s->domains);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen free(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom GundersenDnsServer *dns_scope_get_server(DnsScope *s) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol != DNS_PROTOCOL_DNS)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->link)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return link_get_dns_server(s->link);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return manager_get_dns_server(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid dns_scope_next_dns_server(DnsScope *s) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol != DNS_PROTOCOL_DNS)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->link)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen link_next_dns_server(s->link);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen manager_next_dns_server(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_send(DnsScope *s, DnsPacket *p) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen union in_addr_union addr;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int ifindex = 0, r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint16_t port;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint32_t mtu;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(p);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(p->protocol == s->protocol);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->link) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen mtu = s->link->mtu;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ifindex = s->link->ifindex;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen mtu = manager_find_mtu(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_DNS) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DnsServer *srv;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (DNS_PACKET_QDCOUNT(p) > 1)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOTSUP;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen srv = dns_scope_get_server(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!srv)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ESRCH;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen family = srv->family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen addr = srv->address;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen port = 53;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EMSGSIZE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->size > mtu)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EMSGSIZE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (family == AF_INET)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_dns_ipv4_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (family == AF_INET6)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_dns_ipv6_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (DNS_PACKET_QDCOUNT(p) > 1)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ENOTSUP;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen family = s->family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen port = 5355;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen addr.in = LLMNR_MULTICAST_IPV4_ADDRESS;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv4_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen addr.in6 = LLMNR_MULTICAST_IPV6_ADDRESS;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv6_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_close_ int fd = -1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen union sockaddr_union sa = {};
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen socklen_t salen;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen static const int one = 1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int ret, r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert((family == AF_UNSPEC) == !address);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (family == AF_UNSPEC) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DnsServer *srv;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen srv = dns_scope_get_server(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!srv)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -ESRCH;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.sa.sa_family = srv->family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (srv->family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in.sin_port = htobe16(port);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in.sin_addr = srv->address.in;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen salen = sizeof(sa.in);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (srv->family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_port = htobe16(port);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_addr = srv->address.in6;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen salen = sizeof(sa.in6);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.sa.sa_family = family;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in.sin_port = htobe16(port);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in.sin_addr = address->in;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen salen = sizeof(sa.in);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_port = htobe16(port);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_addr = address->in6;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen salen = sizeof(sa.in6);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->link) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen uint32_t ifindex = htobe32(s->link->ifindex);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (sa.sa.sa_family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (sa.sa.sa_family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_LLMNR) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (sa.sa.sa_family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (sa.sa.sa_family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = connect(fd, &sa.sa, salen);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0 && errno != EINPROGRESS)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen ret = fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = -1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return ret;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom GundersenDnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char **i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(domain);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen STRV_FOREACH(i, s->domains)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dns_name_endswith(domain, *i) > 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_YES;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dns_name_root(domain) != 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_NO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (is_localhost(domain))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_NO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_DNS) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 &&
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 &&
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_name_single_label(domain) == 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_MAYBE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_NO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_MDNS) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_MAYBE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_NO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_LLMNR) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_name_endswith(domain, "ip6.arpa") > 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_name_single_label(domain) > 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_MAYBE;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return DNS_SCOPE_NO;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("Unknown scope protocol");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(key);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol == DNS_PROTOCOL_DNS)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* On mDNS and LLMNR, send A and AAAA queries only on the
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * respective scopes */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_llmnr_membership(DnsScope *s, bool b) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->family == AF_INET) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct ip_mreqn mreqn = {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .imr_ifindex = s->link->ifindex,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen };
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv4_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (s->family == AF_INET6) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen struct ipv6_mreq mreq = {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .ipv6mr_interface = s->link->ifindex,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen };
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv6_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -errno;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EAFNOSUPPORT;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(address);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->protocol != DNS_PROTOCOL_DNS)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 1;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->link)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !!link_find_dns_server(s->link, family, address);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !!manager_find_dns_server(s->manager, family, address);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, DnsPacket **ret) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen unsigned i;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (q->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return -EINVAL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_new(&p, s->protocol, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->id = id;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 1 /* qr */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* opcode */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* c */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* tc */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* t */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (ra) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (ad) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (cd) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen rcode));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (q) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < q->n_keys; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_key(p, q->keys[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (answer) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < answer->n_rrs; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_rr(p, answer->rrs[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (soa) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < soa->n_rrs; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_rr(p, soa->rrs[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return r;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen *ret = p;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen p = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenvoid dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int r, fd;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert(p);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->protocol != DNS_PROTOCOL_LLMNR)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->ipproto == IPPROTO_UDP) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Don't accept UDP queries directed to anything but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * the LLMNR multicast addresses. See RFC 4795,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * section 2.5.*/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_extract(p);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (DNS_PACKET_C(p)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* FIXME: Somebody notified us about a likely conflict */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_zone_lookup(&s->zone, p->question, &answer, &soa);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to lookup key: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r == 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (answer)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, &reply);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to build reply packet: %s", strerror(-r));
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen return;
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen }
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen if (stream)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_stream_write_packet(stream, reply);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->family == AF_INET)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv4_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (p->family == AF_INET6)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = manager_llmnr_ipv6_udp_fd(s->manager);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Unknown protocol");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (fd < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to get reply socket: %s", strerror(-fd));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to send reply packet: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen }
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen}
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen