Skip to content

RFC2136 delete UPDATEs: 0.9.24 parses them into rdata='', but 0.9.25+ rejects them with Error: Empty RR #76

@dbstraffin

Description

@dbstraffin

I think issue #63 fixed a real problem, but it may also have removed practical support for valid RFC2136 UPDATE delete records.

Summary

RFC2136 delete operations can use empty RDATA in the UPDATE section.

Historically, dnslib appears to have supported this by parsing such records into an RR whose rdata was the empty string ''. That representation was flawed, but it was still usable in practice for applications that explicitly checked for rr.rdata == '' when handling delete markers.

As of 0.9.25, issue #63 changed this behavior so empty-RDATA RRs are rejected during parse with:

DNSError: Error: Empty RR

This seems to prevent real RFC2136 delete UPDATEs from reaching application logic at all.

What changed

The relevant historical changes appear to be:

  • commit 036faa9"Don't parse rdata if rdlength is 0."
    • when rdlength == 0, RR.parse() set rdata = ''
  • commit d1d8f36 for issue Records with empty rdata causes pack() to fail #63"Add checks for invalid RD"
    • changed that path to:
      raise DNSError("Error: Empty RR")
    • and also added constructor validation rejecting non-RD values for non-OPT records

So:

  • pre-0.9.25: empty-RDATA UPDATE delete records were parseable, but represented unsafely
  • 0.9.25+: empty-RDATA UPDATE delete records appear to be rejected outright

Minimal repro

I used a tiny dnslib UDP server and sent updates with nsupdate.

Tiny server:

#!/usr/bin/env python3
from dnslib.server import BaseResolver, DNSLogger, DNSServer

class ReproResolver(BaseResolver):
    def resolve(self, request, handler):
        print("RESOLVER_CALLED")
        print(request)
        return request.reply()

server = DNSServer(
    ReproResolver(),
    address="127.0.0.1",
    port=8053,
    logger=DNSLogger(prefix=False),
)
print("LISTENING 127.0.0.1:8053")
server.start()

Control case (works):

printf 'server 127.0.0.1 8053
zone example.com.
update add foo.example.com. 60 A 127.0.0.1
send
' | nsupdate

Delete case:

printf 'server 127.0.0.1 8053
zone example.com.
update delete foo.example.com. A
send
' | nsupdate

Observed behavior

On 0.9.24

The delete request reaches the resolver, but formatting/stringifying the parsed request crashes because the delete RR has rdata = '' and RR.toZone() expects rdata.toZone():

AttributeError: 'str' object has no attribute 'toZone'

So 0.9.24 behavior was flawed, but still usable if application code explicitly handled the sentinel '' representation instead of stringifying it.

On 0.9.25 / 0.9.26

The delete request no longer reaches the resolver. The server reports:

Invalid Request: [127.0.0.1:NNNNN] (udp) :: Error: Empty RR

So the wire-format delete UPDATE is rejected during parse.

Expected behavior

I think the ideal behavior would be:

  • valid RFC2136 delete UPDATE records with empty RDATA should still be parseable
  • but they should use a safe internal representation rather than raw ''
  • application code should be able to distinguish delete markers without either:
    • crashing later on formatting/packing (0.9.24 behavior)
    • or having the records rejected before resolver logic runs (0.9.25+ behavior)

Why this matters

This affects applications using dnslib as a server-side DNS UPDATE handler. In my case, an application had logic that explicitly recognized empty-RDATA delete markers (for example, checking rr.rdata == ''), so the old behavior, while flawed, was practically usable. The newer behavior appears to remove that handling path entirely.

Question

Would you consider restoring support for RFC2136 delete UPDATE parsing with a safe internal representation for empty-RDATA delete markers?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions