summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-scope.c
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-06-23 23:06:09 +0200
committerTom Gundersen <teg@jklm.no>2015-11-27 01:35:34 +0100
commit9c5e12a4314e7192e834e1b855e5e80111e636a6 (patch)
treefc82c7ab5220ad0847ed439b44946528a327d50b /src/resolve/resolved-dns-scope.c
parentdc913c9a1f243bca291d47b1a5d8e270c471d113 (diff)
resolved: implement minimal EDNS0 support
This is a minimal implementation of RFC6891. Only default values are used, so in reality this will be a noop. EDNS0 support is dependent on the current server's feature level, so appending the OPT pseudo RR is done when the packet is emitted, rather than when it is assembled. To handle different feature levels on retransmission, we strip off the OPT RR again after sending the packet. Similarly, to how we fall back to TCP if UDP fails, we fall back to plain UDP if EDNS0 fails (but if EDNS0 ever succeeded we never fall back again, and after a timeout we will retry EDNS0).
Diffstat (limited to 'src/resolve/resolved-dns-scope.c')
-rw-r--r--src/resolve/resolved-dns-scope.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index a8c0ae1569..42478e41e2 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -158,12 +158,13 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec) {
s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC);
}
-int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
+int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {
union in_addr_union addr;
int ifindex = 0, r;
int family;
uint16_t port;
uint32_t mtu;
+ size_t saved_size = 0;
assert(s);
assert(p);
@@ -178,9 +179,19 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
switch (s->protocol) {
case DNS_PROTOCOL_DNS:
+ assert(server);
+
if (DNS_PACKET_QDCOUNT(p) > 1)
return -EOPNOTSUPP;
+ if (server->possible_features >= DNS_SERVER_FEATURE_LEVEL_EDNS0) {
+ r = dns_packet_append_opt_rr(p, DNS_PACKET_UNICAST_SIZE_MAX, &saved_size);
+ if (r < 0)
+ return r;
+
+ DNS_PACKET_HEADER(p)->arcount = htobe16(be16toh(DNS_PACKET_HEADER(p)->arcount) + 1);
+ }
+
if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
return -EMSGSIZE;
@@ -191,6 +202,12 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) {
if (r < 0)
return r;
+ if (saved_size > 0) {
+ dns_packet_truncate(p, saved_size);
+
+ DNS_PACKET_HEADER(p)->arcount = htobe16(be16toh(DNS_PACKET_HEADER(p)->arcount) - 1);
+ }
+
break;
case DNS_PROTOCOL_LLMNR:
@@ -739,7 +756,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
return 0;
}
- r = dns_scope_emit(scope, -1, p);
+ r = dns_scope_emit(scope, -1, NULL, p);
if (r < 0)
log_debug_errno(r, "Failed to send conflict packet: %m");
}