]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/sldns/str2wire.c
unbound: Vendor import 1.18.0
[FreeBSD/FreeBSD.git] / contrib / unbound / sldns / str2wire.c
1 /**
2  * str2wire.c - read txt presentation of RRs
3  *
4  * (c) NLnet Labs, 2005-2006
5  *
6  * See the file LICENSE for the license
7  */
8
9 /**
10  * \file
11  *
12  * Parses text to wireformat.
13  */
14 #include "config.h"
15 #include "sldns/str2wire.h"
16 #include "sldns/wire2str.h"
17 #include "sldns/sbuffer.h"
18 #include "sldns/parse.h"
19 #include "sldns/parseutil.h"
20 #include <ctype.h>
21 #ifdef HAVE_TIME_H
22 #include <time.h>
23 #endif
24 #ifdef HAVE_NETDB_H
25 #include <netdb.h>
26 #endif
27
28 /** bits for the offset */
29 #define RET_OFFSET_MASK (((unsigned)(~LDNS_WIREPARSE_MASK))>>LDNS_WIREPARSE_SHIFT)
30 /** return an error */
31 #define RET_ERR(e, off) ((int)(((e)&LDNS_WIREPARSE_MASK)|(((off)&RET_OFFSET_MASK)<<LDNS_WIREPARSE_SHIFT)))
32 /** Move parse error but keep its ID */
33 #define RET_ERR_SHIFT(e, move) RET_ERR(LDNS_WIREPARSE_ERROR(e), LDNS_WIREPARSE_OFFSET(e)+(move));
34
35 /*
36  * No special care is taken, all dots are translated into
37  * label separators.
38  * @param rel: true if the domain is not absolute (not terminated in .).
39  *      The output is then still terminated with a '0' rootlabel.
40  */
41 static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
42         size_t* olen, int* rel)
43 {
44         size_t len;
45
46         const char *s;
47         uint8_t *q, *pq, label_len;
48
49         if(rel) *rel = 0;
50         len = strlen((char*)str);
51         /* octet representation can make strings a lot longer than actual length */
52         if (len > LDNS_MAX_DOMAINLEN * 4) {
53                 return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 0);
54         }
55         if (0 == len) {
56                 return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, 0);
57         }
58
59         /* root label */
60         if (1 == len && *str == '.') {
61                 if(*olen < 1)
62                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
63                 buf[0] = 0;
64                 *olen = 1;
65                 return LDNS_WIREPARSE_ERR_OK;
66         }
67
68         /* get on with the rest */
69
70         /* s is on the current character in the string
71          * pq points to where the labellength is going to go
72          * label_len keeps track of the current label's length
73          * q builds the dname inside the buf array
74          */
75         len = 0;
76         if(*olen < 1)
77                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
78         q = buf+1;
79         pq = buf;
80         label_len = 0;
81         for (s = str; *s; s++, q++) {
82                 if (q >= buf + *olen)
83                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
84                 if (q >= buf + LDNS_MAX_DOMAINLEN)
85                         return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
86                 switch (*s) {
87                 case '.':
88                         if (label_len > LDNS_MAX_LABELLEN) {
89                                 return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
90                         }
91                         if (label_len == 0) {
92                                 return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
93                         }
94                         len += label_len + 1;
95                         *q = 0;
96                         *pq = label_len;
97                         label_len = 0;
98                         pq = q;
99                         break;
100                 case '\\':
101                         /* octet value or literal char */
102                         s += 1;
103                         if (!sldns_parse_escape(q, &s)) {
104                                 *q = 0;
105                                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, q-buf);
106                         }
107                         s -= 1;
108                         label_len++;
109                         break;
110                 default:
111                         *q = (uint8_t)*s;
112                         label_len++;
113                 }
114         }
115
116         /* add root label if last char was not '.' */
117         if(label_len != 0) {
118                 if(rel) *rel = 1;
119                 if (q >= buf + *olen)
120                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
121                 if (q >= buf + LDNS_MAX_DOMAINLEN) {
122                         return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
123                 }
124                 if (label_len > LDNS_MAX_LABELLEN) {
125                         return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
126                 }
127                 if (label_len == 0) { /* label_len 0 but not . at end? */
128                         return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
129                 }
130                 len += label_len + 1;
131                 *pq = label_len;
132                 *q = 0;
133         }
134         len++;
135         *olen = len;
136
137         return LDNS_WIREPARSE_ERR_OK;
138 }
139
140 int sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len)
141 {
142         return sldns_str2wire_dname_buf_rel(str, buf, len, NULL);
143 }
144
145 int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
146         uint8_t* origin, size_t origin_len)
147 {
148         size_t dlen = *len;
149         int rel = 0;
150         int s = sldns_str2wire_dname_buf_rel(str, buf, &dlen, &rel);
151         if(s) return s;
152
153         if(rel && origin && dlen > 0) {
154                 if((unsigned)dlen >= 0x00ffffffU ||
155                         (unsigned)origin_len >= 0x00ffffffU)
156                         /* guard against integer overflow in addition */
157                         return RET_ERR(LDNS_WIREPARSE_ERR_GENERAL, *len);
158                 if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN)
159                         return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW,
160                                 LDNS_MAX_DOMAINLEN);
161                 if(dlen + origin_len - 1 > *len)
162                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
163                                 *len);
164                 memmove(buf+dlen-1, origin, origin_len);
165                 *len = dlen + origin_len - 1;
166         } else
167                 *len = dlen;
168         return LDNS_WIREPARSE_ERR_OK;
169 }
170
171 uint8_t* sldns_str2wire_dname(const char* str, size_t* len)
172 {
173         uint8_t dname[LDNS_MAX_DOMAINLEN+1];
174         *len = sizeof(dname);
175         if(sldns_str2wire_dname_buf(str, dname, len) == 0) {
176                 uint8_t* r;
177                 if(*len > sizeof(dname)) return NULL;
178                 r = (uint8_t*)malloc(*len);
179                 if(r) return memcpy(r, dname, *len);
180         }
181         *len = 0;
182         return NULL;
183 }
184
185 /** read owner name */
186 static int
187 rrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len,
188         size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
189         size_t prev_len, char* token, size_t token_len)
190 {
191         /* split the rr in its parts -1 signals trouble */
192         if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
193                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
194                         sldns_buffer_position(strbuf));
195         }
196
197         if(token_len < 2) /* make sure there is space to read "@" or "" */
198                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
199                         sldns_buffer_position(strbuf));
200         if(token[0]=='@' && token[1]=='\0') {
201                 uint8_t* tocopy;
202                 if (origin) {
203                         *dname_len = origin_len;
204                         tocopy = origin;
205                 } else if (prev) {
206                         *dname_len = prev_len;
207                         tocopy = prev;
208                 } else {
209                         /* default to root */
210                         *dname_len = 1;
211                         tocopy = (uint8_t*)"\0";
212                 }
213                 if(*len < *dname_len)
214                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
215                                 sldns_buffer_position(strbuf));
216                 memmove(rr, tocopy, *dname_len);
217         } else if(*token == '\0') {
218                 /* no ownername was given, try prev, if that fails
219                  * origin, else default to root */
220                 uint8_t* tocopy;
221                 if(prev) {
222                         *dname_len = prev_len;
223                         tocopy = prev;
224                 } else if(origin) {
225                         *dname_len = origin_len;
226                         tocopy = origin;
227                 } else {
228                         *dname_len = 1;
229                         tocopy = (uint8_t*)"\0";
230                 }
231                 if(*len < *dname_len)
232                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
233                                 sldns_buffer_position(strbuf));
234                 memmove(rr, tocopy, *dname_len);
235         } else {
236                 size_t dlen = *len;
237                 int s = sldns_str2wire_dname_buf_origin(token, rr, &dlen,
238                         origin, origin_len);
239                 if(s) return RET_ERR_SHIFT(s,
240                         sldns_buffer_position(strbuf)-strlen(token));
241                 *dname_len = dlen;
242         }
243         return LDNS_WIREPARSE_ERR_OK;
244 }
245
246 /** read ttl */
247 static int
248 rrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len,
249         int* not_there, uint32_t* ttl, uint32_t default_ttl)
250 {
251         const char* endptr;
252         int overflow;
253         if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
254                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL,
255                         sldns_buffer_position(strbuf));
256         }
257         *ttl = (uint32_t) sldns_str2period(token, &endptr, &overflow);
258         if(overflow) {
259                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW,
260                         sldns_buffer_position(strbuf));
261         }
262
263         if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) {
264                 *not_there = 1;
265                 /* ah, it's not there or something */
266                 if (default_ttl == 0) {
267                         *ttl = LDNS_DEFAULT_TTL;
268                 } else {
269                         *ttl = default_ttl;
270                 }
271         }
272         return LDNS_WIREPARSE_ERR_OK;
273 }
274
275 /** read class */
276 static int
277 rrinternal_get_class(sldns_buffer* strbuf, char* token, size_t token_len,
278         int* not_there, uint16_t* cl)
279 {
280         /* if 'not_there' then we got token from previous parse routine */
281         if(!*not_there) {
282                 /* parse new token for class */
283                 if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
284                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_CLASS,
285                                 sldns_buffer_position(strbuf));
286                 }
287         } else *not_there = 0;
288         *cl = sldns_get_rr_class_by_name(token);
289         /* class can be left out too, assume IN, current token must be type */
290         if(*cl == 0 && strcmp(token, "CLASS0") != 0) {
291                 *not_there = 1;
292                 *cl = LDNS_RR_CLASS_IN;
293         }
294         return LDNS_WIREPARSE_ERR_OK;
295 }
296
297 /** read type */
298 static int
299 rrinternal_get_type(sldns_buffer* strbuf, char* token, size_t token_len,
300         int* not_there, uint16_t* tp)
301 {
302         /* if 'not_there' then we got token from previous parse routine */
303         if(!*not_there) {
304                 /* parse new token for type */
305                 if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
306                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
307                                 sldns_buffer_position(strbuf));
308                 }
309         }
310         *tp = sldns_get_rr_type_by_name(token);
311         if(*tp == 0 && strcmp(token, "TYPE0") != 0) {
312                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
313                         sldns_buffer_position(strbuf));
314         }
315         return LDNS_WIREPARSE_ERR_OK;
316 }
317
318 /** put type, class, ttl into rr buffer */
319 static int
320 rrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len,
321         size_t dname_len, uint16_t tp, uint16_t cl, uint32_t ttl, int question)
322 {
323         if(question) {
324                 /* question is : name, type, class */
325                 if(dname_len + 4 > len)
326                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
327                                 sldns_buffer_position(strbuf));
328                 sldns_write_uint16(rr+dname_len, tp);
329                 sldns_write_uint16(rr+dname_len+2, cl);
330                 return LDNS_WIREPARSE_ERR_OK;
331         }
332
333         /* type(2), class(2), ttl(4), rdatalen(2 (later)) = 10 */
334         if(dname_len + 10 > len)
335                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
336                         sldns_buffer_position(strbuf));
337         sldns_write_uint16(rr+dname_len, tp);
338         sldns_write_uint16(rr+dname_len+2, cl);
339         sldns_write_uint32(rr+dname_len+4, ttl);
340         sldns_write_uint16(rr+dname_len+8, 0); /* rdatalen placeholder */
341         return LDNS_WIREPARSE_ERR_OK;
342 }
343
344 /** find delimiters for type */
345 static const char*
346 rrinternal_get_delims(sldns_rdf_type rdftype, size_t r_cnt, size_t r_max)
347 {
348         switch(rdftype) {
349         case LDNS_RDF_TYPE_B64        :
350         case LDNS_RDF_TYPE_HEX        : /* These rdf types may con- */
351         case LDNS_RDF_TYPE_LOC        : /* tain whitespace, only if */
352         case LDNS_RDF_TYPE_WKS        : /* it is the last rd field. */
353         case LDNS_RDF_TYPE_IPSECKEY   :
354         case LDNS_RDF_TYPE_NSEC       : if (r_cnt == r_max - 1) {
355                                                 return "\n";
356                                         }
357                                         break;
358         default                       : break;
359         }
360         return "\n\t ";
361 }
362
363 /* Syntactic sugar for sldns_rr_new_frm_str_internal */
364 static int
365 sldns_rdf_type_maybe_quoted(sldns_rdf_type rdf_type)
366 {
367         return  rdf_type == LDNS_RDF_TYPE_STR ||
368                 rdf_type == LDNS_RDF_TYPE_LONG_STR;
369 }
370
371 /** see if rdata is quoted */
372 static int
373 rrinternal_get_quoted(sldns_buffer* strbuf, const char** delimiters,
374         sldns_rdf_type rdftype)
375 {
376         if(sldns_rdf_type_maybe_quoted(rdftype) &&
377                 sldns_buffer_remaining(strbuf) > 0) {
378
379                 /* skip spaces */
380                 while(sldns_buffer_remaining(strbuf) > 0 &&
381                         (*(sldns_buffer_current(strbuf)) == ' ' ||
382                         *(sldns_buffer_current(strbuf)) == '\t')) {
383                         sldns_buffer_skip(strbuf, 1);
384                 }
385
386                 if(sldns_buffer_remaining(strbuf) > 0 &&
387                         *(sldns_buffer_current(strbuf)) == '\"') {
388                         *delimiters = "\"\0";
389                         sldns_buffer_skip(strbuf, 1);
390                         return 1;
391                 }
392         }
393         return 0;
394 }
395
396 /** spool hex data into rdata */
397 static int
398 rrinternal_spool_hex(char* token, uint8_t* rr, size_t rr_len,
399         size_t rr_cur_len, size_t* cur_hex_data_size, size_t hex_data_size)
400 {
401         char* p = token;
402         while(*p) {
403                 if(isspace((unsigned char)*p)) {
404                         p++;
405                         continue;
406                 }
407                 if(!isxdigit((unsigned char)*p))
408                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
409                                 p-token);
410                 if(*cur_hex_data_size >= hex_data_size)
411                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
412                                 p-token);
413                 /* extra robust check */
414                 if(rr_cur_len+(*cur_hex_data_size)/2 >= rr_len)
415                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
416                                 p-token);
417                 /* see if 16s or 1s */
418                 if( ((*cur_hex_data_size)&1) == 0) {
419                         rr[rr_cur_len+(*cur_hex_data_size)/2] =
420                                 (uint8_t)sldns_hexdigit_to_int(*p)*16;
421                 } else {
422                         rr[rr_cur_len+(*cur_hex_data_size)/2] +=
423                                 (uint8_t)sldns_hexdigit_to_int(*p);
424                 }
425                 p++;
426                 (*cur_hex_data_size)++;
427         }
428         return LDNS_WIREPARSE_ERR_OK;
429 }
430
431 /** read unknown rr type format */
432 static int
433 rrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len,
434         uint8_t* rr, size_t* rr_len, size_t* rr_cur_len, size_t pre_data_pos)
435 {
436         const char* delim = "\n\t ";
437         size_t hex_data_size, cur_hex_data_size;
438         /* go back to before \#
439          * and skip it while setting delimiters better
440          */
441         sldns_buffer_set_position(strbuf, pre_data_pos);
442         if(sldns_bget_token(strbuf, token, delim, token_len) == -1)
443                 return LDNS_WIREPARSE_ERR_GENERAL; /* should not fail */
444         /* read rdata octet length */
445         if(sldns_bget_token(strbuf, token, delim, token_len) == -1) {
446                 /* something goes very wrong here */
447                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
448                         sldns_buffer_position(strbuf));
449         }
450         hex_data_size = (size_t)atoi(token);
451         if(hex_data_size > LDNS_MAX_RDFLEN ||
452                 *rr_cur_len + hex_data_size > *rr_len) {
453                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
454                         sldns_buffer_position(strbuf));
455         }
456         /* copy hex chars into hex str (2 chars per byte) */
457         hex_data_size *= 2;
458         cur_hex_data_size = 0;
459         while(cur_hex_data_size < hex_data_size) {
460                 int status;
461                 ssize_t c = sldns_bget_token(strbuf, token, delim, token_len);
462                 if((status = rrinternal_spool_hex(token, rr, *rr_len,
463                         *rr_cur_len, &cur_hex_data_size, hex_data_size)) != 0)
464                         return RET_ERR_SHIFT(status,
465                                 sldns_buffer_position(strbuf)-strlen(token));
466                 if(c == -1) {
467                         if(cur_hex_data_size != hex_data_size)
468                                 return RET_ERR(
469                                         LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
470                                         sldns_buffer_position(strbuf));
471                         break;
472                 }
473         }
474         *rr_cur_len += hex_data_size/2;
475         return LDNS_WIREPARSE_ERR_OK;
476 }
477
478 /** parse normal RR rdata element */
479 static int
480 rrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len,
481         uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype,
482         uint16_t rr_type, size_t r_cnt, size_t r_max, size_t dname_len,
483         uint8_t* origin, size_t origin_len)
484 {
485         size_t len;
486         int status;
487
488         switch(rdftype) {
489         case LDNS_RDF_TYPE_DNAME:
490                 /* check if the origin should be used or concatenated */
491                 if(strcmp(token, "@") == 0) {
492                         uint8_t* tocopy;
493                         size_t copylen;
494                         if(origin) {
495                                 copylen = origin_len;
496                                 tocopy = origin;
497                         } else if(rr_type == LDNS_RR_TYPE_SOA) {
498                                 copylen = dname_len;
499                                 tocopy = rr; /* copy rr owner name */
500                         } else {
501                                 copylen = 1;
502                                 tocopy = (uint8_t*)"\0";
503                         }
504                         if((*rr_cur_len) + copylen > rr_len)
505                                 return RET_ERR(
506                                         LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
507                                         sldns_buffer_position(strbuf));
508                         memmove(rr+*rr_cur_len, tocopy, copylen);
509                         (*rr_cur_len) += copylen;
510                 } else {
511                         size_t dlen = rr_len - (*rr_cur_len);
512                         int s = sldns_str2wire_dname_buf_origin(token,
513                                 rr+*rr_cur_len, &dlen, origin, origin_len);
514                         if(s) return RET_ERR_SHIFT(s,
515                                 sldns_buffer_position(strbuf)-strlen(token));
516                         (*rr_cur_len) += dlen;
517                 }
518                 return LDNS_WIREPARSE_ERR_OK;
519
520         case LDNS_RDF_TYPE_HEX:
521         case LDNS_RDF_TYPE_B64:
522                 /* When this is the last rdata field, then the
523                  * rest should be read in (cause then these
524                  * rdf types may contain spaces). */
525                 if(r_cnt == r_max - 1) {
526                         size_t tlen = strlen(token);
527                         (void)sldns_bget_token(strbuf, token+tlen, "\n",
528                                 token_len - tlen);
529                 }
530                 break;
531         default:
532                 break;
533         }
534
535         len = rr_len - (*rr_cur_len);
536         if((status=sldns_str2wire_rdf_buf(token, rr+(*rr_cur_len), &len,
537                 rdftype)) != 0)
538                 return RET_ERR_SHIFT(status,
539                         sldns_buffer_position(strbuf)-strlen(token));
540         *rr_cur_len += len;
541         return LDNS_WIREPARSE_ERR_OK;
542 }
543
544 /**
545  * Parse one rdf token.  Takes care of quotes and parenthesis.
546  */
547 static int
548 sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len,
549         int* quoted, int* parens, size_t* pre_data_pos,
550         const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
551 {
552         size_t slen;
553
554         /* skip spaces and tabs */
555         while(sldns_buffer_remaining(strbuf) > 0 && !*quoted &&
556                 (*(sldns_buffer_current(strbuf)) == ' ' ||
557                 *(sldns_buffer_current(strbuf)) == '\t')) {
558                 sldns_buffer_skip(strbuf, 1);
559         }
560
561         *pre_data_pos = sldns_buffer_position(strbuf);
562         if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters,
563                 token_len, parens, (*quoted)?NULL:" \t") == -1) {
564                 return 0;
565         }
566         slen = strlen(token);
567         /* check if not quoted yet, and we have encountered quotes */
568         if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
569                 slen >= 2 &&
570                 (token[0] == '"' || token[0] == '\'') &&
571                 (token[slen-1] == '"' || token[slen-1] == '\'')) {
572                 /* move token two smaller (quotes) with endnull */
573                 memmove(token, token+1, slen-2);
574                 token[slen-2] = 0;
575                 slen -= 2;
576                 *quoted = 1;
577         } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
578                 slen >= 2 &&
579                 (token[0] == '"' || token[0] == '\'')) {
580                 /* got the start quote (remove it) but read remainder
581                  * of quoted string as well into remainder of token */
582                 memmove(token, token+1, slen-1);
583                 token[slen-1] = 0;
584                 slen -= 1;
585                 *quoted = 1;
586                 /* rewind buffer over skipped whitespace */
587                 while(sldns_buffer_position(strbuf) > 0 &&
588                         (sldns_buffer_current(strbuf)[-1] == ' ' ||
589                         sldns_buffer_current(strbuf)[-1] == '\t')) {
590                         sldns_buffer_skip(strbuf, -1);
591                 }
592                 if(sldns_bget_token_par(strbuf, token+slen,
593                         "\"", token_len-slen,
594                         parens, NULL) == -1) {
595                         return 0;
596                 }
597                 slen = strlen(token);
598         }
599         *token_strlen = slen;
600         return 1;
601 }
602
603 /** Add space and one more rdf token onto the existing token string. */
604 static int
605 sldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len,
606         int* quoted, int* parens, size_t* pre_data_pos,
607         const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
608 {
609         size_t addlen = *token_len - *token_strlen;
610         size_t addstrlen = 0;
611
612         /* add space */
613         /* when addlen < 2, the token buffer is full considering the NULL byte
614          * from strlen and will lead to buffer overflow with the second
615          * assignment below. */
616         if(addlen < 2) return 0;
617         token[*token_strlen] = ' ';
618         token[++(*token_strlen)] = 0;
619
620         /* read another token */
621         addlen = *token_len - *token_strlen;
622         if(!sldns_parse_rdf_token(strbuf, token+*token_strlen, addlen, quoted,
623                 parens, pre_data_pos, delimiters, rdftype, &addstrlen))
624                 return 0;
625         (*token_strlen) += addstrlen;
626         return 1;
627 }
628
629 static int sldns_str2wire_svcparam_key_cmp(const void *a, const void *b)
630 {
631         return sldns_read_uint16(*(uint8_t**) a)
632              - sldns_read_uint16(*(uint8_t**) b);
633 }
634
635 /**
636  * Add constraints to the SVCB RRs which involve the whole set
637  */
638 static int sldns_str2wire_check_svcbparams(uint8_t* rdata, uint16_t rdata_len)
639 {
640         size_t   nparams = 0, i;
641         uint8_t  new_rdata[LDNS_MAX_RDFLEN];
642         uint8_t* new_rdata_ptr = new_rdata;
643         uint8_t* svcparams[MAX_NUMBER_OF_SVCPARAMS];
644         uint8_t* rdata_ptr = rdata;
645         uint16_t rdata_remaining = rdata_len;
646
647         /* find the SvcParams */
648         while (rdata_remaining) {
649                 uint16_t svcbparam_len;
650
651                 svcparams[nparams] = rdata_ptr;
652                 if (rdata_remaining < 4)
653                         return LDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA;
654                 svcbparam_len = sldns_read_uint16(rdata_ptr + 2);
655                 rdata_remaining -= 4;
656                 rdata_ptr += 4;
657
658                 if (rdata_remaining < svcbparam_len)
659                         return LDNS_WIREPARSE_ERR_SVCPARAM_BROKEN_RDATA;
660                 rdata_remaining -= svcbparam_len;
661                 rdata_ptr += svcbparam_len;
662
663                 nparams += 1;
664                 if (nparams >= MAX_NUMBER_OF_SVCPARAMS)
665                         return LDNS_WIREPARSE_ERR_SVCB_TOO_MANY_PARAMS;
666         }
667
668         /* In draft-ietf-dnsop-svcb-https-06 Section 7:
669          *
670          *     In wire format, the keys are represented by their numeric
671          *     values in network byte order, concatenated in ascending order.
672          */
673         qsort((void *)svcparams
674              ,nparams
675              ,sizeof(uint8_t*)
676              ,sldns_str2wire_svcparam_key_cmp);
677
678
679         /* The code below revolves around semantic errors in the SVCParam set.
680          * So long as we do not distinguish between running Unbound as a primary
681          * or as a secondary, we default to secondary behavior and we ignore the
682          * semantic errors. */
683
684 #ifdef SVCB_SEMANTIC_ERRORS
685         {
686                 uint8_t* mandatory = NULL;
687                 /* In draft-ietf-dnsop-svcb-https-06 Section 7:
688                  *
689                  *     Keys (...) MUST NOT appear more than once.
690                  *
691                  * If they key has already been seen, we have a duplicate
692                  */
693                 for(i=0; i < nparams; i++) {
694                         uint16_t key = sldns_read_uint16(svcparams[i]);
695                         if(i + 1 < nparams && key == sldns_read_uint16(svcparams[i+1]))
696                                 return LDNS_WIREPARSE_ERR_SVCB_DUPLICATE_KEYS;
697                         if(key == SVCB_KEY_MANDATORY)
698                                 mandatory = svcparams[i];
699                 }
700
701                 /* Verify that all the SvcParamKeys in mandatory are present */
702                 if(mandatory) {
703                         /* Divide by sizeof(uint16_t)*/
704                         uint16_t mandatory_nkeys = sldns_read_uint16(mandatory + 2) / sizeof(uint16_t);
705
706                         /* Guaranteed by sldns_str2wire_svcparam_key_value */
707                         assert(mandatory_nkeys > 0);
708
709                         for(i=0; i < mandatory_nkeys; i++) {
710                                 uint16_t mandatory_key = sldns_read_uint16(
711                                         mandatory
712                                         + 2 * sizeof(uint16_t)
713                                         + i * sizeof(uint16_t));
714                                 uint8_t found = 0;
715                                 size_t j;
716
717                                 for(j=0; j < nparams; j++) {
718                                         if(mandatory_key == sldns_read_uint16(svcparams[j])) {
719                                                 found = 1;
720                                                 break;
721                                         }
722                                 }
723
724                                 if(!found)
725                                         return LDNS_WIREPARSE_ERR_SVCB_MANDATORY_MISSING_PARAM;
726                         }
727                 }
728         }
729 #endif
730         /* Write rdata in correct order */
731         for (i = 0; i < nparams; i++) {
732                 uint16_t svcparam_len = sldns_read_uint16(svcparams[i] + 2)
733                                       + 2 * sizeof(uint16_t);
734
735                 if ((unsigned)(new_rdata_ptr - new_rdata) + svcparam_len > sizeof(new_rdata))
736                         return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
737
738                 memcpy(new_rdata_ptr, svcparams[i], svcparam_len);
739                 new_rdata_ptr += svcparam_len;
740         }
741         memcpy(rdata, new_rdata, rdata_len);
742         return LDNS_WIREPARSE_ERR_OK;
743 }
744
745 /** parse rdata from string into rr buffer(-remainder after dname). */
746 static int
747 rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
748         uint8_t* rr, size_t* rr_len, size_t dname_len, uint16_t rr_type,
749         uint8_t* origin, size_t origin_len)
750 {
751         const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type);
752         size_t r_cnt, r_min, r_max;
753         size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen;
754         int was_unknown_rr_format = 0, parens = 0, status, quoted;
755         const char* delimiters;
756         sldns_rdf_type rdftype;
757         /* a desc is always returned */
758         if(!desc) return LDNS_WIREPARSE_ERR_GENERAL;
759         r_max = sldns_rr_descriptor_maximum(desc);
760         r_min = sldns_rr_descriptor_minimum(desc);
761         /* robust check */
762         if(rr_cur_len > *rr_len)
763                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
764                         sldns_buffer_position(strbuf));
765
766         /* because number of fields can be variable, we can't rely on
767          * _maximum() only */
768         for(r_cnt=0; r_cnt < r_max; r_cnt++) {
769                 rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
770                 delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max);
771                 quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype);
772
773                 if(!sldns_parse_rdf_token(strbuf, token, token_len, &quoted,
774                         &parens, &pre_data_pos, delimiters, rdftype,
775                         &token_strlen))
776                         break;
777
778                 /* rfc3597 specifies that any type can be represented
779                  * with \# method, which can contain spaces...
780                  * it does specify size though... */
781
782                 /* unknown RR data */
783                 if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 &&
784                         !quoted && (token_strlen == 2 || token[2]==' ' ||
785                         token[2]=='\t')) {
786                         was_unknown_rr_format = 1;
787                         if((status=rrinternal_parse_unknown(strbuf, token,
788                                 token_len, rr, rr_len, &rr_cur_len,
789                                 pre_data_pos)) != 0)
790                                 return status;
791                 } else if(token_strlen > 0 || quoted) {
792                         if(rdftype == LDNS_RDF_TYPE_HIP) {
793                                 /* affix the HIT and PK fields, with a space */
794                                 if(!sldns_affix_token(strbuf, token,
795                                         &token_len, &quoted, &parens,
796                                         &pre_data_pos, delimiters,
797                                         rdftype, &token_strlen))
798                                         break;
799                                 if(!sldns_affix_token(strbuf, token,
800                                         &token_len, &quoted, &parens,
801                                         &pre_data_pos, delimiters,
802                                         rdftype, &token_strlen))
803                                         break;
804                         } else if(rdftype == LDNS_RDF_TYPE_INT16_DATA &&
805                                 strcmp(token, "0")!=0) {
806                                 /* affix len and b64 fields */
807                                 if(!sldns_affix_token(strbuf, token,
808                                         &token_len, &quoted, &parens,
809                                         &pre_data_pos, delimiters,
810                                         rdftype, &token_strlen))
811                                         break;
812                         }
813
814                         /* normal RR */
815                         if((status=rrinternal_parse_rdf(strbuf, token,
816                                 token_len, rr, *rr_len, &rr_cur_len, rdftype,
817                                 rr_type, r_cnt, r_max, dname_len, origin,
818                                 origin_len)) != 0) {
819                                 return status;
820                         }
821                 }
822         }
823         if(!was_unknown_rr_format && r_cnt+1 < r_min) {
824                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE,
825                         sldns_buffer_position(strbuf));
826         }
827         while(parens != 0) {
828                 /* read remainder, must be "" */
829                 if(sldns_bget_token_par(strbuf, token, "\n", token_len,
830                         &parens, " \t") == -1) {
831                         if(parens != 0)
832                                 return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
833                                         sldns_buffer_position(strbuf));
834                         break;
835                 }
836                 if(strcmp(token, "") != 0)
837                         return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
838                                 sldns_buffer_position(strbuf));
839         }
840         /* write rdata length */
841         sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10));
842         *rr_len = rr_cur_len;
843         /* SVCB/HTTPS handling  */
844         if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) {
845                 size_t rdata_len = rr_cur_len - dname_len - 10;
846                 uint8_t *rdata = rr+dname_len + 10;
847
848                 /* skip 1st rdata field SvcPriority (uint16_t) */
849                 if (rdata_len < sizeof(uint16_t))
850                         return LDNS_WIREPARSE_ERR_OK;
851
852                 rdata_len -= sizeof(uint16_t);
853                 rdata += sizeof(uint16_t);
854
855                 /* skip 2nd rdata field dname */
856                 while (rdata_len && *rdata != 0) {
857                         uint8_t label_len;
858
859                         if (*rdata & 0xC0)
860                                 return LDNS_WIREPARSE_ERR_OK;
861
862                         label_len = *rdata + 1;
863                         if (rdata_len < label_len)
864                                 return LDNS_WIREPARSE_ERR_OK;
865
866                         rdata_len -= label_len;
867                         rdata += label_len;
868                 }
869                 /* The root label is one more character, so smaller
870                  * than 1 + 1 means no Svcparam Keys */
871                 if (rdata_len < 2 || *rdata != 0)
872                         return LDNS_WIREPARSE_ERR_OK;
873
874                 rdata_len -= 1;
875                 rdata += 1;
876                 return sldns_str2wire_check_svcbparams(rdata, rdata_len);
877
878         }
879         return LDNS_WIREPARSE_ERR_OK;
880 }
881
882 /*
883  * trailing spaces are allowed
884  * leading spaces are not allowed
885  * allow ttl to be optional
886  * class is optional too
887  * if ttl is missing, and default_ttl is 0, use DEF_TTL
888  * allow ttl to be written as 1d3h
889  * So the RR should look like. e.g.
890  * miek.nl. 3600 IN MX 10 elektron.atoom.net
891  * or
892  * miek.nl. 1h IN MX 10 elektron.atoom.net
893  * or
894  * miek.nl. IN MX 10 elektron.atoom.net
895  */
896 static int
897 sldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len,
898         size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
899         size_t origin_len, uint8_t* prev, size_t prev_len, int question)
900 {
901         int status;
902         int not_there = 0;
903         char token[LDNS_MAX_RDFLEN+1];
904         uint32_t ttl = 0;
905         uint16_t tp = 0, cl = 0;
906         size_t ddlen = 0;
907
908         /* string in buffer */
909         sldns_buffer strbuf;
910         sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
911         if(!dname_len) dname_len = &ddlen;
912
913         /* parse the owner */
914         if((status=rrinternal_get_owner(&strbuf, rr, len, dname_len, origin,
915                 origin_len, prev, prev_len, token, sizeof(token))) != 0)
916                 return status;
917
918         /* parse the [ttl] [class] <type> */
919         if((status=rrinternal_get_ttl(&strbuf, token, sizeof(token),
920                 &not_there, &ttl, default_ttl)) != 0)
921                 return status;
922         if((status=rrinternal_get_class(&strbuf, token, sizeof(token),
923                 &not_there, &cl)) != 0)
924                 return status;
925         if((status=rrinternal_get_type(&strbuf, token, sizeof(token),
926                 &not_there, &tp)) != 0)
927                 return status;
928         /* put ttl, class, type into the rr result */
929         if((status=rrinternal_write_typeclassttl(&strbuf, rr, *len, *dname_len, tp, cl,
930                 ttl, question)) != 0)
931                 return status;
932         /* for a question-RR we are done, no rdata */
933         if(question) {
934                 *len = *dname_len + 4;
935                 return LDNS_WIREPARSE_ERR_OK;
936         }
937
938         /* rdata */
939         if((status=rrinternal_parse_rdata(&strbuf, token, sizeof(token),
940                 rr, len, *dname_len, tp, origin, origin_len)) != 0)
941                 return status;
942
943         return LDNS_WIREPARSE_ERR_OK;
944 }
945
946 int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
947         size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
948         size_t origin_len, uint8_t* prev, size_t prev_len)
949 {
950         return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
951                 default_ttl, origin, origin_len, prev, prev_len, 0);
952 }
953
954 int sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len,
955         size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
956         size_t prev_len)
957 {
958         return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
959                 0, origin, origin_len, prev, prev_len, 1);
960 }
961
962 uint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len)
963 {
964         if(len < dname_len+2)
965                 return 0;
966         return sldns_read_uint16(rr+dname_len);
967 }
968
969 uint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len)
970 {
971         if(len < dname_len+4)
972                 return 0;
973         return sldns_read_uint16(rr+dname_len+2);
974 }
975
976 uint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len)
977 {
978         if(len < dname_len+8)
979                 return 0;
980         return sldns_read_uint32(rr+dname_len+4);
981 }
982
983 uint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len)
984 {
985         if(len < dname_len+10)
986                 return 0;
987         return sldns_read_uint16(rr+dname_len+8);
988 }
989
990 uint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len)
991 {
992         if(len < dname_len+10)
993                 return NULL;
994         return rr+dname_len+10;
995 }
996
997 uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len)
998 {
999         if(len < dname_len+10)
1000                 return NULL;
1001         return rr+dname_len+8;
1002 }
1003
1004 const char* sldns_get_errorstr_parse(int e)
1005 {
1006         sldns_lookup_table *lt;
1007         lt = sldns_lookup_by_id(sldns_wireparse_errors, LDNS_WIREPARSE_ERROR(e));
1008         return lt?lt->name:"unknown error";
1009 }
1010
1011 /* Strip whitespace from the start and the end of <line>.  */
1012 char *
1013 sldns_strip_ws(char *line)
1014 {
1015         char *s = line, *e;
1016
1017         for (s = line; *s && isspace((unsigned char)*s); s++)
1018                 ;
1019         for (e = strchr(s, 0); e > s+2 && isspace((unsigned char)e[-1]) && e[-2] != '\\'; e--)
1020                 ;
1021         *e = 0;
1022         return s;
1023 }
1024
1025 int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
1026         struct sldns_file_parse_state* parse_state)
1027 {
1028         char line[LDNS_RR_BUF_SIZE+1];
1029         ssize_t size;
1030
1031         /* read an entire line in from the file */
1032         if((size = sldns_fget_token_l(in, line, LDNS_PARSE_SKIP_SPACE,
1033                 LDNS_RR_BUF_SIZE, parse_state?&parse_state->lineno:NULL))
1034                 == -1) {
1035                 /* if last line was empty, we are now at feof, which is not
1036                  * always a parse error (happens when for instance last line
1037                  * was a comment)
1038                  */
1039                 return LDNS_WIREPARSE_ERR_SYNTAX;
1040         }
1041
1042         /* we can have the situation, where we've read ok, but still got
1043          * no bytes to play with, in this case size is 0 */
1044         if(size == 0) {
1045                 if(*len > 0)
1046                         rr[0] = 0;
1047                 *len = 0;
1048                 *dname_len = 0;
1049                 return LDNS_WIREPARSE_ERR_OK;
1050         }
1051
1052         if(strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) {
1053                 int s;
1054                 strlcpy((char*)rr, line, *len);
1055                 *len = 0;
1056                 *dname_len = 0;
1057                 if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
1058                 parse_state->origin_len = sizeof(parse_state->origin);
1059                 s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8),
1060                         parse_state->origin, &parse_state->origin_len);
1061                 if(s) parse_state->origin_len = 0;
1062                 return s;
1063         } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) {
1064                 const char* end = NULL;
1065                 int overflow = 0;
1066                 strlcpy((char*)rr, line, *len);
1067                 *len = 0;
1068                 *dname_len = 0;
1069                 if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
1070                 parse_state->default_ttl = sldns_str2period(
1071                         sldns_strip_ws(line+5), &end, &overflow);
1072                 if(overflow)
1073                         return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW;
1074         } else if (strncmp(line, "$INCLUDE", 8) == 0) {
1075                 strlcpy((char*)rr, line, *len);
1076                 *len = 0;
1077                 *dname_len = 0;
1078                 return LDNS_WIREPARSE_ERR_INCLUDE;
1079         } else if (strncmp(line, "$", 1) == 0) {
1080                 strlcpy((char*)rr, line, *len);
1081                 *len = 0;
1082                 *dname_len = 0;
1083                 return LDNS_WIREPARSE_ERR_INCLUDE;
1084         } else {
1085                 int r = sldns_str2wire_rr_buf(line, rr, len, dname_len,
1086                         parse_state?parse_state->default_ttl:0,
1087                         (parse_state&&parse_state->origin_len)?
1088                                 parse_state->origin:NULL,
1089                         parse_state?parse_state->origin_len:0,
1090                         (parse_state&&parse_state->prev_rr_len)?
1091                                 parse_state->prev_rr:NULL,
1092                         parse_state?parse_state->prev_rr_len:0);
1093                 if(r == LDNS_WIREPARSE_ERR_OK && (*dname_len) != 0 &&
1094                         parse_state &&
1095                         (*dname_len) <= sizeof(parse_state->prev_rr)) {
1096                         memmove(parse_state->prev_rr, rr, *dname_len);
1097                         parse_state->prev_rr_len = (*dname_len);
1098                 }
1099                 if(r == LDNS_WIREPARSE_ERR_OK && parse_state) {
1100                         parse_state->default_ttl = sldns_wirerr_get_ttl(
1101                                 rr, *len, *dname_len);
1102                 }
1103                 return r;
1104         }
1105         return LDNS_WIREPARSE_ERR_OK;
1106 }
1107
1108 static int
1109 sldns_str2wire_svcparam_key_lookup(const char *key, size_t key_len)
1110 {
1111         char buf[64];
1112         char *endptr;
1113         unsigned long int key_value;
1114
1115         if (key_len >= 4  && key_len <= 8 && !strncmp(key, "key", 3)) {
1116                 memcpy(buf, key + 3, key_len - 3);
1117                 buf[key_len - 3] = 0;
1118                 key_value = strtoul(buf, &endptr, 10);
1119
1120                 if (endptr > buf        /* digits seen */
1121                 && *endptr == 0         /* no non-digit chars after digits */
1122                 &&  key_value <= 65535) /* no overflow */
1123                         return key_value;
1124
1125         } else switch (key_len) {
1126         case 3:
1127                 if (!strncmp(key, "ech", key_len))
1128                         return SVCB_KEY_ECH;
1129                 break;
1130
1131         case 4:
1132                 if (!strncmp(key, "alpn", key_len))
1133                         return SVCB_KEY_ALPN;
1134                 if (!strncmp(key, "port", key_len))
1135                         return SVCB_KEY_PORT;
1136                 break;
1137
1138         case 7:
1139                 if (!strncmp(key, "dohpath", key_len))
1140                         return SVCB_KEY_DOHPATH;
1141                 break;
1142
1143         case 8:
1144                 if (!strncmp(key, "ipv4hint", key_len))
1145                         return SVCB_KEY_IPV4HINT;
1146                 if (!strncmp(key, "ipv6hint", key_len))
1147                         return SVCB_KEY_IPV6HINT;
1148                 break;
1149
1150         case 9:
1151                 if (!strncmp(key, "mandatory", key_len))
1152                         return SVCB_KEY_MANDATORY;
1153                 if (!strncmp(key, "echconfig", key_len))
1154                         return SVCB_KEY_ECH; /* allow "echconfig" as well as "ech" */
1155                 break;
1156
1157         case 15:
1158                 if (!strncmp(key, "no-default-alpn", key_len))
1159                         return SVCB_KEY_NO_DEFAULT_ALPN;
1160                 break;
1161
1162         default:
1163                 break;
1164         }
1165
1166         /* Although the returned value might be used by the caller,
1167          * the parser has erred, so the zone will not be loaded.
1168          */
1169         return -1;
1170 }
1171
1172 static int
1173 sldns_str2wire_svcparam_port(const char* val, uint8_t* rd, size_t* rd_len)
1174 {
1175         unsigned long int port;
1176         char *endptr;
1177
1178         if (*rd_len < 6)
1179                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1180
1181         port = strtoul(val, &endptr, 10);
1182
1183         if (endptr > val        /* digits seen */
1184         && *endptr == 0         /* no non-digit chars after digits */
1185         &&  port <= 65535) {    /* no overflow */
1186
1187                 sldns_write_uint16(rd, SVCB_KEY_PORT);
1188                 sldns_write_uint16(rd + 2, sizeof(uint16_t));
1189                 sldns_write_uint16(rd + 4, port);
1190                 *rd_len = 6;
1191
1192                 return LDNS_WIREPARSE_ERR_OK;
1193         }
1194
1195         return LDNS_WIREPARSE_ERR_SVCB_PORT_VALUE_SYNTAX;
1196 }
1197
1198 static int
1199 sldns_str2wire_svcbparam_ipv4hint(const char* val, uint8_t* rd, size_t* rd_len)
1200 {
1201         size_t count;
1202         char ip_str[INET_ADDRSTRLEN+1];
1203         char *next_ip_str;
1204         size_t i;
1205
1206         for (i = 0, count = 1; val[i]; i++) {
1207                 if (val[i] == ',')
1208                         count += 1;
1209                 if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
1210                         return LDNS_WIREPARSE_ERR_SVCB_IPV4_TOO_MANY_ADDRESSES;
1211                 }
1212         }
1213
1214         if (*rd_len < (LDNS_IP4ADDRLEN * count) + 4)
1215                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1216
1217         /* count is number of comma's in val + 1; so the actual number of IPv4
1218          * addresses in val
1219          */
1220         sldns_write_uint16(rd, SVCB_KEY_IPV4HINT);
1221         sldns_write_uint16(rd + 2, LDNS_IP4ADDRLEN * count);
1222         *rd_len = 4;
1223
1224         while (count) {
1225                 if (!(next_ip_str = strchr(val, ','))) {
1226                         if (inet_pton(AF_INET, val, rd + *rd_len) != 1)
1227                                 break;
1228                         *rd_len += LDNS_IP4ADDRLEN;
1229
1230                         assert(count == 1);
1231
1232                 } else if (next_ip_str - val >= (int)sizeof(ip_str))
1233                         break;
1234
1235                 else {
1236                         memcpy(ip_str, val, next_ip_str - val);
1237                         ip_str[next_ip_str - val] = 0;
1238                         if (inet_pton(AF_INET, ip_str, rd + *rd_len) != 1) {
1239                                 break;
1240                         }
1241                         *rd_len += LDNS_IP4ADDRLEN;
1242
1243                         val = next_ip_str + 1;
1244                 }
1245                 count--;
1246         }
1247         if (count) /* verify that we parsed all values */
1248                 return LDNS_WIREPARSE_ERR_SYNTAX_IP4;
1249
1250         return LDNS_WIREPARSE_ERR_OK;
1251 }
1252
1253 static int
1254 sldns_str2wire_svcbparam_ipv6hint(const char* val, uint8_t* rd, size_t* rd_len)
1255 {
1256         size_t count;
1257         char ip_str[INET6_ADDRSTRLEN+1];
1258         char *next_ip_str;
1259         size_t i;
1260
1261         for (i = 0, count = 1; val[i]; i++) {
1262                 if (val[i] == ',')
1263                         count += 1;
1264                 if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
1265                         return LDNS_WIREPARSE_ERR_SVCB_IPV6_TOO_MANY_ADDRESSES;
1266                 }
1267         }
1268
1269         if (*rd_len < (LDNS_IP6ADDRLEN * count) + 4)
1270                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1271
1272         /* count is number of comma's in val + 1; so the actual number of IPv6
1273          * addresses in val
1274          */
1275         sldns_write_uint16(rd, SVCB_KEY_IPV6HINT);
1276         sldns_write_uint16(rd + 2, LDNS_IP6ADDRLEN * count);
1277         *rd_len = 4;
1278
1279         while (count) {
1280                 if (!(next_ip_str = strchr(val, ','))) {
1281                         if (inet_pton(AF_INET6, val, rd + *rd_len) != 1)
1282                                 break;
1283                         *rd_len += LDNS_IP6ADDRLEN;
1284
1285                         assert(count == 1);
1286
1287                 } else if (next_ip_str - val >= (int)sizeof(ip_str))
1288                         break;
1289
1290                 else {
1291                         memcpy(ip_str, val, next_ip_str - val);
1292                         ip_str[next_ip_str - val] = 0;
1293                         if (inet_pton(AF_INET6, ip_str, rd + *rd_len) != 1) {
1294                                 break;
1295                         }
1296                         *rd_len += LDNS_IP6ADDRLEN;
1297
1298                         val = next_ip_str + 1;
1299                 }
1300                 count--;
1301         }
1302         if (count) /* verify that we parsed all values */
1303                 return LDNS_WIREPARSE_ERR_SYNTAX_IP6;
1304
1305         return LDNS_WIREPARSE_ERR_OK;
1306 }
1307
1308 /* compare function used for sorting uint16_t's */
1309 static int
1310 sldns_network_uint16_cmp(const void *a, const void *b)
1311 {
1312         return ((int)sldns_read_uint16(a)) - ((int)sldns_read_uint16(b));
1313 }
1314
1315 static int
1316 sldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len)
1317 {
1318         size_t i, count, val_len;
1319         char* next_key;
1320
1321         val_len = strlen(val);
1322
1323         for (i = 0, count = 1; val[i]; i++) {
1324                 if (val[i] == ',')
1325                         count += 1;
1326                 if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
1327                         return LDNS_WIREPARSE_ERR_SVCB_MANDATORY_TOO_MANY_KEYS;
1328                 }
1329         }
1330         if (sizeof(uint16_t) * (count + 2) > *rd_len)
1331                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1332
1333         sldns_write_uint16(rd, SVCB_KEY_MANDATORY);
1334         sldns_write_uint16(rd + 2, sizeof(uint16_t) * count);
1335         *rd_len = 4;
1336
1337         while (1) {
1338                 int svcparamkey;
1339
1340                 if (!(next_key = strchr(val, ','))) {
1341                         svcparamkey = sldns_str2wire_svcparam_key_lookup(val, val_len);
1342
1343                         if (svcparamkey < 0) {
1344                                 return LDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
1345                         }
1346
1347                         sldns_write_uint16(rd + *rd_len, svcparamkey);
1348                         *rd_len += 2;
1349                         break;
1350                 } else {
1351                         svcparamkey = sldns_str2wire_svcparam_key_lookup(val, next_key - val);
1352
1353                         if (svcparamkey < 0) {
1354                                 return LDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
1355                         }
1356
1357                         sldns_write_uint16(rd + *rd_len,
1358                                 svcparamkey);
1359                         *rd_len += 2;
1360                 }
1361
1362                 val_len -= next_key - val + 1;
1363                 val = next_key + 1; /* skip the comma */
1364         }
1365
1366         /* In draft-ietf-dnsop-svcb-https-06 Section 7:
1367          *
1368          *    "In wire format, the keys are represented by their numeric
1369          *     values in network byte order, concatenated in ascending order."
1370          */
1371         qsort((void *)(rd + 4), count, sizeof(uint16_t), sldns_network_uint16_cmp);
1372
1373         /* The code below revolves around semantic errors in the SVCParam set.
1374          * So long as we do not distinguish between running Unbound as a primary
1375          * or as a secondary, we default to secondary behavior and we ignore the
1376          * semantic errors. */
1377 #ifdef SVCB_SEMANTIC_ERRORS
1378         /* In draft-ietf-dnsop-svcb-https-06 Section 8
1379          * automatically mandatory MUST NOT appear in its own value-list
1380          */
1381         if (sldns_read_uint16(rd + 4) == SVCB_KEY_MANDATORY)
1382                 return LDNS_WIREPARSE_ERR_SVCB_MANDATORY_IN_MANDATORY;
1383
1384         /* Guarantee key uniqueness. After the sort we only need to
1385          * compare neighbouring keys */
1386         if (count > 1) {
1387                 for (i = 0; i < count - 1; i++) {
1388                         uint8_t* current_pos = (rd + 4 + (sizeof(uint16_t) * i));
1389                         uint16_t key = sldns_read_uint16(current_pos);
1390
1391                         if (key == sldns_read_uint16(current_pos + 2)) {
1392                                 return LDNS_WIREPARSE_ERR_SVCB_MANDATORY_DUPLICATE_KEY;
1393                         }
1394                 }
1395         }
1396 #endif
1397         return LDNS_WIREPARSE_ERR_OK;
1398 }
1399
1400 static int
1401 sldns_str2wire_svcbparam_ech_value(const char* val, uint8_t* rd, size_t* rd_len)
1402 {
1403         uint8_t buffer[LDNS_MAX_RDFLEN];
1404         int wire_len;
1405
1406         /* single 0 represents empty buffer */
1407         if(strcmp(val, "0") == 0) {
1408                 if (*rd_len < 4)
1409                         return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1410                 sldns_write_uint16(rd, SVCB_KEY_ECH);
1411                 sldns_write_uint16(rd + 2, 0);
1412
1413                 return LDNS_WIREPARSE_ERR_OK;
1414         }
1415
1416         wire_len = sldns_b64_pton(val, buffer, LDNS_MAX_RDFLEN);
1417
1418         if (wire_len <= 0) {
1419                 return LDNS_WIREPARSE_ERR_SYNTAX_B64;
1420         } else if ((unsigned)wire_len + 4 > *rd_len) {
1421                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1422         } else {
1423                 sldns_write_uint16(rd, SVCB_KEY_ECH);
1424                 sldns_write_uint16(rd + 2, wire_len);
1425                 memcpy(rd + 4, buffer, wire_len);
1426                 *rd_len = 4 + wire_len;
1427
1428                 return LDNS_WIREPARSE_ERR_OK;
1429         }
1430 }
1431
1432 static const char*
1433 sldns_str2wire_svcbparam_parse_next_unescaped_comma(const char *val)
1434 {
1435         while (*val) {
1436                 /* Only return when the comma is not escaped*/
1437                 if (*val == '\\'){
1438                         ++val;
1439                         if (!*val)
1440                                 break;
1441                 } else if (*val == ',')
1442                                 return val;
1443
1444                 val++;
1445         }
1446         return NULL;
1447 }
1448
1449 /* The source is already properly unescaped, this double unescaping is purely to allow for
1450  * comma's in comma separated alpn lists.
1451  * 
1452  * In draft-ietf-dnsop-svcb-https-06 Section 7:
1453  * To enable simpler parsing, this SvcParamValue MUST NOT contain escape sequences.
1454  */
1455 static size_t
1456 sldns_str2wire_svcbparam_parse_copy_unescaped(uint8_t *dst,
1457         const char *src, size_t len)
1458 {
1459         uint8_t *orig_dst = dst;
1460
1461         while (len) {
1462                 if (*src == '\\') {
1463                         src++;
1464                         len--;
1465                         if (!len)
1466                                 break;
1467                 }
1468                 *dst++ = *src++;
1469                 len--;
1470         }
1471         return (size_t)(dst - orig_dst);
1472 }
1473
1474 static int
1475 sldns_str2wire_svcbparam_alpn_value(const char* val,
1476         uint8_t* rd, size_t* rd_len)
1477 {
1478         uint8_t     unescaped_dst[LDNS_MAX_RDFLEN];
1479         uint8_t    *dst = unescaped_dst;
1480         const char *next_str;
1481         size_t      str_len;
1482         size_t      dst_len;
1483         size_t      val_len;
1484
1485         val_len = strlen(val);
1486
1487         if (val_len > sizeof(unescaped_dst)) {
1488                 return LDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE;
1489         }
1490         while (val_len) {
1491                 size_t key_len;
1492
1493                 str_len = (next_str = sldns_str2wire_svcbparam_parse_next_unescaped_comma(val))
1494                         ? (size_t)(next_str - val) : val_len;
1495
1496                 if (str_len > 255) {
1497                         return LDNS_WIREPARSE_ERR_SVCB_ALPN_KEY_TOO_LARGE;
1498                 }
1499
1500                 key_len = sldns_str2wire_svcbparam_parse_copy_unescaped(dst + 1, val, str_len);
1501                 *dst++ = key_len;
1502                  dst  += key_len;
1503
1504                 if (!next_str)
1505                         break;
1506
1507                 /* skip the comma in the next iteration */
1508                 val_len -= next_str - val + 1;
1509                 val = next_str + 1;
1510         }
1511         dst_len = dst - unescaped_dst;
1512         if (*rd_len < 4 + dst_len)
1513                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1514         sldns_write_uint16(rd, SVCB_KEY_ALPN);
1515         sldns_write_uint16(rd + 2, dst_len);
1516         memcpy(rd + 4, unescaped_dst, dst_len);
1517         *rd_len = 4 + dst_len;
1518
1519         return LDNS_WIREPARSE_ERR_OK;
1520 }
1521
1522 static int
1523 sldns_str2wire_svcbparam_dohpath_value(const char* val,
1524         uint8_t* rd, size_t* rd_len)
1525 {
1526         size_t val_len;
1527
1528         /* RFC6570#section-2.1
1529          * "The characters outside of expressions in a URI Template string are
1530          * intended to be copied literally"
1531          * Practically this means we do not have to look for "double escapes"
1532          * like in the alpn value list.
1533          */
1534
1535         val_len = strlen(val);
1536
1537         if (*rd_len < 4 + val_len) {
1538                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1539         }
1540
1541         sldns_write_uint16(rd, SVCB_KEY_DOHPATH);
1542         sldns_write_uint16(rd + 2, val_len);
1543         memcpy(rd + 4, val, val_len);
1544         *rd_len = 4 + val_len;
1545
1546         return LDNS_WIREPARSE_ERR_OK;
1547 }
1548
1549 static int
1550 sldns_str2wire_svcparam_value(const char *key, size_t key_len,
1551         const char *val, uint8_t* rd, size_t* rd_len)
1552 {
1553         size_t str_len;
1554         int svcparamkey = sldns_str2wire_svcparam_key_lookup(key, key_len);
1555
1556         if (svcparamkey < 0) {
1557                 return LDNS_WIREPARSE_ERR_SVCB_UNKNOWN_KEY;
1558         }
1559
1560         /* key without value */
1561         if (val == NULL) {
1562                 switch (svcparamkey) {
1563 #ifdef SVCB_SEMANTIC_ERRORS
1564                 case SVCB_KEY_MANDATORY:
1565                 case SVCB_KEY_ALPN:
1566                 case SVCB_KEY_PORT:
1567                 case SVCB_KEY_IPV4HINT:
1568                 case SVCB_KEY_IPV6HINT:
1569                 case SVCB_KEY_DOHPATH:
1570                         return LDNS_WIREPARSE_ERR_SVCB_MISSING_PARAM;
1571 #endif
1572                 default:
1573                         if (*rd_len < 4)
1574                                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1575                         sldns_write_uint16(rd, svcparamkey);
1576                         sldns_write_uint16(rd + 2, 0);
1577                         *rd_len = 4;
1578
1579                         return LDNS_WIREPARSE_ERR_OK;
1580                 }
1581         }
1582
1583         /* value is non-empty */
1584         switch (svcparamkey) {
1585         case SVCB_KEY_PORT:
1586                 return sldns_str2wire_svcparam_port(val, rd, rd_len);
1587         case SVCB_KEY_IPV4HINT:
1588                 return sldns_str2wire_svcbparam_ipv4hint(val, rd, rd_len);
1589         case SVCB_KEY_IPV6HINT:
1590                 return sldns_str2wire_svcbparam_ipv6hint(val, rd, rd_len);
1591         case SVCB_KEY_MANDATORY:
1592                 return sldns_str2wire_svcbparam_mandatory(val, rd, rd_len);
1593 #ifdef SVCB_SEMANTIC_ERRORS
1594         case SVCB_KEY_NO_DEFAULT_ALPN:
1595                 return LDNS_WIREPARSE_ERR_SVCB_NO_DEFAULT_ALPN_VALUE;
1596 #endif
1597         case SVCB_KEY_ECH:
1598                 return sldns_str2wire_svcbparam_ech_value(val, rd, rd_len);
1599         case SVCB_KEY_ALPN:
1600                 return sldns_str2wire_svcbparam_alpn_value(val, rd, rd_len);
1601         case SVCB_KEY_DOHPATH:
1602                 return sldns_str2wire_svcbparam_dohpath_value(val, rd, rd_len);
1603         default:
1604                 str_len = strlen(val);
1605                 if (*rd_len < 4 + str_len)
1606                         return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1607                 sldns_write_uint16(rd, svcparamkey);
1608                 sldns_write_uint16(rd + 2, str_len);
1609                 memcpy(rd + 4, val, str_len);
1610                 *rd_len = 4 + str_len;
1611
1612                 return LDNS_WIREPARSE_ERR_OK;
1613         }
1614
1615         return LDNS_WIREPARSE_ERR_GENERAL;
1616 }
1617
1618 static int sldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_len)
1619 {
1620         const char* eq_pos;
1621         char unescaped_val[LDNS_MAX_RDFLEN];
1622         char* val_out = unescaped_val;
1623         const char* val_in;
1624
1625         eq_pos = strchr(str, '=');
1626
1627         /* case: key=value */
1628         if (eq_pos != NULL && eq_pos[1]) {
1629                 val_in = eq_pos + 1;
1630
1631                 /* unescape characters and "" blocks */
1632                 if (*val_in == '"') {
1633                         val_in++;
1634                         while (*val_in != '"'
1635                         && (size_t)(val_out - unescaped_val + 1) < sizeof(unescaped_val)
1636                         && sldns_parse_char( (uint8_t*) val_out, &val_in)) {
1637                                 val_out++;
1638                         }
1639                 } else {
1640                         while ((size_t)(val_out - unescaped_val + 1) < sizeof(unescaped_val)
1641                         && sldns_parse_char( (uint8_t*) val_out, &val_in)) {
1642                                 val_out++;
1643                         }
1644                 }
1645                 *val_out = 0;
1646
1647                 return sldns_str2wire_svcparam_value(str, eq_pos - str,
1648                         unescaped_val[0] ? unescaped_val : NULL, rd, rd_len);
1649         }
1650         /* case: key= */
1651         else if (eq_pos != NULL && !(eq_pos[1])) {
1652                 return sldns_str2wire_svcparam_value(str, eq_pos - str, NULL, rd, rd_len);
1653         }
1654         /* case: key */
1655         else {
1656                 return sldns_str2wire_svcparam_value(str, strlen(str), NULL, rd, rd_len);
1657         }
1658 }
1659
1660 int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
1661         sldns_rdf_type rdftype)
1662 {
1663         switch (rdftype) {
1664         case LDNS_RDF_TYPE_DNAME:
1665                 return sldns_str2wire_dname_buf(str, rd, len);
1666         case LDNS_RDF_TYPE_INT8:
1667                 return sldns_str2wire_int8_buf(str, rd, len);
1668         case LDNS_RDF_TYPE_INT16:
1669                 return sldns_str2wire_int16_buf(str, rd, len);
1670         case LDNS_RDF_TYPE_INT32:
1671                 return sldns_str2wire_int32_buf(str, rd, len);
1672         case LDNS_RDF_TYPE_A:
1673                 return sldns_str2wire_a_buf(str, rd, len);
1674         case LDNS_RDF_TYPE_AAAA:
1675                 return sldns_str2wire_aaaa_buf(str, rd, len);
1676         case LDNS_RDF_TYPE_STR:
1677                 return sldns_str2wire_str_buf(str, rd, len);
1678         case LDNS_RDF_TYPE_APL:
1679                 return sldns_str2wire_apl_buf(str, rd, len);
1680         case LDNS_RDF_TYPE_B64:
1681                 return sldns_str2wire_b64_buf(str, rd, len);
1682         case LDNS_RDF_TYPE_B32_EXT:
1683                 return sldns_str2wire_b32_ext_buf(str, rd, len);
1684         case LDNS_RDF_TYPE_HEX:
1685                 return sldns_str2wire_hex_buf(str, rd, len);
1686         case LDNS_RDF_TYPE_NSEC:
1687                 return sldns_str2wire_nsec_buf(str, rd, len);
1688         case LDNS_RDF_TYPE_TYPE:
1689                 return sldns_str2wire_type_buf(str, rd, len);
1690         case LDNS_RDF_TYPE_CLASS:
1691                 return sldns_str2wire_class_buf(str, rd, len);
1692         case LDNS_RDF_TYPE_CERT_ALG:
1693                 return sldns_str2wire_cert_alg_buf(str, rd, len);
1694         case LDNS_RDF_TYPE_ALG:
1695                 return sldns_str2wire_alg_buf(str, rd, len);
1696         case LDNS_RDF_TYPE_TIME:
1697                 return sldns_str2wire_time_buf(str, rd, len);
1698         case LDNS_RDF_TYPE_PERIOD:
1699                 return sldns_str2wire_period_buf(str, rd, len);
1700         case LDNS_RDF_TYPE_TSIGTIME:
1701                 return sldns_str2wire_tsigtime_buf(str, rd, len);
1702         case LDNS_RDF_TYPE_LOC:
1703                 return sldns_str2wire_loc_buf(str, rd, len);
1704         case LDNS_RDF_TYPE_WKS:
1705                 return sldns_str2wire_wks_buf(str, rd, len);
1706         case LDNS_RDF_TYPE_NSAP:
1707                 return sldns_str2wire_nsap_buf(str, rd, len);
1708         case LDNS_RDF_TYPE_ATMA:
1709                 return sldns_str2wire_atma_buf(str, rd, len);
1710         case LDNS_RDF_TYPE_IPSECKEY:
1711                 return sldns_str2wire_ipseckey_buf(str, rd, len);
1712         case LDNS_RDF_TYPE_NSEC3_SALT:
1713                 return sldns_str2wire_nsec3_salt_buf(str, rd, len);
1714         case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
1715                 return sldns_str2wire_b32_ext_buf(str, rd, len);
1716         case LDNS_RDF_TYPE_ILNP64:
1717                 return sldns_str2wire_ilnp64_buf(str, rd, len);
1718         case LDNS_RDF_TYPE_EUI48:
1719                 return sldns_str2wire_eui48_buf(str, rd, len);
1720         case LDNS_RDF_TYPE_EUI64:
1721                 return sldns_str2wire_eui64_buf(str, rd, len);
1722         case LDNS_RDF_TYPE_TAG:
1723                 return sldns_str2wire_tag_buf(str, rd, len);
1724         case LDNS_RDF_TYPE_LONG_STR:
1725                 return sldns_str2wire_long_str_buf(str, rd, len);
1726         case LDNS_RDF_TYPE_TSIGERROR:
1727                 return sldns_str2wire_tsigerror_buf(str, rd, len);
1728         case LDNS_RDF_TYPE_HIP:
1729                 return sldns_str2wire_hip_buf(str, rd, len);
1730         case LDNS_RDF_TYPE_INT16_DATA:
1731                 return sldns_str2wire_int16_data_buf(str, rd, len);
1732         case LDNS_RDF_TYPE_SVCPARAM:
1733                 return sldns_str2wire_svcparam_buf(str, rd, len);
1734         case LDNS_RDF_TYPE_UNKNOWN:
1735         case LDNS_RDF_TYPE_SERVICE:
1736                 return LDNS_WIREPARSE_ERR_NOT_IMPL;
1737         case LDNS_RDF_TYPE_NONE:
1738         default:
1739                 break;
1740         }
1741         return LDNS_WIREPARSE_ERR_GENERAL;
1742 }
1743
1744 int sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len)
1745 {
1746         char* end;
1747         uint8_t r = (uint8_t)strtol((char*)str, &end, 10);
1748         if(*end != 0)
1749                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
1750         if(*len < 1)
1751                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1752         rd[0] = r;
1753         *len = 1;
1754         return LDNS_WIREPARSE_ERR_OK;
1755 }
1756
1757 int sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len)
1758 {
1759         char* end;
1760         uint16_t r = (uint16_t)strtol((char*)str, &end, 10);
1761         if(*end != 0)
1762                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
1763         if(*len < 2)
1764                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1765         sldns_write_uint16(rd, r);
1766         *len = 2;
1767         return LDNS_WIREPARSE_ERR_OK;
1768 }
1769
1770 int sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len)
1771 {
1772         char* end;
1773         uint32_t r;
1774         errno = 0; /* must set to zero before call,
1775                         note race condition on errno */
1776         if(*str == '-')
1777                 r = (uint32_t)strtol((char*)str, &end, 10);
1778         else    r = (uint32_t)strtoul((char*)str, &end, 10);
1779         if(*end != 0)
1780                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
1781         if(errno == ERANGE)
1782                 return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW;
1783         if(*len < 4)
1784                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1785         sldns_write_uint32(rd, r);
1786         *len = 4;
1787         return LDNS_WIREPARSE_ERR_OK;
1788 }
1789
1790 int sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len)
1791 {
1792         struct in_addr address;
1793         if(inet_pton(AF_INET, (char*)str, &address) != 1)
1794                 return LDNS_WIREPARSE_ERR_SYNTAX_IP4;
1795         if(*len < sizeof(address))
1796                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1797         memmove(rd, &address, sizeof(address));
1798         *len = sizeof(address);
1799         return LDNS_WIREPARSE_ERR_OK;
1800 }
1801
1802 int sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len)
1803 {
1804 #ifdef AF_INET6
1805         uint8_t address[LDNS_IP6ADDRLEN + 1];
1806         if(inet_pton(AF_INET6, (char*)str, address) != 1)
1807                 return LDNS_WIREPARSE_ERR_SYNTAX_IP6;
1808         if(*len < LDNS_IP6ADDRLEN)
1809                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1810         memmove(rd, address, LDNS_IP6ADDRLEN);
1811         *len = LDNS_IP6ADDRLEN;
1812         return LDNS_WIREPARSE_ERR_OK;
1813 #else
1814         return LDNS_WIREPARSE_ERR_NOT_IMPL;
1815 #endif
1816 }
1817
1818 int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len)
1819 {
1820         uint8_t ch = 0;
1821         size_t sl = 0;
1822         const char* s = str;
1823         /* skip length byte */
1824         if(*len < 1)
1825                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1826
1827         /* read characters */
1828         while(sldns_parse_char(&ch, &s)) {
1829                 if(sl >= 255)
1830                         return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str);
1831                 if(*len < sl+2)
1832                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
1833                                 s-str);
1834                 rd[++sl] = ch;
1835         }
1836         if(!s)
1837                 return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
1838         rd[0] = (uint8_t)sl;
1839         *len = sl+1;
1840         return LDNS_WIREPARSE_ERR_OK;
1841 }
1842
1843 int sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len)
1844 {
1845         const char *my_str = str;
1846
1847         char my_ip_str[64];
1848         size_t ip_str_len;
1849
1850         uint16_t family;
1851         int negation;
1852         size_t adflength = 0;
1853         uint8_t data[16+4];
1854         uint8_t prefix;
1855         size_t i;
1856
1857         if(*my_str == '\0') {
1858                 /* empty APL element, no data, no string */
1859                 *len = 0;
1860                 return LDNS_WIREPARSE_ERR_OK;
1861         }
1862
1863         /* [!]afi:address/prefix */
1864         if (strlen(my_str) < 2
1865                         || strchr(my_str, ':') == NULL
1866                         || strchr(my_str, '/') == NULL
1867                         || strchr(my_str, ':') > strchr(my_str, '/')) {
1868                 return LDNS_WIREPARSE_ERR_INVALID_STR;
1869         }
1870
1871         if (my_str[0] == '!') {
1872                 negation = 1;
1873                 my_str += 1;
1874         } else {
1875                 negation = 0;
1876         }
1877
1878         family = (uint16_t) atoi(my_str);
1879
1880         my_str = strchr(my_str, ':') + 1;
1881
1882         /* need ip addr and only ip addr for inet_pton */
1883         ip_str_len = (size_t) (strchr(my_str, '/') - my_str);
1884         if(ip_str_len+1 > sizeof(my_ip_str))
1885                 return LDNS_WIREPARSE_ERR_INVALID_STR;
1886         (void)strlcpy(my_ip_str, my_str, sizeof(my_ip_str));
1887         my_ip_str[ip_str_len] = 0;
1888
1889         if (family == 1) {
1890                 /* ipv4 */
1891                 if(inet_pton(AF_INET, my_ip_str, data+4) == 0)
1892                         return LDNS_WIREPARSE_ERR_INVALID_STR;
1893                 for (i = 0; i < 4; i++) {
1894                         if (data[i+4] != 0) {
1895                                 adflength = i + 1;
1896                         }
1897                 }
1898         } else if (family == 2) {
1899                 /* ipv6 */
1900                 if (inet_pton(AF_INET6, my_ip_str, data+4) == 0)
1901                         return LDNS_WIREPARSE_ERR_INVALID_STR;
1902                 for (i = 0; i < 16; i++) {
1903                         if (data[i+4] != 0) {
1904                                 adflength = i + 1;
1905                         }
1906                 }
1907         } else {
1908                 /* unknown family */
1909                 return LDNS_WIREPARSE_ERR_INVALID_STR;
1910         }
1911
1912         my_str = strchr(my_str, '/') + 1;
1913         prefix = (uint8_t) atoi(my_str);
1914
1915         sldns_write_uint16(data, family);
1916         data[2] = prefix;
1917         data[3] = (uint8_t)adflength;
1918         if (negation) {
1919                 /* set bit 1 of byte 3 */
1920                 data[3] = data[3] | 0x80;
1921         }
1922
1923         if(*len < 4+adflength)
1924                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1925         memmove(rd, data, 4+adflength);
1926         *len = 4+adflength;
1927         return LDNS_WIREPARSE_ERR_OK;
1928 }
1929
1930 int sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len)
1931 {
1932         size_t sz = sldns_b64_pton_calculate_size(strlen(str));
1933         int n;
1934         if(strcmp(str, "0") == 0) {
1935                 *len = 0;
1936                 return LDNS_WIREPARSE_ERR_OK;
1937         }
1938         if(*len < sz)
1939                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1940         n = sldns_b64_pton(str, rd, *len);
1941         if(n < 0)
1942                 return LDNS_WIREPARSE_ERR_SYNTAX_B64;
1943         *len = (size_t)n;
1944         return LDNS_WIREPARSE_ERR_OK;
1945 }
1946
1947 int sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len)
1948 {
1949         size_t slen = strlen(str);
1950         size_t sz = sldns_b32_pton_calculate_size(slen);
1951         int n;
1952         if(*len < 1+sz)
1953                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
1954         rd[0] = (uint8_t)sz;
1955         n = sldns_b32_pton_extended_hex(str, slen, rd+1, *len-1);
1956         if(n < 0)
1957                 return LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT;
1958         *len = (size_t)n+1;
1959         return LDNS_WIREPARSE_ERR_OK;
1960 }
1961
1962 /** see if the string ends, or ends in whitespace */
1963 static int
1964 sldns_is_last_of_string(const char* str)
1965 {
1966         if(*str == 0) return 1;
1967         while(isspace((unsigned char)*str))
1968                 str++;
1969         if(*str == 0) return 1;
1970         return 0;
1971 }
1972
1973 int sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len)
1974 {
1975         const char* s = str;
1976         size_t dlen = 0; /* number of hexdigits parsed */
1977         while(*s) {
1978                 if(isspace((unsigned char)*s)) {
1979                         s++;
1980                         continue;
1981                 }
1982                 if(dlen == 0 && *s == '0' && sldns_is_last_of_string(s+1)) {
1983                         *len = 0;
1984                         return LDNS_WIREPARSE_ERR_OK;
1985                 }
1986                 if(!isxdigit((unsigned char)*s))
1987                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
1988                 if(*len < dlen/2 + 1)
1989                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
1990                                 s-str);
1991                 if((dlen&1)==0)
1992                         rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
1993                 else    rd[dlen/2] += (uint8_t)sldns_hexdigit_to_int(*s++);
1994                 dlen++;
1995         }
1996         if((dlen&1)!=0)
1997                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
1998         *len = dlen/2;
1999         return LDNS_WIREPARSE_ERR_OK;
2000 }
2001
2002 int sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len)
2003 {
2004         const char *delim = "\n\t ";
2005         char token[64]; /* for a type name */
2006         size_t type_count = 0;
2007         int block;
2008         size_t used = 0;
2009         uint16_t maxtype = 0;
2010         uint8_t typebits[8192]; /* 65536 bits */
2011         uint8_t window_in_use[256];
2012
2013         /* string in buffer */
2014         sldns_buffer strbuf;
2015         sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
2016
2017         /* parse the types */
2018         memset(typebits, 0, sizeof(typebits));
2019         memset(window_in_use, 0, sizeof(window_in_use));
2020         while(sldns_buffer_remaining(&strbuf) > 0 &&
2021                 sldns_bget_token(&strbuf, token, delim, sizeof(token)) != -1) {
2022                 uint16_t t = sldns_get_rr_type_by_name(token);
2023                 if(token[0] == 0)
2024                         continue;
2025                 if(t == 0 && strcmp(token, "TYPE0") != 0)
2026                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
2027                                 sldns_buffer_position(&strbuf));
2028                 typebits[t/8] |= (0x80>>(t%8));
2029                 window_in_use[t/256] = 1;
2030                 type_count++;
2031                 if(t > maxtype) maxtype = t;
2032         }
2033
2034         /* empty NSEC bitmap */
2035         if(type_count == 0) {
2036                 *len = 0;
2037                 return LDNS_WIREPARSE_ERR_OK;
2038         }
2039
2040         /* encode windows {u8 windowblock, u8 bitmaplength, 0-32u8 bitmap},
2041          * block is 0-255 upper octet of types, length if 0-32. */
2042         for(block = 0; block <= (int)maxtype/256; block++) {
2043                 int i, blocklen = 0;
2044                 if(!window_in_use[block])
2045                         continue;
2046                 for(i=0; i<32; i++) {
2047                         if(typebits[block*32+i] != 0)
2048                                 blocklen = i+1;
2049                 }
2050                 if(blocklen == 0)
2051                         continue; /* empty window should have been !in_use */
2052                 if(used+blocklen+2 > *len)
2053                         return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2054                 rd[used+0] = (uint8_t)block;
2055                 rd[used+1] = (uint8_t)blocklen;
2056                 for(i=0; i<blocklen; i++) {
2057                         rd[used+2+i] = typebits[block*32+i];
2058                 }
2059                 used += blocklen+2;
2060         }
2061         *len = used;
2062         return LDNS_WIREPARSE_ERR_OK;
2063 }
2064
2065 int sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len)
2066 {
2067         uint16_t t = sldns_get_rr_type_by_name(str);
2068         if(t == 0 && strcmp(str, "TYPE0") != 0)
2069                 return LDNS_WIREPARSE_ERR_SYNTAX_TYPE;
2070         if(*len < 2)
2071                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2072         sldns_write_uint16(rd, t);
2073         *len = 2;
2074         return LDNS_WIREPARSE_ERR_OK;
2075 }
2076
2077 int sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len)
2078 {
2079         uint16_t c = sldns_get_rr_class_by_name(str);
2080         if(c == 0 && strcmp(str, "CLASS0") != 0)
2081                 return LDNS_WIREPARSE_ERR_SYNTAX_CLASS;
2082         if(*len < 2)
2083                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2084         sldns_write_uint16(rd, c);
2085         *len = 2;
2086         return LDNS_WIREPARSE_ERR_OK;
2087 }
2088
2089 /* An certificate alg field can either be specified as a 8 bits number
2090  * or by its symbolic name. Handle both */
2091 int sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len)
2092 {
2093         sldns_lookup_table *lt = sldns_lookup_by_name(sldns_cert_algorithms,
2094                 str);
2095         if(*len < 2)
2096                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2097         if(lt) {
2098                 sldns_write_uint16(rd, (uint16_t)lt->id);
2099         } else {
2100                 int s = sldns_str2wire_int16_buf(str, rd, len);
2101                 if(s) return s;
2102                 if(sldns_read_uint16(rd) == 0)
2103                         return LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM;
2104         }
2105         *len = 2;
2106         return LDNS_WIREPARSE_ERR_OK;
2107 }
2108
2109 /* An alg field can either be specified as a 8 bits number
2110  * or by its symbolic name. Handle both */
2111 int sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len)
2112 {
2113         sldns_lookup_table *lt = sldns_lookup_by_name(sldns_algorithms, str);
2114         if(*len < 1)
2115                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2116         if(lt) {
2117                 rd[0] = (uint8_t)lt->id;
2118                 *len = 1;
2119         } else {
2120                 /* try as-is (a number) */
2121                 return sldns_str2wire_int8_buf(str, rd, len);
2122         }
2123         return LDNS_WIREPARSE_ERR_OK;
2124 }
2125
2126 int sldns_str2wire_tsigerror_buf(const char* str, uint8_t* rd, size_t* len)
2127 {
2128         sldns_lookup_table *lt = sldns_lookup_by_name(sldns_tsig_errors, str);
2129         if(*len < 2)
2130                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2131         if(lt) {
2132                 sldns_write_uint16(rd, (uint16_t)lt->id);
2133                 *len = 2;
2134         } else {
2135                 /* try as-is (a number) */
2136                 return sldns_str2wire_int16_buf(str, rd, len);
2137         }
2138         return LDNS_WIREPARSE_ERR_OK;
2139 }
2140
2141 int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len)
2142 {
2143         /* convert a time YYYYDDMMHHMMSS to wireformat */
2144         struct tm tm;
2145         if(*len < 4)
2146                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2147
2148         /* Try to scan the time... */
2149         memset(&tm, 0, sizeof(tm));
2150         if (strlen(str) == 14 && sscanf(str, "%4d%2d%2d%2d%2d%2d",
2151                 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour,
2152                 &tm.tm_min, &tm.tm_sec) == 6) {
2153                 tm.tm_year -= 1900;
2154                 tm.tm_mon--;
2155                 /* Check values */
2156                 if (tm.tm_year < 70)
2157                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2158                 if (tm.tm_mon < 0 || tm.tm_mon > 11)
2159                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2160                 if (tm.tm_mday < 1 || tm.tm_mday > 31)
2161                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2162                 if (tm.tm_hour < 0 || tm.tm_hour > 23)
2163                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2164                 if (tm.tm_min < 0 || tm.tm_min > 59)
2165                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2166                 if (tm.tm_sec < 0 || tm.tm_sec > 59)
2167                         return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
2168
2169                 sldns_write_uint32(rd, (uint32_t)sldns_mktime_from_utc(&tm));
2170         } else {
2171                 /* handle it as 32 bits timestamp */
2172                 char *end;
2173                 uint32_t l = (uint32_t)strtol((char*)str, &end, 10);
2174                 if(*end != 0)
2175                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME,
2176                                 end-(char*)str);
2177                 sldns_write_uint32(rd, l);
2178         }
2179         *len = 4;
2180         return LDNS_WIREPARSE_ERR_OK;
2181 }
2182
2183 int sldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len)
2184 {
2185         char* end;
2186         uint64_t t = (uint64_t)strtol((char*)str, &end, 10);
2187         uint16_t high;
2188         uint32_t low;
2189         if(*end != 0)
2190                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME, end-str);
2191         if(*len < 6)
2192                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2193         high = (uint16_t)(t>>32);
2194         low = (uint32_t)(t);
2195         sldns_write_uint16(rd, high);
2196         sldns_write_uint32(rd+2, low);
2197         *len = 6;
2198         return LDNS_WIREPARSE_ERR_OK;
2199 }
2200
2201 int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len)
2202 {
2203         const char* end;
2204         int overflow;
2205         uint32_t p = sldns_str2period(str, &end, &overflow);
2206         if(*end != 0)
2207                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str);
2208         if(overflow)
2209                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW,
2210                         end-str);
2211         if(*len < 4)
2212                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2213         sldns_write_uint32(rd, p);
2214         *len = 4;
2215         return LDNS_WIREPARSE_ERR_OK;
2216 }
2217
2218 /** read "<digits>[.<digits>][mM]" into mantissa exponent format for LOC type */
2219 static int
2220 loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e)
2221 {
2222         uint32_t meters = 0, cm = 0, val;
2223         char* cm_endstr;
2224         while (isblank((unsigned char)*my_str)) {
2225                 my_str++;
2226         }
2227         meters = (uint32_t)strtol(my_str, &my_str, 10);
2228         if (*my_str == '.') {
2229                 my_str++;
2230                 cm = (uint32_t)strtol(my_str, &cm_endstr, 10);
2231                 if(cm_endstr == my_str + 1)
2232                         cm *= 10;
2233                 my_str = cm_endstr;
2234         }
2235         if (meters >= 1) {
2236                 *e = 2;
2237                 val = meters;
2238         } else  {
2239                 *e = 0;
2240                 val = cm;
2241         }
2242         while(val >= 10) {
2243                 (*e)++;
2244                 val /= 10;
2245         }
2246         *m = (uint8_t)val;
2247
2248         if (*e > 9)
2249                 return 0;
2250         if (*my_str == 'm' || *my_str == 'M') {
2251                 my_str++;
2252         }
2253         *endstr = my_str;
2254         return 1;
2255 }
2256
2257 int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
2258 {
2259         uint32_t latitude = 0;
2260         uint32_t longitude = 0;
2261         uint32_t altitude = 0;
2262
2263         uint32_t equator = (uint32_t)1<<31; /* 2**31 */
2264
2265         /* only support version 0 */
2266         uint32_t h = 0;
2267         uint32_t m = 0;
2268         uint8_t size_b = 1, size_e = 2;
2269         uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
2270         uint8_t vert_pre_b = 1, vert_pre_e = 3;
2271
2272         double s = 0.0;
2273         int northerness;
2274         int easterness;
2275
2276         char *my_str = (char *) str;
2277
2278         if (isdigit((unsigned char) *my_str)) {
2279                 h = (uint32_t) strtol(my_str, &my_str, 10);
2280         } else {
2281                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2282         }
2283
2284         while (isblank((unsigned char) *my_str)) {
2285                 my_str++;
2286         }
2287
2288         if (isdigit((unsigned char) *my_str)) {
2289                 m = (uint32_t) strtol(my_str, &my_str, 10);
2290         } else if (*my_str == 'N' || *my_str == 'S') {
2291                 goto north;
2292         } else {
2293                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2294         }
2295
2296         while (isblank((unsigned char) *my_str)) {
2297                 my_str++;
2298         }
2299
2300         if (isdigit((unsigned char) *my_str)) {
2301                 s = strtod(my_str, &my_str);
2302         }
2303
2304         /* skip blanks before northerness */
2305         while (isblank((unsigned char) *my_str)) {
2306                 my_str++;
2307         }
2308
2309 north:
2310         if (*my_str == 'N') {
2311                 northerness = 1;
2312         } else if (*my_str == 'S') {
2313                 northerness = 0;
2314         } else {
2315                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2316         }
2317
2318         my_str++;
2319
2320         /* store number */
2321         s = 1000.0 * s;
2322         /* add a little to make floor in conversion a round */
2323         s += 0.0005;
2324         latitude = (uint32_t) s;
2325         latitude += 1000 * 60 * m;
2326         latitude += 1000 * 60 * 60 * h;
2327         if (northerness) {
2328                 latitude = equator + latitude;
2329         } else {
2330                 latitude = equator - latitude;
2331         }
2332         while (isblank((unsigned char)*my_str)) {
2333                 my_str++;
2334         }
2335
2336         if (isdigit((unsigned char) *my_str)) {
2337                 h = (uint32_t) strtol(my_str, &my_str, 10);
2338         } else {
2339                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2340         }
2341
2342         while (isblank((unsigned char) *my_str)) {
2343                 my_str++;
2344         }
2345
2346         if (isdigit((unsigned char) *my_str)) {
2347                 m = (uint32_t) strtol(my_str, &my_str, 10);
2348         } else if (*my_str == 'E' || *my_str == 'W') {
2349                 goto east;
2350         } else {
2351                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2352         }
2353
2354         while (isblank((unsigned char)*my_str)) {
2355                 my_str++;
2356         }
2357
2358         if (isdigit((unsigned char) *my_str)) {
2359                 s = strtod(my_str, &my_str);
2360         }
2361
2362         /* skip blanks before easterness */
2363         while (isblank((unsigned char)*my_str)) {
2364                 my_str++;
2365         }
2366
2367 east:
2368         if (*my_str == 'E') {
2369                 easterness = 1;
2370         } else if (*my_str == 'W') {
2371                 easterness = 0;
2372         } else {
2373                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2374         }
2375
2376         my_str++;
2377
2378         /* store number */
2379         s *= 1000.0;
2380         /* add a little to make floor in conversion a round */
2381         s += 0.0005;
2382         longitude = (uint32_t) s;
2383         longitude += 1000 * 60 * m;
2384         longitude += 1000 * 60 * 60 * h;
2385
2386         if (easterness) {
2387                 longitude += equator;
2388         } else {
2389                 longitude = equator - longitude;
2390         }
2391
2392         altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
2393                 10000000.0 + 0.5);
2394         if (*my_str == 'm' || *my_str == 'M') {
2395                 my_str++;
2396         }
2397
2398         if (strlen(my_str) > 0) {
2399                 if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
2400                         return LDNS_WIREPARSE_ERR_INVALID_STR;
2401         }
2402
2403         if (strlen(my_str) > 0) {
2404                 if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
2405                         return LDNS_WIREPARSE_ERR_INVALID_STR;
2406         }
2407
2408         if (strlen(my_str) > 0) {
2409                 if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
2410                         return LDNS_WIREPARSE_ERR_INVALID_STR;
2411         }
2412
2413         if(*len < 16)
2414                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2415         rd[0] = 0;
2416         rd[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
2417         rd[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
2418         rd[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
2419         sldns_write_uint32(rd + 4, latitude);
2420         sldns_write_uint32(rd + 8, longitude);
2421         sldns_write_uint32(rd + 12, altitude);
2422         *len = 16;
2423         return LDNS_WIREPARSE_ERR_OK;
2424 }
2425
2426 static void
2427 ldns_tolower_str(char* s)
2428 {
2429         if(s) {
2430                 while(*s) {
2431                         *s = (char)tolower((unsigned char)*s);
2432                         s++;
2433                 }
2434         }
2435 }
2436
2437 int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len)
2438 {
2439         int rd_len = 1;
2440         int have_proto = 0;
2441         char token[50], proto_str[50];
2442         sldns_buffer strbuf;
2443         sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
2444         proto_str[0]=0;
2445
2446         /* check we have one byte for proto */
2447         if(*len < 1)
2448                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2449
2450         while(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) > 0) {
2451                 ldns_tolower_str(token);
2452                 if(!have_proto) {
2453                         struct protoent *p = getprotobyname(token);
2454                         have_proto = 1;
2455                         if(p) rd[0] = (uint8_t)p->p_proto;
2456                         else if(strcasecmp(token, "tcp")==0) rd[0]=6;
2457                         else if(strcasecmp(token, "udp")==0) rd[0]=17;
2458                         else rd[0] = (uint8_t)atoi(token);
2459                         (void)strlcpy(proto_str, token, sizeof(proto_str));
2460                 } else {
2461                         int serv_port;
2462                         struct servent *serv = getservbyname(token, proto_str);
2463                         if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port);
2464                         else if(strcasecmp(token, "domain")==0) serv_port=53;
2465                         else {
2466                                 serv_port = atoi(token);
2467                                 if(serv_port == 0 && strcmp(token, "0") != 0) {
2468 #ifdef HAVE_ENDSERVENT
2469                                         endservent();
2470 #endif
2471 #ifdef HAVE_ENDPROTOENT
2472                                         endprotoent();
2473 #endif
2474                                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
2475                                                 sldns_buffer_position(&strbuf));
2476                                 }
2477                                 if(serv_port < 0 || serv_port > 65535) {
2478 #ifdef HAVE_ENDSERVENT
2479                                         endservent();
2480 #endif
2481 #ifdef HAVE_ENDPROTOENT
2482                                         endprotoent();
2483 #endif
2484                                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
2485                                                 sldns_buffer_position(&strbuf));
2486                                 }
2487                         }
2488                         if(rd_len < 1+serv_port/8+1) {
2489                                 /* bitmap is larger, init new bytes at 0 */
2490                                 if(*len < 1+(size_t)serv_port/8+1) {
2491 #ifdef HAVE_ENDSERVENT
2492                                         endservent();
2493 #endif
2494 #ifdef HAVE_ENDPROTOENT
2495                                         endprotoent();
2496 #endif
2497                                         return RET_ERR(
2498                                         LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
2499                                         sldns_buffer_position(&strbuf));
2500                                 }
2501                                 memset(rd+rd_len, 0, 1+(size_t)serv_port/8+1-rd_len);
2502                                 rd_len = 1+serv_port/8+1;
2503                         }
2504                         rd[1+ serv_port/8] |= (1 << (7 - serv_port % 8));
2505                 }
2506         }
2507         *len = (size_t)rd_len;
2508
2509 #ifdef HAVE_ENDSERVENT
2510         endservent();
2511 #endif
2512 #ifdef HAVE_ENDPROTOENT
2513         endprotoent();
2514 #endif
2515         return LDNS_WIREPARSE_ERR_OK;
2516 }
2517
2518 int sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len)
2519 {
2520         const char* s = str;
2521         size_t slen;
2522         size_t dlen = 0; /* number of hexdigits parsed */
2523
2524         /* just a hex string with optional dots? */
2525         if (s[0] != '0' || s[1] != 'x')
2526                 return LDNS_WIREPARSE_ERR_INVALID_STR;
2527         s += 2;
2528         slen = strlen(s);
2529         if(slen > LDNS_MAX_RDFLEN*2)
2530                 return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
2531         while(*s) {
2532                 if(isspace((unsigned char)*s) || *s == '.') {
2533                         s++;
2534                         continue;
2535                 }
2536                 if(!isxdigit((unsigned char)*s))
2537                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
2538                 if(*len < dlen/2 + 1)
2539                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
2540                                 s-str);
2541                 if((dlen&1)==0)
2542                         rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
2543                 else    rd[dlen/2] += sldns_hexdigit_to_int(*s++);
2544                 dlen++;
2545         }
2546         if((dlen&1)!=0)
2547                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
2548         *len = dlen/2;
2549         return LDNS_WIREPARSE_ERR_OK;
2550 }
2551
2552 int sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len)
2553 {
2554         const char* s = str;
2555         size_t slen = strlen(str);
2556         size_t dlen = 0; /* number of hexdigits parsed */
2557
2558         /* just a hex string with optional dots? */
2559         /* notimpl e.164 format */
2560         if(slen > LDNS_MAX_RDFLEN*2)
2561                 return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
2562         while(*s) {
2563                 if(isspace((unsigned char)*s) || *s == '.') {
2564                         s++;
2565                         continue;
2566                 }
2567                 if(!isxdigit((unsigned char)*s))
2568                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
2569                 if(*len < dlen/2 + 1)
2570                         return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
2571                                 s-str);
2572                 if((dlen&1)==0)
2573                         rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
2574                 else    rd[dlen/2] += sldns_hexdigit_to_int(*s++);
2575                 dlen++;
2576         }
2577         if((dlen&1)!=0)
2578                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
2579         *len = dlen/2;
2580         return LDNS_WIREPARSE_ERR_OK;
2581 }
2582
2583 int sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len)
2584 {
2585         size_t gwlen = 0, keylen = 0;
2586         int s;
2587         uint8_t gwtype;
2588         char token[512];
2589         sldns_buffer strbuf;
2590         sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
2591
2592         if(*len < 3)
2593                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2594         /* precedence */
2595         if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
2596                 return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2597                         sldns_buffer_position(&strbuf));
2598         rd[0] = (uint8_t)atoi(token);
2599         /* gateway_type */
2600         if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
2601                 return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2602                         sldns_buffer_position(&strbuf));
2603         rd[1] = (uint8_t)atoi(token);
2604         gwtype = rd[1];
2605         /* algorithm */
2606         if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
2607                 return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2608                         sldns_buffer_position(&strbuf));
2609         rd[2] = (uint8_t)atoi(token);
2610
2611         /* gateway */
2612         if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
2613                 return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2614                         sldns_buffer_position(&strbuf));
2615         if(gwtype == 0) {
2616                 /* NOGATEWAY */
2617                 if(strcmp(token, ".") != 0)
2618                         return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2619                                 sldns_buffer_position(&strbuf));
2620                 gwlen = 0;
2621         } else if(gwtype == 1) {
2622                 /* IP4 */
2623                 gwlen = *len - 3;
2624                 s = sldns_str2wire_a_buf(token, rd+3, &gwlen);
2625                 if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
2626         } else if(gwtype == 2) {
2627                 /* IP6 */
2628                 gwlen = *len - 3;
2629                 s = sldns_str2wire_aaaa_buf(token, rd+3, &gwlen);
2630                 if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
2631         } else if(gwtype == 3) {
2632                 /* DNAME */
2633                 gwlen = *len - 3;
2634                 s = sldns_str2wire_dname_buf(token, rd+3, &gwlen);
2635                 if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
2636         } else {
2637                 /* unknown gateway type */
2638                 return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
2639                         sldns_buffer_position(&strbuf));
2640         }
2641         /* double check for size */
2642         if(*len < 3 + gwlen)
2643                 return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
2644                         sldns_buffer_position(&strbuf));
2645
2646         /* publickey in remainder of strbuf */
2647         keylen = *len - 3 - gwlen;
2648         s = sldns_str2wire_b64_buf((const char*)sldns_buffer_current(&strbuf),
2649                 rd+3+gwlen, &keylen);
2650         if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
2651
2652         *len = 3 + gwlen + keylen;
2653         return LDNS_WIREPARSE_ERR_OK;
2654 }
2655
2656 int sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len)
2657 {
2658         int i, salt_length_str = (int)strlen(str);
2659         if (salt_length_str == 1 && str[0] == '-') {
2660                 salt_length_str = 0;
2661         } else if (salt_length_str % 2 != 0) {
2662                 return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
2663         }
2664         if (salt_length_str > 512)
2665                 return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
2666         if(*len < 1+(size_t)salt_length_str / 2)
2667                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2668         rd[0] = (uint8_t) (salt_length_str / 2);
2669         for (i = 0; i < salt_length_str; i += 2) {
2670                 if (isxdigit((unsigned char)str[i]) &&
2671                         isxdigit((unsigned char)str[i+1])) {
2672                         rd[1+i/2] = (uint8_t)(sldns_hexdigit_to_int(str[i])*16
2673                                 + sldns_hexdigit_to_int(str[i+1]));
2674                 } else {
2675                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, i);
2676                 }
2677         }
2678         *len = 1 + (size_t)rd[0];
2679         return LDNS_WIREPARSE_ERR_OK;
2680 }
2681
2682 int sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len)
2683 {
2684         unsigned int a, b, c, d;
2685         uint16_t shorts[4];
2686         int l;
2687         if(*len < sizeof(shorts))
2688                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2689
2690         if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 ||
2691                         l != (int)strlen(str) || /* more data to read */
2692                         strpbrk(str, "+-")       /* signed hexes */
2693                         )
2694                 return LDNS_WIREPARSE_ERR_SYNTAX_ILNP64;
2695         shorts[0] = htons(a);
2696         shorts[1] = htons(b);
2697         shorts[2] = htons(c);
2698         shorts[3] = htons(d);
2699         memmove(rd, &shorts, sizeof(shorts));
2700         *len = sizeof(shorts);
2701         return LDNS_WIREPARSE_ERR_OK;
2702 }
2703
2704 int sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len)
2705 {
2706         unsigned int a, b, c, d, e, f;
2707         int l;
2708
2709         if(*len < 6)
2710                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2711         if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n",
2712                         &a, &b, &c, &d, &e, &f, &l) != 6 ||
2713                         l != (int)strlen(str))
2714                 return LDNS_WIREPARSE_ERR_SYNTAX_EUI48;
2715         rd[0] = a;
2716         rd[1] = b;
2717         rd[2] = c;
2718         rd[3] = d;
2719         rd[4] = e;
2720         rd[5] = f;
2721         *len = 6;
2722         return LDNS_WIREPARSE_ERR_OK;
2723 }
2724
2725 int sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len)
2726 {
2727         unsigned int a, b, c, d, e, f, g, h;
2728         int l;
2729
2730         if(*len < 8)
2731                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2732         if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n",
2733                         &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 ||
2734                         l != (int)strlen(str))
2735                 return LDNS_WIREPARSE_ERR_SYNTAX_EUI64;
2736         rd[0] = a;
2737         rd[1] = b;
2738         rd[2] = c;
2739         rd[3] = d;
2740         rd[4] = e;
2741         rd[5] = f;
2742         rd[6] = g;
2743         rd[7] = h;
2744         *len = 8;
2745         return LDNS_WIREPARSE_ERR_OK;
2746 }
2747
2748 int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len)
2749 {
2750         size_t slen = strlen(str);
2751         const char* ptr;
2752
2753         if (slen > 255)
2754                 return LDNS_WIREPARSE_ERR_SYNTAX_TAG;
2755         if(*len < slen+1)
2756                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2757         for (ptr = str; *ptr; ptr++) {
2758                 if(!isalnum((unsigned char)*ptr))
2759                         return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str);
2760         }
2761         rd[0] = (uint8_t)slen;
2762         memmove(rd+1, str, slen);
2763         *len = slen+1;
2764         return LDNS_WIREPARSE_ERR_OK;
2765 }
2766
2767 int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len)
2768 {
2769         uint8_t ch = 0;
2770         const char* pstr = str;
2771         size_t length = 0;
2772
2773         /* Fill data with parsed bytes */
2774         while (sldns_parse_char(&ch, &pstr)) {
2775                 if(*len < length+1)
2776                         return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2777                 rd[length++] = ch;
2778         }
2779         if(!pstr)
2780                 return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
2781         *len = length;
2782         return LDNS_WIREPARSE_ERR_OK;
2783 }
2784
2785 int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len)
2786 {
2787         char* s, *end;
2788         int e;
2789         size_t hitlen, pklen = 0;
2790         /* presentation format:
2791          *      pk-algo HIThex pubkeybase64
2792          * wireformat:
2793          *      hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */
2794         if(*len < 4)
2795                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2796
2797         /* read PK algorithm */
2798         rd[1] = (uint8_t)strtol((char*)str, &s, 10);
2799         if(*s != ' ')
2800                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str);
2801         s++;
2802         while(*s == ' ')
2803                 s++;
2804
2805         /* read HIT hex tag */
2806         /* zero terminate the tag (replace later) */
2807         end = strchr(s, ' ');
2808         if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str);
2809         *end = 0;
2810         hitlen = *len - 4;
2811         if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) {
2812                 *end = ' ';
2813                 return RET_ERR_SHIFT(e, s-(char*)str);
2814         }
2815         if(hitlen > 255) {
2816                 *end = ' ';
2817                 return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2);
2818         }
2819         rd[0] = (uint8_t)hitlen;
2820         *end = ' ';
2821         s = end+1;
2822
2823         /* read pubkey base64 sequence */
2824         pklen = *len - 4 - hitlen;
2825         if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0)
2826                 return RET_ERR_SHIFT(e, s-(char*)str);
2827         if(pklen > 65535)
2828                 return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535);
2829         sldns_write_uint16(rd+2, (uint16_t)pklen);
2830
2831         *len = 4 + hitlen + pklen;
2832         return LDNS_WIREPARSE_ERR_OK;
2833 }
2834
2835 int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len)
2836 {
2837         char* s;
2838         int n;
2839         n = strtol(str, &s, 10);
2840         if(n < 0) /* negative number not allowed */
2841                 return LDNS_WIREPARSE_ERR_SYNTAX;
2842         if(*len < ((size_t)n)+2)
2843                 return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
2844         if(n > 65535)
2845                 return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
2846
2847         if(n == 0) {
2848                 sldns_write_uint16(rd, 0);
2849                 *len = 2;
2850                 return LDNS_WIREPARSE_ERR_OK;
2851         }
2852         if(*s != ' ')
2853                 return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str);
2854         s++;
2855         while(*s == ' ')
2856                 s++;
2857
2858         n = sldns_b64_pton(s, rd+2, (*len)-2);
2859         if(n < 0)
2860                 return LDNS_WIREPARSE_ERR_SYNTAX_B64;
2861         sldns_write_uint16(rd, (uint16_t)n);
2862         *len = ((size_t)n)+2;
2863         return LDNS_WIREPARSE_ERR_OK;
2864 }