Description
Hello!
So I was investigating a failed update to a BIND nameserver that returned FORMERR. Looking with the debugger, I've noticed that the generated wire format was > 65535 here.
After more investigation, I think I identified the issue: I am using a resolver with tsig with algorithm HMAC_SHA384
, and the calculation that is made in TSIG.recordLength() is wrong. More specifically, it considers a MAC size of 16 bytes. While this is true for MD5, it doesn't work for other algorithms such as HMAC_SHA384
, where the hash is greater in length.
This is a small repro (in Kotlin) showing the generated message is higher than the allowed DNS message size of 65535:
import org.xbill.DNS.DClass
import org.xbill.DNS.Message
import org.xbill.DNS.Name
import org.xbill.DNS.SimpleResolver
import org.xbill.DNS.TSIG
import org.xbill.DNS.TXTRecord
import org.xbill.DNS.Update
import org.xbill.DNS.io.IoClientFactory
import org.xbill.DNS.io.TcpIoClient
import org.xbill.DNS.io.UdpIoClient
import java.util.concurrent.CompletableFuture
fun main() {
val update = Update(Name.fromConstantString("zone.example.com."))
repeat(2000) { i ->
val record = TXTRecord(
Name.fromConstantString("name-$i.zone.example.com."),
DClass.IN,
900,
"a",
)
update.absent(record.name, record.type)
update.add(record)
}
val resolver = SimpleResolver().apply {
tsigKey = TSIG(TSIG.HMAC_SHA384, "zone.example.com.", "c2VjcmU=")
ioClientFactory = object : IoClientFactory {
override fun createOrGetTcpClient(): TcpIoClient {
return TcpIoClient { local, remote, query, data, timeout ->
println("Sending data of length: ${data.size}")
println("Is data > max message size (${Message.MAXLENGTH})? ${data.size > Message.MAXLENGTH}")
CompletableFuture.failedFuture(Exception())
}
}
override fun createOrGetUdpClient(): UdpIoClient {
TODO("Not yet implemented")
}
}
}
resolver.send(update)
}
This outputs:
Sending data of length: 65544
Is data > max message size (65535)? true
The FORMERR we got is because the data of 65544 bytes exceeds what can be stored in two bytes so this computation rolls over, so the message gets truncated at a random point and cannot be interpreted by the receiver.
I believe an easy fix for this would be to either give more slack in the calculation and put the max of all supported algorithms, or put the correct number based on the algorithm used.