dns/update_test.go

153 lines
4.4 KiB
Go
Raw Permalink Normal View History

package dns
import (
"bytes"
"testing"
)
2014-11-09 09:57:06 +00:00
func TestDynamicUpdateParsing(t *testing.T) {
Support parsing known RR types in RFC 3597 format (#1211) * Support parsing known RR types in RFC 3597 format This is the format used for "Unknown DNS Resource Records", but it's also useful to support parsing known RR types in this way. RFC 3597 says: An implementation MAY also choose to represent some RRs of known type using the above generic representations for the type, class and/or RDATA, which carries the benefit of making the resulting master file portable to servers where these types are unknown. Using the generic representation for the RDATA of an RR of known type can also be useful in the case of an RR type where the text format varies depending on a version, protocol, or similar field (or several) embedded in the RDATA when such a field has a value for which no text format is known, e.g., a LOC RR [RFC1876] with a VERSION other than 0. Even though an RR of known type represented in the \# format is effectively treated as an unknown type for the purpose of parsing the RDATA text representation, all further processing by the server MUST treat it as a known type and take into account any applicable type- specific rules regarding compression, canonicalization, etc. * Correct mistakes in TestZoneParserAddressAAAA This was spotted when writing TestParseKnownRRAsRFC3597. * Eliminate canParseAsRR This has the advantage that concrete types will now be returned for parsed ANY, NULL, OPT and TSIG records. * Expand TestDynamicUpdateParsing for RFC 3597 This ensures we're properly handling empty RDATA for RFC 3597 parsed records.
2021-01-30 13:05:25 +00:00
const prefix = "example.com. IN "
for typ, name := range TypeToString {
switch typ {
case TypeNone, TypeReserved:
continue
case TypeANY:
// ANY is ambiguous here and ends up parsed as a CLASS.
//
// TODO(tmthrgd): Using TYPE255 here doesn't seem to work and also
// seems to fail for some other record types. Investigate.
continue
}
Support parsing known RR types in RFC 3597 format (#1211) * Support parsing known RR types in RFC 3597 format This is the format used for "Unknown DNS Resource Records", but it's also useful to support parsing known RR types in this way. RFC 3597 says: An implementation MAY also choose to represent some RRs of known type using the above generic representations for the type, class and/or RDATA, which carries the benefit of making the resulting master file portable to servers where these types are unknown. Using the generic representation for the RDATA of an RR of known type can also be useful in the case of an RR type where the text format varies depending on a version, protocol, or similar field (or several) embedded in the RDATA when such a field has a value for which no text format is known, e.g., a LOC RR [RFC1876] with a VERSION other than 0. Even though an RR of known type represented in the \# format is effectively treated as an unknown type for the purpose of parsing the RDATA text representation, all further processing by the server MUST treat it as a known type and take into account any applicable type- specific rules regarding compression, canonicalization, etc. * Correct mistakes in TestZoneParserAddressAAAA This was spotted when writing TestParseKnownRRAsRFC3597. * Eliminate canParseAsRR This has the advantage that concrete types will now be returned for parsed ANY, NULL, OPT and TSIG records. * Expand TestDynamicUpdateParsing for RFC 3597 This ensures we're properly handling empty RDATA for RFC 3597 parsed records.
2021-01-30 13:05:25 +00:00
s := prefix + name
if _, err := NewRR(s); err != nil {
t.Errorf("failure to parse: %s: %v", s, err)
}
s += " \\# 0"
if _, err := NewRR(s); err != nil {
t.Errorf("failure to parse: %s: %v", s, err)
}
}
}
2014-11-09 10:04:46 +00:00
func TestDynamicUpdateUnpack(t *testing.T) {
// From https://github.com/miekg/dns/issues/150#issuecomment-62296803
2014-11-09 16:09:49 +00:00
// It should be an update message for the zone "example.",
// deleting the A RRset "example." and then adding an A record at "example.".
// class ANY, TYPE A
2014-11-09 10:04:46 +00:00
buf := []byte{171, 68, 40, 0, 0, 1, 0, 0, 0, 2, 0, 0, 7, 101, 120, 97, 109, 112, 108, 101, 0, 0, 6, 0, 1, 192, 12, 0, 1, 0, 255, 0, 0, 0, 0, 0, 0, 192, 12, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 127, 0, 0, 1}
msg := new(Msg)
err := msg.Unpack(buf)
if err != nil {
2015-02-26 06:23:47 +00:00
t.Errorf("failed to unpack: %v\n%s", err, msg.String())
2014-11-09 10:04:46 +00:00
}
}
func TestDynamicUpdateZeroRdataUnpack(t *testing.T) {
m := new(Msg)
rr := &RR_Header{Name: ".", Rrtype: 0, Class: 1, Ttl: ^uint32(0), Rdlength: 0}
m.Answer = []RR{rr, rr, rr, rr, rr}
m.Ns = m.Answer
for n, s := range TypeToString {
rr.Rrtype = n
bytes, err := m.Pack()
if err != nil {
t.Errorf("failed to pack %s: %v", s, err)
continue
}
if err := new(Msg).Unpack(bytes); err != nil {
t.Errorf("failed to unpack %s: %v", s, err)
}
}
}
func TestRemoveRRset(t *testing.T) {
// Should add a zero data RR in Class ANY with a TTL of 0
// for each set mentioned in the RRs provided to it.
rr := testRR(". 100 IN A 127.0.0.1")
m := new(Msg)
m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
expectstr := m.String()
expect, err := m.Pack()
if err != nil {
2015-11-26 14:12:38 +00:00
t.Fatalf("error packing expected msg: %v", err)
}
m.Ns = nil
m.RemoveRRset([]RR{rr})
actual, err := m.Pack()
if err != nil {
2015-11-26 14:12:38 +00:00
t.Fatalf("error packing actual msg: %v", err)
}
if !bytes.Equal(actual, expect) {
tmp := new(Msg)
if err := tmp.Unpack(actual); err != nil {
t.Fatalf("error unpacking actual msg: %v\nexpected: %v\ngot: %v\n", err, expect, actual)
}
2015-11-26 14:12:38 +00:00
t.Errorf("expected msg:\n%s", expectstr)
t.Errorf("actual msg:\n%v", tmp)
}
}
func TestPreReqAndRemovals(t *testing.T) {
// Build a list of multiple prereqs and then some removes followed by an insert.
// We should be able to add multiple prereqs and updates.
m := new(Msg)
2016-02-27 12:02:32 +00:00
m.SetUpdate("example.org.")
m.Id = 1234
// Use a full set of RRs each time, so we are sure the rdata is stripped.
rrName1 := testRR("name_used. 3600 IN A 127.0.0.1")
rrName2 := testRR("name_not_used. 3600 IN A 127.0.0.1")
rrRemove1 := testRR("remove1. 3600 IN A 127.0.0.1")
rrRemove2 := testRR("remove2. 3600 IN A 127.0.0.1")
rrRemove3 := testRR("remove3. 3600 IN A 127.0.0.1")
rrInsert := testRR("insert. 3600 IN A 127.0.0.1")
rrRrset1 := testRR("rrset_used1. 3600 IN A 127.0.0.1")
rrRrset2 := testRR("rrset_used2. 3600 IN A 127.0.0.1")
rrRrset3 := testRR("rrset_not_used. 3600 IN A 127.0.0.1")
// Handle the prereqs.
2017-02-15 20:40:16 +00:00
m.NameUsed([]RR{rrName1})
m.NameNotUsed([]RR{rrName2})
m.RRsetUsed([]RR{rrRrset1})
m.Used([]RR{rrRrset2})
m.RRsetNotUsed([]RR{rrRrset3})
// and now the updates.
2017-02-15 20:40:16 +00:00
m.RemoveName([]RR{rrRemove1})
m.RemoveRRset([]RR{rrRemove2})
m.Remove([]RR{rrRemove3})
m.Insert([]RR{rrInsert})
// This test function isn't a Example function because we print these RR with tabs at the
// end and the Example function trim these, thus they never match.
// TODO(miek): don't print these tabs and make this into an Example function.
expect := `;; opcode: UPDATE, status: NOERROR, id: 1234
;; flags:; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 0
;; QUESTION SECTION:
2016-02-27 12:02:32 +00:00
;example.org. IN SOA
;; ANSWER SECTION:
name_used. 0 CLASS255 ANY
name_not_used. 0 NONE ANY
rrset_used1. 0 CLASS255 A
rrset_used2. 0 IN A 127.0.0.1
rrset_not_used. 0 NONE A
;; AUTHORITY SECTION:
remove1. 0 CLASS255 ANY
remove2. 0 CLASS255 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())
}
}