commit
c0d645b51f
2
TODO
2
TODO
|
@ -353,8 +353,6 @@ Features:
|
|||
- edns0
|
||||
- dname
|
||||
- cname on PTR (?)
|
||||
- maybe randomize DNS UDP source ports
|
||||
- maybe compare query section of DNS replies
|
||||
|
||||
* Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
|
|||
|
||||
assert(ret);
|
||||
|
||||
if (mtu <= 0)
|
||||
if (mtu <= UDP_PACKET_HEADER_SIZE)
|
||||
a = DNS_PACKET_SIZE_START;
|
||||
else
|
||||
a = mtu;
|
||||
a = mtu - UDP_PACKET_HEADER_SIZE;
|
||||
|
||||
if (a < DNS_PACKET_HEADER_SIZE)
|
||||
a = DNS_PACKET_HEADER_SIZE;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
@ -53,6 +55,7 @@ struct DnsPacketHeader {
|
|||
};
|
||||
|
||||
#define DNS_PACKET_HEADER_SIZE sizeof(DnsPacketHeader)
|
||||
#define UDP_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))
|
||||
|
||||
/* The various DNS protocols deviate in how large a packet can grow,
|
||||
but the TCP transport has a 16bit size field, hence that appears to
|
||||
|
|
|
@ -125,7 +125,8 @@ void dns_scope_next_dns_server(DnsScope *s) {
|
|||
manager_next_dns_server(s->manager);
|
||||
}
|
||||
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
||||
int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) {
|
||||
DnsServer *srv = NULL;
|
||||
union in_addr_union addr;
|
||||
int ifindex = 0, r;
|
||||
int family;
|
||||
|
@ -144,8 +145,6 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
|||
mtu = manager_find_mtu(s->manager);
|
||||
|
||||
if (s->protocol == DNS_PROTOCOL_DNS) {
|
||||
DnsServer *srv;
|
||||
|
||||
if (DNS_PACKET_QDCOUNT(p) > 1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
@ -160,13 +159,13 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
|||
if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (p->size > mtu)
|
||||
if (p->size + UDP_PACKET_HEADER_SIZE > mtu)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (family == AF_INET)
|
||||
fd = manager_dns_ipv4_fd(s->manager);
|
||||
fd = transaction_dns_ipv4_fd(t);
|
||||
else if (family == AF_INET6)
|
||||
fd = manager_dns_ipv6_fd(s->manager);
|
||||
fd = transaction_dns_ipv6_fd(t);
|
||||
else
|
||||
return -EAFNOSUPPORT;
|
||||
if (fd < 0)
|
||||
|
@ -200,10 +199,14 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (server)
|
||||
*server = srv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port) {
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
|
||||
DnsServer *srv = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
union sockaddr_union sa = {};
|
||||
socklen_t salen;
|
||||
|
@ -214,8 +217,6 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
|
|||
assert((family == AF_UNSPEC) == !address);
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
DnsServer *srv;
|
||||
|
||||
srv = dns_scope_get_dns_server(s);
|
||||
if (!srv)
|
||||
return -ESRCH;
|
||||
|
@ -288,6 +289,9 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
|
|||
if (r < 0 && errno != EINPROGRESS)
|
||||
return -errno;
|
||||
|
||||
if (server)
|
||||
*server = srv;
|
||||
|
||||
ret = fd;
|
||||
fd = -1;
|
||||
|
||||
|
@ -696,7 +700,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = dns_scope_emit(scope, p);
|
||||
r = dns_scope_emit(scope, NULL, p, NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to send conflict packet: %m");
|
||||
}
|
||||
|
|
|
@ -65,8 +65,8 @@ struct DnsScope {
|
|||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
|
||||
DnsScope* dns_scope_free(DnsScope *s);
|
||||
|
||||
int dns_scope_emit(DnsScope *s, DnsPacket *p);
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port);
|
||||
int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server);
|
||||
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
|
||||
|
||||
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
|
||||
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
|
||||
|
|
|
@ -41,6 +41,7 @@ int dns_server_new(
|
|||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->n_ref = 1;
|
||||
s->type = type;
|
||||
s->family = family;
|
||||
s->address = *in_addr;
|
||||
|
@ -74,33 +75,46 @@ int dns_server_new(
|
|||
return 0;
|
||||
}
|
||||
|
||||
DnsServer* dns_server_free(DnsServer *s) {
|
||||
DnsServer* dns_server_ref(DnsServer *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (s->link) {
|
||||
if (s->type == DNS_SERVER_LINK)
|
||||
LIST_REMOVE(servers, s->link->dns_servers, s);
|
||||
assert(s->n_ref > 0);
|
||||
|
||||
if (s->link->current_dns_server == s)
|
||||
link_set_dns_server(s->link, NULL);
|
||||
}
|
||||
s->n_ref ++;
|
||||
|
||||
if (s->manager) {
|
||||
if (s->type == DNS_SERVER_SYSTEM)
|
||||
LIST_REMOVE(servers, s->manager->dns_servers, s);
|
||||
else if (s->type == DNS_SERVER_FALLBACK)
|
||||
LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
if (s->manager->current_dns_server == s)
|
||||
manager_set_dns_server(s->manager, NULL);
|
||||
}
|
||||
static DnsServer* dns_server_free(DnsServer *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (s->link && s->link->current_dns_server == s)
|
||||
link_set_dns_server(s->link, NULL);
|
||||
|
||||
if (s->manager && s->manager->current_dns_server == s)
|
||||
manager_set_dns_server(s->manager, NULL);
|
||||
|
||||
free(s);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DnsServer* dns_server_unref(DnsServer *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
assert(s->n_ref > 0);
|
||||
|
||||
if (s->n_ref == 1)
|
||||
dns_server_free(s);
|
||||
else
|
||||
s->n_ref --;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
|
||||
const DnsServer *s = p;
|
||||
uint64_t u;
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef enum DnsServerType {
|
|||
struct DnsServer {
|
||||
Manager *manager;
|
||||
|
||||
unsigned n_ref;
|
||||
|
||||
DnsServerType type;
|
||||
|
||||
Link *link;
|
||||
|
@ -57,6 +59,9 @@ int dns_server_new(
|
|||
int family,
|
||||
const union in_addr_union *address);
|
||||
|
||||
DnsServer* dns_server_free(DnsServer *s);
|
||||
DnsServer* dns_server_ref(DnsServer *s);
|
||||
DnsServer* dns_server_unref(DnsServer *s);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
|
||||
|
||||
extern const struct hash_ops dns_server_hash_ops;
|
||||
|
|
|
@ -39,6 +39,12 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
|
|||
dns_packet_unref(t->received);
|
||||
dns_answer_unref(t->cached);
|
||||
|
||||
sd_event_source_unref(t->dns_ipv4_event_source);
|
||||
sd_event_source_unref(t->dns_ipv6_event_source);
|
||||
safe_close(t->dns_ipv4_fd);
|
||||
safe_close(t->dns_ipv6_fd);
|
||||
|
||||
dns_server_unref(t->server);
|
||||
dns_stream_free(t->stream);
|
||||
|
||||
if (t->scope) {
|
||||
|
@ -88,6 +94,8 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
|
|||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
t->dns_ipv4_fd = t->dns_ipv6_fd = -1;
|
||||
|
||||
t->question = dns_question_ref(q);
|
||||
|
||||
do
|
||||
|
@ -237,6 +245,7 @@ static int on_stream_complete(DnsStream *s, int error) {
|
|||
}
|
||||
|
||||
static int dns_transaction_open_tcp(DnsTransaction *t) {
|
||||
_cleanup_(dns_server_unrefp) DnsServer *server = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
|
@ -246,12 +255,12 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
return 0;
|
||||
|
||||
if (t->scope->protocol == DNS_PROTOCOL_DNS)
|
||||
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
|
||||
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
|
||||
else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
|
||||
|
||||
/* When we already received a query to this (but it was truncated), send to its sender address */
|
||||
if (t->received)
|
||||
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
|
||||
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
|
||||
else {
|
||||
union in_addr_union address;
|
||||
int family = AF_UNSPEC;
|
||||
|
@ -265,7 +274,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT);
|
||||
fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL);
|
||||
}
|
||||
} else
|
||||
return -EAFNOSUPPORT;
|
||||
|
@ -285,6 +294,9 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
dns_server_unref(t->server);
|
||||
t->server = dns_server_ref(server);
|
||||
t->received = dns_packet_unref(t->received);
|
||||
t->stream->complete = on_stream_complete;
|
||||
t->stream->transaction = t;
|
||||
|
@ -333,10 +345,15 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
|
|||
if (t->scope->protocol == DNS_PROTOCOL_DNS) {
|
||||
|
||||
/* For DNS we are fine with accepting packets on any
|
||||
* interface, but the source IP address must be one of
|
||||
* a valid DNS server */
|
||||
* interface, but the source IP address must be the
|
||||
* one of the DNS server we queried */
|
||||
|
||||
if (!dns_scope_good_dns_server(t->scope, p->family, &p->sender))
|
||||
assert(t->server);
|
||||
|
||||
if (t->server->family != p->family)
|
||||
return;
|
||||
|
||||
if (!in_addr_equal(p->family, &p->sender, &t->server->address))
|
||||
return;
|
||||
|
||||
if (p->sender_port != 53)
|
||||
|
@ -398,6 +415,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
|
|||
return;
|
||||
}
|
||||
|
||||
/* Only consider responses with equivalent query section to the request */
|
||||
if (!dns_question_is_superset(p->question, t->question) ||
|
||||
!dns_question_is_superset(t->question, p->question))
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
|
||||
|
||||
/* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */
|
||||
dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
|
||||
|
||||
|
@ -492,6 +514,7 @@ int dns_transaction_go(DnsTransaction *t) {
|
|||
}
|
||||
|
||||
t->n_attempts++;
|
||||
t->server = dns_server_unref(t->server);
|
||||
t->received = dns_packet_unref(t->received);
|
||||
t->cached = dns_answer_unref(t->cached);
|
||||
t->cached_rcode = 0;
|
||||
|
@ -571,17 +594,20 @@ int dns_transaction_go(DnsTransaction *t) {
|
|||
* always be made via TCP on LLMNR */
|
||||
r = dns_transaction_open_tcp(t);
|
||||
} else {
|
||||
DnsServer *server;
|
||||
|
||||
/* Try via UDP, and if that fails due to large size try via TCP */
|
||||
r = dns_scope_emit(t->scope, t->sent);
|
||||
if (r == -EMSGSIZE)
|
||||
r = dns_scope_emit(t->scope, t, t->sent, &server);
|
||||
if (r >= 0)
|
||||
t->server = dns_server_ref(server);
|
||||
else if (r == -EMSGSIZE)
|
||||
r = dns_transaction_open_tcp(t);
|
||||
}
|
||||
if (r == -ESRCH) {
|
||||
/* No servers to send this to? */
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
} else if (r < 0) {
|
||||
if (t->scope->protocol != DNS_PROTOCOL_DNS) {
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
|
||||
return 0;
|
||||
|
@ -606,6 +632,91 @@ int dns_transaction_go(DnsTransaction *t) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||
DnsTransaction *t = userdata;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(t->scope);
|
||||
|
||||
r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (dns_packet_validate_reply(p) > 0 &&
|
||||
DNS_PACKET_ID(p) == t->id) {
|
||||
dns_transaction_process_reply(t, p);
|
||||
} else
|
||||
log_debug("Invalid DNS packet.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int transaction_dns_ipv4_fd(DnsTransaction *t) {
|
||||
const int one = 1;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(t->scope);
|
||||
assert(t->scope->manager);
|
||||
|
||||
if (t->dns_ipv4_fd >= 0)
|
||||
return t->dns_ipv4_fd;
|
||||
|
||||
t->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (t->dns_ipv4_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(t->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv4_event_source, t->dns_ipv4_fd, EPOLLIN, on_dns_packet, t);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return t->dns_ipv4_fd;
|
||||
|
||||
fail:
|
||||
t->dns_ipv4_fd = safe_close(t->dns_ipv4_fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int transaction_dns_ipv6_fd(DnsTransaction *t) {
|
||||
const int one = 1;
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(t->scope);
|
||||
assert(t->scope->manager);
|
||||
|
||||
if (t->dns_ipv6_fd >= 0)
|
||||
return t->dns_ipv6_fd;
|
||||
|
||||
t->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (t->dns_ipv6_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(t->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(t->scope->manager->event, &t->dns_ipv6_event_source, t->dns_ipv6_fd, EPOLLIN, on_dns_packet, t);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return t->dns_ipv6_fd;
|
||||
|
||||
fail:
|
||||
t->dns_ipv6_fd = safe_close(t->dns_ipv6_fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
|
||||
[DNS_TRANSACTION_NULL] = "null",
|
||||
[DNS_TRANSACTION_PENDING] = "pending",
|
||||
|
|
|
@ -61,6 +61,15 @@ struct DnsTransaction {
|
|||
sd_event_source *timeout_event_source;
|
||||
unsigned n_attempts;
|
||||
|
||||
int dns_ipv4_fd;
|
||||
int dns_ipv6_fd;
|
||||
|
||||
sd_event_source *dns_ipv4_event_source;
|
||||
sd_event_source *dns_ipv6_event_source;
|
||||
|
||||
/* the active server */
|
||||
DnsServer *server;
|
||||
|
||||
/* TCP connection logic, if we need it */
|
||||
DnsStream *stream;
|
||||
|
||||
|
@ -86,6 +95,9 @@ int dns_transaction_go(DnsTransaction *t);
|
|||
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p);
|
||||
void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state);
|
||||
|
||||
int transaction_dns_ipv4_fd(DnsTransaction *t);
|
||||
int transaction_dns_ipv6_fd(DnsTransaction *t);
|
||||
|
||||
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
|
||||
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ int link_new(Manager *m, Link **ret, int ifindex) {
|
|||
}
|
||||
|
||||
Link *link_free(Link *l) {
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
|
@ -68,8 +67,12 @@ Link *link_free(Link *l) {
|
|||
if (l->manager)
|
||||
hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
|
||||
|
||||
while (l->dns_servers)
|
||||
dns_server_free(l->dns_servers);
|
||||
while (l->dns_servers) {
|
||||
DnsServer *s = l->dns_servers;
|
||||
|
||||
LIST_REMOVE(servers, l->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
dns_scope_free(l->unicast_scope);
|
||||
dns_scope_free(l->llmnr_ipv4_scope);
|
||||
|
@ -182,14 +185,20 @@ static int link_update_dns_servers(Link *l) {
|
|||
}
|
||||
|
||||
LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
|
||||
if (s->marked)
|
||||
dns_server_free(s);
|
||||
if (s->marked) {
|
||||
LIST_REMOVE(servers, l->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
while (l->dns_servers)
|
||||
dns_server_free(l->dns_servers);
|
||||
while (l->dns_servers) {
|
||||
s = l->dns_servers;
|
||||
|
||||
LIST_REMOVE(servers, l->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -404,7 +404,6 @@ int manager_new(Manager **ret) {
|
|||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
|
||||
m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
|
||||
m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
|
||||
m->hostname_fd = -1;
|
||||
|
@ -486,11 +485,6 @@ Manager *manager_free(Manager *m) {
|
|||
sd_event_source_unref(m->network_event_source);
|
||||
sd_network_monitor_unref(m->network_monitor);
|
||||
|
||||
sd_event_source_unref(m->dns_ipv4_event_source);
|
||||
sd_event_source_unref(m->dns_ipv6_event_source);
|
||||
safe_close(m->dns_ipv4_fd);
|
||||
safe_close(m->dns_ipv6_fd);
|
||||
|
||||
manager_llmnr_stop(m);
|
||||
|
||||
sd_bus_slot_unref(m->prepare_for_sleep_slot);
|
||||
|
@ -603,8 +597,10 @@ int manager_read_resolv_conf(Manager *m) {
|
|||
}
|
||||
|
||||
LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
|
||||
if (s->marked)
|
||||
dns_server_free(s);
|
||||
if (s->marked) {
|
||||
LIST_REMOVE(servers, m->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
/* Whenever /etc/resolv.conf changes, start using the first
|
||||
* DNS server of it. This is useful to deal with broken
|
||||
|
@ -619,8 +615,12 @@ int manager_read_resolv_conf(Manager *m) {
|
|||
return 0;
|
||||
|
||||
clear:
|
||||
while (m->dns_servers)
|
||||
dns_server_free(m->dns_servers);
|
||||
while (m->dns_servers) {
|
||||
s = m->dns_servers;
|
||||
|
||||
LIST_REMOVE(servers, m->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -923,89 +923,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||
DnsTransaction *t = NULL;
|
||||
Manager *m = userdata;
|
||||
int r;
|
||||
|
||||
r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (dns_packet_validate_reply(p) > 0) {
|
||||
t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
|
||||
if (!t)
|
||||
return 0;
|
||||
|
||||
dns_transaction_process_reply(t, p);
|
||||
|
||||
} else
|
||||
log_debug("Invalid DNS packet.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_dns_ipv4_fd(Manager *m) {
|
||||
const int one = 1;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->dns_ipv4_fd >= 0)
|
||||
return m->dns_ipv4_fd;
|
||||
|
||||
m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (m->dns_ipv4_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(m->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_packet, m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return m->dns_ipv4_fd;
|
||||
|
||||
fail:
|
||||
m->dns_ipv4_fd = safe_close(m->dns_ipv4_fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_dns_ipv6_fd(Manager *m) {
|
||||
const int one = 1;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->dns_ipv6_fd >= 0)
|
||||
return m->dns_ipv6_fd;
|
||||
|
||||
m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (m->dns_ipv6_fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(m->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_packet, m);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return m->dns_ipv6_fd;
|
||||
|
||||
fail:
|
||||
m->dns_ipv6_fd = safe_close(m->dns_ipv6_fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
|
||||
int r;
|
||||
|
||||
|
@ -1381,15 +1298,25 @@ void manager_verify_all(Manager *m) {
|
|||
}
|
||||
|
||||
void manager_flush_dns_servers(Manager *m, DnsServerType t) {
|
||||
DnsServer *s;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (t == DNS_SERVER_SYSTEM)
|
||||
while (m->dns_servers)
|
||||
dns_server_free(m->dns_servers);
|
||||
while (m->dns_servers) {
|
||||
s = m->dns_servers;
|
||||
|
||||
LIST_REMOVE(servers, m->dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
|
||||
if (t == DNS_SERVER_FALLBACK)
|
||||
while (m->fallback_dns_servers)
|
||||
dns_server_free(m->fallback_dns_servers);
|
||||
while (m->fallback_dns_servers) {
|
||||
s = m->fallback_dns_servers;
|
||||
|
||||
LIST_REMOVE(servers, m->fallback_dns_servers, s);
|
||||
dns_server_unref(s);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* const support_table[_SUPPORT_MAX] = {
|
||||
|
|
|
@ -65,12 +65,6 @@ struct Manager {
|
|||
unsigned n_dns_streams;
|
||||
|
||||
/* Unicast dns */
|
||||
int dns_ipv4_fd;
|
||||
int dns_ipv6_fd;
|
||||
|
||||
sd_event_source *dns_ipv4_event_source;
|
||||
sd_event_source *dns_ipv6_event_source;
|
||||
|
||||
LIST_HEAD(DnsServer, dns_servers);
|
||||
LIST_HEAD(DnsServer, fallback_dns_servers);
|
||||
DnsServer *current_dns_server;
|
||||
|
@ -128,9 +122,6 @@ uint32_t manager_find_mtu(Manager *m);
|
|||
int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p);
|
||||
int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret);
|
||||
|
||||
int manager_dns_ipv4_fd(Manager *m);
|
||||
int manager_dns_ipv6_fd(Manager *m);
|
||||
|
||||
int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr);
|
||||
LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr);
|
||||
|
||||
|
|
Loading…
Reference in New Issue