1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <inttypes.h>
5 #include <ctype.h>
6 
7 #include "test-common.h"
8 
9 #include <libmy/ubuf.h>
10 #include <wdns.h>
11 
12 #define NAME "test-rdata_to_str"
13 
14 struct test {
15 	const void *input;
16 	size_t input_len;
17 	uint16_t rrtype;
18 	uint16_t rrclass;
19 	const char *expected;
20 };
21 
22 struct test tdata[] = {
23 	{ "\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xad\xbe\xef", 17, WDNS_TYPE_A6, WDNS_CLASS_IN, "0 2000::dead:beef" },
24 	{ "\x01\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xad\xbe\xef\x03""fsi\x02io\x00", 25, WDNS_TYPE_A6, WDNS_CLASS_IN, "1 2000::dead:beef fsi.io." },
25 	{ "\x80\x03""fsi\x02io\x00", 9, WDNS_TYPE_A6, WDNS_CLASS_IN, "128 fsi.io." },
26 	{ "\x80", 1, WDNS_TYPE_A6, WDNS_CLASS_IN, "128" },
27 
28 	{
29 		.input = "\x00\x0a" "\x00\x01" "ftp://ftp1.example.com/public",
30 		.input_len = 2 + 2 + 29,
31 		.rrtype = WDNS_TYPE_URI,
32 		.rrclass = WDNS_CLASS_IN,
33 		.expected = "10 1 \"ftp://ftp1.example.com/public\"",
34 	},
35 
36 	{
37 		.input = "\x00\x0a" "\x00\x01"
38 			"https://www.isc.org/HolyCowThisSureIsAVeryLongURIRecordIDontEvenKnowWhatSomeoneWouldEverWantWithSuchAThingButTheSpecificationRequiresThatWesupportItSoHereWeGoTestingItLaLaLaLaLaLaLaSeriouslyThoughWhyWouldYouEvenConsiderUsingAURIThisLongItSeemsLikeASillyIdeaButEnhWhatAreYouGonnaDo/",
39 		.input_len = 2 + 2 + 281,
40 		.rrtype = WDNS_TYPE_URI,
41 		.rrclass = WDNS_CLASS_IN,
42 		.expected = "10 1 " "\"" "https://www.isc.org/HolyCowThisSureIsAVeryLongURIRecordIDontEvenKnowWhatSomeoneWouldEverWantWithSuchAThingButTheSpecificationRequiresThatWesupportItSoHereWeGoTestingItLaLaLaLaLaLaLaSeriouslyThoughWhyWouldYouEvenConsiderUsingAURIThisLongItSeemsLikeASillyIdeaButEnhWhatAreYouGonnaDo/" "\"",
43 	},
44 
45 	{
46 		.input = "\x04" "some" "\x04" "text",
47 		.input_len = 1 + 4 + 1 + 4,
48 		.rrtype = WDNS_TYPE_TXT,
49 		.rrclass = WDNS_CLASS_IN,
50 		.expected = "\"some\" \"text\"",
51 	},
52 
53 	/* TXT test for: a string beginning with a " and ending with a " */
54 	{
55 		.input = "\x08" "\x22" "quoted" "\x22",
56 		.input_len = 1 + 1 + 6 + 1,
57 		.rrtype = WDNS_TYPE_TXT,
58 		.rrclass = WDNS_CLASS_IN,
59 		.expected = "\"\\\"quoted\\\"\"",
60 	},
61 
62 	/* TXT test for: one quote sent over the wire */
63 	{
64 		.input = "\x03" "one" "\x05" "quote" "\x01" "\"" "\x04" "sent" "\x04" "over" "\x03" "the" "\x04" "wire",
65 		.input_len = 1 + 3 + 1 + 5 + 1 + 1 + 1 + 4 + 1 + 4 + 1 + 3 + 1 + 4,
66 		.rrtype = WDNS_TYPE_TXT,
67 		.rrclass = WDNS_CLASS_IN,
68 		.expected = "\"one\" \"quote\" \"\\\"\" \"sent\" \"over\" \"the\" \"wire\"",
69 	},
70 
71 	/* TXT test for: 256 characters in length (including the length
72 	   octet) */
73 	{
74 		.input = "\xff" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
75 		.input_len = 1 + 255,
76 		.rrtype = WDNS_TYPE_TXT,
77 		.rrclass = WDNS_CLASS_IN,
78 		.expected = "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"",
79 	},
80 
81 	/* TXT test for: single character string with multiple spaces */
82 	{
83 		.input = "\x19" "one string multiple words",
84 		.input_len = 1 + 25,
85 		.rrtype = WDNS_TYPE_TXT,
86 		.rrclass = WDNS_CLASS_IN,
87 		.expected = "\"one string multiple words\"",
88 	},
89 
90 	/* TXT test for: multiple character strings with spaces */
91 	{
92 		.input = "\x10" "multiple strings" "\x02" "of" "\x0e" "multiple words",
93 		.input_len = 1 + 16 + 1 + 2 + 1+ 14,
94 		.rrtype = WDNS_TYPE_TXT,
95 		.rrclass = WDNS_CLASS_IN,
96 		.expected = "\"multiple strings\" \"of\" \"multiple words\"",
97 	},
98 
99 	/* TXT test for: multiple long character strings */
100 	{
101 		.input = "\xff" "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" "\xff" "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" "\xff" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
102 		.input_len = 1 + 255 + 1 + 255 + 1 + 255,
103 		.rrtype = WDNS_TYPE_TXT,
104 		.rrclass = WDNS_CLASS_IN,
105 		.expected = "\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\" \"ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\" \"ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"",
106 	},
107 
108 	/* TXT test for: real world example of DKIM use.
109 	   The total length was 411 charcters broke up into
110 	   multiple character-strings. */
111 	{
112 		.input = "\xfe" "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2UMfREvlgajdSp3jv1tJ9nLpi/mRYnGyKC3inEQ9a7zqUjLq/yXukgpXs9AEHlvBvioxlgAVCPQQsuc1xp9+KXQGgJ8jTsn5OtKm8u+YBCt6OfvpeCpvt0l9JXMMHBNYV4c0XiPE5RHX2ltI0Av20CfEy+vMecpFtVDg4rMngjLws/ro6qT63S20A4zyVs/V" "\x9c" "19WW5F2Lulgv+l+EJzz9XummIJHOlU5n5ChcWU3Rw5RVGTtNjTZnFUaNXly3fW0ahKcG5Qc3e0Rhztp57JJQTl3OmHiMR5cHsCnrl1VnBi3kaOoQBYsSuBm+KRhMIw/X9wkLY67VLdkrwlX3xxsp6wIDAQAB",
113 		.input_len = 1 + 254 + 1 + 156,
114 		.rrtype = WDNS_TYPE_TXT,
115 		.rrclass = WDNS_CLASS_IN,
116 /* NOTE: the semicolons are not escaped as they would be with dig output */
117 		.expected = "\"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2UMfREvlgajdSp3jv1tJ9nLpi/mRYnGyKC3inEQ9a7zqUjLq/yXukgpXs9AEHlvBvioxlgAVCPQQsuc1xp9+KXQGgJ8jTsn5OtKm8u+YBCt6OfvpeCpvt0l9JXMMHBNYV4c0XiPE5RHX2ltI0Av20CfEy+vMecpFtVDg4rMngjLws/ro6qT63S20A4zyVs/V\" \"19WW5F2Lulgv+l+EJzz9XummIJHOlU5n5ChcWU3Rw5RVGTtNjTZnFUaNXly3fW0ahKcG5Qc3e0Rhztp57JJQTl3OmHiMR5cHsCnrl1VnBi3kaOoQBYsSuBm+KRhMIw/X9wkLY67VLdkrwlX3xxsp6wIDAQAB\"",
118 	},
119 
120 	/* TXT test from RFC 7208 section 3.3:
121 	   concatenated together without adding spaces. */
122 	{
123 		.input = "\x11" "v=spf1 .... first" "\x10" "second string...",
124 		.input_len = 1 + 17 + 1 + 16,
125 		.rrtype = WDNS_TYPE_TXT,
126 		.rrclass = WDNS_CLASS_IN,
127 		.expected = "\"v=spf1 .... first\" \"second string...\"",
128 	},
129 
130 	/* SPF test using real world example, all as one string */
131 	{
132 		.input = "\x63" "v=spf1 a mx ip4:204.152.184.0/21 ip4:149.20.0.0/16 ip6:2001:04F8::0/32 ip6:2001:500:60::65/128 ~all",
133 		.input_len = 1 + 99,
134 		.rrtype = WDNS_TYPE_SPF,
135 		.rrclass = WDNS_CLASS_IN,
136 		.expected = "\"v=spf1 a mx ip4:204.152.184.0/21 ip4:149.20.0.0/16 ip6:2001:04F8::0/32 ip6:2001:500:60::65/128 ~all\"",
137 	},
138 
139 	{
140 		.input =
141 			"\x1a" "Please stop asking for ANY"
142 			"\x1f" "See draft-ietf-dnsop-refuse-any"
143 			,
144 		.input_len = 1 + 0x1a + 1 + 0x1f,
145 		.rrtype = WDNS_TYPE_HINFO,
146 		.rrclass = WDNS_CLASS_IN,
147 		.expected = "\"Please stop asking for ANY\" \"See draft-ietf-dnsop-refuse-any\"",
148 	},
149 
150 	{
151 		.input =
152 			"\x00\x00\x00\x42"
153 			"\x00\x03"
154 			"\x00\x04\x60\x00\x00\x08"
155 			,
156 		.input_len = 4 + 2 + 6,
157 		.rrtype = WDNS_TYPE_CSYNC,
158 		.rrclass = WDNS_CLASS_IN,
159 		.expected = "66 3 A NS AAAA",
160 	},
161 
162 	{
163 		.input = "\xAB\xCD\xEF\x01\x02\x03",
164 		.input_len = 6,
165 		.rrtype = WDNS_TYPE_EUI48,
166 		.rrclass = WDNS_CLASS_IN,
167 		.expected = "ab-cd-ef-01-02-03",
168 	},
169 
170 	{
171 		.input = "\xAB\xCD\xEF\x01\x02\x03\x04\x05",
172 		.input_len = 8,
173 		.rrtype = WDNS_TYPE_EUI64,
174 		.rrclass = WDNS_CLASS_IN,
175 		.expected = "ab-cd-ef-01-02-03-04-05",
176 	},
177 
178 	{
179 		.input = "\x01\x02\x03\x04\x05\x06\x07\x08",
180 		.input_len = 8,
181 		.rrtype = WDNS_TYPE_OPENPGPKEY,
182 		.rrclass = WDNS_CLASS_IN,
183 		.expected = "AQIDBAUGBwg=",
184 	},
185 
186 	{
187 		.input =
188 			"\x01\x00" "\x03" "\x05"
189 			"\x01\x03\xd2\x2a\x6c\xa7\x7f\x35\xb8\x93\x20\x6f\xd3\x5e\x4c\x50"
190 			"\x6d\x83\x78\x84\x37\x09\xb9\x7e\x04\x16\x47\xe1\xbf\xf4\x3d\x8d"
191 			"\x64\xc6\x49\xaf\x1e\x37\x19\x73\xc9\xe8\x91\xfc\xe3\xdf\x51\x9a"
192 			"\x8c\x84\x0a\x63\xee\x42\xa6\xd2\xeb\xdd\xbb\x97\x03\x5d\x21\x5a"
193 			"\xa4\xe4\x17\xb1\xfa\x45\xfa\x11\xa9\x74\x1e\xa2\x09\x8c\x1d\xfa"
194 			"\x5f\xb5\xfe\xb3\x32\xfd\x4b\xc8\x15\x20\x89\xae\xf3\x6b\xa6\x44"
195 			"\xcc\xe2\x41\x3b\x3b\x72\xbe\x18\xcb\xef\x8d\xa2\x53\xf4\xe9\x3d"
196 			"\x21\x03\x86\x6d\x92\x34\xa2\xe2\x8d\xf5\x29\xa6\x7d\x54\x68\xdb"
197 			"\xef\xe3",
198 		.input_len = 2 + 1 + 1 + 130,
199 		.rrtype = WDNS_TYPE_CDNSKEY,
200 		.rrclass = WDNS_CLASS_IN,
201 		.expected =
202 			"256 3 5 "
203 			"AQPSKmynfzW4kyBv015MUG2DeIQ3Cbl+BBZH4b/0PY1kxkmvHjcZc8no "
204 			"kfzj31GajIQKY+5CptLr3buXA10hWqTkF7H6RfoRqXQeogmMHfpftf6z "
205 			"Mv1LyBUgia7za6ZEzOJBOztyvhjL742iU/TpPSEDhm2SNKLijfUppn1U "
206 			"aNvv4w==",
207 	},
208 
209 	{
210 		.input =
211 			"\x01\x00" "\x03" "\x05"
212 			"\x01\x03\xd2\x2a\x6c\xa7\x7f\x35\xb8\x93\x20\x6f\xd3\x5e\x4c\x50"
213 			"\x6d\x83\x78\x84\x37\x09\xb9\x7e\x04\x16\x47\xe1\xbf\xf4\x3d\x8d"
214 			"\x64\xc6\x49\xaf\x1e\x37\x19\x73\xc9\xe8\x91\xfc\xe3\xdf\x51\x9a"
215 			"\x8c\x84\x0a\x63\xee\x42\xa6\xd2\xeb\xdd\xbb\x97\x03\x5d\x21\x5a"
216 			"\xa4\xe4\x17\xb1\xfa\x45\xfa\x11\xa9\x74\x1e\xa2\x09\x8c\x1d\xfa"
217 			"\x5f\xb5\xfe\xb3\x32\xfd\x4b\xc8\x15\x20\x89\xae\xf3\x6b\xa6\x44"
218 			"\xcc\xe2\x41\x3b\x3b\x72\xbe\x18\xcb\xef\x8d\xa2\x53\xf4\xe9\x3d"
219 			"\x21\x03\x86\x6d\x92\x34\xa2\xe2\x8d\xf5\x29\xa6\x7d\x54\x68\xdb"
220 			"\xef\xe3",
221 		.input_len = 2 + 1 + 1 + 130,
222 		.rrtype = WDNS_TYPE_DNSKEY,
223 		.rrclass = WDNS_CLASS_IN,
224 		.expected =
225 			"256 3 5 "
226 			"AQPSKmynfzW4kyBv015MUG2DeIQ3Cbl+BBZH4b/0PY1kxkmvHjcZc8no "
227 			"kfzj31GajIQKY+5CptLr3buXA10hWqTkF7H6RfoRqXQeogmMHfpftf6z "
228 			"Mv1LyBUgia7za6ZEzOJBOztyvhjL742iU/TpPSEDhm2SNKLijfUppn1U "
229 			"aNvv4w==",
230 	},
231 
232 	{
233 		.input =
234 			"\xec\x45" "\x05" "\x01"
235 			"\x2b\xb1\x83\xaf\x5f\x22\x58\x81\x79\xa5\x3b\x0a\x98\x63\x1f\xad\x1a\x29\x21\x18",
236 		.input_len = 2 + 1 + 1 + 20,
237 		.rrtype = WDNS_TYPE_DS,
238 		.rrclass = WDNS_CLASS_IN,
239 		.expected = "60485 5 1 2BB183AF5F22588179A53B0A98631FAD1A292118",
240 	},
241 
242 	{
243 		.input =
244 			"\xec\x45" "\x05" "\x01"
245 			"\x2b\xb1\x83\xaf\x5f\x22\x58\x81\x79\xa5\x3b\x0a\x98\x63\x1f\xad\x1a\x29\x21\x18",
246 		.input_len = 2 + 1 + 1 + 20,
247 		.rrtype = WDNS_TYPE_CDS,
248 		.rrclass = WDNS_CLASS_IN,
249 		.expected = "60485 5 1 2BB183AF5F22588179A53B0A98631FAD1A292118",
250 	},
251 
252 	{
253 		.input =
254 			"\x00" "\x00" "\x01"
255 			"\xd2\xab\xde\x24\x0d\x7c\xd3\xee\x6b\x4b\x28\xc5\x4d\xf0\x34\xb9"
256 			"\x79\x83\xa1\xd1\x6e\x8a\x41\x0e\x45\x61\xcb\x10\x66\x18\xe9\x71",
257 		.input_len = 1 + 1 + 1 + 32,
258 		.rrtype = WDNS_TYPE_TLSA,
259 		.rrclass = WDNS_CLASS_IN,
260 		.expected =
261 			"0 0 1 "
262 			"D2ABDE240D7CD3EE6B4B28C54DF034B9"
263 			"7983A1D16E8A410E4561CB106618E971",
264 	},
265 
266 	/* rrtype bitmap test for rrtypes > 255 */
267 	{
268 		.input =
269 			"\x03""fsi\x02io\x00"
270 			"\x00\x01" "\x40"
271 			"\x01\x01" "\x40"
272 			"\x80\x01" "\x40",
273 		.input_len = 8 + 3 + 3 + 3,
274 		.rrtype = WDNS_TYPE_NSEC,
275 		.rrclass = WDNS_CLASS_IN,
276 		.expected = "fsi.io. A CAA DLV",
277 	},
278 
279 	{ 0 }
280 };
281 
282 
283 static size_t
test_rdata_to_str(void)284 test_rdata_to_str(void) {
285 	ubuf *u;
286 	struct test *cur;
287 	size_t failures = 0;
288 
289 	u = ubuf_init(256);
290 
291 	for(cur = tdata; cur->input != NULL; cur++) {
292 		char * actual = NULL;
293 
294 		ubuf_reset(u);
295 
296 		actual = wdns_rdata_to_str(cur->input, cur->input_len, cur->rrtype, cur->rrclass);
297 
298 		if (strcmp(actual, cur->expected)) {
299 			ubuf_add_fmt(u, "FAIL %" PRIu64 ": input=", cur-tdata);
300 			escape(u, cur->input, cur->input_len);
301 
302 			ubuf_add_fmt(u, " %s %s",
303 					wdns_rrclass_to_str(cur->rrclass),
304 					wdns_rrtype_to_str(cur->rrtype));
305 
306 			ubuf_add_cstr(u, " value=");
307 			escape(u, (const uint8_t*)actual, strlen(actual));
308 			ubuf_add_cstr(u, " != ");
309 			escape(u, (const uint8_t*)cur->expected, strlen(cur->expected));
310 
311 			failures++;
312 		} else {
313 			ubuf_add_fmt(u, "PASS %" PRIu64 ": input=", cur-tdata);
314 			escape(u, cur->input, cur->input_len);
315 			ubuf_add_fmt(u, " %s %s",
316 					wdns_rrclass_to_str(cur->rrclass),
317 					wdns_rrtype_to_str(cur->rrtype));
318 
319 			ubuf_add_cstr(u, " value=");
320 			escape(u, (const uint8_t*)actual, strlen(actual));
321 		}
322 
323 		fprintf (stderr, "%s\n", ubuf_cstr(u));
324 		if (actual != NULL) {
325 			free(actual);
326 			actual = NULL;
327 		}
328 	}
329 
330 	ubuf_destroy(&u);
331 	return failures;
332 }
333 
main(void)334 int main (void) {
335 	int ret = 0;
336 
337 	ret |= check(test_rdata_to_str(), "test_rdata_to_str", NAME);
338 
339 	if (ret)
340 		return (EXIT_FAILURE);
341 	return (EXIT_SUCCESS);
342 }
343