fix OPT Record deep copy (#902)

* - implement deep-copy for OPT records + simple UT

* - adding ztypes.go (generated).

* - properly comment the specific behavior for EDNS0

* - remove too narrow UT + down-scope copy() method to package level only

* - tune comment
This commit is contained in:
Francois Tur 2019-01-30 13:11:33 -05:00 committed by Miek Gieben
parent 2df14c5c9f
commit 896800ef1d
3 changed files with 43 additions and 1 deletions

33
edns.go
View File

@ -159,6 +159,8 @@ type EDNS0 interface {
unpack([]byte) error
// String returns the string representation of the option.
String() string
// copy returns a deep-copy of the option.
copy() EDNS0
}
// EDNS0_NSID option is used to retrieve a nameserver
@ -190,6 +192,7 @@ func (e *EDNS0_NSID) pack() ([]byte, error) {
func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code.
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
func (e *EDNS0_NSID) String() string { return e.Nsid }
func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid} }
// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
// an idea of where the client lives. See RFC 7871. It can then give back a different
@ -307,6 +310,16 @@ func (e *EDNS0_SUBNET) String() (s string) {
return
}
func (e *EDNS0_SUBNET) copy() EDNS0 {
return &EDNS0_SUBNET{
e.Code,
e.Family,
e.SourceNetmask,
e.SourceScope,
e.Address,
}
}
// The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
//
// o := new(dns.OPT)
@ -342,6 +355,7 @@ func (e *EDNS0_COOKIE) pack() ([]byte, error) {
func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
func (e *EDNS0_COOKIE) String() string { return e.Cookie }
func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.Cookie} }
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
// an expiration on an update RR. This is helpful for clients that cannot clean
@ -363,6 +377,7 @@ type EDNS0_UL struct {
// Option implements the EDNS0 interface.
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease} }
// Copied: http://golang.org/src/pkg/net/dnsmsg.go
func (e *EDNS0_UL) pack() ([]byte, error) {
@ -421,6 +436,9 @@ func (e *EDNS0_LLQ) String() string {
" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
return s
}
func (e *EDNS0_LLQ) copy() EDNS0 {
return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
}
// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
type EDNS0_DAU struct {
@ -444,6 +462,7 @@ func (e *EDNS0_DAU) String() string {
}
return s
}
func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
type EDNS0_DHU struct {
@ -467,6 +486,7 @@ func (e *EDNS0_DHU) String() string {
}
return s
}
func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
type EDNS0_N3U struct {
@ -491,6 +511,7 @@ func (e *EDNS0_N3U) String() string {
}
return s
}
func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
// EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314.
type EDNS0_EXPIRE struct {
@ -501,6 +522,7 @@ type EDNS0_EXPIRE struct {
// Option implements the EDNS0 interface.
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} }
func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
b := make([]byte, 4)
@ -539,6 +561,11 @@ func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
func (e *EDNS0_LOCAL) String() string {
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
}
func (e *EDNS0_LOCAL) copy() EDNS0 {
b := make([]byte, len(e.Data))
copy(b, e.Data)
return &EDNS0_LOCAL{e.Code, b}
}
func (e *EDNS0_LOCAL) pack() ([]byte, error) {
b := make([]byte, len(e.Data))
@ -611,6 +638,7 @@ func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
}
return
}
func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Length, e.Timeout} }
// EDNS0_PADDING option is used to add padding to a request/response. The default
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
@ -624,3 +652,8 @@ func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }
func (e *EDNS0_PADDING) copy() EDNS0 {
b := make([]byte, len(e.Padding))
copy(b, e.Padding)
return &EDNS0_PADDING{b}
}

View File

@ -244,6 +244,13 @@ func main() {
splits := strings.Split(t, ".")
t = splits[len(splits)-1]
}
// For the EDNS0 interface (used in the OPT RR), we need to call the copy method on each element.
if t == "EDNS0" {
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s));\nfor i,e := range rr.%s {\n %s[i] = e.copy()\n}\n",
f, t, f, f, f)
fields = append(fields, f)
continue
}
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
f, t, f, f, f)
fields = append(fields, f)

View File

@ -798,7 +798,9 @@ func (rr *OPENPGPKEY) copy() RR {
}
func (rr *OPT) copy() RR {
Option := make([]EDNS0, len(rr.Option))
copy(Option, rr.Option)
for i, e := range rr.Option {
Option[i] = e.copy()
}
return &OPT{rr.Hdr, Option}
}
func (rr *PTR) copy() RR {