resolved-dns-scope.c revision fcf57f9cf706ff5be2b5e6d41b2ac48e3e98467b
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2014 Lennart Poettering
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 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 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 Gundersenint dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
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 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 while ((t = s->transactions)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Abort the transaction, but make sure it is not
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * freed while we still look at it */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_query_transaction_complete(t, DNS_QUERY_ABORTED);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen LIST_REMOVE(scopes, s->manager->dns_scopes, s);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_send(DnsScope *s, DnsPacket *p) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen } else if (s->protocol == DNS_PROTOCOL_LLMNR) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* RFC 4795, section 2.5 requires the TTL to be set to 1 */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom GundersenDnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
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 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 if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* On mDNS and LLMNR, send A and AAAA queries only on the
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen * respective scopes */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_llmnr_membership(DnsScope *s, bool b) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenint dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !!link_find_dns_server(s->link, family, address);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return !!manager_find_dns_server(s->manager, family, address);
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 if (q->n_keys <= 0 && answer->n_rrs <= 0 && soa->n_rrs <= 0)
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* opcode */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (ra) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (ad) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen 0 /* (cd) */,
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen for (i = 0; i < q->n_keys; i++) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_key(p, q->keys[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->qdcount = htobe16(q->n_keys);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_rr(p, answer->rrs[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->ancount = htobe16(answer->n_rrs);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_packet_append_rr(p, soa->rrs[i], NULL);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen DNS_PACKET_HEADER(p)->arcount = htobe16(soa->n_rrs);
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 /* 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 if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* FIXME: Somebody notified us about a likely conflict */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_zone_lookup(&s->zone, p->question, &answer, &soa);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to lookup key: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dns_answer_order_by_scope(answer, in_addr_is_link_local(p->family, &p->sender) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, &reply);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to build reply packet: %s", strerror(-r));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to get reply socket: %s", strerror(-fd));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen r = manager_send(s->manager, fd, p->ifindex, p->family, &p->sender, p->sender_port, reply);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_debug("Failed to send reply packet: %s", strerror(-r));