Skip to content

Commit d7de0c1

Browse files
johanbrandhorstnoxerTim Scheuermannjimlambrtmiekg
authored
Merge upstream changes (#3)
* Swap closing order in `inAxfr` and `inIxfr` (miekg#1511) * Fix closing order * Comment to make clear that the close order is deliberate --------- Co-authored-by: Tim Scheuermann <[email protected]> * feat: add support for ReuseAddr (miekg#1510) * feat: add support for ReuseAddr * Update listen_reuseport.go * Update listen_reuseport.go * fixup! feat: add support for ReuseAddr --------- Co-authored-by: Miek Gieben <[email protected]> * Release 1.1.57 * Try explaining duplicate RCODEs Add extra link to the docs for the duplicate Rcode entries See miekg#1523 Signed-off-by: Miek Gieben <[email protected]> * docs: added ninedos to readme (miekg#1522) * Allow use of fs.FS for $INCLUDE and wrap errors (miekg#1526) * Allow use of fs.FS for $INCLUDE and wrap errors This adds ZoneParser.SetIncludeAllowedFS, to specify an fs.FS when enabling support for $INCLUDE, for reading included files from somewhere other than the local filesystem. I've also modified ParseError to support wrapping another error, such as errors encountered while opening the $INCLUDE target. This allows for much more robust handling, using errors.Is() instead of testing for particular strings (which may not be identical between fs.FS implementations). ParseError was being constructed in a lot of places using positional instead of named members. Updating ParseError initialization after the new member field was added makes this change seem a lot larger than it actually is. The changes here should be completely backwards compatible. The ParseError change should be invisible to anyone not trying to unwrap it, and ZoneParser will continue to use os.Open if the existing SetIncludeAllowed method is called instead of the new SetIncludeAllowedFS method. * Don't duplicate SetIncludeAllowed; clarify edge cases Rather than duplicate functionality between SetIncludeAllowed and SetIncludeAllowedFS, have a method SetIncludeFS, which only sets the fs.FS. I've improved the documentation to point out some considerations for users hoping to use fs.FS as a security boundary. Per the fs.ValidPath documentation, fs.FS implementations must use path (not filepath) semantics, with slash as a separator (even on Windows). Some, like os.DirFS, also require all paths to be relative. I've clarified this in the documentation, made the includePath manipulation more robust to edge cases, and added some additional tests for relative and absolute paths. * Bump golang.org/x/net from 0.17.0 to 0.19.0 (miekg#1520) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.19.0. - [Commits](golang/net@v0.17.0...v0.19.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/sys from 0.13.0 to 0.15.0 (miekg#1518) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.15.0. - [Commits](golang/sys@v0.13.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add NXT record (miekg#1516) This add the NXT record (2535) to implement all records from the RFC. Also does a s/RFC RFC/RFC/ as I happen to bumb into that will editing the comments. Signed-off-by: Miek Gieben <[email protected]> * Add ISDN record (miekg#1515) We had the type code, this add the rest. Other RRs from 1183 are also fully impl. don't know why this one wasn't. Signed-off-by: Miek Gieben <[email protected]> * Bump golang.org/x/tools from 0.13.0 to 0.17.0 (miekg#1529) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.13.0 to 0.17.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](golang/tools@v0.13.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Release 1.1.58 * Improve NewRR documentation (miekg#1531) In particular, document the default origin. * Add incus to the list of users (miekg#1535) * Add option to do a zone transfer via TLS (miekg#1533) * New func InTLS Perform zone transfer via TLS * Test xfr via TLS * New field TLS, used to transfer via TLS --------- Co-authored-by: Cesar Kuroiwa <[email protected]> * IsDomainName: check for escape as last character (miekg#1532) Keep track if the escape, if still true when returning isDomainName should return false. TODO: - Should still be done in packDomainName as well. - And that should be tested - Some tests now fail There are multiple other places that supposedly also check for this, but they are not called in the parsing. Fixes: miekg#1528 Signed-off-by: Miek Gieben <[email protected]> * Bump golang.org/x/sys from 0.16.0 to 0.17.0 (miekg#1541) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.16.0 to 0.17.0. - [Commits](golang/sys@v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/net from 0.20.0 to 0.21.0 (miekg#1542) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.21.0. - [Commits](golang/net@v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/tools from 0.17.0 to 0.19.0 (miekg#1551) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.17.0 to 0.19.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](golang/tools@v0.17.0...v0.19.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: fix some comments (miekg#1547) Signed-off-by: xiaoxiangxianzi <[email protected]> * Add ifconfig.es to the list of users (miekg#1554) * Fix counting of escape sequences when splitting TXT strings (miekg#1540) `endingToTxtSlice`, used by TXT, SPF and a few other types, parses a string such as `"hello world"` from an RR's content in a zone file. These strings are limited to 255 characters, and `endingToTxtSlice` automatically splits them if they're longer than that. However, it didn't count the length correctly: escape sequences such as `\\` or `\123` were counted as multiple characters (2 and 4 respectively in these examples), but they should only count as one character because they represent a single byte in wire format (which is where this 255 character limit comes from). This commit fixes that. * Fix possible out-of-bounds read in endingToTxtSlice (miekg#1557) * Update escapedStringOffset to improve readability This function was, admittedly, a little difficult to follow. This new version is slightly more verbose, but, in my opinion, easier to understand. * Fix possible out-of-bounds read in endingToTxtSlice caused by escapedStringOffset If the input had a trailing backslash (normally the start of an escape sequence) with nothing following it, `escapedStringOffset` would return the length of the input, plus one (!), as the result index, causing an out-of-bounds read and panic in `endingToTxtSlice`. Consistent with, e.g., commit 2230854, I've decided to make this an error since it definitely indicates that the string isn't valid. Credit to OSS-Fuzz -- thank you! * Bump golang.org/x/sys from 0.18.0 to 0.20.0 (miekg#1571) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.18.0 to 0.20.0. - [Commits](golang/sys@v0.18.0...v0.20.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/net from 0.22.0 to 0.25.0 (miekg#1569) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.25.0. - [Commits](golang/net@v0.22.0...v0.25.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump golang.org/x/tools from 0.19.0 to 0.22.0 (miekg#1574) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.19.0 to 0.22.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](golang/tools@v0.19.0...v0.22.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * (*Transfer) Out: Increment WaitGroup in example (miekg#1572) * Add a hook to catch invalid messages (miekg#1568) * Add a hook to catch invalid messages Currently there are hooks for reading messages off the wire (DecorateReader), checking if they comply with policy (MsgAcceptFunc), and generating responses (Handler). However, there is no hook that notifies the server when a message is dropped or rejected due to a syntax error. That makes it hard to monitor these packets without repeating the parsing process. This PR adds a hook for notifications about invalid packets. * s/InvalidMsg/MsgInvalid/g * These two too Signed-off-by: Miek Gieben <[email protected]> * Add RFC 9540 oblivious services via service binding records (miekg#1567) * update list of RFCs Signed-off-by: Miek Gieben <[email protected]> * add rfc3596 to the list (miekg#1577) --------- Signed-off-by: Miek Gieben <[email protected]> Signed-off-by: dependabot[bot] <[email protected]> Signed-off-by: xiaoxiangxianzi <[email protected]> Co-authored-by: Tim Scheuermann <[email protected]> Co-authored-by: Tim Scheuermann <[email protected]> Co-authored-by: Jim <[email protected]> Co-authored-by: Miek Gieben <[email protected]> Co-authored-by: WintBit <[email protected]> Co-authored-by: Dave Pifke <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Richard Gibson <[email protected]> Co-authored-by: montag451 <[email protected]> Co-authored-by: Cesar Kuroiwa <[email protected]> Co-authored-by: Cesar Kuroiwa <[email protected]> Co-authored-by: xiaoxiangxianzi <[email protected]> Co-authored-by: dcarrillo <[email protected]> Co-authored-by: Janik Rabe <[email protected]> Co-authored-by: Patrik Lundin <[email protected]> Co-authored-by: Benjamin M. Schwartz <[email protected]> Co-authored-by: Steffen Sassalla <[email protected]> Co-authored-by: Infinoid <[email protected]>
1 parent 9d11e97 commit d7de0c1

26 files changed

+1108
-283
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
8282
* https://dnscheck.tools/
8383
* https://github.com/egbakou/domainverifier
8484
* https://github.com/semihalev/sdns
85+
* https://github.com/wintbiit/NineDNS
86+
* https://linuxcontainers.org/incus/
87+
* https://ifconfig.es
8588

8689

8790
Send pull request if you want to be listed here.
@@ -125,6 +128,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
125128
*all of them*
126129

127130
* 103{4,5} - DNS standard
131+
* 1183 - ISDN, X25 and other deprecated records
128132
* 1348 - NSAP record (removed the record)
129133
* 1982 - Serial Arithmetic
130134
* 1876 - LOC record
@@ -144,6 +148,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
144148
* 3225 - DO bit (DNSSEC OK)
145149
* 340{1,2,3} - NAPTR record
146150
* 3445 - Limiting the scope of (DNS)KEY
151+
* 3596 - AAAA record
147152
* 3597 - Unknown RRs
148153
* 4025 - A Method for Storing IPsec Keying Material in DNS
149154
* 403{3,4,5} - DNSSEC + validation functions
@@ -184,6 +189,9 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
184189
* 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery
185190
* 8914 - Extended DNS Errors
186191
* 8976 - Message Digest for DNS Zones (ZONEMD RR)
192+
* 9460 - Service Binding and Parameter Specification via the DNS
193+
* 9461 - Service Binding Mapping for DNS Servers
194+
* 9462 - Discovery of Designated Resolvers
187195

188196
## Loosely Based Upon
189197

acceptfunc_test.go

+85
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package dns
22

33
import (
4+
"encoding/binary"
5+
"net"
46
"testing"
57
)
68

@@ -33,3 +35,86 @@ func handleNotify(w ResponseWriter, req *Msg) {
3335
m.SetReply(req)
3436
w.WriteMsg(m)
3537
}
38+
39+
func TestInvalidMsg(t *testing.T) {
40+
HandleFunc("example.org.", func(ResponseWriter, *Msg) {
41+
t.Fatal("the handler must not be called in any of these tests")
42+
})
43+
s, addrstr, _, err := RunLocalTCPServer(":0")
44+
if err != nil {
45+
t.Fatalf("unable to run test server: %v", err)
46+
}
47+
defer s.Shutdown()
48+
49+
s.MsgAcceptFunc = func(dh Header) MsgAcceptAction {
50+
switch dh.Id {
51+
case 0x0001:
52+
return MsgAccept
53+
case 0x0002:
54+
return MsgReject
55+
case 0x0003:
56+
return MsgIgnore
57+
case 0x0004:
58+
return MsgRejectNotImplemented
59+
default:
60+
t.Errorf("unexpected ID %x", dh.Id)
61+
return -1
62+
}
63+
}
64+
65+
invalidErrors := make(chan error)
66+
s.MsgInvalidFunc = func(m []byte, err error) {
67+
invalidErrors <- err
68+
}
69+
70+
c, err := net.Dial("tcp", addrstr)
71+
if err != nil {
72+
t.Fatalf("cannot connect to test server: %v", err)
73+
}
74+
75+
write := func(m []byte) {
76+
var length [2]byte
77+
binary.BigEndian.PutUint16(length[:], uint16(len(m)))
78+
_, err := c.Write(length[:])
79+
if err != nil {
80+
t.Fatalf("length write failed: %v", err)
81+
}
82+
_, err = c.Write(m)
83+
if err != nil {
84+
t.Fatalf("content write failed: %v", err)
85+
}
86+
}
87+
88+
/* Message is too short, so there is no header to accept or reject. */
89+
90+
tooShortMessage := make([]byte, 11)
91+
tooShortMessage[1] = 0x3 // ID = 3, would be ignored if it were parsable.
92+
93+
write(tooShortMessage)
94+
// Expect an error to be reported.
95+
<-invalidErrors
96+
97+
/* Message is accepted but is actually invalid. */
98+
99+
badMessage := make([]byte, 13)
100+
badMessage[1] = 0x1 // ID = 1, Accept.
101+
badMessage[5] = 1 // QDCOUNT = 1
102+
badMessage[12] = 99 // Bad question section. Invalid!
103+
104+
write(badMessage)
105+
// Expect an error to be reported.
106+
<-invalidErrors
107+
108+
/* Message is rejected before it can be determined to be invalid. */
109+
110+
close(invalidErrors) // A call to InvalidMsgFunc would panic due to the closed chan.
111+
112+
badMessage[1] = 0x2 // ID = 2, Reject
113+
write(badMessage)
114+
115+
badMessage[1] = 0x3 // ID = 3, Ignore
116+
write(badMessage)
117+
118+
badMessage[1] = 0x4 // ID = 4, RejectNotImplemented
119+
write(badMessage)
120+
}

defaults.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,12 @@ func IsDomainName(s string) (labels int, ok bool) {
198198
off int
199199
begin int
200200
wasDot bool
201+
escape bool
201202
)
202203
for i := 0; i < len(s); i++ {
203204
switch s[i] {
204205
case '\\':
206+
escape = !escape
205207
if off+1 > lenmsg {
206208
return labels, false
207209
}
@@ -217,6 +219,7 @@ func IsDomainName(s string) (labels int, ok bool) {
217219

218220
wasDot = false
219221
case '.':
222+
escape = false
220223
if i == 0 && len(s) > 1 {
221224
// leading dots are not legal except for the root zone
222225
return labels, false
@@ -243,10 +246,13 @@ func IsDomainName(s string) (labels int, ok bool) {
243246
labels++
244247
begin = i + 1
245248
default:
249+
escape = false
246250
wasDot = false
247251
}
248252
}
249-
253+
if escape {
254+
return labels, false
255+
}
250256
return labels, true
251257
}
252258

dnssec_keyscan.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
160160
k = l.token
161161
case zValue:
162162
if k == "" {
163-
return nil, &ParseError{file, "no private key seen", l}
163+
return nil, &ParseError{file: file, err: "no private key seen", lex: l}
164164
}
165165

166166
m[strings.ToLower(k)] = l.token

generate.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (r *generateReader) parseError(msg string, end int) *ParseError {
116116
l.token = r.s[r.si-1 : end]
117117
l.column += r.si // l.column starts one zBLANK before r.s
118118

119-
return &ParseError{r.file, msg, l}
119+
return &ParseError{file: r.file, err: msg, lex: l}
120120
}
121121

122122
func (r *generateReader) Read(p []byte) (int, error) {

go.mod

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ module github.com/miekg/dns
33
go 1.19
44

55
require (
6-
golang.org/x/net v0.17.0
7-
golang.org/x/sync v0.4.0
8-
golang.org/x/sys v0.13.0
9-
golang.org/x/tools v0.13.0
6+
golang.org/x/net v0.26.0
7+
golang.org/x/sync v0.7.0
8+
golang.org/x/sys v0.21.0
9+
golang.org/x/tools v0.22.0
1010
)
1111

12-
require golang.org/x/mod v0.12.0 // indirect
12+
require golang.org/x/mod v0.18.0 // indirect

go.sum

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
2-
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
3-
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
4-
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
5-
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
6-
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
7-
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
8-
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9-
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
10-
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
1+
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
2+
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
3+
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
4+
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
5+
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
6+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
7+
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
8+
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
9+
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
10+
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=

listen_no_reuseport.go

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, e
1515
return net.Listen(network, addr)
1616
}
1717

18+
const supportsReuseAddr = false
19+
1820
func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
1921
if reuseport || reuseaddr {
2022
// TODO(tmthrgd): return an error?

listen_reuseport.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ func reuseportControl(network, address string, c syscall.RawConn) error {
2525
return opErr
2626
}
2727

28+
const supportsReuseAddr = true
29+
2830
func reuseaddrControl(network, address string, c syscall.RawConn) error {
2931
var opErr error
3032
err := c.Control(func(fd uintptr) {
@@ -37,7 +39,7 @@ func reuseaddrControl(network, address string, c syscall.RawConn) error {
3739
return opErr
3840
}
3941

40-
func listenTCP(network, addr string, reuseport bool, reuseaddr bool) (net.Listener, error) {
42+
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
4143
var lc net.ListenConfig
4244
switch {
4345
case reuseaddr && reuseport:
@@ -50,7 +52,7 @@ func listenTCP(network, addr string, reuseport bool, reuseaddr bool) (net.Listen
5052
return lc.Listen(context.Background(), network, addr)
5153
}
5254

53-
func listenUDP(network, addr string, reuseport bool, reuseaddr bool) (net.PacketConn, error) {
55+
func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
5456
var lc net.ListenConfig
5557
switch {
5658
case reuseaddr && reuseport:

msg.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ func (h *MsgHdr) String() string {
714714
return s
715715
}
716716

717-
// Pack packs a Msg: it is converted to to wire format.
717+
// Pack packs a Msg: it is converted to wire format.
718718
// If the dns.Compress is true the message will be in compressed wire format.
719719
func (dns *Msg) Pack() (msg []byte, err error) {
720720
return dns.PackBuffer(nil)

parse_test.go

+59-8
Original file line numberDiff line numberDiff line change
@@ -1098,18 +1098,41 @@ func TestTXT(t *testing.T) {
10981098
}
10991099
}
11001100

1101-
// Test TXT record with chunk larger than 255 bytes, they should be split up, by the parser
1102-
s := ""
1103-
for i := 0; i < 255; i++ {
1104-
s += "a"
1101+
// Test TXT record with string larger than 255 bytes that should be split
1102+
// up by the parser. Add some escape sequences too to ensure their length
1103+
// is counted correctly.
1104+
s := `"\;\\\120` + strings.Repeat("a", 255) + `b"`
1105+
rr, err = NewRR(`test.local. 60 IN TXT ` + s)
1106+
if err != nil {
1107+
t.Error("failed to parse empty-string TXT record", err)
1108+
}
1109+
if rr.(*TXT).Txt[1] != "aaab" {
1110+
t.Errorf("Txt should have two strings, last one must be 'aaab', but is %s", rr.(*TXT).Txt[1])
11051111
}
1106-
s += "b"
1107-
rr, err = NewRR(`test.local. 60 IN TXT "` + s + `"`)
1112+
rrContent := strings.Replace(rr.String(), rr.Header().String(), "", 1)
1113+
expectedRRContent := `";\\x` + strings.Repeat("a", 252) + `" "aaab"`
1114+
if expectedRRContent != rrContent {
1115+
t.Errorf("Expected TXT RR content to be %#q but got %#q", expectedRRContent, rrContent)
1116+
}
1117+
1118+
// Test TXT record that is already split up into strings of len <= 255.
1119+
s = fmt.Sprintf(
1120+
"%q %q %q %q %q %q",
1121+
strings.Repeat(`a`, 255),
1122+
strings.Repeat("b", 255),
1123+
strings.Repeat("c", 255),
1124+
strings.Repeat("d", 0),
1125+
strings.Repeat("e", 1),
1126+
strings.Repeat("f", 123),
1127+
)
1128+
rr, err = NewRR(`test.local. 60 IN TXT ` + s)
11081129
if err != nil {
11091130
t.Error("failed to parse empty-string TXT record", err)
11101131
}
1111-
if rr.(*TXT).Txt[1] != "b" {
1112-
t.Errorf("Txt should have two chunk, last one my be 'b', but is %s", rr.(*TXT).Txt[1])
1132+
rrContent = strings.Replace(rr.String(), rr.Header().String(), "", 1)
1133+
expectedRRContent = s // same as input
1134+
if expectedRRContent != rrContent {
1135+
t.Errorf("Expected TXT RR content to be %#q but got %#q", expectedRRContent, rrContent)
11131136
}
11141137
}
11151138

@@ -1450,6 +1473,23 @@ func TestParseHINFO(t *testing.T) {
14501473
}
14511474
}
14521475

1476+
func TestParseISDN(t *testing.T) {
1477+
dt := map[string]string{
1478+
"example.net. ISDN A B": "example.net. 3600 IN ISDN \"A\" \"B\"",
1479+
"example.net. ISDN \"A\" \"B\"": "example.net. 3600 IN ISDN \"A\" \"B\"",
1480+
}
1481+
for i, o := range dt {
1482+
rr, err := NewRR(i)
1483+
if err != nil {
1484+
t.Error("failed to parse RR: ", err)
1485+
continue
1486+
}
1487+
if rr.String() != o {
1488+
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
1489+
}
1490+
}
1491+
}
1492+
14531493
func TestParseCAA(t *testing.T) {
14541494
lt := map[string]string{
14551495
"example.net. CAA 0 issue \"symantec.com\"": "example.net.\t3600\tIN\tCAA\t0 issue \"symantec.com\"",
@@ -1569,7 +1609,18 @@ func TestParseSVCB(t *testing.T) {
15691609
// From draft-ietf-add-ddr-06
15701610
`_dns.example.net. SVCB 1 example.net. alpn=h2 dohpath=/dns-query{?dns}`: `_dns.example.net. 3600 IN SVCB 1 example.net. alpn="h2" dohpath="/dns-query{?dns}"`,
15711611
`_dns.example.net. SVCB 1 example.net. alpn=h2 dohpath=/dns\045query{\?dns}`: `_dns.example.net. 3600 IN SVCB 1 example.net. alpn="h2" dohpath="/dns-query{?dns}"`,
1612+
// From RFC9461 Section 7 (https://datatracker.ietf.org/doc/html/rfc9461#section-7)
1613+
`_dns.simple.example. 7200 IN SVCB 1 simple.example. alpn=dot`: `_dns.simple.example. 7200 IN SVCB 1 simple.example. alpn="dot"`,
1614+
`_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn=h2 dohpath=/dns-query{?dns}`: `_dns.doh.example. 7200 IN SVCB 1 doh.example. alpn="h2" dohpath="/dns-query{?dns}"`,
1615+
`_dns.resolver.example. 7200 IN SVCB 1 resolver.example. alpn=dot,doq,h2,h3 dohpath=/q{?dns}`: `_dns.resolver.example. 7200 IN SVCB 1 resolver.example. alpn="dot,doq,h2,h3" dohpath="/q{?dns}"`,
1616+
`_dns.resolver.example. 7200 IN SVCB 2 resolver.example. alpn=dot port=8530`: `_dns.resolver.example. 7200 IN SVCB 2 resolver.example. alpn="dot" port="8530"`,
1617+
// From RFC 9540 Section 4.2.1 (https://www.rfc-editor.org/rfc/rfc9540.html#name-the-ohttp-svcparamkey)
1618+
`_dns.resolver.arpa 7200 IN SVCB 1 doh.example.net alpn=h2 dohpath=/dns-query{?dns} ohttp`: `_dns.resolver.arpa. 7200 IN SVCB 1 doh.example.net. alpn="h2" dohpath="/dns-query{?dns}" ohttp=""`,
1619+
// From RFC 9540 Section 4.1 (HTTPS RR) (https://www.rfc-editor.org/rfc/rfc9540.html#name-use-in-https-service-rrs)
1620+
`svc.example.com. 7200 IN HTTPS 1 . alpn=h2 ohttp`: `svc.example.com. 7200 IN HTTPS 1 . alpn="h2" ohttp=""`,
1621+
`svc.example.com. 7200 IN HTTPS 1 . mandatory=ohttp ohttp`: `svc.example.com. 7200 IN HTTPS 1 . mandatory="ohttp" ohttp=""`,
15721622
}
1623+
15731624
for s, o := range svcbs {
15741625
rr, err := NewRR(s)
15751626
if err != nil {

privaterr.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Fetch:
8484

8585
err := r.Data.Parse(text)
8686
if err != nil {
87-
return &ParseError{"", err.Error(), l}
87+
return &ParseError{wrappedErr: err, lex: l}
8888
}
8989

9090
return nil

0 commit comments

Comments
 (0)