An update msg can have multiple, different prerequests and also multiple,

dfferent remove and inserts. The old code did a reset of the ANSWER and
AUTHORITY section each time a rrset was added.

Made a slight optimalisation that the first time an rrset is added, we
take it length as the initial size. Helps for the one-time add cases.

Added test to prevent regressions.
This commit is contained in:
Pauline Middelink 2016-02-27 02:44:33 +01:00
parent f89e57ed50
commit 13a6137d79
2 changed files with 108 additions and 38 deletions

View File

@ -3,18 +3,22 @@ package dns
// NameUsed sets the RRs in the prereq section to
// "Name is in use" RRs. RFC 2136 section 2.4.4.
func (u *Msg) NameUsed(rr []RR) {
u.Answer = make([]RR, len(rr))
for i, r := range rr {
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
if u.Answer == nil {
u.Answer = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
}
}
// NameNotUsed sets the RRs in the prereq section to
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
func (u *Msg) NameNotUsed(rr []RR) {
u.Answer = make([]RR, len(rr))
for i, r := range rr {
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
if u.Answer == nil {
u.Answer = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}})
}
}
@ -24,34 +28,34 @@ func (u *Msg) Used(rr []RR) {
if len(u.Question) == 0 {
panic("dns: empty question section")
}
u.Answer = make([]RR, len(rr))
for i, r := range rr {
u.Answer[i] = r
u.Answer[i].Header().Class = u.Question[0].Qclass
if u.Answer == nil {
u.Answer = make([]RR, 0, len(rr))
}
for _, r := range rr {
r.Header().Class = u.Question[0].Qclass
u.Answer = append(u.Answer, r)
}
}
// RRsetUsed sets the RRs in the prereq section to
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
func (u *Msg) RRsetUsed(rr []RR) {
u.Answer = make([]RR, len(rr))
for i, r := range rr {
u.Answer[i] = r
u.Answer[i].Header().Class = ClassANY
u.Answer[i].Header().Ttl = 0
u.Answer[i].Header().Rdlength = 0
if u.Answer == nil {
u.Answer = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
}
}
// RRsetNotUsed sets the RRs in the prereq section to
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
func (u *Msg) RRsetNotUsed(rr []RR) {
u.Answer = make([]RR, len(rr))
for i, r := range rr {
u.Answer[i] = r
u.Answer[i].Header().Class = ClassNONE
u.Answer[i].Header().Rdlength = 0
u.Answer[i].Header().Ttl = 0
if u.Answer == nil {
u.Answer = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
}
}
@ -60,35 +64,43 @@ func (u *Msg) Insert(rr []RR) {
if len(u.Question) == 0 {
panic("dns: empty question section")
}
u.Ns = make([]RR, len(rr))
for i, r := range rr {
u.Ns[i] = r
u.Ns[i].Header().Class = u.Question[0].Qclass
if u.Ns == nil {
u.Ns = make([]RR, 0, len(rr))
}
for _, r := range rr {
r.Header().Class = u.Question[0].Qclass
u.Ns = append(u.Ns, r)
}
}
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
func (u *Msg) RemoveRRset(rr []RR) {
u.Ns = make([]RR, len(rr))
for i, r := range rr {
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}
if u.Ns == nil {
u.Ns = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
}
}
// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
func (u *Msg) RemoveName(rr []RR) {
u.Ns = make([]RR, len(rr))
for i, r := range rr {
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
if u.Ns == nil {
u.Ns = make([]RR, 0, len(rr))
}
for _, r := range rr {
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
}
}
// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4
// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
func (u *Msg) Remove(rr []RR) {
u.Ns = make([]RR, len(rr))
for i, r := range rr {
u.Ns[i] = r
u.Ns[i].Header().Class = ClassNONE
u.Ns[i].Header().Ttl = 0
if u.Ns == nil {
u.Ns = make([]RR, 0, len(rr))
}
for _, r := range rr {
r.Header().Class = ClassNONE
r.Header().Ttl = 0
u.Ns = append(u.Ns, r)
}
}

View File

@ -6,6 +6,7 @@ import (
)
func TestDynamicUpdateParsing(t *testing.T) {
// This does nothing with dynamic updates, move elsewhere?
prefix := "example.com. IN "
for _, typ := range TypeToString {
if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
@ -83,3 +84,60 @@ func TestRemoveRRset(t *testing.T) {
t.Errorf("actual msg:\n%v", tmp)
}
}
func TestPreReqAndRemovals(t *testing.T) {
// Build a list of multiple prereqs and then somes removes followed by an insert.
// We should be able to add multiple prereqs and updates.
m := new(Msg)
m.SetUpdate("some_zone.")
m.Id = 1234
// Use a full set of RRs each time, so we are sure the rdata is stripped.
rr_name1, _ := NewRR("name_used. 3600 IN A 127.0.0.1")
rr_name2, _ := NewRR("name_not_used. 3600 IN A 127.0.0.1")
rr_remove1, _ := NewRR("remove1. 3600 IN A 127.0.0.1")
rr_remove2, _ := NewRR("remove2. 3600 IN A 127.0.0.1")
rr_remove3, _ := NewRR("remove3. 3600 IN A 127.0.0.1")
rr_insert, _ := NewRR("insert. 3600 IN A 127.0.0.1")
rr_rrset1, _ := NewRR("rrset_used1. 3600 IN A 127.0.0.1")
rr_rrset2, _ := NewRR("rrset_used2. 3600 IN A 127.0.0.1")
rr_rrset3, _ := NewRR("rrset_not_used. 3600 IN A 127.0.0.1")
// Handle the prereqs.
m.NameUsed([]RR{rr_name1})
m.NameNotUsed([]RR{rr_name2})
m.RRsetUsed([]RR{rr_rrset1})
m.Used([]RR{rr_rrset2})
m.RRsetNotUsed([]RR{rr_rrset3})
// and now the updates.
m.RemoveName([]RR{rr_remove1})
m.RemoveRRset([]RR{rr_remove2})
m.Remove([]RR{rr_remove3})
m.Insert([]RR{rr_insert})
expect := `;; opcode: UPDATE, status: NOERROR, id: 1234
;; flags:; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 0
;; QUESTION SECTION:
;some_zone. IN SOA
;; ANSWER SECTION:
name_used. 0 ANY ANY
name_not_used. 0 NONE ANY
rrset_used1. 0 ANY A
rrset_used2. 3600 IN A 127.0.0.1
rrset_not_used. 0 NONE A
;; AUTHORITY SECTION:
remove1. 0 ANY ANY
remove2. 0 ANY A
remove3. 0 NONE A 127.0.0.1
insert. 3600 IN A 127.0.0.1
`
if m.String() != expect {
t.Errorf("expected msg:\n%s", expect)
t.Errorf("actual msg:\n%v", m.String())
}
}