1 /* Copyright (C) 2015 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 <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <sys/socket.h>
21 #include <tap/basic.h>
22
23 #include "libknot/yparser/yptrafo.h"
24 #include "libknot/libknot.h"
25
int_test(const char * txt,int64_t num,yp_style_t s,int64_t min,int64_t max)26 static void int_test(const char *txt, int64_t num, yp_style_t s,
27 int64_t min, int64_t max)
28 {
29 int ret;
30 uint8_t b[64];
31 size_t b_len = sizeof(b);
32 char t[64];
33 size_t t_len = sizeof(t);
34 yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
35
36 diag("integer \"%s\":", txt);
37 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
38 is_int(KNOT_EOK, ret, "txt to bin");
39 ok(yp_int(b) == num, "compare");
40 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, s | YP_SNOQUOTE);
41 is_int(KNOT_EOK, ret, "bin to txt");
42 ok(strlen(t) == t_len, "txt ret length");
43 ok(strlen(txt) == t_len, "txt length");
44 ok(memcmp(txt, t, t_len) == 0, "compare");
45 }
46
int_bad_test(const char * txt,int code,yp_style_t s,int64_t min,int64_t max)47 static void int_bad_test(const char *txt, int code, yp_style_t s,
48 int64_t min, int64_t max)
49 {
50 int ret;
51 uint8_t b[64];
52 size_t b_len = sizeof(b);
53 yp_item_t i = { NULL, YP_TINT, YP_VINT = { min, max, YP_NIL, s } };
54
55 diag("integer \"%s\":", txt);
56 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
57 ok(ret == code, "invalid txt to bin");
58 }
59
bool_test(const char * txt,bool val)60 static void bool_test(const char *txt, bool val)
61 {
62 int ret;
63 uint8_t b[64];
64 size_t b_len = sizeof(b);
65 char t[64];
66 size_t t_len = sizeof(t);
67 yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
68
69 diag("boolean \"%s\":", txt);
70 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
71 is_int(KNOT_EOK, ret, "txt to bin");
72 ok(yp_bool(b) == val, "compare");
73 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
74 is_int(KNOT_EOK, ret, "bin to txt");
75 ok(strlen(t) == t_len, "txt ret length");
76 ok(strlen(txt) == t_len, "txt length");
77 ok(memcmp(txt, t, t_len) == 0, "compare");
78 }
79
bool_bad_test(const char * txt,int code)80 static void bool_bad_test(const char *txt, int code)
81 {
82 int ret;
83 uint8_t b[64];
84 size_t b_len = sizeof(b);
85 yp_item_t i = { NULL, YP_TBOOL, YP_VNONE };
86
87 diag("boolean \"%s\":", txt);
88 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
89 ok(ret == code, "invalid txt to bin");
90 }
91
opt_test(const char * txt,unsigned val,const knot_lookup_t * opts)92 static void opt_test(const char *txt, unsigned val, const knot_lookup_t *opts)
93 {
94 int ret;
95 uint8_t b[64];
96 size_t b_len = sizeof(b);
97 char t[64];
98 size_t t_len = sizeof(t);
99 yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
100
101 diag("option \"%s\":", txt);
102 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
103 is_int(KNOT_EOK, ret, "txt to bin");
104 ok(b_len == 1, "compare length");
105 ok(yp_opt(b) == val, "compare");
106 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
107 is_int(KNOT_EOK, ret, "bin to txt");
108 ok(strlen(t) == t_len, "txt ret length");
109 ok(strlen(txt) == t_len, "txt length");
110 ok(memcmp(txt, t, t_len) == 0, "compare");
111 }
112
opt_bad_test(const char * txt,int code,const knot_lookup_t * opts)113 static void opt_bad_test(const char *txt, int code, const knot_lookup_t *opts)
114 {
115 int ret;
116 uint8_t b[64];
117 size_t b_len = sizeof(b);
118 yp_item_t i = { NULL, YP_TOPT, YP_VOPT = { opts } };
119
120 diag("option \"%s\":", txt);
121 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
122 ok(ret == code, "invalid txt to bin");
123 }
124
str_test(const char * txt,const char * val)125 static void str_test(const char *txt, const char *val)
126 {
127 int ret;
128 uint8_t b[64];
129 size_t b_len = sizeof(b);
130 char t[64];
131 size_t t_len = sizeof(t);
132 yp_item_t i = { NULL, YP_TSTR, YP_VNONE };
133
134 diag("string \"%s\":", txt);
135 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
136 is_int(KNOT_EOK, ret, "txt to bin");
137 ok(b_len == strlen(txt) + 1, "compare length");
138 ok(memcmp(yp_str(b), val, b_len) == 0, "compare");
139 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
140 is_int(KNOT_EOK, ret, "bin to txt");
141 ok(strlen(t) == t_len, "txt ret length");
142 ok(strlen(txt) == t_len, "txt length");
143 ok(memcmp(txt, t, t_len) == 0, "compare");
144 }
145
addr_test(const char * txt,bool port)146 static void addr_test(const char *txt, bool port)
147 {
148 int ret;
149 uint8_t b[64];
150 size_t b_len = sizeof(b);
151 char t[64];
152 size_t t_len = sizeof(t);
153 yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
154
155 diag("address \"%s\":", txt);
156 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
157 is_int(KNOT_EOK, ret, "txt to bin");
158 bool no_port;
159 yp_addr(b, &no_port);
160 ok(no_port == port, "compare port presence");
161 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
162 is_int(KNOT_EOK, ret, "bin to txt");
163 ok(strlen(t) == t_len, "txt ret length");
164 ok(strlen(txt) == t_len, "txt length");
165 ok(memcmp(txt, t, t_len) == 0, "compare");
166 }
167
addr_bad_test(const char * txt,int code)168 static void addr_bad_test(const char *txt, int code)
169 {
170 int ret;
171 uint8_t b[64];
172 size_t b_len = sizeof(b);
173 yp_item_t i = { NULL, YP_TADDR, YP_VNONE };
174
175 diag("address \"%s\":", txt);
176 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
177 ok(ret == code, "invalid txt to bin");
178 }
179
addr_range_test(const char * txt)180 static void addr_range_test(const char *txt)
181 {
182 int ret;
183 uint8_t b[64];
184 size_t b_len = sizeof(b);
185 char t[64];
186 size_t t_len = sizeof(t);
187 yp_item_t i = { NULL, YP_TNET, YP_VNONE };
188
189 diag("address range \"%s\":", txt);
190 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
191 is_int(KNOT_EOK, ret, "txt to bin");
192 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
193 is_int(KNOT_EOK, ret, "bin to txt");
194 ok(strlen(t) == t_len, "txt ret length");
195 ok(strlen(txt) == t_len, "txt length");
196 ok(memcmp(txt, t, t_len) == 0, "compare");
197 }
198
addr_range_bad_test(const char * txt,int code)199 static void addr_range_bad_test(const char *txt, int code)
200 {
201 int ret;
202 uint8_t b[64];
203 size_t b_len = sizeof(b);
204 yp_item_t i = { NULL, YP_TNET, YP_VNONE };
205
206 diag("address range \"%s\":", txt);
207 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
208 ok(ret == code, "invalid txt to bin");
209 }
210
dname_test(const char * txt,const char * val)211 static void dname_test(const char *txt, const char *val)
212 {
213 int ret;
214 uint8_t b[64];
215 size_t b_len = sizeof(b);
216 char t[64];
217 size_t t_len = sizeof(t);
218 yp_item_t i = { NULL, YP_TDNAME, YP_VNONE };
219
220 diag("dname \"%s\":", txt);
221 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
222 is_int(KNOT_EOK, ret, "txt to bin");
223 ok(memcmp(yp_dname(b), val, b_len) == 0, "compare");
224 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
225 is_int(KNOT_EOK, ret, "bin to txt");
226 ok(strlen(t) == t_len, "txt ret length");
227 ok(strlen(txt) == t_len, "txt length");
228 ok(memcmp(txt, t, t_len) == 0, "compare");
229 }
230
hex_test(const char * txt,const char * val,const char * txt_out)231 static void hex_test(const char *txt, const char *val, const char *txt_out)
232 {
233 int ret;
234 uint8_t b[64];
235 size_t b_len = sizeof(b);
236 char t[64];
237 size_t t_len = sizeof(t);
238 yp_item_t i = { NULL, YP_THEX, YP_VNONE };
239
240 if (txt_out == NULL) {
241 txt_out = txt;
242 }
243
244 diag("hex \"%s\":", txt);
245 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
246 is_int(KNOT_EOK, ret, "txt to bin");
247 ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
248 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
249 is_int(KNOT_EOK, ret, "bin to txt");
250 ok(strlen(t) == t_len, "txt ret length");
251 ok(strlen(txt_out) == t_len, "txt length");
252 ok(memcmp(txt_out, t, t_len) == 0, "compare");
253 }
254
hex_bad_test(const char * txt,int code)255 static void hex_bad_test(const char *txt, int code)
256 {
257 int ret;
258 uint8_t b[64];
259 size_t b_len = sizeof(b);
260 yp_item_t i = { NULL, YP_THEX, YP_VNONE };
261
262 diag("hex \"%s\":", txt);
263 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
264 ok(ret == code, "invalid txt to bin");
265 }
266
base64_test(const char * txt,const char * val)267 static void base64_test(const char *txt, const char *val)
268 {
269 int ret;
270 uint8_t b[64];
271 size_t b_len = sizeof(b);
272 char t[64];
273 size_t t_len = sizeof(t);
274 yp_item_t i = { NULL, YP_TB64, YP_VNONE };
275
276 diag("base64 \"%s\":", txt);
277 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
278 is_int(KNOT_EOK, ret, "txt to bin");
279 ok(memcmp(yp_bin(b), val, yp_bin_len(b)) == 0, "compare");
280 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
281 is_int(KNOT_EOK, ret, "bin to txt");
282 ok(strlen(t) == t_len, "txt ret length");
283 ok(strlen(txt) == t_len, "txt length");
284 ok(memcmp(txt, t, t_len) == 0, "compare");
285 }
286
ref_test(const char * txt,bool val)287 static void ref_test(const char *txt, bool val)
288 {
289 int ret;
290 uint8_t b[64];
291 size_t b_len = sizeof(b);
292 char t[64];
293 size_t t_len = sizeof(t);
294 yp_item_t id = { NULL, YP_TBOOL, YP_VNONE };
295 yp_item_t ref = { NULL, YP_TGRP, YP_VNONE };
296 yp_item_t i = { NULL, YP_TREF, YP_VNONE };
297 ref.var.g.id = &id;
298 i.var.r.ref = &ref;
299
300 diag("reference to boolean \"%s\":", txt);
301 ret = yp_item_to_bin(&i, txt, strlen(txt), b, &b_len);
302 is_int(KNOT_EOK, ret, "txt to bin");
303 ok(yp_bool(b) == val, "compare");
304 ret = yp_item_to_txt(&i, b, b_len, t, &t_len, YP_SNOQUOTE);
305 is_int(KNOT_EOK, ret, "bin to txt");
306 ok(strlen(t) == t_len, "txt ret length");
307 ok(strlen(txt) == t_len, "txt length");
308 ok(memcmp(txt, t, t_len) == 0, "compare");
309 }
310
main(int argc,char * argv[])311 int main(int argc, char *argv[])
312 {
313 plan_lazy();
314
315 /* Integer tests. */
316 int64_t min = -20000000000, max = 20000000000;
317 int_test("5", 5, YP_SNONE, min, max);
318 int_test("0", 0, YP_SNONE, min, max);
319 int_test("-5", -5, YP_SNONE, min, max);
320 int_test("20000000000", max, YP_SNONE, min, max);
321 int_test("-20000000000", min, YP_SNONE, min, max);
322 int_test("11B", 11LL * 1, YP_SSIZE, min, max);
323 int_test("11K", 11LL * 1024, YP_SSIZE, min, max);
324 int_test("11M", 11LL * 1024 * 1024, YP_SSIZE, min, max);
325 int_test("11G", 11LL * 1024 * 1024 * 1024, YP_SSIZE, min, max);
326 int_test("11s", 11LL * 1, YP_STIME, min, max);
327 int_test("11m", 11LL * 60, YP_STIME, min, max);
328 int_test("11h", 11LL * 3600, YP_STIME, min, max);
329 int_test("11d", 11LL * 24 * 3600, YP_STIME, min, max);
330 int_test("1025B", 1025LL, YP_SSIZE, min, max);
331 int_test("61s", 61LL, YP_STIME, min, max);
332 int_bad_test("20000000001", KNOT_ERANGE, YP_SNONE, min, max);
333 int_bad_test("-20000000001", KNOT_ERANGE, YP_SNONE, min, max);
334 int_bad_test("1x", KNOT_EINVAL, YP_SNONE, min, max);
335 int_bad_test("1sx", KNOT_EINVAL, YP_STIME, min, max);
336
337 /* Boolean tests. */
338 bool_test("on", true);
339 bool_test("off", false);
340 bool_bad_test("onx", KNOT_EINVAL);
341 bool_bad_test("enable", KNOT_EINVAL);
342
343 /* Option tests. */
344 static const knot_lookup_t opts[] = {
345 { 1, "one" },
346 { 10, "ten" },
347 { 255, "max" },
348 { 0, NULL }
349 };
350 opt_test("one", 1, opts);
351 opt_test("ten", 10, opts);
352 opt_test("max", 255, opts);
353 opt_bad_test("onex", KNOT_EINVAL, opts);
354 opt_bad_test("word", KNOT_EINVAL, opts);
355
356 /* String tests. */
357 str_test("Test string!", "Test string!");
358
359 /* Address tests. */
360 addr_test("192.168.123.1", true);
361 addr_test("192.168.123.1@12345", false);
362 addr_test("2001:db8::1", true);
363 addr_test("::1@12345", false);
364 addr_test("/tmp/test.sock", true);
365 addr_test("eth1@53", true);
366 addr_bad_test("192.168.123.x", KNOT_EINVAL);
367 addr_bad_test("192.168.123.1@", KNOT_EINVAL);
368 addr_bad_test("192.168.123.1@1x", KNOT_EINVAL);
369 addr_bad_test("192.168.123.1@65536", KNOT_ERANGE);
370
371 /* Address range tests. */
372 addr_range_test("1.1.1.1");
373 addr_range_test("1.1.1.1/0");
374 addr_range_test("1.1.1.1/32");
375 addr_range_test("1.1.1.1-1.2.3.4");
376 addr_range_test("::1");
377 addr_range_test("::1/0");
378 addr_range_test("::1/32");
379 addr_range_test("1::-5::");
380 addr_range_bad_test("unix", KNOT_EINVAL);
381 addr_range_bad_test("1.1.1", KNOT_EINVAL);
382 addr_range_bad_test("1.1.1.1/", KNOT_EINVAL);
383 addr_range_bad_test("1.1.1.1/33", KNOT_ERANGE);
384 addr_range_bad_test("1.1.1.1-", KNOT_EINVAL);
385 addr_range_bad_test("1.1.1.1-::1", KNOT_EINVAL);
386
387 /* Dname tests. */
388 dname_test("example.com.", "\x07""example""\x03""com""\x00");
389
390 /* Hex tests. */
391 hex_test("", "", NULL);
392 hex_test("0x", "", "");
393 hex_test("Hello World!", "Hello World!", NULL);
394 hex_test("0x0155FF", "\x01\x55\xFF", NULL);
395 hex_bad_test("0xA", KNOT_EINVAL);
396
397 /* Base64 tests. */
398 base64_test("Zm9vYmFy", "foobar");
399
400 /* Ref tests. */
401 ref_test("on", true);
402
403 return 0;
404 }
405