1package dns
2
3import (
4	"bytes"
5	"encoding/hex"
6	"net"
7	"testing"
8)
9
10func TestPackUnpack(t *testing.T) {
11	out := new(Msg)
12	out.Answer = make([]RR, 1)
13	key := &DNSKEY{Flags: 257, Protocol: 3, Algorithm: RSASHA1}
14	key.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 3600}
15	key.PublicKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
16
17	out.Answer[0] = key
18	msg, err := out.Pack()
19	if err != nil {
20		t.Error("failed to pack msg with DNSKEY")
21	}
22	in := new(Msg)
23	if in.Unpack(msg) != nil {
24		t.Error("failed to unpack msg with DNSKEY")
25	}
26
27	sig := &RRSIG{TypeCovered: TypeDNSKEY, Algorithm: RSASHA1, Labels: 2,
28		OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.",
29		Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"}
30	sig.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeRRSIG, Class: ClassINET, Ttl: 3600}
31
32	out.Answer[0] = sig
33	msg, err = out.Pack()
34	if err != nil {
35		t.Error("failed to pack msg with RRSIG")
36	}
37
38	if in.Unpack(msg) != nil {
39		t.Error("failed to unpack msg with RRSIG")
40	}
41}
42
43func TestPackUnpack2(t *testing.T) {
44	m := new(Msg)
45	m.Extra = make([]RR, 1)
46	m.Answer = make([]RR, 1)
47	dom := "miek.nl."
48	rr := new(A)
49	rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
50	rr.A = net.IPv4(127, 0, 0, 1)
51
52	x := new(TXT)
53	x.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
54	x.Txt = []string{"heelalaollo"}
55
56	m.Extra[0] = x
57	m.Answer[0] = rr
58	_, err := m.Pack()
59	if err != nil {
60		t.Error("Packing failed: ", err)
61		return
62	}
63}
64
65func TestPackUnpack3(t *testing.T) {
66	m := new(Msg)
67	m.Extra = make([]RR, 2)
68	m.Answer = make([]RR, 1)
69	dom := "miek.nl."
70	rr := new(A)
71	rr.Hdr = RR_Header{Name: dom, Rrtype: TypeA, Class: ClassINET, Ttl: 0}
72	rr.A = net.IPv4(127, 0, 0, 1)
73
74	x1 := new(TXT)
75	x1.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
76	x1.Txt = []string{}
77
78	x2 := new(TXT)
79	x2.Hdr = RR_Header{Name: dom, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}
80	x2.Txt = []string{"heelalaollo"}
81
82	m.Extra[0] = x1
83	m.Extra[1] = x2
84	m.Answer[0] = rr
85	b, err := m.Pack()
86	if err != nil {
87		t.Error("packing failed: ", err)
88		return
89	}
90
91	var unpackMsg Msg
92	err = unpackMsg.Unpack(b)
93	if err != nil {
94		t.Error("unpacking failed")
95		return
96	}
97}
98
99func TestBailiwick(t *testing.T) {
100	yes := map[string]string{
101		"miek1.nl": "miek1.nl",
102		"miek.nl":  "ns.miek.nl",
103		".":        "miek.nl",
104	}
105	for parent, child := range yes {
106		if !IsSubDomain(parent, child) {
107			t.Errorf("%s should be child of %s", child, parent)
108			t.Errorf("comparelabels %d", CompareDomainName(parent, child))
109			t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
110		}
111	}
112	no := map[string]string{
113		"www.miek.nl":  "ns.miek.nl",
114		"m\\.iek.nl":   "ns.miek.nl",
115		"w\\.iek.nl":   "w.iek.nl",
116		"p\\\\.iek.nl": "ns.p.iek.nl", // p\\.iek.nl , literal \ in domain name
117		"miek.nl":      ".",
118	}
119	for parent, child := range no {
120		if IsSubDomain(parent, child) {
121			t.Errorf("%s should not be child of %s", child, parent)
122			t.Errorf("comparelabels %d", CompareDomainName(parent, child))
123			t.Errorf("lenlabels %d %d", CountLabel(parent), CountLabel(child))
124		}
125	}
126}
127
128func TestPackNAPTR(t *testing.T) {
129	for _, n := range []string{
130		`apple.com. IN NAPTR   100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`,
131		`apple.com. IN NAPTR   90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`,
132		`apple.com. IN NAPTR   50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`,
133	} {
134		rr := testRR(n)
135		msg := make([]byte, Len(rr))
136		if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
137			t.Errorf("packing failed: %v", err)
138			t.Errorf("length %d, need more than %d", Len(rr), off)
139		}
140	}
141}
142
143func TestToRFC3597(t *testing.T) {
144	a := testRR("miek.nl. IN A 10.0.1.1")
145	x := new(RFC3597)
146	x.ToRFC3597(a)
147	if x.String() != `miek.nl.	3600	CLASS1	TYPE1	\# 4 0a000101` {
148		t.Errorf("string mismatch, got: %s", x)
149	}
150
151	b := testRR("miek.nl. IN MX 10 mx.miek.nl.")
152	x.ToRFC3597(b)
153	if x.String() != `miek.nl.	3600	CLASS1	TYPE15	\# 14 000a026d78046d69656b026e6c00` {
154		t.Errorf("string mismatch, got: %s", x)
155	}
156}
157
158func TestNoRdataPack(t *testing.T) {
159	data := make([]byte, 1024)
160	for typ, fn := range TypeToRR {
161		r := fn()
162		*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 16}
163		_, err := PackRR(r, data, 0, nil, false)
164		if err != nil {
165			t.Errorf("failed to pack RR with zero rdata: %s: %v", TypeToString[typ], err)
166		}
167	}
168}
169
170func TestNoRdataUnpack(t *testing.T) {
171	data := make([]byte, 1024)
172	for typ, fn := range TypeToRR {
173		if typ == TypeSOA || typ == TypeTSIG || typ == TypeTKEY {
174			// SOA, TSIG will not be seen (like this) in dyn. updates?
175			// TKEY requires length fields to be present for the Key and OtherData fields
176			continue
177		}
178		r := fn()
179		*r.Header() = RR_Header{Name: "miek.nl.", Rrtype: typ, Class: ClassINET, Ttl: 16}
180		off, err := PackRR(r, data, 0, nil, false)
181		if err != nil {
182			// Should always works, TestNoDataPack should have caught this
183			t.Errorf("failed to pack RR: %v", err)
184			continue
185		}
186		if _, _, err := UnpackRR(data[:off], 0); err != nil {
187			t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err)
188		}
189	}
190}
191
192func TestRdataOverflow(t *testing.T) {
193	rr := new(RFC3597)
194	rr.Hdr.Name = "."
195	rr.Hdr.Class = ClassINET
196	rr.Hdr.Rrtype = 65280
197	rr.Rdata = hex.EncodeToString(make([]byte, 0xFFFF))
198	buf := make([]byte, 0xFFFF*2)
199	if _, err := PackRR(rr, buf, 0, nil, false); err != nil {
200		t.Fatalf("maximum size rrdata pack failed: %v", err)
201	}
202	rr.Rdata += "00"
203	if _, err := PackRR(rr, buf, 0, nil, false); err != ErrRdata {
204		t.Fatalf("oversize rrdata pack didn't return ErrRdata - instead: %v", err)
205	}
206}
207
208func TestCopy(t *testing.T) {
209	rr := testRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
210	rr1 := Copy(rr)
211	if rr.String() != rr1.String() {
212		t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
213	}
214}
215
216func TestMsgCopy(t *testing.T) {
217	m := new(Msg)
218	m.SetQuestion("miek.nl.", TypeA)
219	rr := testRR("miek.nl. 2311 IN A 127.0.0.1")
220	m.Answer = []RR{rr}
221	rr = testRR("miek.nl. 2311 IN NS 127.0.0.1")
222	m.Ns = []RR{rr}
223
224	m1 := m.Copy()
225	if m.String() != m1.String() {
226		t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String())
227	}
228
229	m1.Answer[0] = testRR("somethingelse.nl. 2311 IN A 127.0.0.1")
230	if m.String() == m1.String() {
231		t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String())
232	}
233
234	rr = testRR("miek.nl. 2311 IN A 127.0.0.2")
235	m1.Answer = append(m1.Answer, rr)
236	if m1.Ns[0].String() == m1.Answer[1].String() {
237		t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String())
238	}
239}
240
241func TestMsgPackBuffer(t *testing.T) {
242	var testMessages = []string{
243		// news.ycombinator.com.in.escapemg.com.	IN	A, response
244		"586285830001000000010000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001c0210006000100000e10002c036e7332c02103646e730b67726f6f7665736861726bc02d77ed50e600002a3000000e1000093a8000000e10",
245
246		// news.ycombinator.com.in.escapemg.com.	IN	A, question
247		"586201000001000000000000046e6577730b79636f6d62696e61746f7203636f6d02696e086573636170656d6703636f6d0000010001",
248
249		"398781020001000000000000046e6577730b79636f6d62696e61746f7203636f6d0000010001",
250	}
251
252	for i, hexData := range testMessages {
253		// we won't fail the decoding of the hex
254		input, _ := hex.DecodeString(hexData)
255		m := new(Msg)
256		if err := m.Unpack(input); err != nil {
257			t.Errorf("packet %d failed to unpack", i)
258			continue
259		}
260	}
261}
262
263// Make sure we can decode a TKEY packet from the string, modify the RR, and then pack it again.
264func TestTKEY(t *testing.T) {
265	// An example TKEY RR captured.  There is no known accepted standard text format for a TKEY
266	// record so we do this from a hex string instead of from a text readable string.
267	tkeyStr := "0737362d6d732d370932322d3332633233332463303439663961662d633065612d313165372d363839362d6463333937396666656666640000f900ff0000000000d2086773732d747369670059fd01f359fe53730003000000b8a181b53081b2a0030a0100a10b06092a864882f712010202a2819d04819a60819706092a864886f71201020202006f8187308184a003020105a10302010fa2783076a003020112a26f046db29b1b1d2625da3b20b49dafef930dd1e9aad335e1c5f45dcd95e0005d67a1100f3e573d70506659dbed064553f1ab890f68f65ae10def0dad5b423b39f240ebe666f2886c5fe03819692d29182bbed87b83e1f9d16b7334ec16a3c4fc5ad4a990088e0be43f0c6957916f5fe60000"
268	tkeyBytes, err := hex.DecodeString(tkeyStr)
269	if err != nil {
270		t.Fatal("unable to decode TKEY string ", err)
271	}
272	// Decode the RR
273	rr, tkeyLen, unPackErr := UnpackRR(tkeyBytes, 0)
274	if unPackErr != nil {
275		t.Fatal("unable to decode TKEY RR", unPackErr)
276	}
277	// Make sure it's a TKEY record
278	if rr.Header().Rrtype != TypeTKEY {
279		t.Fatal("Unable to decode TKEY")
280	}
281	// Make sure we get back the same length
282	if Len(rr) != len(tkeyBytes) {
283		t.Fatalf("Lengths don't match %d != %d", Len(rr), len(tkeyBytes))
284	}
285	// make space for it with some fudge room
286	msg := make([]byte, tkeyLen+1000)
287	offset, packErr := PackRR(rr, msg, 0, nil, false)
288	if packErr != nil {
289		t.Fatal("unable to pack TKEY RR", packErr)
290	}
291	if offset != len(tkeyBytes) {
292		t.Fatalf("mismatched TKEY RR size %d != %d", len(tkeyBytes), offset)
293	}
294	if !bytes.Equal(tkeyBytes, msg[0:offset]) {
295		t.Fatal("mismatched TKEY data after rewriting bytes")
296	}
297
298	// Now add some bytes to this and make sure we can encode OtherData properly
299	tkey := rr.(*TKEY)
300	tkey.OtherData = "abcd"
301	tkey.OtherLen = 2
302	offset, packErr = PackRR(tkey, msg, 0, nil, false)
303	if packErr != nil {
304		t.Fatal("unable to pack TKEY RR after modification", packErr)
305	}
306	if offset != len(tkeyBytes)+2 {
307		t.Fatalf("mismatched TKEY RR size %d != %d", offset, len(tkeyBytes)+2)
308	}
309
310	// Make sure we can parse our string output
311	tkey.Hdr.Class = ClassINET // https://github.com/miekg/dns/issues/577
312	_, newError := NewRR(tkey.String())
313	if newError != nil {
314		t.Fatalf("unable to parse TKEY string: %s", newError)
315	}
316}
317