resolved-dns-scope.c revision 80a62095dc5af36d9f46de693f3a84835bc28e96
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync This file is part of systemd.
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync Copyright 2014 Lennart Poettering
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync systemd is free software; you can redistribute it and/or modify it
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync under the terms of the GNU Lesser General Public License as published by
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync the Free Software Foundation; either version 2.1 of the License, or
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync (at your option) any later version.
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync systemd is distributed in the hope that it will be useful, but
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync WITHOUT ANY WARRANTY; without even the implied warranty of
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync Lesser General Public License for more details.
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync You should have received a copy of the GNU Lesser General Public License
a260560bdbc7bd737d59547882cd5e8d77b80d0avboxsync along with systemd; If not, see <http://www.gnu.org/licenses/>.
#include "socket-util.h"
#include "strv.h"
DnsScope *s;
assert(m);
return -ENOMEM;
s->manager = m;
s->link = l;
dns_scope_llmnr_membership(s, true);
dns_scope_mdns_membership(s, true);
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));
*ret = s;
assert(s);
while (s->transactions) {
t->block_gc++;
t->block_gc--;
return NULL;
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));
dns_scope_llmnr_membership(s, false);
dns_scope_mdns_membership(s, false);
while (s->query_candidates)
free(s);
return NULL;
assert(s);
return NULL;
if (s->link)
assert(s);
if (s->link)
assert(s);
s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), MULTICAST_RESEND_TIMEOUT_MAX_USEC);
assert(s);
int ifindex = 0, r;
int family;
assert(s);
assert(p);
if (s->link) {
switch (s->protocol) {
case DNS_PROTOCOL_DNS:
return -EOPNOTSUPP;
bool edns_do;
return -EMSGSIZE;
return -EMSGSIZE;
if (saved_size > 0) {
case DNS_PROTOCOL_LLMNR:
return -EOPNOTSUPP;
return -EBUSY;
return -EAFNOSUPPORT;
if (fd < 0)
return fd;
case DNS_PROTOCOL_MDNS:
return -EBUSY;
return -EAFNOSUPPORT;
if (fd < 0)
return fd;
return -EAFNOSUPPORT;
assert(s);
assert(p);
if (p->more) {
dns_packet_set_truncated_flag(p, true);
p = p->more;
static int dns_scope_socket(DnsScope *s, int type, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
int ret, r;
assert(s);
if (!srv)
return -ESRCH;
return -EAGAIN;
return -EAFNOSUPPORT;
return -EAFNOSUPPORT;
if (fd < 0)
return -errno;
return -errno;
if (s->link) {
return -errno;
return -errno;
return -errno;
return -errno;
return -errno;
if (server)
return ret;
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
DnsSearchDomain *d;
assert(s);
return DNS_SCOPE_NO;
return DNS_SCOPE_NO;
dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
return DNS_SCOPE_NO;
dns_name_equal(domain, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
return DNS_SCOPE_NO;
return DNS_SCOPE_YES;
switch (s->protocol) {
case DNS_PROTOCOL_DNS:
/* If networks use .local in their private setups, they are supposed to also add .local to their search
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
case DNS_PROTOCOL_MDNS:
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
case DNS_PROTOCOL_LLMNR:
!is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
assert(s);
static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) {
int fd;
assert(s);
if (fd < 0)
return fd;
if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
return -errno;
if (fd < 0)
return fd;
if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
return -EAFNOSUPPORT;
return dns_scope_multicast_membership(s, b, LLMNR_MULTICAST_IPV4_ADDRESS, LLMNR_MULTICAST_IPV6_ADDRESS);
return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS);
static int dns_scope_make_reply_packet(
DnsScope *s,
int rcode,
DnsQuestion *q,
bool tentative,
assert(s);
if ((!q || q->n_keys <= 0)
return -EINVAL;
rcode));
for (i = 0; i < q->n_keys; i++) {
if (answer) {
if (soa) {
*ret = p;
p = NULL;
assert(s);
assert(p);
if (p->question)
if (p->answer)
bool tentative = false;
int r, fd;
assert(s);
assert(p);
if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS))
if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS))
r = dns_packet_extract(p);
if (DNS_PACKET_LLMNR_C(p)) {
dns_scope_verify_conflicts(s, p);
if (answer)
r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
if (stream)
if (fd < 0) {
DnsTransaction *t;
return NULL;
if (!cache_ok &&
return NULL;
static int dns_scope_make_conflict_packet(
DnsScope *s,
assert(s);
*ret = p;
p = NULL;
if (!rr)
log_oom();
if (r == -EEXIST || r == 0)
assert(p);
if (DNS_PACKET_RRCOUNT(p) <= 0)
if (DNS_PACKET_LLMNR_C(p) != 0)
if (DNS_PACKET_LLMNR_T(p) != 0)
r = dns_packet_extract(p);
assert(s);
f = stdout;
if (s->link) {
assert(s);
return NULL;
if (s->link)
assert(s);