1package dns 2 3import ( 4 "bytes" 5 "testing" 6) 7 8func TestDynamicUpdateParsing(t *testing.T) { 9 const prefix = "example.com. IN " 10 11 for typ, name := range TypeToString { 12 switch typ { 13 case TypeNone, TypeReserved: 14 continue 15 case TypeANY: 16 // ANY is ambiguous here and ends up parsed as a CLASS. 17 // 18 // TODO(tmthrgd): Using TYPE255 here doesn't seem to work and also 19 // seems to fail for some other record types. Investigate. 20 continue 21 } 22 23 s := prefix + name 24 if _, err := NewRR(s); err != nil { 25 t.Errorf("failure to parse: %s: %v", s, err) 26 } 27 28 s += " \\# 0" 29 if _, err := NewRR(s); err != nil { 30 t.Errorf("failure to parse: %s: %v", s, err) 31 } 32 } 33} 34 35func TestDynamicUpdateUnpack(t *testing.T) { 36 // From https://github.com/miekg/dns/issues/150#issuecomment-62296803 37 // It should be an update message for the zone "example.", 38 // deleting the A RRset "example." and then adding an A record at "example.". 39 // class ANY, TYPE A 40 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} 41 msg := new(Msg) 42 err := msg.Unpack(buf) 43 if err != nil { 44 t.Errorf("failed to unpack: %v\n%s", err, msg.String()) 45 } 46} 47 48func TestDynamicUpdateZeroRdataUnpack(t *testing.T) { 49 m := new(Msg) 50 rr := &RR_Header{Name: ".", Rrtype: 0, Class: 1, Ttl: ^uint32(0), Rdlength: 0} 51 m.Answer = []RR{rr, rr, rr, rr, rr} 52 m.Ns = m.Answer 53 for n, s := range TypeToString { 54 rr.Rrtype = n 55 bytes, err := m.Pack() 56 if err != nil { 57 t.Errorf("failed to pack %s: %v", s, err) 58 continue 59 } 60 if err := new(Msg).Unpack(bytes); err != nil { 61 t.Errorf("failed to unpack %s: %v", s, err) 62 } 63 } 64} 65 66func TestRemoveRRset(t *testing.T) { 67 // Should add a zero data RR in Class ANY with a TTL of 0 68 // for each set mentioned in the RRs provided to it. 69 rr := testRR(". 100 IN A 127.0.0.1") 70 m := new(Msg) 71 m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}} 72 expectstr := m.String() 73 expect, err := m.Pack() 74 if err != nil { 75 t.Fatalf("error packing expected msg: %v", err) 76 } 77 78 m.Ns = nil 79 m.RemoveRRset([]RR{rr}) 80 actual, err := m.Pack() 81 if err != nil { 82 t.Fatalf("error packing actual msg: %v", err) 83 } 84 if !bytes.Equal(actual, expect) { 85 tmp := new(Msg) 86 if err := tmp.Unpack(actual); err != nil { 87 t.Fatalf("error unpacking actual msg: %v\nexpected: %v\ngot: %v\n", err, expect, actual) 88 } 89 t.Errorf("expected msg:\n%s", expectstr) 90 t.Errorf("actual msg:\n%v", tmp) 91 } 92} 93 94func TestPreReqAndRemovals(t *testing.T) { 95 // Build a list of multiple prereqs and then somes removes followed by an insert. 96 // We should be able to add multiple prereqs and updates. 97 m := new(Msg) 98 m.SetUpdate("example.org.") 99 m.Id = 1234 100 101 // Use a full set of RRs each time, so we are sure the rdata is stripped. 102 rrName1 := testRR("name_used. 3600 IN A 127.0.0.1") 103 rrName2 := testRR("name_not_used. 3600 IN A 127.0.0.1") 104 rrRemove1 := testRR("remove1. 3600 IN A 127.0.0.1") 105 rrRemove2 := testRR("remove2. 3600 IN A 127.0.0.1") 106 rrRemove3 := testRR("remove3. 3600 IN A 127.0.0.1") 107 rrInsert := testRR("insert. 3600 IN A 127.0.0.1") 108 rrRrset1 := testRR("rrset_used1. 3600 IN A 127.0.0.1") 109 rrRrset2 := testRR("rrset_used2. 3600 IN A 127.0.0.1") 110 rrRrset3 := testRR("rrset_not_used. 3600 IN A 127.0.0.1") 111 112 // Handle the prereqs. 113 m.NameUsed([]RR{rrName1}) 114 m.NameNotUsed([]RR{rrName2}) 115 m.RRsetUsed([]RR{rrRrset1}) 116 m.Used([]RR{rrRrset2}) 117 m.RRsetNotUsed([]RR{rrRrset3}) 118 119 // and now the updates. 120 m.RemoveName([]RR{rrRemove1}) 121 m.RemoveRRset([]RR{rrRemove2}) 122 m.Remove([]RR{rrRemove3}) 123 m.Insert([]RR{rrInsert}) 124 125 // This test function isn't a Example function because we print these RR with tabs at the 126 // end and the Example function trim these, thus they never match. 127 // TODO(miek): don't print these tabs and make this into an Example function. 128 expect := `;; opcode: UPDATE, status: NOERROR, id: 1234 129;; flags:; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 0 130 131;; QUESTION SECTION: 132;example.org. IN SOA 133 134;; ANSWER SECTION: 135name_used. 0 CLASS255 ANY 136name_not_used. 0 NONE ANY 137rrset_used1. 0 CLASS255 A 138rrset_used2. 3600 IN A 127.0.0.1 139rrset_not_used. 0 NONE A 140 141;; AUTHORITY SECTION: 142remove1. 0 CLASS255 ANY 143remove2. 0 CLASS255 A 144remove3. 0 NONE A 127.0.0.1 145insert. 3600 IN A 127.0.0.1 146` 147 148 if m.String() != expect { 149 t.Errorf("expected msg:\n%s", expect) 150 t.Errorf("actual msg:\n%v", m.String()) 151 } 152} 153