1 static size_t
rdata_to_str_string_unquoted(const uint8_t * src,size_t len,ubuf * u)2 rdata_to_str_string_unquoted(const uint8_t *src, size_t len, ubuf *u)
3 {
4 	size_t n_bytes = 0;
5 
6 	while (len--) {
7 		uint8_t c;
8 
9 		c = *src++;
10 		if (c == '"') {
11 			ubuf_add_cstr(u, "\\\"");
12 		} else if (c == '\\') {
13 			ubuf_add_cstr(u, "\\\\");
14 		} else if (c >= ' ' && c <= '~') {
15 			ubuf_append(u, &c, 1);
16 		} else {
17 			ubuf_add_fmt(u, "\\%.3d", c);
18 		}
19 		n_bytes += 1;
20 	}
21 
22 	return n_bytes; /* number of bytes consumed from src */
23 }
24 
25 static size_t
rdata_to_str_string(const uint8_t * src,size_t len,ubuf * u)26 rdata_to_str_string(const uint8_t *src, size_t len, ubuf *u)
27 {
28 	ubuf_add(u, '"');
29 	size_t n_bytes = rdata_to_str_string_unquoted(src, len, u);
30 	ubuf_add(u, '"');
31 
32 	/* Will be truncated later, if unused. */
33 	ubuf_add(u, ' ');
34 
35 	return n_bytes;
36 }
37 
38 void
_wdns_rdata_to_ubuf(ubuf * u,const uint8_t * rdata,uint16_t rdlen,uint16_t rrtype,uint16_t rrclass)39 _wdns_rdata_to_ubuf(ubuf *u, const uint8_t *rdata, uint16_t rdlen,
40 		    uint16_t rrtype, uint16_t rrclass)
41 {
42 
43 #define bytes_required(n) do { \
44 	if (src_bytes < ((signed) (n))) \
45 		goto err; \
46 } while(0)
47 
48 #define bytes_consumed(n) do { \
49 	src += n; \
50 	src_bytes -= n; \
51 } while(0)
52 
53 	char domain_name[WDNS_PRESLEN_NAME];
54 	const record_descr *descr = NULL;
55 	const uint8_t *src;
56 	size_t len;
57 	ssize_t src_bytes;
58 	uint8_t oclen;
59 	wdns_res res;
60 
61 	if (rrtype < record_descr_len)
62 		descr = &record_descr_array[rrtype];
63 
64 	if (rrtype >= record_descr_len ||
65 	    (descr != NULL && descr->types[0] == rdf_unknown))
66 	{
67 		/* generic encoding */
68 
69 		ubuf_add_cstr(u, "\\# ");
70 		ubuf_add_fmt(u, "%u ", rdlen);
71 
72 		for (unsigned i = 0; i < rdlen; i++)
73 			ubuf_add_fmt(u, "%02x ", rdata[i]);
74 
75 		return;
76 
77 	} else if (descr != NULL && !(descr->record_class == class_un ||
78 				      descr->record_class == rrclass))
79 	{
80 		return;
81 	}
82 
83 	src = rdata;
84 	src_bytes = (ssize_t) rdlen;
85 
86 	for (const uint8_t *t = &descr->types[0]; *t != rdf_end; t++) {
87 		if (src_bytes == 0)
88 			break;
89 
90 		switch (*t) {
91 		case rdf_name:
92 		case rdf_uname:
93 			res = wdns_len_uname(src, src + src_bytes, &len);
94 			if (res != wdns_res_success)
95 				goto err_res;
96 			wdns_domain_to_str(src, len, domain_name);
97 			ubuf_add_cstr(u, domain_name);
98 			ubuf_add_cstr(u, " ");
99 			bytes_consumed(len);
100 			break;
101 
102 		case rdf_bytes:
103 			len = src_bytes;
104 			while (len > 0) {
105 				ubuf_add_fmt(u, "%02X", *src);
106 				src++;
107 				len--;
108 			}
109 			src_bytes = 0;
110 			break;
111 
112 		case rdf_bytes_b64: {
113 			base64_encodestate b64;
114 			char *buf;
115 			base64_init_encodestate(&b64);
116 			buf = alloca(2 * src_bytes + 1);
117 			len = base64_encode_block((const char *) src, src_bytes, buf, &b64);
118 			ubuf_append(u, (uint8_t *) buf, len);
119 			len = base64_encode_blockend(buf, &b64);
120 			ubuf_append(u, (uint8_t *) buf, len);
121 			src_bytes = 0;
122 			break;
123 		}
124 
125 		case rdf_bytes_str:
126 			len = rdata_to_str_string(src, src_bytes, u);
127 			bytes_consumed(len);
128 			break;
129 
130 		case rdf_ipv6prefix: {
131 			uint8_t prefix_len;
132 			uint8_t addr[16];
133 			char pres[WDNS_PRESLEN_TYPE_AAAA];
134 
135 			bytes_required(1);
136 			prefix_len = *src++;
137 
138 			if (prefix_len > 128) {
139 				goto err;
140 			}
141 
142 			oclen = (128-prefix_len) / 8;
143 			if (prefix_len % 8 != 0) {
144 				oclen++;
145 			}
146 			bytes_required(1 + oclen);
147 
148 			ubuf_add_fmt(u, "%d ", prefix_len);
149 
150 			if (oclen > 0) {
151 				memset(addr, 0, sizeof(addr));
152 				memcpy(addr, src, oclen);
153 				inet_ntop(AF_INET6, addr, pres, sizeof(pres));
154 				ubuf_add_cstr(u, pres);
155 				ubuf_add_cstr(u, " ");
156 			}
157 			src_bytes -= oclen + 1;
158 			src += oclen;
159 			break;
160 		}
161 
162 		case rdf_salt:
163 			bytes_required(1);
164 			len = oclen = *src++;
165 			bytes_required(1 + oclen);
166 			if (oclen == 0)
167 				ubuf_add_cstr(u, "-");
168 			while (len > 0) {
169 				ubuf_add_fmt(u, "%02x", *src);
170 				src++;
171 				len--;
172 			}
173 			ubuf_add_cstr(u, " ");
174 			src_bytes -= oclen + 1;
175 			break;
176 
177 		case rdf_hash: {
178 			char *buf;
179 			bytes_required(1);
180 			oclen = *src++;
181 			bytes_required(1 + oclen);
182 			/*
183 			 * RFC 5155 provides a "-" notation for salt with length zero,
184 			 * but no similar notation for hash with length zero. We use a
185 			 * single "0" character in this case to preserve the presentation
186 			 * syntax requirement of a sequence of base32 digits, while not
187 			 * conflicting with the base32 encoding of any one (or more) byte
188 			 * sequences.
189 			 */
190 			if (oclen == 0) {
191 				ubuf_add_cstr(u, "0 ");
192 				src_bytes --;
193 				break;
194 			}
195 
196 			buf = alloca(2 * oclen + 1);
197 			len = base32_encode(buf, 2 * oclen + 1, src, oclen);
198 			ubuf_append(u, (uint8_t *) buf, len);
199 			ubuf_add_cstr(u, " ");
200 			src += oclen;
201 			src_bytes -= oclen + 1;
202 			break;
203 		}
204 
205 		case rdf_int8: {
206 			uint8_t val;
207 			bytes_required(1);
208 			memcpy(&val, src, sizeof(val));
209 			ubuf_add_fmt(u, "%u ", val);
210 			bytes_consumed(1);
211 			break;
212 		}
213 
214 		case rdf_int16: {
215 			uint16_t val;
216 			bytes_required(2);
217 			memcpy(&val, src, sizeof(val));
218 			val = ntohs(val);
219 			ubuf_add_fmt(u, "%hu ", val);
220 			bytes_consumed(2);
221 			break;
222 		}
223 
224 		case rdf_int32: {
225 			uint32_t val;
226 			bytes_required(4);
227 			memcpy(&val, src, sizeof(val));
228 			val = ntohl(val);
229 			ubuf_add_fmt(u, "%u ", val);
230 			bytes_consumed(4);
231 			break;
232 		}
233 
234 		case rdf_ipv4: {
235 			char pres[WDNS_PRESLEN_TYPE_A];
236 			bytes_required(4);
237 			inet_ntop(AF_INET, src, pres, sizeof(pres));
238 			ubuf_add_cstr(u, pres);
239 			ubuf_add_cstr(u, " ");
240 			bytes_consumed(4);
241 			break;
242 		}
243 
244 		case rdf_ipv6: {
245 			char pres[WDNS_PRESLEN_TYPE_AAAA];
246 			bytes_required(16);
247 			inet_ntop(AF_INET6, src, pres, sizeof(pres));
248 			ubuf_add_cstr(u, pres);
249 			ubuf_add_cstr(u, " ");
250 			bytes_consumed(16);
251 			break;
252 		}
253 
254 		case rdf_eui48: {
255 			bytes_required(6);
256 			for (size_t i = 0; i < 6; i++) {
257 				if (i != 0) {
258 					ubuf_add(u, '-');
259 				}
260 				ubuf_add_fmt(u, "%02x", src[i]);
261 			}
262 			bytes_consumed(6);
263 			break;
264 		}
265 
266 		case rdf_eui64: {
267 			bytes_required(8);
268 			for (size_t i = 0; i < 8; i++) {
269 				if (i != 0) {
270 					ubuf_add(u, '-');
271 				}
272 				ubuf_add_fmt(u, "%02x", src[i]);
273 			}
274 			bytes_consumed(8);
275 			break;
276 		}
277 
278 		case rdf_string: {
279 			bytes_required(1);
280 			oclen = *src;
281 			bytes_consumed(1);
282 
283 			bytes_required(oclen);
284 			len = rdata_to_str_string(src, oclen, u);
285 			bytes_consumed(len);
286 			break;
287 		}
288 
289 		case rdf_repstring:
290 			while (src_bytes > 0) {
291 				bytes_required(1);
292 				oclen = *src;
293 				bytes_consumed(1);
294 
295 				bytes_required(oclen);
296 				len = rdata_to_str_string(src, oclen, u);
297 				bytes_consumed(len);
298 			}
299 			break;
300 
301 		case rdf_rrtype: {
302 			const char *s_rrtype;
303 			uint16_t my_rrtype;
304 
305 			bytes_required(2);
306 			memcpy(&my_rrtype, src, 2);
307 			my_rrtype = ntohs(my_rrtype);
308 			bytes_consumed(2);
309 
310 			s_rrtype = wdns_rrtype_to_str(my_rrtype);
311 			if (s_rrtype != NULL) {
312 				ubuf_add_cstr(u, s_rrtype);
313 				ubuf_add_cstr(u, " ");
314 			} else {
315 				ubuf_add_fmt(u, "TYPE%hu ", my_rrtype);
316 			}
317 
318 			break;
319 		}
320 
321 		case rdf_type_bitmap: {
322 			const char *s_rrtype;
323 			uint16_t my_rrtype, lo;
324 			uint8_t a, b, window_block, bitmap_len;
325 
326 			bytes_required(2);
327 			while (src_bytes >= 2) {
328 				window_block = *src;
329 				bitmap_len = *(src + 1);
330 				bytes_consumed(2);
331 				bytes_required(bitmap_len);
332 				lo = 0;
333 				for (int i = 0; i < bitmap_len; i++) {
334 					a = src[i];
335 					for (int j = 1; j <= 8; j++) {
336 						b = a & (1 << (8 - j));
337 						if (b != 0) {
338 							my_rrtype = (window_block << 8) | lo;
339 							s_rrtype = wdns_rrtype_to_str(my_rrtype);
340 							if (s_rrtype != NULL) {
341 								ubuf_add_cstr(u, s_rrtype);
342 								ubuf_add_cstr(u, " ");
343 							} else {
344 								ubuf_add_fmt(u, "TYPE%hu ", my_rrtype);
345 							}
346 						}
347 						lo += 1;
348 					}
349 				}
350 				bytes_consumed(bitmap_len);
351 			}
352 			break;
353 		} /* end case */
354 
355 		}
356 	}
357 
358 	/* truncate trailing " " */
359 	if (ubuf_size(u) > 0 && ubuf_value(u, ubuf_size(u) - 1) == ' ')
360 		ubuf_clip(u, ubuf_size(u) - 1);
361 
362 	return;
363 
364 err:
365 	ubuf_add_fmt(u, " ### PARSE ERROR ###");
366 	return;
367 
368 err_res:
369 	ubuf_add_fmt(u, " ### PARSE ERROR #%u ###", res);
370 	return;
371 }
372