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:
parent
f89e57ed50
commit
13a6137d79
88
update.go
88
update.go
|
@ -3,18 +3,22 @@ package dns
|
||||||
// NameUsed sets the RRs in the prereq section to
|
// NameUsed sets the RRs in the prereq section to
|
||||||
// "Name is in use" RRs. RFC 2136 section 2.4.4.
|
// "Name is in use" RRs. RFC 2136 section 2.4.4.
|
||||||
func (u *Msg) NameUsed(rr []RR) {
|
func (u *Msg) NameUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
}
|
||||||
|
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
|
// NameNotUsed sets the RRs in the prereq section to
|
||||||
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
|
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
|
||||||
func (u *Msg) NameNotUsed(rr []RR) {
|
func (u *Msg) NameNotUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
|
}
|
||||||
|
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 {
|
if len(u.Question) == 0 {
|
||||||
panic("dns: empty question section")
|
panic("dns: empty question section")
|
||||||
}
|
}
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = u.Question[0].Qclass
|
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
|
// RRsetUsed sets the RRs in the prereq section to
|
||||||
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
|
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
|
||||||
func (u *Msg) RRsetUsed(rr []RR) {
|
func (u *Msg) RRsetUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = ClassANY
|
for _, r := range rr {
|
||||||
u.Answer[i].Header().Ttl = 0
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
|
||||||
u.Answer[i].Header().Rdlength = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RRsetNotUsed sets the RRs in the prereq section to
|
// RRsetNotUsed sets the RRs in the prereq section to
|
||||||
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
|
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
|
||||||
func (u *Msg) RRsetNotUsed(rr []RR) {
|
func (u *Msg) RRsetNotUsed(rr []RR) {
|
||||||
u.Answer = make([]RR, len(rr))
|
if u.Answer == nil {
|
||||||
for i, r := range rr {
|
u.Answer = make([]RR, 0, len(rr))
|
||||||
u.Answer[i] = r
|
}
|
||||||
u.Answer[i].Header().Class = ClassNONE
|
for _, r := range rr {
|
||||||
u.Answer[i].Header().Rdlength = 0
|
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
|
||||||
u.Answer[i].Header().Ttl = 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,35 +64,43 @@ func (u *Msg) Insert(rr []RR) {
|
||||||
if len(u.Question) == 0 {
|
if len(u.Question) == 0 {
|
||||||
panic("dns: empty question section")
|
panic("dns: empty question section")
|
||||||
}
|
}
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = r
|
}
|
||||||
u.Ns[i].Header().Class = u.Question[0].Qclass
|
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.
|
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
|
||||||
func (u *Msg) RemoveRRset(rr []RR) {
|
func (u *Msg) RemoveRRset(rr []RR) {
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}
|
}
|
||||||
|
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
|
// 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) {
|
func (u *Msg) RemoveName(rr []RR) {
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
}
|
||||||
|
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) {
|
func (u *Msg) Remove(rr []RR) {
|
||||||
u.Ns = make([]RR, len(rr))
|
if u.Ns == nil {
|
||||||
for i, r := range rr {
|
u.Ns = make([]RR, 0, len(rr))
|
||||||
u.Ns[i] = r
|
}
|
||||||
u.Ns[i].Header().Class = ClassNONE
|
for _, r := range rr {
|
||||||
u.Ns[i].Header().Ttl = 0
|
r.Header().Class = ClassNONE
|
||||||
|
r.Header().Ttl = 0
|
||||||
|
u.Ns = append(u.Ns, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDynamicUpdateParsing(t *testing.T) {
|
func TestDynamicUpdateParsing(t *testing.T) {
|
||||||
|
// This does nothing with dynamic updates, move elsewhere?
|
||||||
prefix := "example.com. IN "
|
prefix := "example.com. IN "
|
||||||
for _, typ := range TypeToString {
|
for _, typ := range TypeToString {
|
||||||
if typ == "OPT" || typ == "AXFR" || typ == "IXFR" || typ == "ANY" || typ == "TKEY" ||
|
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)
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue