Skip to content

Message.toWire(Message.MAXLENGTH) can generate byte[] > Message.MAXLENGTH #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MMauro94 opened this issue Dec 5, 2024 · 0 comments
Closed
Assignees
Labels
Milestone

Comments

@MMauro94
Copy link

MMauro94 commented Dec 5, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy