summaryrefslogtreecommitdiff
path: root/src/resolve
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve')
-rw-r--r--src/resolve/resolved-dns-packet.c51
-rw-r--r--src/resolve/resolved-dns-question.c40
-rw-r--r--src/resolve/resolved-dns-question.h2
-rw-r--r--src/resolve/resolved-dns-scope.c57
-rw-r--r--src/resolve/resolved-dns-scope.h3
-rw-r--r--src/resolve/resolved-dns-transaction.c192
-rw-r--r--src/resolve/resolved-dns-transaction.h10
-rw-r--r--src/resolve/resolved-manager.c46
-rw-r--r--src/resolve/resolved-manager.h1
9 files changed, 209 insertions, 193 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 649e8b74e1..39951a362c 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -508,23 +508,21 @@ static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t l
assert(p);
assert(types);
+ assert(length > 0);
saved_size = p->size;
- if (length != 0) {
-
- r = dns_packet_append_uint8(p, window, NULL);
- if (r < 0)
- goto fail;
+ r = dns_packet_append_uint8(p, window, NULL);
+ if (r < 0)
+ goto fail;
- r = dns_packet_append_uint8(p, length, NULL);
- if (r < 0)
- goto fail;
+ r = dns_packet_append_uint8(p, length, NULL);
+ if (r < 0)
+ goto fail;
- r = dns_packet_append_blob(p, types, length, NULL);
- if (r < 0)
- goto fail;
- }
+ r = dns_packet_append_blob(p, types, length, NULL);
+ if (r < 0)
+ goto fail;
if (start)
*start = saved_size;
@@ -538,7 +536,7 @@ fail:
static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
Iterator i;
uint8_t window = 0;
- uint8_t len = 0;
+ uint8_t entry = 0;
uint8_t bitmaps[32] = {};
unsigned n;
size_t saved_size;
@@ -550,30 +548,24 @@ static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
saved_size = p->size;
BITMAP_FOREACH(n, types, i) {
- uint8_t entry;
-
assert(n <= 0xffff);
- if ((n << 8) != window) {
- r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ if ((n >> 8) != window && bitmaps[entry / 8] != 0) {
+ r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
if (r < 0)
goto fail;
- if (len > 0) {
- len = 0;
- zero(bitmaps);
- }
+ zero(bitmaps);
}
- window = n << 8;
- len ++;
+ window = n >> 8;
entry = n & 255;
bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
}
- r = dns_packet_append_type_window(p, window, len, bitmaps, NULL);
+ r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
if (r < 0)
goto fail;
@@ -1164,6 +1156,7 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
uint8_t window;
uint8_t length;
const uint8_t *bitmap;
+ uint8_t bit = 0;
unsigned i;
bool found = false;
size_t saved_rindex;
@@ -1195,10 +1188,10 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
for (i = 0; i < length; i++) {
uint8_t bitmask = 1 << 7;
- uint8_t bit = 0;
if (!bitmap[i]) {
found = false;
+ bit += 8;
continue;
}
@@ -1673,8 +1666,12 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
if (r < 0)
goto fail;
- /* NSEC RRs with empty bitmpas makes no sense, but the RFC does not explicitly forbid them
- so we allow it */
+ /* The types bitmap must contain at least the NSEC record itself, so an empty bitmap means
+ something went wrong */
+ if (bitmap_isclear(rr->nsec.types)) {
+ r = -EBADMSG;
+ goto fail;
+ }
break;
diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c
index 4d71f5e3d4..0efe740d1a 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/resolved-dns-question.c
@@ -188,6 +188,46 @@ int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
return 1;
}
+int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
+ unsigned j;
+ int r;
+
+ assert(a);
+ assert(k);
+
+ for (j = 0; j < a->n_keys; j++) {
+ r = dns_resource_key_equal(a->keys[j], k);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
+ unsigned j;
+ int r;
+
+ assert(a);
+ assert(b);
+
+ /* Checks if all keys in a are also contained b, and vice versa */
+
+ for (j = 0; j < a->n_keys; j++) {
+ r = dns_question_contains(b, a->keys[j]);
+ if (r <= 0)
+ return r;
+ }
+
+ for (j = 0; j < b->n_keys; j++) {
+ r = dns_question_contains(a, b->keys[j]);
+ if (r <= 0)
+ return r;
+ }
+
+ return 1;
+}
+
int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
_cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
bool same = true;
diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h
index 4ba2fe9f0e..fc98677798 100644
--- a/src/resolve/resolved-dns-question.h
+++ b/src/resolve/resolved-dns-question.h
@@ -43,6 +43,8 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr);
int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr);
int dns_question_is_valid(DnsQuestion *q);
int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other);
+int dns_question_contains(DnsQuestion *a, DnsResourceKey *k);
+int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b);
int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret);
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 0aab1e35d3..927a1ddc26 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -125,18 +125,17 @@ void dns_scope_next_dns_server(DnsScope *s) {
manager_next_dns_server(s->manager);
}
-int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **server) {
- DnsServer *srv = NULL;
+int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
union in_addr_union addr;
int ifindex = 0, r;
int family;
uint16_t port;
uint32_t mtu;
- int fd;
assert(s);
assert(p);
assert(p->protocol == s->protocol);
+ assert((s->protocol == DNS_PROTOCOL_DNS) != (fd < 0));
if (s->link) {
mtu = s->link->mtu;
@@ -148,28 +147,15 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser
if (DNS_PACKET_QDCOUNT(p) > 1)
return -EOPNOTSUPP;
- srv = dns_scope_get_dns_server(s);
- if (!srv)
- return -ESRCH;
-
- family = srv->family;
- addr = srv->address;
- port = 53;
-
if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
return -EMSGSIZE;
if (p->size + UDP_PACKET_HEADER_SIZE > mtu)
return -EMSGSIZE;
- if (family == AF_INET)
- fd = transaction_dns_ipv4_fd(t);
- else if (family == AF_INET6)
- fd = transaction_dns_ipv6_fd(t);
- else
- return -EAFNOSUPPORT;
- if (fd < 0)
- return fd;
+ r = manager_write(s->manager, fd, p);
+ if (r < 0)
+ return r;
} else if (s->protocol == DNS_PROTOCOL_LLMNR) {
@@ -192,20 +178,17 @@ int dns_scope_emit(DnsScope *s, DnsTransaction *t, DnsPacket *p, DnsServer **ser
return -EAFNOSUPPORT;
if (fd < 0)
return fd;
+
+ r = manager_send(s->manager, fd, ifindex, family, &addr, port, p);
+ if (r < 0)
+ return r;
} else
return -EAFNOSUPPORT;
- r = manager_send(s->manager, fd, ifindex, family, &addr, port, 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, DnsServer **server) {
+static int dns_scope_socket(DnsScope *s, int type, 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 = {};
@@ -249,13 +232,15 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
return -EAFNOSUPPORT;
}
- fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ fd = socket(sa.sa.sa_family, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
- r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
- if (r < 0)
- return -errno;
+ if (type == SOCK_STREAM) {
+ r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
+ if (r < 0)
+ return -errno;
+ }
if (s->link) {
uint32_t ifindex = htobe32(s->link->ifindex);
@@ -298,6 +283,14 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add
return ret;
}
+int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server) {
+ return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, 53, server);
+}
+
+int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {
+ return dns_scope_socket(s, SOCK_STREAM, family, address, port, server);
+}
+
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
char **i;
@@ -687,7 +680,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
return 0;
}
- r = dns_scope_emit(scope, NULL, p, NULL);
+ r = dns_scope_emit(scope, -1, p);
if (r < 0)
log_debug_errno(r, "Failed to send conflict packet: %m");
}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 21a160ea39..29479ad550 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -65,8 +65,9 @@ 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, DnsTransaction *t, DnsPacket *p, DnsServer **server);
+int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p);
int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server);
+int dns_scope_udp_dns_socket(DnsScope *s, 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);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3d46c99df8..8a93b265c6 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -39,10 +39,8 @@ 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);
+ sd_event_source_unref(t->dns_event_source);
+ safe_close(t->dns_fd);
dns_server_unref(t->server);
dns_stream_free(t->stream);
@@ -94,7 +92,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
if (!t)
return -ENOMEM;
- t->dns_ipv4_fd = t->dns_ipv6_fd = -1;
+ t->dns_fd = -1;
t->question = dns_question_ref(q);
@@ -245,7 +243,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;
+ DnsServer *server = NULL;
_cleanup_close_ int fd = -1;
int r;
@@ -310,6 +308,16 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
return 0;
}
+static void dns_transaction_next_dns_server(DnsTransaction *t) {
+ assert(t);
+
+ t->server = dns_server_unref(t->server);
+ t->dns_event_source = sd_event_source_unref(t->dns_event_source);
+ t->dns_fd = safe_close(t->dns_fd);
+
+ dns_scope_next_dns_server(t->scope);
+}
+
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
int r;
@@ -342,24 +350,6 @@ 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 the
- * one of the DNS server we queried */
-
- 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)
- return;
- }
-
if (t->received != p) {
dns_packet_unref(t->received);
t->received = dns_packet_ref(p);
@@ -396,7 +386,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
}
/* On DNS, couldn't send? Try immediately again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
r = dns_transaction_go(t);
if (r < 0) {
@@ -416,8 +406,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
}
/* 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)) {
+ r = dns_question_is_equal(p->question, t->question);
+ if (r <= 0) {
dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
return;
}
@@ -431,6 +421,56 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
dns_transaction_complete(t, DNS_TRANSACTION_FAILURE);
}
+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;
+}
+
+static int dns_transaction_emit(DnsTransaction *t) {
+ int r;
+
+ assert(t);
+
+ if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) {
+ DnsServer *server = NULL;
+ _cleanup_close_ int fd = -1;
+
+ fd = dns_scope_udp_dns_socket(t->scope, &server);
+ if (fd < 0)
+ return fd;
+
+ r = sd_event_add_io(t->scope->manager->event, &t->dns_event_source, fd, EPOLLIN, on_dns_packet, t);
+ if (r < 0)
+ return r;
+
+ t->dns_fd = fd;
+ fd = -1;
+ t->server = dns_server_ref(server);
+ }
+
+ r = dns_scope_emit(t->scope, t->dns_fd, t->sent);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) {
DnsTransaction *t = userdata;
int r;
@@ -439,7 +479,7 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat
assert(t);
/* Timeout reached? Try again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
r = dns_transaction_go(t);
if (r < 0)
@@ -516,7 +556,6 @@ 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;
@@ -596,13 +635,9 @@ 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, t->sent, &server);
- if (r >= 0)
- t->server = dns_server_ref(server);
- else if (r == -EMSGSIZE)
+ r = dns_transaction_emit(t);
+ if (r == -EMSGSIZE)
r = dns_transaction_open_tcp(t);
}
if (r == -ESRCH) {
@@ -616,7 +651,7 @@ int dns_transaction_go(DnsTransaction *t) {
}
/* Couldn't send? Try immediately again, with a new server */
- dns_scope_next_dns_server(t->scope);
+ dns_transaction_next_dns_server(t);
return dns_transaction_go(t);
}
@@ -634,91 +669,6 @@ 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",
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 87f342ca11..a8f4267bc8 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -61,11 +61,8 @@ 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;
+ int dns_fd;
+ sd_event_source *dns_event_source;
/* the active server */
DnsServer *server;
@@ -95,9 +92,6 @@ 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_;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 17de14bae1..5be01d3cb8 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -912,10 +912,12 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (p->ifindex == LOOPBACK_IFINDEX)
p->ifindex = 0;
- /* If we don't know the interface index still, we look for the
- * first local interface with a matching address. Yuck! */
- if (p->ifindex <= 0)
- p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
+ if (protocol != DNS_PROTOCOL_DNS) {
+ /* If we don't know the interface index still, we look for the
+ * first local interface with a matching address. Yuck! */
+ if (p->ifindex <= 0)
+ p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
+ }
*ret = p;
p = NULL;
@@ -947,6 +949,42 @@ static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
}
}
+static int write_loop(int fd, void *message, size_t length) {
+ int r;
+
+ assert(fd >= 0);
+ assert(message);
+
+ for (;;) {
+ if (write(fd, message, length) >= 0)
+ return 0;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != EAGAIN)
+ return -errno;
+
+ r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ETIMEDOUT;
+ }
+}
+
+int manager_write(Manager *m, int fd, DnsPacket *p) {
+ int r;
+
+ log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
+
+ r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 005f844df2..53b5acb33c 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -119,6 +119,7 @@ void manager_next_dns_server(Manager *m);
uint32_t manager_find_mtu(Manager *m);
+int manager_write(Manager *m, int fd, DnsPacket *p);
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);