1package dns
2
3import (
4	"net"
5	"testing"
6)
7
8// TestPackDataOpt tests generated using fuzz.go and with a message pack
9// containing the following bytes:
10// "0000\x00\x00000000\x00\x00/00000" +
11// "0\x00\v\x00#\b00000000\x00\x00)000" +
12// "000\x00\x1c00\x00\x0000\x00\x01000\x00\x00\x00\b" +
13// "\x00\v\x00\x02\x0000000000"
14// That bytes sequence created the overflow error.
15func TestPackDataOpt(t *testing.T) {
16	type args struct {
17		option []EDNS0
18		msg    []byte
19		off    int
20	}
21	tests := []struct {
22		name       string
23		args       args
24		want       int
25		wantErr    bool
26		wantErrMsg string
27	}{
28		{
29			name: "overflow",
30			args: args{
31				option: []EDNS0{
32					&EDNS0_LOCAL{Code: 0x3030, Data: []uint8{}},
33					&EDNS0_LOCAL{Code: 0x3030, Data: []uint8{0x30}},
34					&EDNS0_LOCAL{Code: 0x3030, Data: []uint8{}},
35					&EDNS0_SUBNET{
36						Code: 0x0, Family: 0x2,
37						SourceNetmask: 0x0, SourceScope: 0x30,
38						Address: net.IP{0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
39				},
40				msg: []byte{
41					0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x2,
42					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x30,
43					0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x0b, 0x00,
44					0x23, 0x08, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
45					0x30, 0x30, 0x00, 0x00, 0x29, 0x30, 0x30, 0x30,
46					0x30, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
47					0x00, 0x30, 0x30, 0x00, 0x01, 0x30, 0x00, 0x00,
48					0x00,
49				},
50				off: 54,
51			},
52			wantErr:    true,
53			wantErrMsg: "dns: overflow packing opt",
54			want:       57,
55		},
56	}
57	for _, tt := range tests {
58		t.Run(tt.name, func(t *testing.T) {
59			got, err := packDataOpt(tt.args.option, tt.args.msg, tt.args.off)
60			if (err != nil) != tt.wantErr {
61				t.Errorf("packDataOpt() error = %v, wantErr %v", err, tt.wantErr)
62				return
63			}
64			if err != nil && tt.wantErrMsg != err.Error() {
65				t.Errorf("packDataOpt() error msg = %v, wantErrMsg %v", err.Error(), tt.wantErrMsg)
66				return
67			}
68			if got != tt.want {
69				t.Errorf("packDataOpt() = %v, want %v", got, tt.want)
70			}
71		})
72	}
73}
74
75// TestCrashNSEC tests generated using fuzz.go and with a message pack
76// containing the following bytes:
77// "0000\x00\x00000000\x00\x00/00000" +
78// "0\x00\v\x00#\b00000\x00\x00\x00\x00\x00\x1a000" +
79// "000\x00\x00\x00\x00\x1a000000\x00\x00\x00\x00\x1a0" +
80// "00000\x00\v00\a0000000\x00"
81// That byte sequence, when Unpack() and subsequential Pack() created a
82// panic: runtime error: slice bounds out of range
83// which was attributed to the fact that NSEC RR length computation was different (and smaller)
84// then when within packDataNsec.
85func TestCrashNSEC(t *testing.T) {
86	compression := make(map[string]struct{})
87	nsec := &NSEC{
88		Hdr: RR_Header{
89			Name:     ".",
90			Rrtype:   0x2f,
91			Class:    0x3030,
92			Ttl:      0x30303030,
93			Rdlength: 0xb,
94		},
95		NextDomain: ".",
96		TypeBitMap: []uint16{
97			0x2302, 0x2303, 0x230a, 0x230b,
98			0x2312, 0x2313, 0x231a, 0x231b,
99			0x2322, 0x2323,
100		},
101	}
102	expectedLength := 19
103	l := nsec.len(0, compression)
104	if l != expectedLength {
105		t.Fatalf("expected length of %d, got %d", expectedLength, l)
106	}
107}
108
109// TestCrashNSEC3 tests generated using fuzz.go and with a message pack
110// containing the following bytes:
111// "0000\x00\x00000000\x00\x00200000" +
112// "0\x00\v0000\x00\x00#\x0300\x00\x00\x00\x1a000" +
113// "000\x00\v00\x0200\x00\x03000\x00"
114// That byte sequence, when Unpack() and subsequential Pack() created a
115// panic: runtime error: slice bounds out of range
116// which was attributed to the fact that NSEC3 RR length computation was
117// different (and smaller) then within NSEC3.pack (which relies on
118// packDataNsec).
119func TestCrashNSEC3(t *testing.T) {
120	compression := make(map[string]struct{})
121	nsec3 := &NSEC3{
122		Hdr: RR_Header{
123			Name:     ".",
124			Rrtype:   0x32,
125			Class:    0x3030,
126			Ttl:      0x30303030,
127			Rdlength: 0xb,
128		},
129		Hash:       0x30,
130		Flags:      0x30,
131		Iterations: 0x3030,
132		SaltLength: 0x0,
133		Salt:       "",
134		HashLength: 0x0,
135		NextDomain: ".",
136		TypeBitMap: []uint16{
137			0x2302, 0x2303, 0x230a, 0x230b,
138		},
139	}
140	expectedLength := 24
141	l := nsec3.len(0, compression)
142	if l != expectedLength {
143		t.Fatalf("expected length of %d, got %d", expectedLength, l)
144	}
145}
146
147// TestNewRRCommentLengthCrasherString test inputs to NewRR that generated crashes.
148func TestNewRRCommentLengthCrasherString(t *testing.T) {
149	tests := []struct {
150		name string
151		in   string
152		err  string
153	}{
154
155		{
156			"HINFO1", " HINFO ;;;;;;;;;;;;;" +
157				";;;;;;;;\x00\x19;;;;;;;;;;" +
158				";\u007f;;;;;;;;;;;;;;;;;;" +
159				";;}mP_Qq_3sJ_1_84X_5" +
160				"45iW_3K4p8J8_v9_LT3_" +
161				"6_0l_3D4VT3xq6N_3K__" +
162				"_U_xX2m;;;;;;(;;;;;;" +
163				";;;;;;;;;;;;;;;\x1d;;;;" +
164				";;;;;;-0x804dBDe8ba " +
165				"\t \t\tr  HINFO \" \t\t\tve" +
166				"k1xH11e__P6_dk1_51bo" +
167				"g8gJK1V_O_v84_Bw4_1_" +
168				"72jQ3_0J3V_S5iYn4h5X" +
169				"R_2n___51J nN_  \t\tm " +
170				"aa_XO4_5\t   \t\t \t\tg6b" +
171				"p_KI_1_YWc_K8c2b___A" +
172				"e_Y1m__4Y_R_avy6t08x" +
173				"b5Cp9_7uS_yLa\t\t\t  d " +
174				"EKe1Q83vS___ a  \t\t  " +
175				"\tmP_Qq_3sJ_1_84X_545" +
176				"iW_3K4p8J8_v9_LT3_6_" +
177				"0l_3D4VT3xq6N_3K___U" +
178				"_xX2\"\"   \t \t_fL Ogl5" +
179				"_09i_9__3O7C__QMAG2U" +
180				"35IO8RRU6aJ9_6_57_6_" +
181				"b05BMoX5I__4833_____" +
182				"yfD_2_OPs__sqzM_pqQi" +
183				"_\t\t \tN__GuY4_Trath_0" +
184				"yy___cAK_a__0J0q5 L_" +
185				"p63Fzdva_Lb_29V7_R__" +
186				"Go_H2_8m_4__FJM5B_Y5" +
187				"Slw_ghp_55l_X2_Pnt6Y" +
188				"_Wd_hM7jRZ_\t\t   \tm \t" +
189				"  \t\ta md rK \x00 7_\"sr " +
190				"- sg o  -0x804dBDe8b" +
191				"a \t \t\tN_W6J3PBS_W__C" +
192				"yJu__k6F_jY0INI_LC27" +
193				"7x14b_1b___Y8f_K_3y_" +
194				"0055yaP_LKu_72g_T_32" +
195				"iBk1Zm_o  9i1P44_S0_" +
196				"_4AXUpo2__H55tL_g78_" +
197				"8V_8l0yg6bp_KI_1_YWc" +
198				"_K8c2b  \t \tmaa_XO4_5" +
199				"rg6bp_KI_1_YWc_K8c2b" +
200				" _C20w i_4 \t\t  u_k d" +
201				" rKsg09099 \"\"2335779" +
202				"05047986112651e025 \t" +
203				" \t\tN_W6J3PBS_W__CyJu" +
204				"__k6F_jY0INI_LC277x1" +
205				"4b_1b___Y8f_K_3y_005" +
206				"5yaP_LKu_72g_T_32iBk" +
207				"1Zm_o  9i1P44_S0__4A" +
208				"XUpo2__H55tL_g78_8V_" +
209				"8l0y_9K9_C__6af__wj_" +
210				"UbSYy_ge29S_s_Qe259q" +
211				"_kGod \t\t\t\t :0xb1AF1F" +
212				"b71D2ACeaB3FEce2ssg " +
213				"o dr-0x804dBDe8ba \t " +
214				"\t\t$  Y5 _BzOc6S_Lk0K" +
215				"y43j1TzV__9367tbX56_" +
216				"6B3__q6_v8_4_0_t_2q_" +
217				"nJ2gV3j9_tkOrx_H__a}" +
218				"mT 0g6bp_KI_1_YWc_K8" +
219				"c2b\t_ a\t \t54KM8f9_63" +
220				"zJ2Q_c1_C_Zf4ICF4m0q" +
221				"_RVm_3Zh4vr7yI_H2  a" +
222				" m 0yq__TiqA_FQBv_SS" +
223				"_Hm_8T8__M8F2_53TTo_" +
224				"k_o2__u_W6Vr__524q9l" +
225				"9CQsC_kOU___g_94   \"" +
226				" ~a_j_16_6iUSu_96V1W" +
227				"5r01j____gn157__8_LO" +
228				"0y_08Jr6OR__WF8__JK_" +
229				"N_wx_k_CGB_SjJ9R74i_" +
230				"7_1t_6 m NULLNULLNUL" +
231				"L \t \t\t\t drK\t\x00 7_\"\" 5" +
232				"_5_y732S43__D_8U9FX2" +
233				"27_k\t\tg6bp_KI_1_YWc_" +
234				"K8c2b_J_wx8yw1CMw27j" +
235				"___f_a8uw_ Er9gB_L2 " +
236				"\t\t  \t\t\tm aa_XO4_5 Y_" +
237				" I_T7762_zlMi_n8_FjH" +
238				"vy62p__M4S_8__r092af" +
239				"P_T_vhp6__SA_jVF13c5" +
240				"2__8J48K__S4YcjoY91X" +
241				"_iNf06  am aa_XO4_5\t" +
242				" d _ am_SYY4G__2h4QL" +
243				"iUIDd \t\t  \tXXp__KFjR" +
244				"V__JU3o\"\" d  \t_Iks_ " +
245				"aa_XO4_5<g6bp_KI_1_Y" +
246				"Wc_K8c2b _BzOc6S_Lk0" +
247				"Ky43j1TzV__9367tbX56" +
248				"_6B3__q6_v8_4_0_t_2q" +
249				"_nJ2gV3j9_tkOrx_H__ " +
250				"a\t_Iks_ \\ ma 0_58_r1" +
251				"y8jib_FaV_C_e \t \td\"\"" +
252				" ^Dy_0  \t\t \t ;;;;;;;" +
253				";;;;;;;;;;;",
254			`dns: bad HINFO Fields: "comment length insufficient for parsing" at line: 1:1951`,
255		},
256	}
257
258	for _, tc := range tests {
259		t.Run(tc.name, func(t *testing.T) {
260			_, err := NewRR(tc.in)
261			if err == nil {
262				t.Errorf("Expecting error for crasher line %s", tc.in)
263			}
264			if tc.err != err.Error() {
265				t.Errorf("Expecting error %s, got %s", tc.err, err.Error())
266			}
267		})
268	}
269}
270