dns: @hnw alternate proposal (#193)

* fix(dns): resolve CNAME chains and prevent invalid IP parsing

- Add automated in-band CNAME chain resolution to extract final A/AAAA IP addresses.
- Replace `MaxResponseAnswers` with `MaxIPs` and `MaxCNAMEs` to explicitly bound resource decoding and prevent memory exhaustion.
- Bound CNAME chain traversal to prevent infinite loops from cyclic records.

* refactor(dns): eagerly decode CNAME target into r.data, drop target field

Address review feedback on #189:

- Remove Resource.target: Resource.Decode expands CNAME RDATA in place
  into r.data (uncompressed wire format) while the full message is still
  available and updates header.Length, storing the name bytes exactly once.
- Add Resource.CNAMEView returning a length-bounded view of the expanded
  target; Message.WriteAnswers uses it.
- Rename matchesHost to ResourceHeader.pertainsTo.
- Make ResolveConfig.MaxCNAMEs explicit: drop the silent default in
  Client.StartResolve and let callers opt in (x/xnet).
- Reduce test suite to regression coverage only.

refs #189

* dns: simplify @hnw function and additional fixes

---------

Co-authored-by: Yoshio HANAWA <y@hnw.jp>
This commit is contained in:
Pat Whittingslow
2026-08-28 21:39:12 -03:00
committed by GitHub
parent ab9d3ee691
commit 75f1e02a20
9 changed files with 369 additions and 56 deletions
+1 -19
View File
@@ -300,25 +300,7 @@ func (kvb *kvBuffer) getFoldIdx(key string) int {
// EqualFoldASCII reports whether a and b are equal under ASCII case folding.
// Unlike strings.EqualFold it does not fold non-ASCII runes, so no multi-byte
// rune such as U+212A KELVIN SIGN can alias a header key.
func EqualFoldASCII(a, b string) bool {
if len(a) != len(b) {
return false
}
const asciiCapDiff = 'a' - 'A'
for i := 0; i < len(a); i++ {
ca, cb := a[i], b[i]
if ca >= 'A' && ca <= 'Z' {
ca += asciiCapDiff
}
if cb >= 'A' && cb <= 'Z' {
cb += asciiCapDiff
}
if ca != cb {
return false
}
}
return true
}
func EqualFoldASCII(a, b string) bool { return internal.EqualFoldASCII(a, b) }
// reserve ensures need free bytes are available in the buffer, growing it when
// permitted. It accounts for the byte-0 reservation on an empty buffer (see
+2 -15
View File
@@ -253,20 +253,7 @@ func trimOWS(b []byte) []byte {
return b
}
// equalFold compares b to the ASCII lowercase key, case insensitively.
// equalFold compares b to key, case insensitively.
func equalFold(b []byte, key string) bool {
if len(b) != len(key) {
return false
}
const asciiCapDiff = 'a' - 'A'
for i := range b {
c := b[i]
if c >= 'A' && c <= 'Z' {
c += asciiCapDiff
}
if c != key[i] {
return false
}
}
return true
return EqualFoldASCII(b2s(b), key)
}