6
85
Fork
You've already forked dns
39

Default DNS server behavior should pass RFC-8906 #873

Open
opened 2026年05月18日 19:05:43 +02:00 by hmholschuh · 3 comments
Contributor
Copy link

The ISC compliance checker tests a few very important behaviors expected of anything operating in EDNS0 mode.

It can be found at:
https://ednscomp.isc.org/

Its source code (with the dig commands it uses) can be found at:
https://gitlab.isc.org/isc-projects/DNS-Compliance-Testing

It would be really good if DNS servers implemented using miekg/dns would pass these tests by default, or at least if all examples and documentation would include the required handling for it.

To pass the ISC EDNS compliance tests on a DNS authoritative server written using miekg/dns, I had to add specific handing to:

  • enable EDNS response only for EDNS requests, keep it disabled for non-EDNS requests on every handler that generates an response of some sort (including error responses)
  • do the EDNS version check, and return the BADVER RCODE if it is not EDNS0, on every handler.

It basically boiled down to:

// right at the start of every DNS message handler (or a common one that always runs first)
err := r.Unpack() // error handling omitted for brevity. Required to populate MsgHeader with EDNS OPT RR data.
if r.Version != 0 { 
 IssueBADVERerror(w, r) // omitted for brevity. composes an EDNS*0* reply with RcodeBadVers and sends it
 return
}
m := &dns.Msg{ Data: r.Data }
dnsutil.SetReply(m, r)
if r.UDPSize > 0 { m.UDPSize = 1232 } // r.UDPSize is only changed from 0 if an EDNS OPT RR is processed by r.Unpack()
// rest of DNS message handler, io.Copy(w, m)

Obviously, the 1232 bytes size limit in the example above is just my own preference to stick to DNS Flag Day 2020 parameters.

The need for explicitly doing the r.Version check is IMHO worrisome, because it is important to do so for the DNS ecosystem as a whole (it avoids contributing to DNS ossification), but it is a very non-obvious thing that is only going to be done on most dns servers written using miekg/dns if it happens by default. Heck, I am not sure I implemented it correctly either :-(

Any suggestions on an acceptable way to add the r.Version error handling to miekg/dns ? I am up to trying to write a patch and submit a PR... but I am unsure if doing it on ServeDNS, perhaps gated by an option in the server struct would be acceptable, since it does require a full unpack.

If it cannot be done by default in miekg/dns, my suggestion is that the documentation should explain how to do it and the examples should include it. Maybe a dnsutil function could be provided that helps implementing it correctly, too.

Also, atomdns likely should implement that EDNS version check too [at a first look it doesn't appear to, but I didn't try running atomdns and pointing dig +edns=1 at it, so I apologize if it already does that EDNS version checking].

The ISC compliance checker tests a few very important behaviors expected of anything operating in EDNS0 mode. It can be found at: https://ednscomp.isc.org/ Its source code (with the dig commands it uses) can be found at: https://gitlab.isc.org/isc-projects/DNS-Compliance-Testing It would be really good if DNS servers implemented using miekg/dns would pass these tests by default, or at least if all examples and documentation would include the required handling for it. To pass the ISC EDNS compliance tests on a DNS authoritative server written using miekg/dns, I had to add specific handing to: * enable EDNS response only for EDNS requests, keep it disabled for non-EDNS requests on every handler that generates an response of some sort (including error responses) * do the EDNS version check, and return the BADVER RCODE if it is not EDNS0, on every handler. It basically boiled down to: ``` // right at the start of every DNS message handler (or a common one that always runs first) err := r.Unpack() // error handling omitted for brevity. Required to populate MsgHeader with EDNS OPT RR data. if r.Version != 0 { IssueBADVERerror(w, r) // omitted for brevity. composes an EDNS*0* reply with RcodeBadVers and sends it return } m := &dns.Msg{ Data: r.Data } dnsutil.SetReply(m, r) if r.UDPSize > 0 { m.UDPSize = 1232 } // r.UDPSize is only changed from 0 if an EDNS OPT RR is processed by r.Unpack() // rest of DNS message handler, io.Copy(w, m) ``` Obviously, the 1232 bytes size limit in the example above is just my own preference to stick to DNS Flag Day 2020 parameters. The need for explicitly doing the r.Version check is IMHO worrisome, because it is important to do so for the DNS ecosystem as a whole (it avoids contributing to DNS ossification), but it is a very non-obvious thing that is only going to be done on most dns servers written using miekg/dns if it happens by default. Heck, I am not sure I implemented it correctly either :-( Any suggestions on an acceptable way to add the r.Version error handling to miekg/dns ? I am up to trying to write a patch and submit a PR... but I am unsure if doing it on ServeDNS, perhaps gated by an option in the server struct would be acceptable, since it *does* require a full unpack. If it cannot be done by default in miekg/dns, my suggestion is that the documentation should explain how to do it and the examples should include it. Maybe a dnsutil function could be provided that helps implementing it correctly, too. Also, atomdns likely should implement that EDNS version check too [at a first look it doesn't appear to, but I didn't try running atomdns and pointing dig +edns=1 at it, so I apologize if it already does that EDNS version checking].
Owner
Copy link

thanks for this, yes it probably should.

Also, atomdns likely should implement that EDNS version check too [at a first look it doesn't appear to, but I didn't try running atomdns and pointing dig +edns=1 at it, so I apologize if it already does that EDNS version checking].

yeah, I've also used gonemaster and it flagged some issues, but didn't have time to fix.

Think most of this could maybe be done in a MsgAcceptFunction ? Patches welcome.

thanks for this, yes it probably should. > Also, atomdns likely should implement that EDNS version check too [at a first look it doesn't appear to, but I didn't try running atomdns and pointing dig +edns=1 at it, so I apologize if it already does that EDNS version checking]. yeah, I've also used [gonemaster](https://codeberg.org/pawal/gonemaster) and it flagged some issues, but didn't have time to fix. Think most of this could maybe be done in a MsgAcceptFunction ? Patches welcome.
Author
Contributor
Copy link

Lots of more strict RFC compliance depend on actually being able to reply EDNS messages in EDNS mode and never replying to non-EDNS messages with EDNS mode(*). I should file a separate issue about it.

Doing so would make it easier to address the EDNS version check and appropriately reply with an EDNS error, so I will think about it a bit before proposing either a PR or a way to fix it.

MsgAcceptFunction would need to be extended to be able to return at least an Rcode to be used for query rejection, I think. And obviously, one that can handle EDNS version check would need OPT RR parsing to have been done already.

(*) This is actually a RFC MUST requirement, and AFAIK it exists to avoid creating extra interoperability issues for legacy non-EDNS aware DNS clients.

Lots of more strict RFC compliance depend on actually being able to reply EDNS messages in EDNS mode and never replying to non-EDNS messages with EDNS mode(*). I should file a separate issue about it. Doing so would make it easier to address the EDNS version check and appropriately reply with an EDNS error, so I will think about it a bit before proposing either a PR or a way to fix it. MsgAcceptFunction would need to be extended to be able to return at least an Rcode to be used for query rejection, I think. And obviously, one that can handle EDNS version check would need OPT RR parsing to have been done already. (*) This is actually a RFC MUST requirement, and AFAIK it exists to avoid creating extra interoperability issues for legacy non-EDNS aware DNS clients.
Author
Contributor
Copy link

Note: ednscomp.isc.org is actually implementing RFC8906 / BCP231, https://www.rfc-editor.org/rfc/rfc8906.html.

Note: ednscomp.isc.org is actually implementing RFC8906 / BCP231, https://www.rfc-editor.org/rfc/rfc8906.html.
hmholschuh changed title from (削除) Default DNS server behavior should pass https://ednscomp.isc.org/ (削除ここまで) to Default DNS server behavior should pass RFC-8906 2026年05月25日 19:26:36 +02:00
Sign in to join this conversation.
No Branch/Tag specified
main
miek/26/jun24wo/14
miek/26/mrt24di/tls
miek/26/mrt09ma/17
miek/26/feb15zo/13
miek/zo-07-dec-25/gslb1
miek/2025-10-26@1431
miek/2025-10-18@2017
v0.6.83
v0.6.82
v0.6.81
v0.6.80
v0.6.79
v0.6.78
v0.6.77
v0.6.76
v0.6.75
v0.6.74
v0.6.73
v0.6.72
v0.6.71
v0.6.70
v0.6.69
v0.6.68
v0.6.67
v0.6.66
v0.6.65
v0.6.64
v0.6.63
v0.6.62
v0.6.61
v0.6.60
v0.6.59
v0.6.58
v0.6.57
v0.6.56
v0.6.55
v0.6.54
v0.6.53
v0.6.52
v0.6.51
v0.6.50
v0.6.49
v0.6.48
v0.6.47
v0.6.46
v0.6.45
v0.6.44
v0.6.43
v0.6.42
v0.6.41
v0.6.40
v0.6.39
v0.6.38
v0.6.37
v0.6.36
v0.6.35
v0.6.34
v0.6.33
v0.6.32
v0.6.31
v0.6.30
v0.6.29
v0.6.28
v0.6.27
v0.6.26
v0.6.25
v0.6.24
v0.6.23
v0.6.22
v0.6.21
v0.6.20
v0.6.19
v0.6.18
v0.6.17
v0.6.16
v0.6.15
v0.6.14
v0.6.13
v0.6.12
v0.6.11
v0.6.10
v0.6.9
v0.6.8
v0.6.7
v0.6.6
v0.6.5
v0.6.4
v0.6.3
v0.6.2
v0.6.1
v0.6.0
v0.5.38
v0.5.37
v0.5.36
v0.5.35
v0.5.34
v0.5.33
v0.5.32
v0.5.31
v0.5.30
v0.5.29
v0.5.28
v0.5.27
v0.5.26
v0.5.25
v0.5.24
v0.5.23
v0.5.22
v0.5.21
v0.5.20
v0.5.19
v0.5.18
v0.5.17
v0.5.16
v0.5.15
v0.5.14
v0.5.13
v0.5.12
v0.5.11
v0.5.10
v0.5.9
v0.5.8
v0.5.7
v0.5.6
v0.5.5
v0.5.4
v0.5.3
v0.5.2
v0.5.1
v0.5.0
v0.1.12
v0.1.11
v0.1.10
v0.1.9
v0.1.8
v0.1.7
v0.1.6
v0.1.5
v0.1.4
v0.0.4
v0.0.3
v0.0.2
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
miekg/dns#873
Reference in a new issue
miekg/dns
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?