1package dns
2
3import (
4	"fmt"
5	"testing"
6)
7
8func TestRequestTruncateAnswer(t *testing.T) {
9	m := new(Msg)
10	m.SetQuestion("large.example.com.", TypeSRV)
11
12	reply := new(Msg)
13	reply.SetReply(m)
14	for i := 1; i < 200; i++ {
15		reply.Answer = append(reply.Answer, testRR(
16			fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
17	}
18
19	reply.Truncate(MinMsgSize)
20	if want, got := MinMsgSize, reply.Len(); want < got {
21		t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
22	}
23	if !reply.Truncated {
24		t.Errorf("truncated bit should be set")
25	}
26}
27
28func TestRequestTruncateExtra(t *testing.T) {
29	m := new(Msg)
30	m.SetQuestion("large.example.com.", TypeSRV)
31
32	reply := new(Msg)
33	reply.SetReply(m)
34	for i := 1; i < 200; i++ {
35		reply.Extra = append(reply.Extra, testRR(
36			fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
37	}
38
39	reply.Truncate(MinMsgSize)
40	if want, got := MinMsgSize, reply.Len(); want < got {
41		t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
42	}
43	if !reply.Truncated {
44		t.Errorf("truncated bit should be set")
45	}
46}
47
48func TestRequestTruncateExtraEdns0(t *testing.T) {
49	const size = 4096
50
51	m := new(Msg)
52	m.SetQuestion("large.example.com.", TypeSRV)
53	m.SetEdns0(size, true)
54
55	reply := new(Msg)
56	reply.SetReply(m)
57	for i := 1; i < 200; i++ {
58		reply.Extra = append(reply.Extra, testRR(
59			fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
60	}
61	reply.SetEdns0(size, true)
62
63	reply.Truncate(size)
64	if want, got := size, reply.Len(); want < got {
65		t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
66	}
67	if !reply.Truncated {
68		t.Errorf("truncated bit should be set")
69	}
70	opt := reply.Extra[len(reply.Extra)-1]
71	if opt.Header().Rrtype != TypeOPT {
72		t.Errorf("expected last RR to be OPT")
73	}
74}
75
76func TestRequestTruncateExtraRegression(t *testing.T) {
77	const size = 2048
78
79	m := new(Msg)
80	m.SetQuestion("large.example.com.", TypeSRV)
81	m.SetEdns0(size, true)
82
83	reply := new(Msg)
84	reply.SetReply(m)
85	for i := 1; i < 33; i++ {
86		reply.Answer = append(reply.Answer, testRR(
87			fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
88	}
89	for i := 1; i < 33; i++ {
90		reply.Extra = append(reply.Extra, testRR(
91			fmt.Sprintf("10-0-0-%d.default.pod.k8s.example.com. 10 IN A 10.0.0.%d", i, i)))
92	}
93	reply.SetEdns0(size, true)
94
95	reply.Truncate(size)
96	if want, got := size, reply.Len(); want < got {
97		t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
98	}
99	if !reply.Truncated {
100		t.Errorf("truncated bit should be set")
101	}
102	opt := reply.Extra[len(reply.Extra)-1]
103	if opt.Header().Rrtype != TypeOPT {
104		t.Errorf("expected last RR to be OPT")
105	}
106}
107
108func TestTruncation(t *testing.T) {
109	reply := new(Msg)
110
111	for i := 0; i < 61; i++ {
112		reply.Answer = append(reply.Answer, testRR(fmt.Sprintf("http.service.tcp.srv.k8s.example.org. 5 IN SRV 0 0 80 10-144-230-%d.default.pod.k8s.example.org.", i)))
113	}
114
115	for i := 0; i < 5; i++ {
116		reply.Extra = append(reply.Extra, testRR(fmt.Sprintf("ip-10-10-52-5%d.subdomain.example.org. 5 IN A 10.10.52.5%d", i, i)))
117	}
118
119	for i := 0; i < 5; i++ {
120		reply.Ns = append(reply.Ns, testRR(fmt.Sprintf("srv.subdomain.example.org. 5 IN NS ip-10-10-33-6%d.subdomain.example.org.", i)))
121	}
122
123	for bufsize := 1024; bufsize <= 4096; bufsize += 12 {
124		m := new(Msg)
125		m.SetQuestion("http.service.tcp.srv.k8s.example.org.", TypeSRV)
126		m.SetEdns0(uint16(bufsize), true)
127
128		copy := reply.Copy()
129		copy.SetReply(m)
130
131		copy.Truncate(bufsize)
132		if want, got := bufsize, copy.Len(); want < got {
133			t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
134		}
135	}
136}
137
138func TestRequestTruncateAnswerExact(t *testing.T) {
139	const size = 867 // Bit fiddly, but this hits the rl == size break clause in Truncate, 52 RRs should remain.
140
141	m := new(Msg)
142	m.SetQuestion("large.example.com.", TypeSRV)
143	m.SetEdns0(size, false)
144
145	reply := new(Msg)
146	reply.SetReply(m)
147	for i := 1; i < 200; i++ {
148		reply.Answer = append(reply.Answer, testRR(fmt.Sprintf("large.example.com. 10 IN A 127.0.0.%d", i)))
149	}
150
151	reply.Truncate(size)
152	if want, got := size, reply.Len(); want < got {
153		t.Errorf("message length should be bellow %d bytes, got %d bytes", want, got)
154	}
155	if expected := 52; len(reply.Answer) != expected {
156		t.Errorf("wrong number of answers; expected %d, got %d", expected, len(reply.Answer))
157	}
158}
159
160func BenchmarkMsgTruncate(b *testing.B) {
161	const size = 2048
162
163	m := new(Msg)
164	m.SetQuestion("example.com.", TypeA)
165	m.SetEdns0(size, true)
166
167	reply := new(Msg)
168	reply.SetReply(m)
169	for i := 1; i < 33; i++ {
170		reply.Answer = append(reply.Answer, testRR(
171			fmt.Sprintf("large.example.com. 10 IN SRV 0 0 80 10-0-0-%d.default.pod.k8s.example.com.", i)))
172	}
173	for i := 1; i < 33; i++ {
174		reply.Extra = append(reply.Extra, testRR(
175			fmt.Sprintf("10-0-0-%d.default.pod.k8s.example.com. 10 IN A 10.0.0.%d", i, i)))
176	}
177
178	b.ResetTimer()
179
180	for i := 0; i < b.N; i++ {
181		b.StopTimer()
182		copy := reply.Copy()
183		b.StartTimer()
184
185		copy.Truncate(size)
186	}
187}
188