mirror of
https://github.com/miekg/dns.git
synced 2025-08-10 03:26:57 +02:00
* 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.
114 lines
3.2 KiB
Go
114 lines
3.2 KiB
Go
package dns
|
|
|
|
import "strings"
|
|
|
|
// PrivateRdata is an interface used for implementing "Private Use" RR types, see
|
|
// RFC 6895. This allows one to experiment with new RR types, without requesting an
|
|
// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove.
|
|
type PrivateRdata interface {
|
|
// String returns the text presentation of the Rdata of the Private RR.
|
|
String() string
|
|
// Parse parses the Rdata of the private RR.
|
|
Parse([]string) error
|
|
// Pack is used when packing a private RR into a buffer.
|
|
Pack([]byte) (int, error)
|
|
// Unpack is used when unpacking a private RR from a buffer.
|
|
Unpack([]byte) (int, error)
|
|
// Copy copies the Rdata into the PrivateRdata argument.
|
|
Copy(PrivateRdata) error
|
|
// Len returns the length in octets of the Rdata.
|
|
Len() int
|
|
}
|
|
|
|
// PrivateRR represents an RR that uses a PrivateRdata user-defined type.
|
|
// It mocks normal RRs and implements dns.RR interface.
|
|
type PrivateRR struct {
|
|
Hdr RR_Header
|
|
Data PrivateRdata
|
|
|
|
generator func() PrivateRdata // for copy
|
|
}
|
|
|
|
// Header return the RR header of r.
|
|
func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
|
|
|
|
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
|
|
|
// Private len and copy parts to satisfy RR interface.
|
|
func (r *PrivateRR) len(off int, compression map[string]struct{}) int {
|
|
l := r.Hdr.len(off, compression)
|
|
l += r.Data.Len()
|
|
return l
|
|
}
|
|
|
|
func (r *PrivateRR) copy() RR {
|
|
// make new RR like this:
|
|
rr := &PrivateRR{r.Hdr, r.generator(), r.generator}
|
|
|
|
if err := r.Data.Copy(rr.Data); err != nil {
|
|
panic("dns: got value that could not be used to copy Private rdata: " + err.Error())
|
|
}
|
|
|
|
return rr
|
|
}
|
|
|
|
func (r *PrivateRR) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
|
n, err := r.Data.Pack(msg[off:])
|
|
if err != nil {
|
|
return len(msg), err
|
|
}
|
|
off += n
|
|
return off, nil
|
|
}
|
|
|
|
func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
|
|
off1, err := r.Data.Unpack(msg[off:])
|
|
off += off1
|
|
return off, err
|
|
}
|
|
|
|
func (r *PrivateRR) parse(c *zlexer, origin string) *ParseError {
|
|
var l lex
|
|
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
|
Fetch:
|
|
for {
|
|
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
|
// be an issue (basically parsing TXT becomes hard)
|
|
switch l, _ = c.Next(); l.value {
|
|
case zNewline, zEOF:
|
|
break Fetch
|
|
case zString:
|
|
text = append(text, l.token)
|
|
}
|
|
}
|
|
|
|
err := r.Data.Parse(text)
|
|
if err != nil {
|
|
return &ParseError{wrappedErr: err, lex: l}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *PrivateRR) isDuplicate(r2 RR) bool { return false }
|
|
|
|
// PrivateHandle registers a private resource record type. It requires
|
|
// string and numeric representation of private RR type and generator function as argument.
|
|
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
|
rtypestr = strings.ToUpper(rtypestr)
|
|
|
|
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator(), generator} }
|
|
TypeToString[rtype] = rtypestr
|
|
StringToType[rtypestr] = rtype
|
|
}
|
|
|
|
// PrivateHandleRemove removes definitions required to support private RR type.
|
|
func PrivateHandleRemove(rtype uint16) {
|
|
rtypestr, ok := TypeToString[rtype]
|
|
if ok {
|
|
delete(TypeToRR, rtype)
|
|
delete(TypeToString, rtype)
|
|
delete(StringToType, rtypestr)
|
|
}
|
|
}
|