4 * conversion routines from the presentation format
7 * a Net::DNS like library for C
9 * (c) NLnet Labs, 2004-2006
11 * See the file LICENSE for the license
13 #include <ldns/config.h>
15 #include <ldns/ldns.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 #include <sys/socket.h>
20 #ifdef HAVE_ARPA_INET_H
21 #include <arpa/inet.h>
31 #ifdef HAVE_SYS_PARAM_H
32 #include <sys/param.h>
36 ldns_str2rdf_int16(ldns_rdf
**rd
, const char *shortstr
)
40 r
= LDNS_MALLOC(uint16_t);
41 if(!r
) return LDNS_STATUS_MEM_ERR
;
43 *r
= htons((uint16_t)strtol((char *)shortstr
, &end
, 10));
47 return LDNS_STATUS_INVALID_INT
;
49 *rd
= ldns_rdf_new_frm_data(
50 LDNS_RDF_TYPE_INT16
, sizeof(uint16_t), r
);
52 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
57 ldns_str2rdf_time(ldns_rdf
**rd
, const char *time
)
59 /* convert a time YYYYDDMMHHMMSS to wireformat */
65 /* Try to scan the time... */
66 r
= (uint32_t *)LDNS_MALLOC(uint32_t);
67 if(!r
) return LDNS_STATUS_MEM_ERR
;
69 memset(&tm
, 0, sizeof(tm
));
71 if (strlen(time
) == 14 &&
72 sscanf(time
, "%4d%2d%2d%2d%2d%2d", &tm
.tm_year
, &tm
.tm_mon
, &tm
.tm_mday
, &tm
.tm_hour
, &tm
.tm_min
, &tm
.tm_sec
) == 6
77 if (tm
.tm_year
< 70) {
80 if (tm
.tm_mon
< 0 || tm
.tm_mon
> 11) {
83 if (tm
.tm_mday
< 1 || tm
.tm_mday
> 31) {
87 if (tm
.tm_hour
< 0 || tm
.tm_hour
> 23) {
91 if (tm
.tm_min
< 0 || tm
.tm_min
> 59) {
95 if (tm
.tm_sec
< 0 || tm
.tm_sec
> 59) {
99 l
= htonl(ldns_mktime_from_utc(&tm
));
100 memcpy(r
, &l
, sizeof(uint32_t));
101 *rd
= ldns_rdf_new_frm_data(
102 LDNS_RDF_TYPE_TIME
, sizeof(uint32_t), r
);
104 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
106 /* handle it as 32 bits timestamp */
107 l
= htonl((uint32_t)strtol((char*)time
, &end
, 10));
110 return LDNS_STATUS_ERR
;
112 memcpy(r
, &l
, sizeof(uint32_t));
113 *rd
= ldns_rdf_new_frm_data(
114 LDNS_RDF_TYPE_INT32
, sizeof(uint32_t), r
);
116 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
122 return LDNS_STATUS_INVALID_TIME
;
126 ldns_str2rdf_nsec3_salt(ldns_rdf
**rd
, const char *salt_str
)
135 return LDNS_STATUS_NULL
;
138 salt_length_str
= (int)strlen(salt_str
);
139 if (salt_length_str
== 1 && salt_str
[0] == '-') {
141 } else if (salt_length_str
% 2 != 0) {
142 return LDNS_STATUS_INVALID_HEX
;
144 if (salt_length_str
> 512) {
145 return LDNS_STATUS_INVALID_HEX
;
148 salt
= LDNS_XMALLOC(uint8_t, salt_length_str
/ 2);
150 return LDNS_STATUS_MEM_ERR
;
152 for (c
= 0; c
< salt_length_str
; c
+= 2) {
153 if (isxdigit((int) salt_str
[c
]) && isxdigit((int) salt_str
[c
+1])) {
154 salt
[c
/2] = (uint8_t) ldns_hexdigit_to_int(salt_str
[c
]) * 16 +
155 ldns_hexdigit_to_int(salt_str
[c
+1]);
158 return LDNS_STATUS_INVALID_HEX
;
161 salt_length
= (uint8_t) (salt_length_str
/ 2);
163 data
= LDNS_XMALLOC(uint8_t, 1 + salt_length
);
166 return LDNS_STATUS_MEM_ERR
;
168 data
[0] = salt_length
;
169 memcpy(&data
[1], salt
, salt_length
);
170 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT
, 1 + salt_length
, data
);
174 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
178 ldns_str2rdf_period(ldns_rdf
**rd
,const char *period
)
183 /* Allocate required space... */
184 p
= ldns_str2period(period
, &end
);
187 return LDNS_STATUS_ERR
;
189 p
= (uint32_t) htonl(p
);
190 *rd
= ldns_rdf_new_frm_data(
191 LDNS_RDF_TYPE_PERIOD
, sizeof(uint32_t), &p
);
193 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
197 ldns_str2rdf_int32(ldns_rdf
**rd
, const char *longstr
)
203 r
= (uint32_t*)LDNS_MALLOC(uint32_t);
204 if(!r
) return LDNS_STATUS_MEM_ERR
;
205 errno
= 0; /* must set to zero before call,
206 note race condition on errno */
208 l
= htonl((uint32_t)strtol((char*)longstr
, &end
, 10));
209 else l
= htonl((uint32_t)strtoul((char*)longstr
, &end
, 10));
213 return LDNS_STATUS_ERR
;
215 if (errno
== ERANGE
) {
217 return LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW
;
219 memcpy(r
, &l
, sizeof(uint32_t));
220 *rd
= ldns_rdf_new_frm_data(
221 LDNS_RDF_TYPE_INT32
, sizeof(uint32_t), r
);
223 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
228 ldns_str2rdf_int8(ldns_rdf
**rd
, const char *bytestr
)
233 r
= LDNS_MALLOC(uint8_t);
234 if(!r
) return LDNS_STATUS_MEM_ERR
;
236 *r
= (uint8_t)strtol((char*)bytestr
, &end
, 10);
240 return LDNS_STATUS_ERR
;
242 *rd
= ldns_rdf_new_frm_data(
243 LDNS_RDF_TYPE_INT8
, sizeof(uint8_t), r
);
245 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
251 * Checks whether the escaped value at **s is an decimal value or
252 * a 'normally' escaped character (and not eos)
254 * The string pointer at *s is increased by either 0 (on error), 1 (on
255 * normal escapes), or 3 (on decimals)
257 * Returns the number of bytes read from the escaped string, or
261 parse_escape(uint8_t *ch_p
, const char** str_p
)
265 if ((*str_p
)[0] && isdigit((unsigned char)(*str_p
)[0]) &&
266 (*str_p
)[1] && isdigit((unsigned char)(*str_p
)[1]) &&
267 (*str_p
)[2] && isdigit((unsigned char)(*str_p
)[2])) {
269 val
= (uint16_t)(((*str_p
)[0] - '0') * 100 +
270 ((*str_p
)[1] - '0') * 10 +
271 ((*str_p
)[2] - '0'));
276 *ch_p
= (uint8_t)val
;
280 } else if ((*str_p
)[0] && !isdigit((unsigned char)(*str_p
)[0])) {
282 *ch_p
= (uint8_t)*(*str_p
)++;
287 return false; /* LDNS_STATUS_SYNTAX_BAD_ESCAPE */
291 parse_char(uint8_t *ch_p
, const char** str_p
)
295 case '\0': return false;
297 case '\\': *str_p
+= 1;
298 return parse_escape(ch_p
, str_p
);
300 default: *ch_p
= (uint8_t)*(*str_p
)++;
306 * No special care is taken, all dots are translated into
308 * Could be made more efficient....we do 3 memcpy's in total...
311 ldns_str2rdf_dname(ldns_rdf
**d
, const char *str
)
316 uint8_t *q
, *pq
, label_len
;
317 uint8_t buf
[LDNS_MAX_DOMAINLEN
+ 1];
320 len
= strlen((char*)str
);
321 /* octet representation can make strings a lot longer than actual length */
322 if (len
> LDNS_MAX_DOMAINLEN
* 4) {
323 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
326 return LDNS_STATUS_DOMAINNAME_UNDERFLOW
;
330 if (1 == len
&& *str
== '.') {
331 *d
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME
, 1, "\0");
332 return LDNS_STATUS_OK
;
335 /* get on with the rest */
337 /* s is on the current character in the string
338 * pq points to where the labellength is going to go
339 * label_len keeps track of the current label's length
340 * q builds the dname inside the buf array
346 for (s
= str
; *s
; s
++, q
++) {
347 if (q
>= buf
+ LDNS_MAX_DOMAINLEN
) {
348 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
353 if (label_len
> LDNS_MAX_LABELLEN
) {
354 return LDNS_STATUS_LABEL_OVERFLOW
;
356 if (label_len
== 0) {
357 return LDNS_STATUS_EMPTY_LABEL
;
359 len
+= label_len
+ 1;
365 /* octet value or literal char */
367 if (! parse_escape(q
, &s
)) {
368 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
379 /* add root label if last char was not '.' */
380 if (!ldns_dname_str_absolute(str
)) {
381 if (q
>= buf
+ LDNS_MAX_DOMAINLEN
) {
382 return LDNS_STATUS_DOMAINNAME_OVERFLOW
;
384 if (label_len
> LDNS_MAX_LABELLEN
) {
385 return LDNS_STATUS_LABEL_OVERFLOW
;
387 if (label_len
== 0) { /* label_len 0 but not . at end? */
388 return LDNS_STATUS_EMPTY_LABEL
;
390 len
+= label_len
+ 1;
396 *d
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME
, len
, buf
);
397 return LDNS_STATUS_OK
;
401 ldns_str2rdf_a(ldns_rdf
**rd
, const char *str
)
404 if (inet_pton(AF_INET
, (char*)str
, &address
) != 1) {
405 return LDNS_STATUS_INVALID_IP4
;
407 *rd
= ldns_rdf_new_frm_data(
408 LDNS_RDF_TYPE_A
, sizeof(address
), &address
);
410 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
414 ldns_str2rdf_aaaa(ldns_rdf
**rd
, const char *str
)
416 uint8_t address
[LDNS_IP6ADDRLEN
+ 1];
418 if (inet_pton(AF_INET6
, (char*)str
, address
) != 1) {
419 return LDNS_STATUS_INVALID_IP6
;
421 *rd
= ldns_rdf_new_frm_data(
422 LDNS_RDF_TYPE_AAAA
, sizeof(address
) - 1, &address
);
424 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
428 ldns_str2rdf_str(ldns_rdf
**rd
, const char *str
)
430 uint8_t *data
, *dp
, ch
= 0;
433 /* Worst case space requirement. We'll realloc to actual size later. */
434 dp
= data
= LDNS_XMALLOC(uint8_t, strlen(str
) > 255 ? 256 : (strlen(str
) + 1));
436 return LDNS_STATUS_MEM_ERR
;
439 /* Fill data (up to 255 characters) */
440 while (parse_char(&ch
, &str
)) {
441 if (dp
- data
>= 255) {
443 return LDNS_STATUS_INVALID_STR
;
449 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
451 length
= (size_t)(dp
- data
);
452 /* Fix last length byte */
453 data
[0] = (uint8_t)length
;
455 /* Lose the overmeasure */
456 data
= LDNS_XREALLOC(dp
= data
, uint8_t, length
+ 1);
459 return LDNS_STATUS_MEM_ERR
;
463 *rd
= ldns_rdf_new(LDNS_RDF_TYPE_STR
, length
+ 1, data
);
466 return LDNS_STATUS_MEM_ERR
;
468 return LDNS_STATUS_OK
;
472 ldns_str2rdf_apl(ldns_rdf
**rd
, const char *str
)
474 const char *my_str
= str
;
481 uint8_t afdlength
= 0;
489 /* [!]afi:address/prefix */
490 if (strlen(my_str
) < 2
491 || strchr(my_str
, ':') == NULL
492 || strchr(my_str
, '/') == NULL
493 || strchr(my_str
, ':') > strchr(my_str
, '/')) {
494 return LDNS_STATUS_INVALID_STR
;
497 if (my_str
[0] == '!') {
504 family
= (uint16_t) atoi(my_str
);
506 my_str
= strchr(my_str
, ':') + 1;
508 /* need ip addr and only ip addr for inet_pton */
509 ip_str_len
= (size_t) (strchr(my_str
, '/') - my_str
);
510 my_ip_str
= LDNS_XMALLOC(char, ip_str_len
+ 1);
511 if(!my_ip_str
) return LDNS_STATUS_MEM_ERR
;
512 strncpy(my_ip_str
, my_str
, ip_str_len
+ 1);
513 my_ip_str
[ip_str_len
] = '\0';
517 afdpart
= LDNS_XMALLOC(uint8_t, 4);
519 LDNS_FREE(my_ip_str
);
520 return LDNS_STATUS_MEM_ERR
;
522 if (inet_pton(AF_INET
, my_ip_str
, afdpart
) == 0) {
523 LDNS_FREE(my_ip_str
);
525 return LDNS_STATUS_INVALID_STR
;
527 for (i
= 0; i
< 4; i
++) {
528 if (afdpart
[i
] != 0) {
532 } else if (family
== 2) {
534 afdpart
= LDNS_XMALLOC(uint8_t, 16);
536 LDNS_FREE(my_ip_str
);
537 return LDNS_STATUS_MEM_ERR
;
539 if (inet_pton(AF_INET6
, my_ip_str
, afdpart
) == 0) {
540 LDNS_FREE(my_ip_str
);
542 return LDNS_STATUS_INVALID_STR
;
544 for (i
= 0; i
< 16; i
++) {
545 if (afdpart
[i
] != 0) {
551 LDNS_FREE(my_ip_str
);
552 return LDNS_STATUS_INVALID_STR
;
555 my_str
= strchr(my_str
, '/') + 1;
556 prefix
= (uint8_t) atoi(my_str
);
558 data
= LDNS_XMALLOC(uint8_t, 4 + afdlength
);
561 LDNS_FREE(my_ip_str
);
562 return LDNS_STATUS_INVALID_STR
;
564 ldns_write_uint16(data
, family
);
568 /* set bit 1 of byte 3 */
569 data
[3] = data
[3] | 0x80;
572 memcpy(data
+ 4, afdpart
, afdlength
);
574 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_APL
, afdlength
+ 4, data
);
577 LDNS_FREE(my_ip_str
);
579 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
583 ldns_str2rdf_b64(ldns_rdf
**rd
, const char *str
)
588 if ((*str
== '-' || *str
== '0') && str
[1] == '\0') {
589 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64
, 0, NULL
);
590 return *rd
? LDNS_STATUS_OK
: LDNS_STATUS_MEM_ERR
;
593 buffer
= LDNS_XMALLOC(uint8_t, ldns_b64_ntop_calculate_size(strlen(str
)));
595 return LDNS_STATUS_MEM_ERR
;
598 i
= (uint16_t)ldns_b64_pton((const char*)str
, buffer
,
599 ldns_b64_ntop_calculate_size(strlen(str
)));
602 return LDNS_STATUS_INVALID_B64
;
604 *rd
= ldns_rdf_new_frm_data(
605 LDNS_RDF_TYPE_B64
, (uint16_t) i
, buffer
);
609 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
613 ldns_str2rdf_b32_ext(ldns_rdf
**rd
, const char *str
)
617 /* first byte contains length of actual b32 data */
618 size_t slen
= strlen(str
);
619 size_t len
= ldns_b32_pton_calculate_size(slen
);
621 return LDNS_STATUS_INVALID_B32_EXT
;
623 buffer
= LDNS_XMALLOC(uint8_t, len
+ 1);
625 return LDNS_STATUS_MEM_ERR
;
629 i
= ldns_b32_pton_extended_hex((const char*)str
, slen
, buffer
+ 1,
630 ldns_b32_ntop_calculate_size(slen
));
633 return LDNS_STATUS_INVALID_B32_EXT
;
635 *rd
= ldns_rdf_new_frm_data(
636 LDNS_RDF_TYPE_B32_EXT
, (uint16_t) i
+ 1, buffer
);
640 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
644 ldns_str2rdf_hex(ldns_rdf
**rd
, const char *str
)
652 if (len
> LDNS_MAX_RDFLEN
* 2) {
653 return LDNS_STATUS_LABEL_OVERFLOW
;
655 t
= LDNS_XMALLOC(uint8_t, (len
/ 2) + 1);
657 return LDNS_STATUS_MEM_ERR
;
660 /* Now process octet by octet... */
663 if (isspace((int) *str
)) {
666 for (i
= 16; i
>= 1; i
-= 15) {
667 while (*str
&& isspace((int) *str
)) { str
++; }
669 if (isxdigit((int) *str
)) {
670 *t
+= ldns_hexdigit_to_int(*str
) * i
;
673 return LDNS_STATUS_ERR
;
681 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX
,
682 (size_t) (t
- t_orig
),
686 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
690 ldns_str2rdf_nsec(ldns_rdf
**rd
, const char *str
)
692 const char *delimiters
= "\n\t ";
693 char *token
= LDNS_XMALLOC(char, LDNS_MAX_RDFLEN
);
694 ldns_buffer
*str_buf
;
697 size_t type_count
= 0;
698 ldns_rr_type type_list
[65536];
699 if(!token
) return LDNS_STATUS_MEM_ERR
;
702 return LDNS_STATUS_NULL
;
705 str_buf
= LDNS_MALLOC(ldns_buffer
);
708 return LDNS_STATUS_MEM_ERR
;
710 ldns_buffer_new_frm_data(str_buf
, (char *)str
, strlen(str
));
711 if(ldns_buffer_status(str_buf
) != LDNS_STATUS_OK
) {
714 return LDNS_STATUS_MEM_ERR
;
717 while ((c
= ldns_bget_token(str_buf
, token
, delimiters
, LDNS_MAX_RDFLEN
)) != -1 && c
!= 0) {
718 if(type_count
>= sizeof(type_list
)) {
721 return LDNS_STATUS_ERR
;
723 cur_type
= ldns_get_rr_type_by_name(token
);
724 type_list
[type_count
] = cur_type
;
728 *rd
= ldns_dnssec_create_nsec_bitmap(type_list
,
733 ldns_buffer_free(str_buf
);
734 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
738 ldns_str2rdf_type(ldns_rdf
**rd
, const char *str
)
741 type
= htons(ldns_get_rr_type_by_name(str
));
742 /* ldns_rr_type is a 16 bit value */
743 *rd
= ldns_rdf_new_frm_data(
744 LDNS_RDF_TYPE_TYPE
, sizeof(uint16_t), &type
);
745 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
749 ldns_str2rdf_class(ldns_rdf
**rd
, const char *str
)
752 klass
= htons(ldns_get_rr_class_by_name(str
));
753 /* class is 16 bit */
754 *rd
= ldns_rdf_new_frm_data(
755 LDNS_RDF_TYPE_CLASS
, sizeof(uint16_t), &klass
);
756 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
759 /* An certificate alg field can either be specified as a 8 bits number
760 * or by its symbolic name. Handle both
763 ldns_str2rdf_cert_alg(ldns_rdf
**rd
, const char *str
)
765 ldns_lookup_table
*lt
;
768 lt
= ldns_lookup_by_name(ldns_cert_algorithms
, str
);
772 ldns_write_uint16(idd
, (uint16_t) lt
->id
);
773 *rd
= ldns_rdf_new_frm_data(
774 LDNS_RDF_TYPE_INT16
, sizeof(uint16_t), idd
);
776 st
= LDNS_STATUS_ERR
;
779 /* try as-is (a number) */
780 st
= ldns_str2rdf_int16(rd
, str
);
781 if (st
== LDNS_STATUS_OK
&&
782 ldns_rdf2native_int16(*rd
) == 0) {
783 st
= LDNS_STATUS_CERT_BAD_ALGORITHM
;
790 static ldns_lookup_table ldns_tlsa_certificate_usages
[] = {
791 { LDNS_TLSA_USAGE_PKIX_TA
, "PKIX-TA" },
792 { LDNS_TLSA_USAGE_PKIX_EE
, "PKIX-EE" },
793 { LDNS_TLSA_USAGE_DANE_TA
, "DANE-TA" },
794 { LDNS_TLSA_USAGE_DANE_EE
, "DANE-EE" },
795 { LDNS_TLSA_USAGE_PRIVCERT
, "PrivCert" },
799 static ldns_lookup_table ldns_tlsa_selectors
[] = {
800 { LDNS_TLSA_SELECTOR_CERT
, "Cert" },
801 { LDNS_TLSA_SELECTOR_SPKI
, "SPKI" },
802 { LDNS_TLSA_SELECTOR_PRIVSEL
, "PrivSel" },
806 static ldns_lookup_table ldns_tlsa_matching_types
[] = {
807 { LDNS_TLSA_MATCHING_TYPE_FULL
, "Full" },
808 { LDNS_TLSA_MATCHING_TYPE_SHA2_256
, "SHA2-256" },
809 { LDNS_TLSA_MATCHING_TYPE_SHA2_512
, "SHA2-512" },
810 { LDNS_TLSA_MATCHING_TYPE_PRIVMATCH
, "PrivMatch" },
815 ldns_str2rdf_mnemonic4int8(ldns_lookup_table
*lt
,
816 ldns_rdf
**rd
, const char *str
)
818 if ((lt
= ldns_lookup_by_name(lt
, str
))) {
819 /* it was given as a integer */
820 *rd
= ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8
, (uint8_t) lt
->id
);
822 return LDNS_STATUS_ERR
;
824 return LDNS_STATUS_OK
;
826 return ldns_str2rdf_int8(rd
, str
);
829 /* An alg field can either be specified as a 8 bits number
830 * or by its symbolic name. Handle both
833 ldns_str2rdf_alg(ldns_rdf
**rd
, const char *str
)
835 return ldns_str2rdf_mnemonic4int8(ldns_algorithms
, rd
, str
);
839 ldns_str2rdf_certificate_usage(ldns_rdf
**rd
, const char *str
)
841 return ldns_str2rdf_mnemonic4int8(
842 ldns_tlsa_certificate_usages
, rd
, str
);
846 ldns_str2rdf_selector(ldns_rdf
**rd
, const char *str
)
848 return ldns_str2rdf_mnemonic4int8(ldns_tlsa_selectors
, rd
, str
);
852 ldns_str2rdf_matching_type(ldns_rdf
**rd
, const char *str
)
854 return ldns_str2rdf_mnemonic4int8(ldns_tlsa_matching_types
, rd
, str
);
858 ldns_str2rdf_unknown( ATTR_UNUSED(ldns_rdf
**rd
)
859 , ATTR_UNUSED(const char *str
)
862 /* this should be caught in an earlier time (general str2host for
864 return LDNS_STATUS_NOT_IMPL
;
868 ldns_str2rdf_service( ATTR_UNUSED(ldns_rdf
**rd
)
869 , ATTR_UNUSED(const char *str
)
872 /* is this used? is this actually WKS? or SRV? */
873 return LDNS_STATUS_NOT_IMPL
;
877 loc_parse_cm(char* my_str
, char** endstr
, uint8_t* m
, uint8_t* e
)
879 /* read <digits>[.<digits>][mM] */
880 /* into mantissa exponent format for LOC type */
881 uint32_t meters
= 0, cm
= 0, val
;
883 while (isblank((unsigned char)*my_str
)) {
886 meters
= (uint32_t)strtol(my_str
, &my_str
, 10);
887 if (*my_str
== '.') {
889 cm
= (uint32_t)strtol(my_str
, &cm_endstr
, 10);
890 if (cm_endstr
- my_str
== 1) cm
*= 10;
908 if (*my_str
== 'm' || *my_str
== 'M') {
916 ldns_str2rdf_loc(ldns_rdf
**rd
, const char *str
)
918 uint32_t latitude
= 0;
919 uint32_t longitude
= 0;
920 uint32_t altitude
= 0;
923 uint32_t equator
= (uint32_t) ldns_power(2, 31);
927 uint8_t size_b
= 1, size_e
= 2;
928 uint8_t horiz_pre_b
= 1, horiz_pre_e
= 6;
929 uint8_t vert_pre_b
= 1, vert_pre_e
= 3;
932 bool northern_hemisphere
;
933 bool eastern_hemisphere
;
935 char *my_str
= (char *) str
;
937 /* only support version 0 */
938 if (isdigit((int) *my_str
)) {
939 h
= (uint32_t) strtol(my_str
, &my_str
, 10);
941 return LDNS_STATUS_INVALID_STR
;
944 while (isblank((int) *my_str
)) {
948 if (isdigit((int) *my_str
)) {
949 m
= (uint32_t) strtol(my_str
, &my_str
, 10);
950 } else if (*my_str
== 'N' || *my_str
== 'S') {
953 return LDNS_STATUS_INVALID_STR
;
956 while (isblank((int) *my_str
)) {
960 if (isdigit((int) *my_str
)) {
961 s
= strtod(my_str
, &my_str
);
964 while (isblank((int) *my_str
)) {
968 if (*my_str
== 'N') {
969 northern_hemisphere
= true;
970 } else if (*my_str
== 'S') {
971 northern_hemisphere
= false;
973 return LDNS_STATUS_INVALID_STR
;
980 /* add a little to make floor in conversion a round */
982 latitude
= (uint32_t) s
;
983 latitude
+= 1000 * 60 * m
;
984 latitude
+= 1000 * 60 * 60 * h
;
985 if (northern_hemisphere
) {
986 latitude
= equator
+ latitude
;
988 latitude
= equator
- latitude
;
990 while (isblank((unsigned char)*my_str
)) {
994 if (isdigit((int) *my_str
)) {
995 h
= (uint32_t) strtol(my_str
, &my_str
, 10);
997 return LDNS_STATUS_INVALID_STR
;
1000 while (isblank((int) *my_str
)) {
1004 if (isdigit((int) *my_str
)) {
1005 m
= (uint32_t) strtol(my_str
, &my_str
, 10);
1006 } else if (*my_str
== 'E' || *my_str
== 'W') {
1009 return LDNS_STATUS_INVALID_STR
;
1012 while (isblank((unsigned char)*my_str
)) {
1016 if (isdigit((int) *my_str
)) {
1017 s
= strtod(my_str
, &my_str
);
1021 while (isblank((unsigned char)*my_str
)) {
1025 if (*my_str
== 'E') {
1026 eastern_hemisphere
= true;
1027 } else if (*my_str
== 'W') {
1028 eastern_hemisphere
= false;
1030 return LDNS_STATUS_INVALID_STR
;
1037 /* add a little to make floor in conversion a round */
1039 longitude
= (uint32_t) s
;
1040 longitude
+= 1000 * 60 * m
;
1041 longitude
+= 1000 * 60 * 60 * h
;
1043 if (eastern_hemisphere
) {
1044 longitude
+= equator
;
1046 longitude
= equator
- longitude
;
1049 altitude
= (uint32_t)(strtod(my_str
, &my_str
)*100.0 +
1051 if (*my_str
== 'm' || *my_str
== 'M') {
1055 if (strlen(my_str
) > 0) {
1056 if(!loc_parse_cm(my_str
, &my_str
, &size_b
, &size_e
))
1057 return LDNS_STATUS_INVALID_STR
;
1060 if (strlen(my_str
) > 0) {
1061 if(!loc_parse_cm(my_str
, &my_str
, &horiz_pre_b
, &horiz_pre_e
))
1062 return LDNS_STATUS_INVALID_STR
;
1065 if (strlen(my_str
) > 0) {
1066 if(!loc_parse_cm(my_str
, &my_str
, &vert_pre_b
, &vert_pre_e
))
1067 return LDNS_STATUS_INVALID_STR
;
1070 data
= LDNS_XMALLOC(uint8_t, 16);
1072 return LDNS_STATUS_MEM_ERR
;
1076 data
[1] = ((size_b
<< 4) & 0xf0) | (size_e
& 0x0f);
1077 data
[2] = ((horiz_pre_b
<< 4) & 0xf0) | (horiz_pre_e
& 0x0f);
1078 data
[3] = ((vert_pre_b
<< 4) & 0xf0) | (vert_pre_e
& 0x0f);
1079 ldns_write_uint32(data
+ 4, latitude
);
1080 ldns_write_uint32(data
+ 8, longitude
);
1081 ldns_write_uint32(data
+ 12, altitude
);
1083 *rd
= ldns_rdf_new_frm_data(
1084 LDNS_RDF_TYPE_LOC
, 16, data
);
1087 return *rd
?LDNS_STATUS_OK
:LDNS_STATUS_MEM_ERR
;
1091 ldns_str2rdf_wks(ldns_rdf
**rd
, const char *str
)
1093 uint8_t *bitmap
= NULL
;
1097 struct protoent
*proto
= NULL
;
1098 struct servent
*serv
= NULL
;
1101 ldns_buffer
*str_buf
;
1103 char *proto_str
= NULL
;
1104 char *lc_proto_str
= NULL
;
1108 if(strlen(str
) == 0)
1109 token
= LDNS_XMALLOC(char, 50);
1110 else token
= LDNS_XMALLOC(char, strlen(str
)+2);
1111 if(!token
) return LDNS_STATUS_MEM_ERR
;
1113 str_buf
= LDNS_MALLOC(ldns_buffer
);
1114 if(!str_buf
) {LDNS_FREE(token
); return LDNS_STATUS_MEM_ERR
;}
1115 ldns_buffer_new_frm_data(str_buf
, (char *)str
, strlen(str
));
1116 if(ldns_buffer_status(str_buf
) != LDNS_STATUS_OK
) {
1119 return LDNS_STATUS_MEM_ERR
;
1122 while(ldns_bget_token(str_buf
, token
, "\t\n ", strlen(str
)) > 0) {
1124 proto_str
= strdup(token
);
1125 lc_proto_str
= strdup(token
);
1126 for (c
= lc_proto_str
; *c
; c
++) {
1127 *c
= tolower((unsigned char)*c
);
1129 if (!proto_str
|| !lc_proto_str
) {
1134 ldns_buffer_free(str_buf
);
1135 return LDNS_STATUS_INVALID_STR
;
1138 serv
= getservbyname(token
, proto_str
);
1140 serv
= getservbyname(token
, lc_proto_str
);
1142 if (!serv
&& (lc_token
= strdup(token
))) {
1143 for (c
= lc_token
; *c
; c
++) {
1144 *c
= tolower((unsigned char)*c
);
1146 serv
= getservbyname(lc_token
, proto_str
);
1148 serv
= getservbyname(lc_token
, lc_proto_str
);
1153 serv_port
= (int) ntohs((uint16_t) serv
->s_port
);
1155 serv_port
= atoi(token
);
1157 if (serv_port
< 0 || serv_port
> 65535) {
1160 ldns_buffer_free(str_buf
);
1163 return LDNS_STATUS_INVALID_STR
;
1165 if (serv_port
/ 8 >= bm_len
) {
1166 uint8_t *b2
= LDNS_XREALLOC(bitmap
, uint8_t, (serv_port
/ 8) + 1);
1170 ldns_buffer_free(str_buf
);
1173 return LDNS_STATUS_INVALID_STR
;
1176 /* set to zero to be sure */
1177 for (; bm_len
<= serv_port
/ 8; bm_len
++) {
1181 ldns_set_bit(bitmap
+ (serv_port
/ 8), 7 - (serv_port
% 8), true);
1185 if (!proto_str
|| !bitmap
) {
1188 ldns_buffer_free(str_buf
);
1191 return LDNS_STATUS_INVALID_STR
;
1194 data
= LDNS_XMALLOC(uint8_t, bm_len
+ 1);
1197 ldns_buffer_free(str_buf
);
1201 return LDNS_STATUS_INVALID_STR
;
1204 proto
= getprotobyname(proto_str
);
1206 proto
= getprotobyname(lc_proto_str
);
1209 data
[0] = (uint8_t) proto
->p_proto
;
1210 } else if (proto_str
) {
1211 data
[0] = (uint8_t) atoi(proto_str
);
1213 memcpy(data
+ 1, bitmap
, (size_t) bm_len
);
1215 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_WKS
, (uint16_t) (bm_len
+ 1), data
);
1219 ldns_buffer_free(str_buf
);
1223 #ifdef HAVE_ENDSERVENT
1226 #ifdef HAVE_ENDPROTOENT
1230 if(!*rd
) return LDNS_STATUS_MEM_ERR
;
1232 return LDNS_STATUS_OK
;
1236 ldns_str2rdf_nsap(ldns_rdf
**rd
, const char *str
)
1239 char* nsap_str
= (char*) str
;
1241 /* just a hex string with optional dots? */
1242 if (str
[0] != '0' || str
[1] != 'x') {
1243 return LDNS_STATUS_INVALID_STR
;
1246 for (i
=0; i
< len
; i
++) {
1247 if (nsap_str
[i
] == '.')
1250 return ldns_str2rdf_hex(rd
, str
+2);
1255 ldns_str2rdf_atma(ldns_rdf
**rd
, const char *str
)
1258 char* atma_str
= (char*) str
;
1261 /* just a hex string with optional dots? */
1263 for (i
=0; i
< len
; i
++) {
1264 if (atma_str
[i
] == '.')
1267 status
= ldns_str2rdf_hex(rd
, str
);
1268 if (status
!= LDNS_STATUS_OK
) {
1269 ; /* probably in e.164 format than */
1275 ldns_str2rdf_ipseckey(ldns_rdf
**rd
, const char *str
)
1277 uint8_t precedence
= 0;
1278 uint8_t gateway_type
= 0;
1279 uint8_t algorithm
= 0;
1280 char* gateway
= NULL
;
1281 char* publickey
= NULL
;
1283 ldns_buffer
*str_buf
;
1285 int token_count
= 0;
1286 int ipseckey_len
= 0;
1287 ldns_rdf
* gateway_rdf
= NULL
;
1288 ldns_rdf
* publickey_rdf
= NULL
;
1289 ldns_status status
= LDNS_STATUS_OK
;
1291 if(strlen(str
) == 0)
1292 token
= LDNS_XMALLOC(char, 256);
1293 else token
= LDNS_XMALLOC(char, strlen(str
)+2);
1294 if(!token
) return LDNS_STATUS_MEM_ERR
;
1296 str_buf
= LDNS_MALLOC(ldns_buffer
);
1297 if(!str_buf
) {LDNS_FREE(token
); return LDNS_STATUS_MEM_ERR
;}
1298 ldns_buffer_new_frm_data(str_buf
, (char *)str
, strlen(str
));
1299 if(ldns_buffer_status(str_buf
) != LDNS_STATUS_OK
) {
1302 return LDNS_STATUS_MEM_ERR
;
1304 while(ldns_bget_token(str_buf
, token
, "\t\n ", strlen(str
)) > 0) {
1305 switch (token_count
) {
1307 precedence
= (uint8_t)atoi(token
);
1310 gateway_type
= (uint8_t)atoi(token
);
1313 algorithm
= (uint8_t)atoi(token
);
1316 gateway
= strdup(token
);
1317 if (!gateway
|| (gateway_type
== 0 &&
1318 (token
[0] != '.' || token
[1] != '\0'))) {
1321 ldns_buffer_free(str_buf
);
1322 return LDNS_STATUS_INVALID_STR
;
1326 publickey
= strdup(token
);
1330 ldns_buffer_free(str_buf
);
1331 return LDNS_STATUS_INVALID_STR
;
1337 if (!gateway
|| !publickey
) {
1341 LDNS_FREE(publickey
);
1343 ldns_buffer_free(str_buf
);
1344 return LDNS_STATUS_INVALID_STR
;
1347 if (gateway_type
== 1) {
1348 status
= ldns_str2rdf_a(&gateway_rdf
, gateway
);
1349 } else if (gateway_type
== 2) {
1350 status
= ldns_str2rdf_aaaa(&gateway_rdf
, gateway
);
1351 } else if (gateway_type
== 3) {
1352 status
= ldns_str2rdf_dname(&gateway_rdf
, gateway
);
1353 } else if (gateway_type
> 3) {
1354 status
= LDNS_STATUS_INVALID_STR
;
1357 if (status
!= LDNS_STATUS_OK
) {
1361 LDNS_FREE(publickey
);
1363 ldns_buffer_free(str_buf
);
1364 return LDNS_STATUS_INVALID_STR
;
1367 status
= ldns_str2rdf_b64(&publickey_rdf
, publickey
);
1369 if (status
!= LDNS_STATUS_OK
) {
1373 LDNS_FREE(publickey
);
1375 ldns_buffer_free(str_buf
);
1376 if (gateway_rdf
) ldns_rdf_free(gateway_rdf
);
1377 return LDNS_STATUS_INVALID_STR
;
1380 /* now copy all into one ipseckey rdf */
1382 ipseckey_len
= 3 + (int)ldns_rdf_size(gateway_rdf
) + (int)ldns_rdf_size(publickey_rdf
);
1384 ipseckey_len
= 3 + (int)ldns_rdf_size(publickey_rdf
);
1386 data
= LDNS_XMALLOC(uint8_t, ipseckey_len
);
1391 LDNS_FREE(publickey
);
1393 ldns_buffer_free(str_buf
);
1394 if (gateway_rdf
) ldns_rdf_free(gateway_rdf
);
1395 if (publickey_rdf
) ldns_rdf_free(publickey_rdf
);
1396 return LDNS_STATUS_MEM_ERR
;
1399 data
[0] = precedence
;
1400 data
[1] = gateway_type
;
1401 data
[2] = algorithm
;
1405 ldns_rdf_data(gateway_rdf
), ldns_rdf_size(gateway_rdf
));
1406 memcpy(data
+ 3 + ldns_rdf_size(gateway_rdf
),
1407 ldns_rdf_data(publickey_rdf
), ldns_rdf_size(publickey_rdf
));
1410 ldns_rdf_data(publickey_rdf
), ldns_rdf_size(publickey_rdf
));
1413 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_IPSECKEY
, (uint16_t) ipseckey_len
, data
);
1418 LDNS_FREE(publickey
);
1420 ldns_buffer_free(str_buf
);
1421 ldns_rdf_deep_free(gateway_rdf
);
1422 ldns_rdf_deep_free(publickey_rdf
);
1424 if(!*rd
) return LDNS_STATUS_MEM_ERR
;
1425 return LDNS_STATUS_OK
;
1429 ldns_str2rdf_ilnp64(ldns_rdf
**rd
, const char *str
)
1431 unsigned int a
, b
, c
, d
;
1435 if (sscanf(str
, "%4x:%4x:%4x:%4x%n", &a
, &b
, &c
, &d
, &l
) != 4 ||
1436 l
!= (int)strlen(str
) || /* more data to read */
1437 strpbrk(str
, "+-") /* signed hexes */
1439 return LDNS_STATUS_INVALID_ILNP64
;
1441 shorts
[0] = htons(a
);
1442 shorts
[1] = htons(b
);
1443 shorts
[2] = htons(c
);
1444 shorts
[3] = htons(d
);
1445 *rd
= ldns_rdf_new_frm_data(
1446 LDNS_RDF_TYPE_ILNP64
, 4 * sizeof(uint16_t), &shorts
);
1448 return *rd
? LDNS_STATUS_OK
: LDNS_STATUS_MEM_ERR
;
1452 ldns_str2rdf_eui48(ldns_rdf
**rd
, const char *str
)
1454 unsigned int a
, b
, c
, d
, e
, f
;
1458 if (sscanf(str
, "%2x-%2x-%2x-%2x-%2x-%2x%n",
1459 &a
, &b
, &c
, &d
, &e
, &f
, &l
) != 6 ||
1460 l
!= (int)strlen(str
)) {
1461 return LDNS_STATUS_INVALID_EUI48
;
1469 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI48
, 6, &bytes
);
1471 return *rd
? LDNS_STATUS_OK
: LDNS_STATUS_MEM_ERR
;
1475 ldns_str2rdf_eui64(ldns_rdf
**rd
, const char *str
)
1477 unsigned int a
, b
, c
, d
, e
, f
, g
, h
;
1481 if (sscanf(str
, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n",
1482 &a
, &b
, &c
, &d
, &e
, &f
, &g
, &h
, &l
) != 8 ||
1483 l
!= (int)strlen(str
)) {
1484 return LDNS_STATUS_INVALID_EUI64
;
1494 *rd
= ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI64
, 8, &bytes
);
1496 return *rd
? LDNS_STATUS_OK
: LDNS_STATUS_MEM_ERR
;
1500 ldns_str2rdf_tag(ldns_rdf
**rd
, const char *str
)
1505 if (strlen(str
) > 255) {
1506 return LDNS_STATUS_INVALID_TAG
;
1508 for (ptr
= str
; *ptr
; ptr
++) {
1509 if (! isalnum((unsigned char)*ptr
)) {
1510 return LDNS_STATUS_INVALID_TAG
;
1513 data
= LDNS_XMALLOC(uint8_t, strlen(str
) + 1);
1515 return LDNS_STATUS_MEM_ERR
;
1517 data
[0] = strlen(str
);
1518 memcpy(data
+ 1, str
, strlen(str
));
1520 *rd
= ldns_rdf_new(LDNS_RDF_TYPE_TAG
, strlen(str
) + 1, data
);
1523 return LDNS_STATUS_MEM_ERR
;
1525 return LDNS_STATUS_OK
;
1529 ldns_str2rdf_long_str(ldns_rdf
**rd
, const char *str
)
1531 uint8_t *data
, *dp
, ch
= 0;
1534 /* Worst case space requirement. We'll realloc to actual size later. */
1535 dp
= data
= LDNS_XMALLOC(uint8_t, strlen(str
));
1537 return LDNS_STATUS_MEM_ERR
;
1540 /* Fill data with parsed bytes */
1541 while (parse_char(&ch
, &str
)) {
1543 if (dp
- data
> LDNS_MAX_RDFLEN
) {
1545 return LDNS_STATUS_INVALID_STR
;
1550 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
1552 if (!(length
= (size_t)(dp
- data
))) {
1553 /* An empty string is a data buffer of 0 bytes. The rdf for
1554 * this long string has to have length 0 and point to NULL.
1559 /* Lose the overmeasure */
1560 data
= LDNS_XREALLOC(dp
= data
, uint8_t, length
);
1563 return LDNS_STATUS_MEM_ERR
;
1567 *rd
= ldns_rdf_new(LDNS_RDF_TYPE_LONG_STR
, length
, data
);
1570 return LDNS_STATUS_MEM_ERR
;
1572 return LDNS_STATUS_OK
;
1576 ldns_str2rdf_hip(ldns_rdf
**rd
, const char *str
)
1578 const char *hit
= str
== NULL
? NULL
: strchr(str
, ' ');
1579 const char *pk
= hit
== NULL
? NULL
: strchr(hit
+ 1, ' ');
1580 size_t hit_size
= hit
== NULL
? 0
1581 : pk
== NULL
? strlen(hit
+ 1) : (size_t) (pk
- hit
) - 1;
1582 size_t pk_size
= pk
== NULL
? 0 : strlen(pk
+ 1);
1583 size_t hit_wire_size
= (hit_size
+ 1) / 2;
1584 size_t pk_wire_size
= ldns_b64_pton_calculate_size(pk_size
);
1585 size_t rdf_size
= 4 + hit_wire_size
+ pk_wire_size
;
1587 char *endptr
; /* utility var for strtol usage */
1588 int algorithm
= str
== NULL
? 0 : strtol(str
, &endptr
, 10);
1591 int hi
, lo
, written
;
1593 if (hit_size
== 0 || pk_size
== 0 || (hit_size
+ 1) / 2 > 255
1594 || rdf_size
> LDNS_MAX_RDFLEN
1595 || algorithm
< 0 || algorithm
> 255
1596 || (errno
!= 0 && algorithm
== 0) /* out of range */
1597 || endptr
== str
/* no digits */) {
1599 return LDNS_STATUS_SYNTAX_ERR
;
1603 if ((data
= LDNS_XMALLOC(uint8_t, rdf_size
)) == NULL
) {
1605 return LDNS_STATUS_MEM_ERR
;
1607 /* From RFC 5205 section 5. HIP RR Storage Format:
1608 *************************************************
1611 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1612 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1613 | HIT length | PK algorithm | PK length |
1614 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1618 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1620 +-+-+-+-+-+-+-+-+-+-+-+ +
1624 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1626 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
1628 ~ Rendezvous Servers ~
1630 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1634 data
[0] = (uint8_t) hit_wire_size
;
1635 data
[1] = (uint8_t) algorithm
;
1637 for (dp
= data
+ 4; *hit
&& *hit
!= ' '; dp
++) {
1639 if ((hi
= ldns_hexdigit_to_int(*hit
++)) == -1 ||
1640 (lo
= ldns_hexdigit_to_int(*hit
++)) == -1) {
1643 return LDNS_STATUS_INVALID_HEX
;
1645 *dp
= (uint8_t) hi
<< 4 | lo
;
1647 if ((written
= ldns_b64_pton(pk
, dp
, pk_wire_size
)) <= 0) {
1650 return LDNS_STATUS_INVALID_B64
;
1653 /* Because ldns_b64_pton_calculate_size isn't always correct:
1654 * (we have to fix it at some point)
1656 pk_wire_size
= (uint16_t) written
;
1657 ldns_write_uint16(data
+ 2, pk_wire_size
);
1658 rdf_size
= 4 + hit_wire_size
+ pk_wire_size
;
1661 if (! (*rd
= ldns_rdf_new(LDNS_RDF_TYPE_HIP
, rdf_size
, data
))) {
1664 return LDNS_STATUS_MEM_ERR
;
1666 return LDNS_STATUS_OK
;
1670 /* Implementation mimics ldns_str2rdf_ipseckey */
1672 ldns_str2rdf_amtrelay(ldns_rdf
**rd
, const char *str
)
1674 /* From draft-ietf-mboned-driad-amt-discovery
1675 * Section 4.2. AMTRELAY RData Format
1676 *************************************************
1679 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1680 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1681 | precedence |D| type | |
1682 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
1684 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
1686 uint8_t precedence
= 0;
1687 uint8_t relay_type
= 0;
1688 uint8_t discovery_optional
= 0;
1691 ldns_buffer
*str_buf
;
1693 int token_count
= 0;
1694 int amtrelay_len
= 0;
1695 ldns_rdf
* relay_rdf
= NULL
;
1696 ldns_status status
= LDNS_STATUS_OK
;
1698 if(strlen(str
) == 0)
1699 token
= LDNS_XMALLOC(char, 256);
1700 else token
= LDNS_XMALLOC(char, strlen(str
)+2);
1701 if(!token
) return LDNS_STATUS_MEM_ERR
;
1703 str_buf
= LDNS_MALLOC(ldns_buffer
);
1704 if(!str_buf
) {LDNS_FREE(token
); return LDNS_STATUS_MEM_ERR
;}
1705 ldns_buffer_new_frm_data(str_buf
, (char *)str
, strlen(str
));
1706 if(ldns_buffer_status(str_buf
) != LDNS_STATUS_OK
) {
1709 return LDNS_STATUS_MEM_ERR
;
1711 while(ldns_bget_token(str_buf
, token
, "\t\n ", strlen(str
)) > 0) {
1712 switch (token_count
) {
1714 precedence
= (uint8_t)atoi(token
);
1717 discovery_optional
= (uint8_t)atoi(token
);
1718 if (discovery_optional
!= 0 &&
1719 discovery_optional
!= 1) {
1722 ldns_buffer_free(str_buf
);
1723 return LDNS_STATUS_INVALID_STR
;
1727 relay_type
= (uint8_t)atoi(token
);
1730 relay
= strdup(token
);
1731 if (!relay
|| (relay_type
== 0 &&
1732 (token
[0] != '.' || token
[1] != '\0'))) {
1735 ldns_buffer_free(str_buf
);
1736 return LDNS_STATUS_INVALID_STR
;
1741 ldns_buffer_free(str_buf
);
1742 return LDNS_STATUS_INVALID_STR
;
1747 if (!relay
&& relay_type
> 0) {
1751 ldns_buffer_free(str_buf
);
1752 return LDNS_STATUS_INVALID_STR
;
1755 if (relay_type
== 1) {
1756 status
= ldns_str2rdf_a(&relay_rdf
, relay
);
1757 } else if (relay_type
== 2) {
1758 status
= ldns_str2rdf_aaaa(&relay_rdf
, relay
);
1759 } else if (relay_type
== 3) {
1760 status
= ldns_str2rdf_dname(&relay_rdf
, relay
);
1761 } else if (relay_type
> 3) {
1762 status
= LDNS_STATUS_INVALID_STR
;
1765 if (status
!= LDNS_STATUS_OK
) {
1769 ldns_buffer_free(str_buf
);
1770 return LDNS_STATUS_INVALID_STR
;
1773 /* now copy all into one amtrelay rdf */
1775 amtrelay_len
= 2 + (int)ldns_rdf_size(relay_rdf
);
1779 data
= LDNS_XMALLOC(uint8_t, amtrelay_len
);
1784 ldns_buffer_free(str_buf
);
1785 if (relay_rdf
) ldns_rdf_free(relay_rdf
);
1786 return LDNS_STATUS_MEM_ERR
;
1789 data
[0] = precedence
;
1790 data
[1] = relay_type
;
1791 data
[1] |= (discovery_optional
<< 7);
1795 ldns_rdf_data(relay_rdf
), ldns_rdf_size(relay_rdf
));
1797 *rd
= ldns_rdf_new_frm_data( LDNS_RDF_TYPE_AMTRELAY
1798 , (uint16_t) amtrelay_len
, data
);
1803 ldns_buffer_free(str_buf
);
1804 ldns_rdf_free(relay_rdf
);
1806 if(!*rd
) return LDNS_STATUS_MEM_ERR
;
1807 return LDNS_STATUS_OK
;
1810 #ifdef RRTYPE_SVCB_HTTPS
1812 network_uint16_cmp(const void *a
, const void *b
)
1814 return ((int)ldns_read_uint16(a
)) - ((int)ldns_read_uint16(b
));
1817 static ldns_status
parse_svcparam_key(const char **s
, ldns_svcparam_key
*key
);
1819 parse_svcparam_mandatory(const char **s
, uint8_t **dp
, uint8_t *eod
)
1821 bool quoted
= false;
1822 uint8_t *keys
= *dp
;
1831 ldns_svcparam_key key
;
1833 if ((st
= parse_svcparam_key(s
, &key
)))
1837 return LDNS_STATUS_RDATA_OVERFLOW
;
1839 ldns_write_uint16(*dp
, key
);
1849 return LDNS_STATUS_INVALID_STR
;
1852 if (*dp
- keys
== 0)
1853 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
1855 if (**s
&& !isspace((unsigned char)**s
))
1856 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
1858 /* In draft-ietf-dnsop-svcb-https-02 Section 7:
1860 * In wire format, the keys are represented by their numeric
1861 * values in network byte order, concatenated in ascending order.
1863 qsort(keys
, (*dp
- keys
) / 2, 2, network_uint16_cmp
);
1865 /* In draft-ietf-dnsop-svcb-https-02 Section 7:
1867 * Keys ...<snip>... MUST NOT appear more than once.
1870 while (keys
< *dp
) {
1871 uint16_t key
= ldns_read_uint16(keys
);
1873 if (key
== prev_key
) {
1874 /* "Be conservative in what you send,
1875 * be liberal in what you accept"
1878 * `return LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE;`,
1880 * we eliminate the double occurrence.
1882 memmove(keys
- 2, keys
, *dp
- keys
);
1889 return LDNS_STATUS_OK
;
1892 INLINE
bool parse_escape2(uint8_t *ch_p
, const char** str_p
)
1893 { *str_p
+= 1; return parse_escape(ch_p
, str_p
); }
1896 parse_svcparam_alpn(const char **s
, uint8_t **dp
, uint8_t *eod
)
1902 return LDNS_STATUS_RDATA_OVERFLOW
;
1907 while (**s
!= '"') {
1909 return LDNS_STATUS_INVALID_STR
;
1911 else if (**s
== ',') {
1913 if (len
== 0 || len
> 255)
1914 return LDNS_STATUS_INVALID_STR
;
1917 return LDNS_STATUS_RDATA_OVERFLOW
;
1922 } else if (*dp
+ 1 > eod
)
1923 return LDNS_STATUS_RDATA_OVERFLOW
;
1925 else if (**s
!= '\\')
1926 *(*dp
)++ = (uint8_t)*(*s
)++;
1928 else if (!parse_escape2(*dp
, s
))
1929 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
1935 } else while (**s
&& !isspace((unsigned char)**s
)) {
1938 if (len
== 0 || len
> 255)
1939 return LDNS_STATUS_INVALID_STR
;
1942 return LDNS_STATUS_RDATA_OVERFLOW
;
1947 } else if (*dp
+ 1 > eod
)
1948 return LDNS_STATUS_RDATA_OVERFLOW
;
1950 else if (**s
!= '\\')
1951 *(*dp
)++ = (uint8_t)*(*s
)++;
1953 else if (!parse_escape2(*dp
, s
))
1954 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
1959 if (len
== 0 || len
> 255)
1960 return LDNS_STATUS_INVALID_STR
;
1962 return **s
&& !isspace((unsigned char)**s
)
1963 ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
1968 parse_svcparam_value(const char **s
, uint8_t **dp
, uint8_t *eod
)
1972 while (**s
!= '"') {
1974 return LDNS_STATUS_INVALID_STR
;
1976 else if (*dp
+ 1 > eod
)
1977 return LDNS_STATUS_RDATA_OVERFLOW
;
1979 else if (**s
!= '\\')
1980 *(*dp
)++ = (uint8_t)*(*s
)++;
1982 else if (!parse_escape2(*dp
, s
))
1983 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
1989 } else while (**s
&& !isspace((unsigned char)**s
)) {
1991 return LDNS_STATUS_RDATA_OVERFLOW
;
1993 else if (**s
!= '\\')
1994 *(*dp
)++ = (uint8_t)*(*s
)++;
1996 else if (!parse_escape2(*dp
, s
))
1997 return LDNS_STATUS_SYNTAX_BAD_ESCAPE
;
2001 return **s
&& !isspace((unsigned char)**s
)
2002 ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
2007 parse_svcparam_port(const char **s
, uint8_t **dp
, uint8_t *eod
)
2014 unsigned long int num
;
2016 if ((st
= parse_svcparam_value(s
, dp
, eod
)))
2019 if (len
== 0 || len
> 5)
2020 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2022 memcpy(num_str
, val
, len
);
2024 num
= strtoul(num_str
, &endptr
, 10);
2026 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2028 ldns_write_uint16(val
, num
);
2030 return LDNS_STATUS_OK
;
2034 parse_svcparam_ipv4hint(const char **s
, uint8_t **dp
, uint8_t *eod
)
2036 bool quoted
= false;
2043 const char *ipv4_start
= *s
;
2047 while (isdigit((unsigned char)**s
) || **s
== '.')
2050 len
= *s
- ipv4_start
;
2051 if (len
== 0 || len
> 15)
2052 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2055 return LDNS_STATUS_RDATA_OVERFLOW
;
2057 memcpy(ipv4_str
, ipv4_start
, len
);
2059 if (inet_pton(AF_INET
, ipv4_str
, *dp
) != 1)
2060 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2070 return LDNS_STATUS_INVALID_STR
;
2073 return **s
&& !isspace((unsigned char)**s
)
2074 ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
2079 parse_svcparam_ech(const char **s
, uint8_t **dp
, uint8_t *eod
)
2081 bool quoted
= false;
2082 const char *b64_str
;
2083 size_t len
, pad
, out_len
;
2093 while (isalnum((unsigned char)**s
) || **s
== '+'
2100 pad
= pad
? 4 - pad
: 0;
2101 if (len
== 0 || pad
== 3)
2102 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2106 return LDNS_STATUS_INVALID_STR
;
2109 if (**s
&& !isspace((unsigned char)**s
))
2110 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2112 out_len
= ldns_b64_pton_calculate_size(len
);
2113 if (*dp
+ out_len
> eod
)
2114 return LDNS_STATUS_RDATA_OVERFLOW
;
2116 if (len
+ pad
> sizeof(in_buf
) - 1
2117 && !(in
= LDNS_XMALLOC(char, len
+ pad
+ 1)))
2118 return LDNS_STATUS_MEM_ERR
;
2120 memcpy(in
, b64_str
, len
);
2124 out
= ldns_b64_pton(in
, *dp
, out_len
);
2129 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2132 return LDNS_STATUS_OK
;
2136 parse_svcparam_ipv6hint(const char **s
, uint8_t **dp
, uint8_t *eod
)
2138 bool quoted
= false;
2145 const char *ipv6_start
= *s
;
2146 char ipv6_str
[INET6_ADDRSTRLEN
];
2149 while (isxdigit((unsigned char)**s
) || **s
== ':' || **s
== '.')
2152 len
= *s
- ipv6_start
;
2153 if (len
== 0 || len
> INET6_ADDRSTRLEN
)
2154 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2157 return LDNS_STATUS_RDATA_OVERFLOW
;
2159 memcpy(ipv6_str
, ipv6_start
, len
);
2161 if (inet_pton(AF_INET6
, ipv6_str
, *dp
) != 1)
2162 return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
;
2172 return LDNS_STATUS_INVALID_STR
;
2175 return **s
&& !isspace((unsigned char)**s
)
2176 ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
2180 struct struct_svcparam_key_def
{
2184 typedef struct struct_svcparam_key_def svcparam_key_def
;
2186 static svcparam_key_def svcparam_key_defs
[] = { { "mandatory" , 9 }
2188 , { "no-default-alpn", 15 }
2190 , { "ipv4hint" , 8 }
2192 , { "ipv6hint" , 8 }
2193 , { "dohpath" , 7 } };
2195 static const size_t svcparam_key_defs_len
= sizeof(svcparam_key_defs
)
2196 / sizeof(svcparam_key_def
);
2198 /* svcparam_key2buffer_str() should actually be in host2str.c, but we need the
2199 * svcparam_key_defs for it and it is not an exposed symbol anyway.
2201 ldns_status
svcparam_key2buffer_str(ldns_buffer
*output
, uint16_t key
)
2203 if (key
<= LDNS_SVCPARAM_KEY_LAST_KEY
)
2204 ldns_buffer_write_string(output
, svcparam_key_defs
[key
].str
);
2206 ldns_buffer_printf(output
, "key%d", (int)key
);
2207 return ldns_buffer_status(output
);
2211 parse_svcparam_key(const char **s
, ldns_svcparam_key
*key
)
2214 const char *key_str
= *s
;
2217 unsigned long int num
;
2220 while (islower((unsigned char)**s
) || isdigit((unsigned char)**s
)
2225 for (i
= 0; i
< svcparam_key_defs_len
; i
++) {
2226 if (len
== svcparam_key_defs
[i
].len
2227 && !strncmp(key_str
, svcparam_key_defs
[i
].str
, len
)) {
2229 return LDNS_STATUS_OK
;
2232 /* Also allow "echconfig" from earlier draft versions. */
2233 if (len
== 9 && !strncmp(key_str
, "echconfig", 9)) {
2234 *key
= LDNS_SVCPARAM_KEY_ECH
;
2235 return LDNS_STATUS_OK
;
2237 if (len
< 4 || len
> 8 || strncmp(key_str
, "key", 3))
2238 return LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR
;
2240 memcpy(num_str
, key_str
+ 3, len
- 3);
2241 num_str
[len
- 3] = 0;
2242 num
= strtoul(num_str
, &endptr
, 10);
2243 if (*endptr
|| num
> 65535)
2244 return LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR
;
2246 /* key65535 is Reserved to be an ("Invalid key"), though there is no
2247 * physiological reason to deny usage. We restrict ourselves to the
2248 * anatomical limitations only to maximize serviceability.
2251 * return LDNS_STATUS_RESERVED_SVCPARAM_KEY;
2255 return LDNS_STATUS_OK
;
2259 parse_svcparam(const char **s
, uint8_t **dp
, uint8_t *eod
)
2261 ldns_svcparam_key key
;
2266 return LDNS_STATUS_RDATA_OVERFLOW
;
2268 if ((st
= parse_svcparam_key(s
, &key
)))
2271 ldns_write_uint16(*dp
, key
);
2272 ldns_write_uint16(*dp
+ 2, 0);
2274 if (isspace((unsigned char)**s
) || !**s
)
2275 return LDNS_STATUS_OK
;
2277 else if (**s
!= '=')
2278 return LDNS_STATUS_SYNTAX_ERR
;
2282 case LDNS_SVCPARAM_KEY_MANDATORY
:
2283 st
= parse_svcparam_mandatory(s
, dp
, eod
);
2285 case LDNS_SVCPARAM_KEY_ALPN
:
2286 st
= parse_svcparam_alpn(s
, dp
, eod
);
2288 case LDNS_SVCPARAM_KEY_NO_DEFAULT_ALPN
:
2289 return LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED
;
2290 case LDNS_SVCPARAM_KEY_PORT
:
2291 st
= parse_svcparam_port(s
, dp
, eod
);
2293 case LDNS_SVCPARAM_KEY_IPV4HINT
:
2294 st
= parse_svcparam_ipv4hint(s
, dp
, eod
);
2296 case LDNS_SVCPARAM_KEY_ECH
:
2297 st
= parse_svcparam_ech(s
, dp
, eod
);
2299 case LDNS_SVCPARAM_KEY_IPV6HINT
:
2300 st
= parse_svcparam_ipv6hint(s
, dp
, eod
);
2303 st
= parse_svcparam_value(s
, dp
, eod
);
2308 ldns_write_uint16(val
- 2, *dp
- val
);
2309 return LDNS_STATUS_OK
;
2313 svcparam_ptr_cmp(const void *a
, const void *b
)
2315 uint8_t *x
= *(uint8_t **)a
, *y
= *(uint8_t **)b
;
2316 uint16_t x_type
= ldns_read_uint16(x
), y_type
= ldns_read_uint16(y
);
2317 uint16_t x_len
, y_len
;
2319 if (x_type
!= y_type
)
2320 return x_type
> y_type
? 1 : -1;
2322 x_len
= ldns_read_uint16(x
+ 2);
2323 y_len
= ldns_read_uint16(y
+ 2);
2325 return x_len
!= y_len
2326 ? (x_len
> y_len
? 1 : -1)
2327 : (x_len
== 0 ? 0 : memcmp(x
+ 4, y
+ 4, x_len
));
2331 ldns_str2rdf_svcparams(ldns_rdf
**rd
, const char *str
)
2333 uint8_t *data
, *dp
, *eod
, *p
, *new_data
;
2334 ldns_status st
= LDNS_STATUS_OK
;
2337 uint8_t **svcparams
;
2341 return LDNS_STATUS_NULL
;
2343 length
= strlen(str
);
2344 /* Worst case space requirement. We'll realloc to actual size later. */
2345 if (!(dp
= data
= LDNS_XMALLOC(uint8_t, length
* 4)))
2346 return LDNS_STATUS_MEM_ERR
;
2347 eod
= data
+ length
* 4;
2349 /* Fill data with parsed bytes */
2351 while (isspace((unsigned char)*str
))
2355 if ((st
= parse_svcparam(&str
, &dp
, eod
))) {
2362 /* draft-ietf-dnsop-svcb-https-02 in Section 2.2:
2364 * SvcParamKeys SHALL appear in increasing numeric order
2366 * A svcparams array (with pointers to the individual key, value pairs)
2367 * is created to qsort the pairs in increasing numeric order.
2369 if (!(svcparams
= LDNS_XMALLOC(uint8_t *, nparams
))) {
2371 return LDNS_STATUS_MEM_ERR
;
2373 for ( p
= data
, i
= 0
2374 ; p
< dp
&& i
< nparams
2375 ; p
+= 4 + ldns_read_uint16(p
+ 2))
2378 qsort(svcparams
, i
, sizeof(uint8_t *), svcparam_ptr_cmp
);
2380 /* Write out the (key, value) pairs to a newly allocated data in
2384 if (!(new_data
= LDNS_XMALLOC(uint8_t, length
))) {
2386 LDNS_FREE(svcparams
);
2387 return LDNS_STATUS_MEM_ERR
;
2390 for ( p
= new_data
, i
= 0
2391 ; p
< new_data
+ length
&& i
< nparams
2392 ; p
+= 4 + ldns_read_uint16(p
+ 2), i
+= 1) {
2393 uint16_t key
= ldns_read_uint16(svcparams
[i
]);
2395 /* In draft-ietf-dnsop-svcb-https-02 Section 2.1:
2397 * SvcParams ...<snip>... keys MUST NOT be repeated.
2399 * ldns will not impose this limitation on the library user,
2400 * but we can merge completely equal repetitions into one.
2403 * if (key == prev_key)
2404 * return LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE;
2408 if (key
== prev_key
&& ldns_read_uint16(svcparams
[i
] + 2)
2409 == ldns_read_uint16(svcparams
[i
- 1] + 2)
2410 && 0 == memcmp( svcparams
[i
] + 4
2411 , svcparams
[i
- 1] + 4
2412 , ldns_read_uint16(svcparams
[i
] + 2))) {
2413 p
-= 4 + ldns_read_uint16(svcparams
[i
] + 2);
2416 memcpy(p
, svcparams
[i
], 4 + ldns_read_uint16(svcparams
[i
] + 2));
2420 LDNS_FREE(svcparams
);
2423 *rd
= ldns_rdf_new(LDNS_RDF_TYPE_SVCPARAMS
, p
- new_data
, new_data
);
2425 LDNS_FREE(new_data
);
2426 return LDNS_STATUS_MEM_ERR
;
2428 return LDNS_STATUS_OK
;
2430 #else /* #ifdef RRTYPE_SVCB_HTTPS */
2432 ldns_str2rdf_svcparams(ldns_rdf
**rd
, const char *str
)
2434 (void)rd
; (void)str
;
2435 return LDNS_STATUS_NOT_IMPL
;
2437 #endif /* #ifdef RRTYPE_SVCB_HTTPS */