1 /* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <assert.h>
18 #include <tap/basic.h>
19
20 #include "libknot/packet/rrset-wire.h"
21 #include "libknot/descriptor.h"
22 #include "libknot/errcode.h"
23
24 // Wire initializers
25
26 #define MESSAGE_HEADER(AN, AUTH, ADD) 0xd4, 0xec, 0x81, 0xa0, 0x00, 0x01, \
27 0x00, AN, 0x00, AUTH, 0x00, ADD
28
29 #define QUERY(qname, type) qname, 0x00, type, 0x00, 0x01
30
31 #define RR_HEADER(owner, type, rdlength0, rdlength1) owner, 0x00, type, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, rdlength0, rdlength1
32
33 #define QNAME_POINTER 0xc0, 0x0c
34
35 // Initializers' sizes
36
37 #define QUERY_SIZE 12 + 4
38 #define RR_HEADER_SIZE 10
39
40 // Sample domain names
41
42 #define QNAME 0x03, 0x6e, 0x69, 0x63, 0x02, 0x63, 0x7a, 0x00
43 #define QNAME_SIZE 8
44 #define QNAME_LONG \
45 0x3f,'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', \
46 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', \
47 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', \
48 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'w', 'y', \
49 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 0x3f,\
50 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', \
51 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', \
52 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', \
53 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'x', 'y', 'z', \
54 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 0x3f,'a', \
55 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', \
56 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', \
57 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', \
58 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'x', 'y', 'z', 'a', \
59 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'i', 'k', 0x3d,'a', 'b', \
60 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', \
61 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', \
62 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', \
63 'p', 'q', 'r', 's', 't', 'u', 'v', 'x', 'x', 'y', 'z', 'a', 'b', \
64 'c', 'd', 'e', 'f', 'g', 'h', 'i', 0x00
65 #define QNAME_LONG_SIZE 255
66 #define POINTER_SIZE 2
67
68 struct wire_data {
69 uint8_t wire[65535];
70 size_t size;
71 size_t pos;
72 int code;
73 const char *msg;
74 };
75
76 #define FROM_CASE_COUNT 17
77
78 static const struct wire_data FROM_CASES[FROM_CASE_COUNT] = {
79 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A)},
80 .size = QUERY_SIZE + QNAME_SIZE,
81 .pos = QUERY_SIZE + QNAME_SIZE,
82 .code = KNOT_EMALF,
83 .msg = "No header" },
84 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A), 0x00, 0x00, 0x01},
85 .size = QUERY_SIZE + QNAME_SIZE + 3,
86 .pos = QUERY_SIZE + QNAME_SIZE,
87 .code = KNOT_EMALF,
88 .msg = "Partial header" },
89 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A),
90 RR_HEADER(QNAME, KNOT_RRTYPE_A, 0x00, 0x04) },
91 .size = QUERY_SIZE + RR_HEADER_SIZE + QNAME_SIZE * 2,
92 .pos = QUERY_SIZE + QNAME_SIZE,
93 .code = KNOT_EMALF,
94 .msg = "No RDATA" },
95 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A),
96 RR_HEADER(QNAME, KNOT_RRTYPE_A, 0x00, 0x04), 0x01 },
97 .size = QUERY_SIZE + RR_HEADER_SIZE + QNAME_SIZE * 2 + 1,
98 .pos = QUERY_SIZE + QNAME_SIZE,
99 .code = KNOT_EMALF,
100 .msg = "Partial RDATA" },
101 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A),
102 RR_HEADER(QNAME, KNOT_RRTYPE_A, 0x00, 0x04), 0x01, 0x02, 0x03, 0x04 },
103 .size = QUERY_SIZE + RR_HEADER_SIZE + QNAME_SIZE * 2 + 4,
104 .pos = QUERY_SIZE + QNAME_SIZE,
105 .code = KNOT_EOK,
106 .msg = "OK RDATA" },
107 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_A),
108 RR_HEADER(QNAME, KNOT_RRTYPE_A, 0x00, 0x05), 0x01, 0x02, 0x03, 0x04, 0x05 },
109 .size = QUERY_SIZE + RR_HEADER_SIZE + QNAME_SIZE * 2 + 5,
110 .pos = QUERY_SIZE + QNAME_SIZE,
111 .code = KNOT_EMALF,
112 .msg = "Trailing RDATA" },
113 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME_LONG, KNOT_RRTYPE_SOA),
114 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_SOA, 0x00, 0x18), QNAME_POINTER, QNAME_POINTER,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
117 .size = QUERY_SIZE + RR_HEADER_SIZE + QNAME_LONG_SIZE + 6 + 20,
118 .pos = QUERY_SIZE + QNAME_LONG_SIZE,
119 .code = KNOT_EOK,
120 .msg = "Max DNAME" },
121 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_SIG),
122 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_SIG, 0xff, 0xdb),
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, QNAME },
125 .size = 65535,
126 .pos = QUERY_SIZE + QNAME_SIZE,
127 .code = KNOT_EOK,
128 .msg = "Max RDLENGTH" },
129 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME_LONG, KNOT_RRTYPE_SIG),
130 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_SIG, 0xff, 0xff),
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, QNAME_POINTER },
133 .size = 65535 + QNAME_LONG_SIZE + QUERY_SIZE + RR_HEADER_SIZE + 2,
134 .pos = QUERY_SIZE + QNAME_LONG_SIZE,
135 .code = KNOT_EMALF,
136 .msg = "Max RDLENGTH + compression"},
137 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_NSEC),
138 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_NSEC, 0x00, 0x03),
139 QNAME_POINTER, 0x00},
140 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 2 + 1,
141 .pos = QUERY_SIZE + QNAME_SIZE,
142 .code = KNOT_EOK,
143 .msg = "DNAME wrong compression"},
144 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_NAPTR),
145 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_NAPTR, 0x00, 0x01),
146 0x00},
147 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 1,
148 .pos = QUERY_SIZE + QNAME_SIZE,
149 .code = KNOT_EMALF,
150 .msg = "NAPTR missing header"},
151 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_NAPTR),
152 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_NAPTR, 0x00, 0x09),
153 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, QNAME_POINTER},
154 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 9,
155 .pos = QUERY_SIZE + QNAME_SIZE,
156 .code = KNOT_EMALF,
157 .msg = "NAPTR bad offset"},
158 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_NAPTR),
159 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_NAPTR, 0x00, 0x09),
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
161 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 7,
162 .pos = QUERY_SIZE + QNAME_SIZE,
163 .code = KNOT_EMALF,
164 .msg = "NAPTR no DNAME"},
165 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_NAPTR),
166 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_NAPTR, 0x00, 0x0c),
167 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, QNAME_POINTER},
168 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 10 + 2,
169 .pos = QUERY_SIZE + QNAME_SIZE,
170 .code = KNOT_EOK,
171 .msg = "NAPTR valid"},
172 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_APL),
173 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_APL, 0x00, 0x00) },
174 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2,
175 .pos = QUERY_SIZE + QNAME_SIZE,
176 .code = KNOT_EOK,
177 .msg = "Valid 0 RDATA"},
178 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_TXT),
179 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_TXT, 0x00, 0x00) },
180 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2,
181 .pos = QUERY_SIZE + QNAME_SIZE,
182 .code = KNOT_EMALF,
183 .msg = "Invalid 0 RDATA"},
184 { .wire = { MESSAGE_HEADER(1, 0, 0), QUERY(QNAME, KNOT_RRTYPE_PX),
185 RR_HEADER(QNAME_POINTER, KNOT_RRTYPE_PX, 0x00, 0x06),
186 0x00, 0x00, QNAME_POINTER, QNAME_POINTER },
187 .size = QUERY_SIZE + QNAME_SIZE + RR_HEADER_SIZE + 2 + 6,
188 .pos = QUERY_SIZE + QNAME_SIZE,
189 .code = KNOT_EOK,
190 .msg = "Obsolete RR type"},
191 };
192
193 #define TEST_CASE_FROM(rrset, i) size_t _pos##i = FROM_CASES[i].pos; \
194 ok(knot_rrset_rr_from_wire(FROM_CASES[i].wire, &_pos##i, FROM_CASES[i].size, \
195 rrset, NULL, true) == FROM_CASES[i].code, "rrset wire: %s", FROM_CASES[i].msg)
196
test_inputs(void)197 static void test_inputs(void)
198 {
199 for (size_t i = 0; i < FROM_CASE_COUNT; ++i) {
200 knot_rrset_t rrset;
201 knot_rrset_init_empty(&rrset);
202 TEST_CASE_FROM(&rrset, i);
203 knot_rrset_clear(&rrset, NULL);
204 }
205 }
206
check_canon(uint8_t * wire,size_t size,size_t pos,bool canon,knot_dname_t * qname,knot_dname_t * dname)207 static void check_canon(uint8_t *wire, size_t size, size_t pos, bool canon,
208 knot_dname_t *qname, knot_dname_t *dname)
209 {
210 knot_rrset_t rrset;
211 knot_rrset_init_empty(&rrset);
212
213 int ret = knot_rrset_rr_from_wire(wire, &pos, size, &rrset, NULL, canon);
214 is_int(KNOT_EOK, ret, "OK %s canonization", canon ? "with" : "without");
215 ok(memcmp(rrset.owner, qname, knot_dname_size(qname)) == 0, "compare owner");
216
217 uint8_t *rdata = rrset.rrs.rdata->data;
218 ok(memcmp(rdata, dname, knot_dname_size(dname)) == 0, "compare rdata dname");
219
220 knot_rrset_clear(&rrset, NULL);
221 }
222
test_canonization(void)223 static void test_canonization(void)
224 {
225 #define UPP_QNAME_SIZE 5
226 #define UPP_QNAME 0x01, 0x41, 0x01, 0x5a, 0x00 // A.Z.
227 #define LOW_QNAME 0x01, 0x61, 0x01, 0x7a, 0x00 // a.z.
228
229 #define UPP_DNAME_SIZE 3
230 #define UPP_DNAME 0x01, 0x58, 0x00 // X.
231 #define LOW_DNAME 0x01, 0x78, 0x00 // x.
232
233 uint8_t wire[] = {
234 MESSAGE_HEADER(1, 0, 0), QUERY(UPP_QNAME, KNOT_RRTYPE_NS),
235 RR_HEADER(UPP_QNAME, KNOT_RRTYPE_NS, 0x00, UPP_DNAME_SIZE), UPP_DNAME
236 };
237 size_t size = QUERY_SIZE + RR_HEADER_SIZE + UPP_QNAME_SIZE * 2 + UPP_DNAME_SIZE;
238 size_t pos = QUERY_SIZE + UPP_QNAME_SIZE;
239
240 knot_dname_t upp_qname[] = { UPP_QNAME };
241 knot_dname_t upp_dname[] = { UPP_DNAME };
242 check_canon(wire, size, pos, false, upp_qname, upp_dname);
243
244 knot_dname_t low_qname[] = { LOW_QNAME };
245 knot_dname_t low_dname[] = { LOW_DNAME };
246 check_canon(wire, size, pos, true, low_qname, low_dname);
247 }
248
main(int argc,char * argv[])249 int main(int argc, char *argv[])
250 {
251 plan_lazy();
252
253 diag("Test NULL parameters");
254 int ret = knot_rrset_rr_from_wire(NULL, NULL, 0, NULL, NULL, true);
255 is_int(KNOT_EINVAL, ret, "rr wire: Invalid params");
256
257 diag("Test various inputs");
258 test_inputs();
259
260 diag("Test canonization");
261 test_canonization();
262
263 return 0;
264 }
265