mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-12 02:06:59 +00:00
- Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks
to Qifan Zhang, Palo Alto Networks, for the report. In addition, thanks to Trung Nguyen (@everping) of CyStack, for also reporting this issue.
This commit is contained in:
+9
-1
@@ -1550,6 +1550,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
dname_str(qinfo.qname, buf);
|
||||
@@ -1568,6 +1569,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
worker->stats.num_query_dnscrypt_cert++;
|
||||
@@ -1828,7 +1830,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
server_stats_insquery(&worker->stats, c, qinfo.qtype,
|
||||
qinfo.qclass, &edns, repinfo);
|
||||
if(c->type != comm_udp)
|
||||
#ifdef USE_DNSCRYPT
|
||||
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
|
||||
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
|
||||
: 65535;
|
||||
#else
|
||||
edns.udp_size = 65535; /* max size for TCP replies */
|
||||
#endif
|
||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||
&edns, repinfo, c->buffer)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -2112,7 +2120,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
+12
-2
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
uint8_t *const buf = sldns_buffer_begin(buffer);
|
||||
size_t len = sldns_buffer_limit(buffer);
|
||||
|
||||
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
|
||||
return -1;
|
||||
sldns_buffer_clear(buffer);
|
||||
|
||||
if(udp){
|
||||
if (max_len > max_reply_size)
|
||||
max_len = max_reply_size;
|
||||
}
|
||||
if(max_len > sldns_buffer_capacity(buffer))
|
||||
max_len = sldns_buffer_capacity(buffer);
|
||||
if(max_len > 65535)
|
||||
max_len = 65535;
|
||||
|
||||
|
||||
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
|
||||
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN,
|
||||
nonce,
|
||||
crypto_box_NONCEBYTES);
|
||||
sldns_buffer_flip(buffer);
|
||||
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
@@ -912,12 +921,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
}
|
||||
|
||||
int
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo)
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer)
|
||||
{
|
||||
if(!repinfo->c->dnscrypt) {
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
|
||||
if(!repinfo->is_dnscrypted) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
+2
-1
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
* \return 0 in case of failure.
|
||||
*/
|
||||
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo);
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Computes the size of the shared secret cache entry.
|
||||
|
||||
+9
-8
@@ -9,20 +9,21 @@ PRE="../.."
|
||||
|
||||
# do the test
|
||||
|
||||
# Query plain request over DNSCrypt channel get closed
|
||||
# We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig TCP www.example.com. DNSCrypt port"
|
||||
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
# Query plain request over DNSCrypt.
|
||||
# This used to close the channel; now it returns SERVFAIL.
|
||||
# Old: We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig www.example.com. DNSCrypt port"
|
||||
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
echo "> cat logfiles"
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
echo "> check answer"
|
||||
if grep "QUESTION SECTION" outfile; then
|
||||
if grep "SERVFAIL" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "NOK"
|
||||
exit 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -9,20 +9,21 @@ PRE="../.."
|
||||
|
||||
# do the test
|
||||
|
||||
# Query plain request over DNSCrypt channel get closed
|
||||
# We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig TCP www.example.com. DNSCrypt port"
|
||||
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
# Query plain request over DNSCrypt.
|
||||
# This used to close the channel; now it returns SERVFAIL.
|
||||
# Old: We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig www.example.com. DNSCrypt port"
|
||||
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
echo "> cat logfiles"
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
echo "> check answer"
|
||||
if grep "QUESTION SECTION" outfile; then
|
||||
if grep "SERVFAIL" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "NOK"
|
||||
exit 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
+3
-1
@@ -6677,7 +6677,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
|
||||
log_assert(repinfo && repinfo->c);
|
||||
#ifdef USE_DNSCRYPT
|
||||
buffer = repinfo->c->dnscrypt_buffer;
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo,
|
||||
repinfo->c->tcp_req_info?
|
||||
repinfo->c->tcp_req_info->spool_buffer:repinfo->c->buffer)) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user