Skip to content
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

Trailing backslash results in non-FQDN targets #1528

Closed
janik-cloudflare opened this issue Jan 17, 2024 · 6 comments · Fixed by #1532
Closed

Trailing backslash results in non-FQDN targets #1528

janik-cloudflare opened this issue Jan 17, 2024 · 6 comments · Fixed by #1532

Comments

@janik-cloudflare
Copy link
Collaborator

Calling NewRR(". 1 IN CNAME example.com") normally turns example.com into an FQDN, example.com., before storing it in the RR's Target variable.

However, NewRR(". 1 IN CNAME example.com\\") with a trailing backslash results in example.com\., which is not an FQDN since the last dot is escaped.

It seems to me like the parser should either add another dot in these cases, or (perhaps better) reject the trailing backslash with an error.

package main

import (
	"fmt"

	"github.com/miekg/dns"
)

func test(content string) {
	rr, err := dns.NewRR(content)
	if err != nil {
		panic(err)
	}

	target := rr.(*dns.CNAME).Target
	fmt.Printf("target %s is FQDN: %t\n", target, dns.IsFqdn(target))
}

func main() {
	test(`. 1 IN CNAME example.com`)
	test(`. 1 IN CNAME example.com\`)
}
$ go run ./...
target example.com. is FQDN: true
target example.com\. is FQDN: false

This may be related to #1384.

@miekg
Copy link
Owner

miekg commented Jan 18, 2024

but \\ is legal, no?
There is def. a problem here, but if we are going to reject \\ there is bound to be more stuff that will be deemed illegal in the future.
Is blindly Fqdn-ing the real problem here? Or is doing Fqdn in the first place the actual, actual problem?

@janik-cloudflare
Copy link
Collaborator Author

An even number of slashes definitely seems legal.

Digging a bit, it looks like CNAME.parse() receives an example.com\ token. Maybe (*zlexer).Next() should return an error when escape is still true when returning? I need to look more into how (and if) this would work.

FQDN-ing seems fine to me since CNAME.parse() calls toAbsoluteName based on the provided origin, right?

@miekg
Copy link
Owner

miekg commented Jan 19, 2024 via email

@gibson042
Copy link
Collaborator

It's not a corner case in the RFC; CNAME RDATA format is just a <domain-name> and per RFC 1035 section 5.1:

The labels in the domain name are expressed as character strings and
separated by dots. Quoting conventions allow arbitrary characters to be
stored in domain names. Domain names that end in a dot are called
absolute, and are taken as complete. Domain names which do not end in a
dot are called relative; the actual domain name is the concatenation of
the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
an argument to the master file loading routine. A relative name is an error when no origin is available.

(where «<character-string> is expressed in one or two ways: as a contiguous set of characters without interior spaces, or as a string beginning with a " and ending with a "… [and] \X where X is any character other than a digit (0-9), is used to quote that character so that its special meaning does not apply»)

So in a zone file, . 1 IN CNAME example.com\ is simply invalid while . 1 IN CNAME example.com and . 1 IN CNAME example.com\\ are both valid, and the target domain name for each is relative to the current origin. NewRR promoting relative domain names in isolated RRs to be root-relative is a design decision, and should be (and AFAIK, is) applied universally—to have those example records respectively target "example.com." (i.e., a domain name in which the first label is "example", the second label is "com", and the third and final label is the DNS root label) and "example.com\092." or equivalently "example.com\\." (i.e., a domain name in which the first label is "example", the second label is the four ASCII characters "com\", and the third and final label is the DNS root label).

@miekg
Copy link
Owner

miekg commented Jan 20, 2024

ack

So in a zone file, . 1 IN CNAME example.com\ is simply invalid while . 1 IN CNAME example.com and . 1 IN CNAME example.com\ are both valid

you agree with returning an error from the parser is escape == true then too?

@gibson042
Copy link
Collaborator

Yes, I think NewRR(". 1 IN CNAME example.com\\") or any other attempt to parse an incomplete escape should return an error. 👍

miekg added a commit that referenced this issue Jan 21, 2024
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: #1528

Signed-off-by: Miek Gieben <[email protected]>
miekg added a commit that referenced this issue Feb 15, 2024
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: #1528

Signed-off-by: Miek Gieben <[email protected]>
jefferai pushed a commit to jefferai/dns that referenced this issue Aug 7, 2024
* 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants