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