aboutsummaryrefslogtreecommitdiff
path: root/sldns
diff options
context:
space:
mode:
Diffstat (limited to 'sldns')
-rw-r--r--sldns/keyraw.c370
-rw-r--r--sldns/keyraw.h112
-rw-r--r--sldns/parse.c470
-rw-r--r--sldns/parse.h184
-rw-r--r--sldns/parseutil.c726
-rw-r--r--sldns/parseutil.h148
-rw-r--r--sldns/pkthdr.h158
-rw-r--r--sldns/rrdef.c728
-rw-r--r--sldns/rrdef.h502
-rw-r--r--sldns/sbuffer.c178
-rw-r--r--sldns/sbuffer.h706
-rw-r--r--sldns/str2wire.c2023
-rw-r--r--sldns/str2wire.h541
-rw-r--r--sldns/wire2str.c1967
-rw-r--r--sldns/wire2str.h984
15 files changed, 9797 insertions, 0 deletions
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
new file mode 100644
index 000000000000..59e8000f5abf
--- /dev/null
+++ b/sldns/keyraw.c
@@ -0,0 +1,370 @@
+/*
+ * keyraw.c - raw key operations and conversions
+ *
+ * (c) NLnet Labs, 2004-2008
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ * Implementation of raw DNSKEY functions (work on wire rdata).
+ */
+
+#include "config.h"
+#include "sldns/keyraw.h"
+#include "sldns/rrdef.h"
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+# include <openssl/engine.h>
+#endif
+#endif /* HAVE_SSL */
+
+size_t
+sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
+ const size_t len, int alg)
+{
+ /* for DSA keys */
+ uint8_t t;
+
+ /* for RSA keys */
+ uint16_t exp;
+ uint16_t int16;
+
+ switch ((sldns_algorithm)alg) {
+ case LDNS_DSA:
+ case LDNS_DSA_NSEC3:
+ if (len > 0) {
+ t = keydata[0];
+ return (64 + t*8)*8;
+ } else {
+ return 0;
+ }
+ break;
+ case LDNS_RSAMD5:
+ case LDNS_RSASHA1:
+ case LDNS_RSASHA1_NSEC3:
+#ifdef USE_SHA2
+ case LDNS_RSASHA256:
+ case LDNS_RSASHA512:
+#endif
+ if (len > 0) {
+ if (keydata[0] == 0) {
+ /* big exponent */
+ if (len > 3) {
+ memmove(&int16, keydata + 1, 2);
+ exp = ntohs(int16);
+ return (len - exp - 3)*8;
+ } else {
+ return 0;
+ }
+ } else {
+ exp = keydata[0];
+ return (len-exp-1)*8;
+ }
+ } else {
+ return 0;
+ }
+ break;
+#ifdef USE_GOST
+ case LDNS_ECC_GOST:
+ return 512;
+#endif
+#ifdef USE_ECDSA
+ case LDNS_ECDSAP256SHA256:
+ return 256;
+ case LDNS_ECDSAP384SHA384:
+ return 384;
+#endif
+ default:
+ return 0;
+ }
+}
+
+uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize)
+{
+ if(keysize < 4) {
+ return 0;
+ }
+ /* look at the algorithm field, copied from 2535bis */
+ if (key[3] == LDNS_RSAMD5) {
+ uint16_t ac16 = 0;
+ if (keysize > 4) {
+ memmove(&ac16, key + keysize - 3, 2);
+ }
+ ac16 = ntohs(ac16);
+ return (uint16_t) ac16;
+ } else {
+ size_t i;
+ uint32_t ac32 = 0;
+ for (i = 0; i < keysize; ++i) {
+ ac32 += (i & 1) ? key[i] : key[i] << 8;
+ }
+ ac32 += (ac32 >> 16) & 0xFFFF;
+ return (uint16_t) (ac32 & 0xFFFF);
+ }
+}
+
+#ifdef HAVE_SSL
+#ifdef USE_GOST
+/** store GOST engine reference loaded into OpenSSL library */
+ENGINE* sldns_gost_engine = NULL;
+
+int
+sldns_key_EVP_load_gost_id(void)
+{
+ static int gost_id = 0;
+ const EVP_PKEY_ASN1_METHOD* meth;
+ ENGINE* e;
+
+ if(gost_id) return gost_id;
+
+ /* see if configuration loaded gost implementation from other engine*/
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
+ if(meth) {
+ EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+ return gost_id;
+ }
+
+ /* see if engine can be loaded already */
+ e = ENGINE_by_id("gost");
+ if(!e) {
+ /* load it ourself, in case statically linked */
+ ENGINE_load_builtin_engines();
+ ENGINE_load_dynamic();
+ e = ENGINE_by_id("gost");
+ }
+ if(!e) {
+ /* no gost engine in openssl */
+ return 0;
+ }
+ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
+ ENGINE_finish(e);
+ ENGINE_free(e);
+ return 0;
+ }
+
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
+ if(!meth) {
+ /* algo not found */
+ ENGINE_finish(e);
+ ENGINE_free(e);
+ return 0;
+ }
+ /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
+ * on some platforms this frees up the meth and unloads gost stuff */
+ sldns_gost_engine = e;
+
+ EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+ return gost_id;
+}
+
+void sldns_key_EVP_unload_gost(void)
+{
+ if(sldns_gost_engine) {
+ ENGINE_finish(sldns_gost_engine);
+ ENGINE_free(sldns_gost_engine);
+ sldns_gost_engine = NULL;
+ }
+}
+#endif /* USE_GOST */
+
+DSA *
+sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
+{
+ uint8_t T;
+ uint16_t length;
+ uint16_t offset;
+ DSA *dsa;
+ BIGNUM *Q; BIGNUM *P;
+ BIGNUM *G; BIGNUM *Y;
+
+ if(len == 0)
+ return NULL;
+ T = (uint8_t)key[0];
+ length = (64 + T * 8);
+ offset = 1;
+
+ if (T > 8) {
+ return NULL;
+ }
+ if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
+ return NULL;
+
+ Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
+ offset += SHA_DIGEST_LENGTH;
+
+ P = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ G = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ Y = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ /* create the key and set its properties */
+ if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
+ BN_free(Q);
+ BN_free(P);
+ BN_free(G);
+ BN_free(Y);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ dsa->p = P;
+ dsa->q = Q;
+ dsa->g = G;
+ dsa->pub_key = Y;
+#endif /* splint */
+
+ return dsa;
+}
+
+RSA *
+sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
+{
+ uint16_t offset;
+ uint16_t exp;
+ uint16_t int16;
+ RSA *rsa;
+ BIGNUM *modulus;
+ BIGNUM *exponent;
+
+ if (len == 0)
+ return NULL;
+ if (key[0] == 0) {
+ if(len < 3)
+ return NULL;
+ memmove(&int16, key+1, 2);
+ exp = ntohs(int16);
+ offset = 3;
+ } else {
+ exp = key[0];
+ offset = 1;
+ }
+
+ /* key length at least one */
+ if(len < (size_t)offset + exp + 1)
+ return NULL;
+
+ /* Exponent */
+ exponent = BN_new();
+ if(!exponent) return NULL;
+ (void) BN_bin2bn(key+offset, (int)exp, exponent);
+ offset += exp;
+
+ /* Modulus */
+ modulus = BN_new();
+ if(!modulus) {
+ BN_free(exponent);
+ return NULL;
+ }
+ /* length of the buffer must match the key length! */
+ (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
+
+ rsa = RSA_new();
+ if(!rsa) {
+ BN_free(exponent);
+ BN_free(modulus);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ rsa->n = modulus;
+ rsa->e = exponent;
+#endif /* splint */
+
+ return rsa;
+}
+
+#ifdef USE_GOST
+EVP_PKEY*
+sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
+{
+ /* prefix header for X509 encoding */
+ uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
+ 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
+ unsigned char encoded[37+64];
+ const unsigned char* pp;
+ if(keylen != 64) {
+ /* key wrong size */
+ return NULL;
+ }
+
+ /* create evp_key */
+ memmove(encoded, asn, 37);
+ memmove(encoded+37, key, 64);
+ pp = (unsigned char*)&encoded[0];
+
+ return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
+}
+#endif /* USE_GOST */
+
+#ifdef USE_ECDSA
+EVP_PKEY*
+sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
+{
+ unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
+ const unsigned char* pp = buf;
+ EVP_PKEY *evp_key;
+ EC_KEY *ec;
+ /* check length, which uncompressed must be 2 bignums */
+ if(algo == LDNS_ECDSAP256SHA256) {
+ if(keylen != 2*256/8) return NULL;
+ ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ } else if(algo == LDNS_ECDSAP384SHA384) {
+ if(keylen != 2*384/8) return NULL;
+ ec = EC_KEY_new_by_curve_name(NID_secp384r1);
+ } else ec = NULL;
+ if(!ec) return NULL;
+ if(keylen+1 > sizeof(buf)) { /* sanity check */
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ /* prepend the 0x02 (from docs) (or actually 0x04 from implementation
+ * of openssl) for uncompressed data */
+ buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+ memmove(buf+1, key, keylen);
+ if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ evp_key = EVP_PKEY_new();
+ if(!evp_key) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+ EVP_PKEY_free(evp_key);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ return evp_key;
+}
+#endif /* USE_ECDSA */
+
+int
+sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
+ const EVP_MD* md)
+{
+ EVP_MD_CTX* ctx;
+ ctx = EVP_MD_CTX_create();
+ if(!ctx)
+ return 0;
+ if(!EVP_DigestInit_ex(ctx, md, NULL) ||
+ !EVP_DigestUpdate(ctx, data, len) ||
+ !EVP_DigestFinal_ex(ctx, dest, NULL)) {
+ EVP_MD_CTX_destroy(ctx);
+ return 0;
+ }
+ EVP_MD_CTX_destroy(ctx);
+ return 1;
+}
+#endif /* HAVE_SSL */
diff --git a/sldns/keyraw.h b/sldns/keyraw.h
new file mode 100644
index 000000000000..8abe235097b2
--- /dev/null
+++ b/sldns/keyraw.h
@@ -0,0 +1,112 @@
+/*
+ * keyraw.h -- raw key and signature access and conversion
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+
+/**
+ * \file
+ *
+ * raw key and signature access and conversion
+ *
+ * Since those functions heavily rely op cryptographic operations,
+ * this module is dependent on openssl.
+ *
+ */
+
+#ifndef LDNS_KEYRAW_H
+#define LDNS_KEYRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+# include <openssl/ssl.h>
+# include <openssl/evp.h>
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * get the length of the keydata in bits
+ * \param[in] keydata the raw key data
+ * \param[in] len the length of the keydata
+ * \param[in] alg the cryptographic algorithm this is a key for
+ * \return the keysize in bits, or 0 on error
+ */
+size_t sldns_rr_dnskey_key_size_raw(const unsigned char *keydata,
+ const size_t len, int alg);
+
+/**
+ * Calculates keytag of DNSSEC key, operates on wireformat rdata.
+ * \param[in] key the key as uncompressed wireformat rdata.
+ * \param[in] keysize length of key data.
+ * \return the keytag
+ */
+uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * Get the PKEY id for GOST, loads GOST into openssl as a side effect.
+ * Only available if GOST is compiled into the library and openssl.
+ * \return the gost id for EVP_CTX creation.
+ */
+int sldns_key_EVP_load_gost_id(void);
+
+/** Release the engine reference held for the GOST engine. */
+void sldns_key_EVP_unload_gost(void);
+
+/**
+ * Like sldns_key_buf2dsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a DSA * structure with the key material
+ */
+DSA *sldns_key_buf2dsa_raw(unsigned char* key, size_t len);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with GOST.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* sldns_gost2pkey_raw(unsigned char* key, size_t keylen);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with ECDSA.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \param[in] algo precise algorithm to initialize ECC group values.
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo);
+
+/**
+ * Like sldns_key_buf2rsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a RSA * structure with the key material
+ */
+RSA *sldns_key_buf2rsa_raw(unsigned char* key, size_t len);
+
+/**
+ * Utility function to calculate hash using generic EVP_MD pointer.
+ * \param[in] data the data to hash.
+ * \param[in] len length of data.
+ * \param[out] dest the destination of the hash, must be large enough.
+ * \param[in] md the message digest to use.
+ * \return true if worked, false on failure.
+ */
+int sldns_digest_evp(unsigned char* data, unsigned int len,
+ unsigned char* dest, const EVP_MD* md);
+
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_KEYRAW_H */
diff --git a/sldns/parse.c b/sldns/parse.c
new file mode 100644
index 000000000000..35dee719628c
--- /dev/null
+++ b/sldns/parse.c
@@ -0,0 +1,470 @@
+/*
+ * a generic (simple) parser. Use to parse rr's, private key
+ * information and /etc/resolv.conf files
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+#include "config.h"
+#include "sldns/parse.h"
+#include "sldns/parseutil.h"
+#include "sldns/sbuffer.h"
+
+#include <limits.h>
+#include <strings.h>
+
+sldns_lookup_table sldns_directive_types[] = {
+ { LDNS_DIR_TTL, "$TTL" },
+ { LDNS_DIR_ORIGIN, "$ORIGIN" },
+ { LDNS_DIR_INCLUDE, "$INCLUDE" },
+ { 0, NULL }
+};
+
+/* add max_limit here? */
+ssize_t
+sldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
+{
+ return sldns_fget_token_l(f, token, delim, limit, NULL);
+}
+
+ssize_t
+sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
+{
+ int c, prev_c;
+ int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+ int com, quoted;
+ char *t;
+ size_t i;
+ const char *d;
+ const char *del;
+
+ /* standard delimeters */
+ if (!delim) {
+ /* from isspace(3) */
+ del = LDNS_PARSE_NORMAL;
+ } else {
+ del = delim;
+ }
+
+ p = 0;
+ i = 0;
+ com = 0;
+ quoted = 0;
+ prev_c = 0;
+ t = token;
+ if (del[0] == '"') {
+ quoted = 1;
+ }
+ while ((c = getc(f)) != EOF) {
+ if (c == '\r') /* carriage return */
+ c = ' ';
+ if (c == '(' && prev_c != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p++;
+ }
+ prev_c = c;
+ continue;
+ }
+
+ if (c == ')' && prev_c != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p--;
+ }
+ prev_c = c;
+ continue;
+ }
+
+ if (p < 0) {
+ /* more ) then ( - close off the string */
+ *t = '\0';
+ return 0;
+ }
+
+ /* do something with comments ; */
+ if (c == ';' && quoted == 0) {
+ if (prev_c != '\\') {
+ com = 1;
+ }
+ }
+ if (c == '\"' && com == 0 && prev_c != '\\') {
+ quoted = 1 - quoted;
+ }
+
+ if (c == '\n' && com != 0) {
+ /* comments */
+ com = 0;
+ *t = ' ';
+ if (line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ if (p == 0 && i > 0) {
+ goto tokenread;
+ } else {
+ prev_c = c;
+ continue;
+ }
+ }
+
+ if (com == 1) {
+ *t = ' ';
+ prev_c = c;
+ continue;
+ }
+
+ if (c == '\n' && p != 0 && t > token) {
+ /* in parentheses */
+ if (line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ *t++ = ' ';
+ prev_c = c;
+ continue;
+ }
+
+ /* check if we hit the delim */
+ for (d = del; *d; d++) {
+ if (c == *d && i > 0 && prev_c != '\\' && p == 0) {
+ if (c == '\n' && line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ goto tokenread;
+ }
+ }
+ if (c != '\0' && c != '\n') {
+ i++;
+ }
+ if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
+ *t = '\0';
+ return -1;
+ }
+ if (c != '\0' && c != '\n') {
+ *t++ = c;
+ }
+ if (c == '\\' && prev_c == '\\')
+ prev_c = 0;
+ else prev_c = c;
+ }
+ *t = '\0';
+ if (c == EOF) {
+ return (ssize_t)i;
+ }
+
+ if (i == 0) {
+ /* nothing read */
+ return -1;
+ }
+ if (p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+
+tokenread:
+ if(*del == '"')
+ /* do not skip over quotes after the string, they are part
+ * of the next string. But skip over whitespace (if needed)*/
+ sldns_fskipcs_l(f, del+1, line_nr);
+ else sldns_fskipcs_l(f, del, line_nr);
+ *t = '\0';
+ if (p != 0) {
+ return -1;
+ }
+
+ return (ssize_t)i;
+}
+
+ssize_t
+sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
+ const char *d_del, size_t data_limit)
+{
+ return sldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
+ data_limit, NULL);
+}
+
+ssize_t
+sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
+ const char *d_del, size_t data_limit, int *line_nr)
+{
+ /* we assume: keyword|sep|data */
+ char *fkeyword;
+ ssize_t i;
+
+ if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+ return -1;
+ fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
+ if(!fkeyword)
+ return -1;
+
+ i = sldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
+ if(i==0 || i==-1) {
+ free(fkeyword);
+ return -1;
+ }
+
+ /* case??? i instead of strlen? */
+ if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
+ /* whee! */
+ /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
+ i = sldns_fget_token_l(f, data, d_del, data_limit, line_nr);
+ free(fkeyword);
+ return i;
+ } else {
+ /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
+ free(fkeyword);
+ return -1;
+ }
+}
+
+int
+sldns_bgetc(sldns_buffer *buffer)
+{
+ if (!sldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
+ sldns_buffer_set_position(buffer, sldns_buffer_limit(buffer));
+ /* sldns_buffer_rewind(buffer);*/
+ return EOF;
+ }
+ return (int)sldns_buffer_read_u8(buffer);
+}
+
+ssize_t
+sldns_bget_token(sldns_buffer *b, char *token, const char *delim, size_t limit)
+{
+ return sldns_bget_token_par(b, token, delim, limit, NULL, NULL);
+}
+
+ssize_t
+sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
+ size_t limit, int* par, const char* skipw)
+{
+ int c, lc;
+ int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+ int com, quoted;
+ char *t;
+ size_t i;
+ const char *d;
+ const char *del;
+
+ /* standard delimiters */
+ if (!delim) {
+ /* from isspace(3) */
+ del = LDNS_PARSE_NORMAL;
+ } else {
+ del = delim;
+ }
+
+ p = (par?*par:0);
+ i = 0;
+ com = 0;
+ quoted = 0;
+ t = token;
+ lc = 0;
+ if (del[0] == '"') {
+ quoted = 1;
+ }
+
+ while ((c = sldns_bgetc(b)) != EOF) {
+ if (c == '\r') /* carriage return */
+ c = ' ';
+ if (c == '(' && lc != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ if(par) (*par)++;
+ p++;
+ }
+ lc = c;
+ continue;
+ }
+
+ if (c == ')' && lc != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ if(par) (*par)--;
+ p--;
+ }
+ lc = c;
+ continue;
+ }
+
+ if (p < 0) {
+ /* more ) then ( */
+ *t = '\0';
+ return 0;
+ }
+
+ /* do something with comments ; */
+ if (c == ';' && quoted == 0) {
+ if (lc != '\\') {
+ com = 1;
+ }
+ }
+ if (c == '"' && com == 0 && lc != '\\') {
+ quoted = 1 - quoted;
+ }
+
+ if (c == '\n' && com != 0) {
+ /* comments */
+ com = 0;
+ *t = ' ';
+ lc = c;
+ continue;
+ }
+
+ if (com == 1) {
+ *t = ' ';
+ lc = c;
+ continue;
+ }
+
+ if (c == '\n' && p != 0) {
+ /* in parentheses */
+ /* do not write ' ' if we want to skip spaces */
+ if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' '))))
+ *t++ = ' ';
+ lc = c;
+ continue;
+ }
+
+ /* check to skip whitespace at start, but also after ( */
+ if(skipw && i==0 && !com && !quoted && lc != '\\') {
+ if(strchr(skipw, c)) {
+ lc = c;
+ continue;
+ }
+ }
+
+ /* check if we hit the delim */
+ for (d = del; *d; d++) {
+ /* we can only exit if no parens or user tracks them */
+ if (c == *d && lc != '\\' && (p == 0 || par)) {
+ goto tokenread;
+ }
+ }
+
+ i++;
+ if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
+ *t = '\0';
+ return -1;
+ }
+ *t++ = c;
+
+ if (c == '\\' && lc == '\\') {
+ lc = 0;
+ } else {
+ lc = c;
+ }
+ }
+ *t = '\0';
+ if (i == 0) {
+ /* nothing read */
+ return -1;
+ }
+ if (!par && p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+
+tokenread:
+ if(*del == '"')
+ /* do not skip over quotes after the string, they are part
+ * of the next string. But skip over whitespace (if needed)*/
+ sldns_bskipcs(b, del+1);
+ else sldns_bskipcs(b, del);
+ *t = '\0';
+
+ if (!par && p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+}
+
+
+void
+sldns_bskipcs(sldns_buffer *buffer, const char *s)
+{
+ int found;
+ char c;
+ const char *d;
+
+ while(sldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) {
+ c = (char) sldns_buffer_read_u8_at(buffer, buffer->_position);
+ found = 0;
+ for (d = s; *d; d++) {
+ if (*d == c) {
+ found = 1;
+ }
+ }
+ if (found && buffer->_limit > buffer->_position) {
+ buffer->_position += sizeof(char);
+ } else {
+ return;
+ }
+ }
+}
+
+void
+sldns_fskipcs(FILE *fp, const char *s)
+{
+ sldns_fskipcs_l(fp, s, NULL);
+}
+
+void
+sldns_fskipcs_l(FILE *fp, const char *s, int *line_nr)
+{
+ int found;
+ int c;
+ const char *d;
+
+ while ((c = fgetc(fp)) != EOF) {
+ if (line_nr && c == '\n') {
+ *line_nr = *line_nr + 1;
+ }
+ found = 0;
+ for (d = s; *d; d++) {
+ if (*d == c) {
+ found = 1;
+ }
+ }
+ if (!found) {
+ /* with getc, we've read too far */
+ ungetc(c, fp);
+ return;
+ }
+ }
+}
+
+ssize_t
+sldns_bget_keyword_data(sldns_buffer *b, const char *keyword, const char *k_del, char
+*data, const char *d_del, size_t data_limit)
+{
+ /* we assume: keyword|sep|data */
+ char *fkeyword;
+ ssize_t i;
+
+ if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+ return -1;
+ fkeyword = (char*)malloc(LDNS_MAX_KEYWORDLEN);
+ if(!fkeyword)
+ return -1; /* out of memory */
+
+ i = sldns_bget_token(b, fkeyword, k_del, data_limit);
+ if(i==0 || i==-1) {
+ free(fkeyword);
+ return -1; /* nothing read */
+ }
+
+ /* case??? */
+ if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) {
+ free(fkeyword);
+ /* whee, the match! */
+ /* retrieve it's data */
+ i = sldns_bget_token(b, data, d_del, 0);
+ return i;
+ } else {
+ free(fkeyword);
+ return -1;
+ }
+}
+
diff --git a/sldns/parse.h b/sldns/parse.h
new file mode 100644
index 000000000000..7b7456dd2068
--- /dev/null
+++ b/sldns/parse.h
@@ -0,0 +1,184 @@
+/*
+ * parse.h
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_PARSE_H
+#define LDNS_PARSE_H
+
+struct sldns_buffer;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_PARSE_SKIP_SPACE "\f\n\r\v"
+#define LDNS_PARSE_NORMAL " \f\n\r\t\v"
+#define LDNS_PARSE_NO_NL " \t"
+#define LDNS_MAX_LINELEN 10230
+#define LDNS_MAX_KEYWORDLEN 32
+
+
+/**
+ * \file
+ *
+ * Contains some low-level parsing functions, mostly used in the _frm_str
+ * family of functions.
+ */
+
+/**
+ * different type of directives in zone files
+ * We now deal with $TTL, $ORIGIN and $INCLUDE.
+ * The latter is not implemented in ldns (yet)
+ */
+enum sldns_enum_directive
+{
+ LDNS_DIR_TTL,
+ LDNS_DIR_ORIGIN,
+ LDNS_DIR_INCLUDE
+};
+typedef enum sldns_enum_directive sldns_directive;
+
+/**
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores them when encountered
+ * \param[in] *f the file to read from
+ * \param[out] *token the read token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \return 0 on error of EOF of the stream F. Otherwise return the length of what is read
+ */
+ssize_t sldns_fget_token(FILE *f, char *token, const char *delim, size_t limit);
+
+/**
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores when it finds them.
+ * \param[in] *f the file to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 use builtin maximum
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return 0 on error of EOF of F otherwise return the length of what is read
+ */
+ssize_t sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr);
+
+/**
+ * returns a token/char from the buffer b.
+ * This function deals with ( and ) in the buffer,
+ * and ignores when it finds them.
+ * \param[in] *b the buffer to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \param[in] *par if you pass nonNULL, set to 0 on first call, the parenthesis
+ * state is stored in it, for use on next call. User must check it is back
+ * to zero after last bget in string (for parse error). If you pass NULL,
+ * the entire parenthesized string is read in.
+ * \param[in] skipw string with whitespace to skip before the start of the
+ * token, like " ", or " \t", or NULL for none.
+ * \returns 0 on error of EOF of b. Otherwise return the length of what is read
+ */
+ssize_t sldns_bget_token_par(struct sldns_buffer *b, char *token, const char *delim, size_t limit, int* par, const char* skipw);
+
+/**
+ * returns a token/char from the buffer b.
+ * This function deals with ( and ) in the buffer,
+ * and ignores when it finds them.
+ * \param[in] *b the buffer to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \returns 0 on error of EOF of b. Otherwise return the length of what is read
+ */
+ssize_t sldns_bget_token(struct sldns_buffer *b, char *token, const char *delim, size_t limit);
+
+/*
+ * searches for keyword and delim in a file. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/*
+ * searches for keyword and delim. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \param[in] line_nr pointer to an integer containing the current line number (for
+debugging purposes)
+ * \return the number of character read
+ */
+ssize_t sldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit, int *line_nr);
+
+/*
+ * searches for keyword and delim in a buffer. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] b buffer pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t sldns_bget_keyword_data(struct sldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/**
+ * returns the next character from a buffer. Advances the position pointer with 1.
+ * When end of buffer is reached returns EOF. This is the buffer's equivalent
+ * for getc().
+ * \param[in] *buffer buffer to read from
+ * \return EOF on failure otherwise return the character
+ */
+int sldns_bgetc(struct sldns_buffer *buffer);
+
+/**
+ * skips all of the characters in the given string in the buffer, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *buffer buffer to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void sldns_bskipcs(struct sldns_buffer *buffer, const char *s);
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void sldns_fskipcs(FILE *fp, const char *s);
+
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return void
+ */
+void sldns_fskipcs_l(FILE *fp, const char *s, int *line_nr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PARSE_H */
diff --git a/sldns/parseutil.c b/sldns/parseutil.c
new file mode 100644
index 000000000000..2a2ebbb08c38
--- /dev/null
+++ b/sldns/parseutil.c
@@ -0,0 +1,726 @@
+/*
+ * parseutil.c - parse utilities for string and wire conversion
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Utility functions for parsing, base32(DNS variant) and base64 encoding
+ * and decoding, Hex, Time units, Escape codes.
+ */
+
+#include "config.h"
+#include "sldns/parseutil.h"
+#include <sys/time.h>
+#include <time.h>
+#include <ctype.h>
+
+sldns_lookup_table *
+sldns_lookup_by_name(sldns_lookup_table *table, const char *name)
+{
+ while (table->name != NULL) {
+ if (strcasecmp(name, table->name) == 0)
+ return table;
+ table++;
+ }
+ return NULL;
+}
+
+sldns_lookup_table *
+sldns_lookup_by_id(sldns_lookup_table *table, int id)
+{
+ while (table->name != NULL) {
+ if (table->id == id)
+ return table;
+ table++;
+ }
+ return NULL;
+}
+
+/* Number of days per month (except for February in leap years). */
+static const int mdays[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
+#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y)))
+
+static int
+is_leap_year(int year)
+{
+ return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0
+ || LDNS_MOD(year, 400) == 0);
+}
+
+static int
+leap_days(int y1, int y2)
+{
+ --y1;
+ --y2;
+ return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) -
+ (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
+ (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
+}
+
+/*
+ * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
+ */
+time_t
+sldns_mktime_from_utc(const struct tm *tm)
+{
+ int year = 1900 + tm->tm_year;
+ time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
+ time_t hours;
+ time_t minutes;
+ time_t seconds;
+ int i;
+
+ for (i = 0; i < tm->tm_mon; ++i) {
+ days += mdays[i];
+ }
+ if (tm->tm_mon > 1 && is_leap_year(year)) {
+ ++days;
+ }
+ days += tm->tm_mday - 1;
+
+ hours = days * 24 + tm->tm_hour;
+ minutes = hours * 60 + tm->tm_min;
+ seconds = minutes * 60 + tm->tm_sec;
+
+ return seconds;
+}
+
+#if SIZEOF_TIME_T <= 4
+
+static void
+sldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
+{
+ int year = 1970;
+ int new_year;
+
+ while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
+ new_year = year + (int) LDNS_DIV(days, 365);
+ days -= (new_year - year) * 365;
+ days -= leap_days(year, new_year);
+ year = new_year;
+ }
+ result->tm_year = year;
+ result->tm_yday = (int) days;
+}
+
+/* Number of days per month in a leap year. */
+static const int leap_year_mdays[] = {
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static void
+sldns_mon_and_mday_from_year_and_yday(struct tm *result)
+{
+ int idays = result->tm_yday;
+ const int *mon_lengths = is_leap_year(result->tm_year) ?
+ leap_year_mdays : mdays;
+
+ result->tm_mon = 0;
+ while (idays >= mon_lengths[result->tm_mon]) {
+ idays -= mon_lengths[result->tm_mon++];
+ }
+ result->tm_mday = idays + 1;
+}
+
+static void
+sldns_wday_from_year_and_yday(struct tm *result)
+{
+ result->tm_wday = 4 /* 1-1-1970 was a thursday */
+ + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
+ + leap_days(1970, result->tm_year)
+ + result->tm_yday;
+ result->tm_wday = LDNS_MOD(result->tm_wday, 7);
+ if (result->tm_wday < 0) {
+ result->tm_wday += 7;
+ }
+}
+
+static struct tm *
+sldns_gmtime64_r(int64_t clock, struct tm *result)
+{
+ result->tm_isdst = 0;
+ result->tm_sec = (int) LDNS_MOD(clock, 60);
+ clock = LDNS_DIV(clock, 60);
+ result->tm_min = (int) LDNS_MOD(clock, 60);
+ clock = LDNS_DIV(clock, 60);
+ result->tm_hour = (int) LDNS_MOD(clock, 24);
+ clock = LDNS_DIV(clock, 24);
+
+ sldns_year_and_yday_from_days_since_epoch(clock, result);
+ sldns_mon_and_mday_from_year_and_yday(result);
+ sldns_wday_from_year_and_yday(result);
+ result->tm_year -= 1900;
+
+ return result;
+}
+
+#endif /* SIZEOF_TIME_T <= 4 */
+
+static int64_t
+sldns_serial_arithmitics_time(int32_t time, time_t now)
+{
+ int32_t offset = time - (int32_t) now;
+ return (int64_t) now + offset;
+}
+
+struct tm *
+sldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
+{
+#if SIZEOF_TIME_T <= 4
+ int64_t secs_since_epoch = sldns_serial_arithmitics_time(time, now);
+ return sldns_gmtime64_r(secs_since_epoch, result);
+#else
+ time_t secs_since_epoch = sldns_serial_arithmitics_time(time, now);
+ return gmtime_r(&secs_since_epoch, result);
+#endif
+}
+
+int
+sldns_hexdigit_to_int(char ch)
+{
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default:
+ return -1;
+ }
+}
+
+uint32_t
+sldns_str2period(const char *nptr, const char **endptr)
+{
+ int sign = 0;
+ uint32_t i = 0;
+ uint32_t seconds = 0;
+
+ for(*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case '-':
+ if(sign == 0) {
+ sign = -1;
+ } else {
+ return seconds;
+ }
+ break;
+ case '+':
+ if(sign == 0) {
+ sign = 1;
+ } else {
+ return seconds;
+ }
+ break;
+ case 's':
+ case 'S':
+ seconds += i;
+ i = 0;
+ break;
+ case 'm':
+ case 'M':
+ seconds += i * 60;
+ i = 0;
+ break;
+ case 'h':
+ case 'H':
+ seconds += i * 60 * 60;
+ i = 0;
+ break;
+ case 'd':
+ case 'D':
+ seconds += i * 60 * 60 * 24;
+ i = 0;
+ break;
+ case 'w':
+ case 'W':
+ seconds += i * 60 * 60 * 24 * 7;
+ i = 0;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ seconds += i;
+ /* disregard signedness */
+ return seconds;
+ }
+ }
+ seconds += i;
+ /* disregard signedness */
+ return seconds;
+}
+
+int
+sldns_parse_escape(uint8_t *ch_p, const char** str_p)
+{
+ uint16_t val;
+
+ if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) &&
+ (*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) &&
+ (*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) {
+
+ val = (uint16_t)(((*str_p)[0] - '0') * 100 +
+ ((*str_p)[1] - '0') * 10 +
+ ((*str_p)[2] - '0'));
+
+ if (val > 255) {
+ goto error;
+ }
+ *ch_p = (uint8_t)val;
+ *str_p += 3;
+ return 1;
+
+ } else if ((*str_p)[0] && !isdigit((unsigned char)(*str_p)[0])) {
+
+ *ch_p = (uint8_t)*(*str_p)++;
+ return 1;
+ }
+error:
+ *str_p = NULL;
+ return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */
+}
+
+/** parse one character, with escape codes */
+int
+sldns_parse_char(uint8_t *ch_p, const char** str_p)
+{
+ switch (**str_p) {
+
+ case '\0': return 0;
+
+ case '\\': *str_p += 1;
+ return sldns_parse_escape(ch_p, str_p);
+
+ default: *ch_p = (uint8_t)*(*str_p)++;
+ return 1;
+ }
+}
+
+size_t sldns_b32_ntop_calculate_size(size_t src_data_length)
+{
+ return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8;
+}
+
+size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length)
+{
+ return ((src_data_length + 3) * 8 / 5) - 4;
+}
+
+static int
+sldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz,
+ int extended_hex, int add_padding)
+{
+ size_t ret_sz;
+ const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv"
+ : "abcdefghijklmnopqrstuvwxyz234567";
+
+ size_t c = 0; /* c is used to carry partial base32 character over
+ * byte boundaries for sizes with a remainder.
+ * (i.e. src_sz % 5 != 0)
+ */
+
+ ret_sz = add_padding ? sldns_b32_ntop_calculate_size(src_sz)
+ : sldns_b32_ntop_calculate_size_no_padding(src_sz);
+
+ /* Do we have enough space? */
+ if (dst_sz < ret_sz + 1)
+ return -1;
+
+ /* We know the size; terminate the string */
+ dst[ret_sz] = '\0';
+
+ /* First process all chunks of five */
+ while (src_sz >= 5) {
+ /* 00000... ........ ........ ........ ........ */
+ dst[0] = b32[(src[0] ) >> 3];
+
+ /* .....111 11...... ........ ........ ........ */
+ dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6];
+
+ /* ........ ..22222. ........ ........ ........ */
+ dst[2] = b32[(src[1] & 0x3e) >> 1];
+
+ /* ........ .......3 3333.... ........ ........ */
+ dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4];
+
+ /* ........ ........ ....4444 4....... ........ */
+ dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7];
+
+ /* ........ ........ ........ .55555.. ........ */
+ dst[5] = b32[(src[3] & 0x7c) >> 2];
+
+ /* ........ ........ ........ ......66 666..... */
+ dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5];
+
+ /* ........ ........ ........ ........ ...77777 */
+ dst[7] = b32[(src[4] & 0x1f) ];
+
+ src_sz -= 5;
+ src += 5;
+ dst += 8;
+ }
+ /* Process what remains */
+ switch (src_sz) {
+ case 4: /* ........ ........ ........ ......66 666..... */
+ dst[6] = b32[(src[3] & 0x03) << 3];
+
+ /* ........ ........ ........ .55555.. ........ */
+ dst[5] = b32[(src[3] & 0x7c) >> 2];
+
+ /* ........ ........ ....4444 4....... ........ */
+ c = src[3] >> 7 ;
+ case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
+
+ /* ........ .......3 3333.... ........ ........ */
+ c = src[2] >> 4 ;
+ case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c];
+
+ /* ........ ..22222. ........ ........ ........ */
+ dst[2] = b32[(src[1] & 0x3e) >> 1];
+
+ /* .....111 11...... ........ ........ ........ */
+ c = src[1] >> 6 ;
+ case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c];
+
+ /* 00000... ........ ........ ........ ........ */
+ dst[0] = b32[ src[0] >> 3];
+ }
+ /* Add padding */
+ if (add_padding) {
+ switch (src_sz) {
+ case 1: dst[2] = '=';
+ dst[3] = '=';
+ case 2: dst[4] = '=';
+ case 3: dst[5] = '=';
+ dst[6] = '=';
+ case 4: dst[7] = '=';
+ }
+ }
+ return (int)ret_sz;
+}
+
+int
+sldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz)
+{
+ return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1);
+}
+
+int
+sldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz,
+ char* dst, size_t dst_sz)
+{
+ return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1);
+}
+
+size_t sldns_b32_pton_calculate_size(size_t src_text_length)
+{
+ return src_text_length * 5 / 8;
+}
+
+static int
+sldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz,
+ int extended_hex, int check_padding)
+{
+ size_t i = 0;
+ char ch = '\0';
+ uint8_t buf[8];
+ uint8_t* start = dst;
+
+ while (src_sz) {
+ /* Collect 8 characters in buf (if possible) */
+ for (i = 0; i < 8; i++) {
+
+ do {
+ ch = *src++;
+ --src_sz;
+
+ } while (isspace((unsigned char)ch) && src_sz > 0);
+
+ if (ch == '=' || ch == '\0')
+ break;
+
+ else if (extended_hex)
+
+ if (ch >= '0' && ch <= '9')
+ buf[i] = (uint8_t)ch - '0';
+ else if (ch >= 'a' && ch <= 'v')
+ buf[i] = (uint8_t)ch - 'a' + 10;
+ else if (ch >= 'A' && ch <= 'V')
+ buf[i] = (uint8_t)ch - 'A' + 10;
+ else
+ return -1;
+
+ else if (ch >= 'a' && ch <= 'z')
+ buf[i] = (uint8_t)ch - 'a';
+ else if (ch >= 'A' && ch <= 'Z')
+ buf[i] = (uint8_t)ch - 'A';
+ else if (ch >= '2' && ch <= '7')
+ buf[i] = (uint8_t)ch - '2' + 26;
+ else
+ return -1;
+ }
+ /* Less that 8 characters. We're done. */
+ if (i < 8)
+ break;
+
+ /* Enough space available at the destination? */
+ if (dst_sz < 5)
+ return -1;
+
+ /* 00000... ........ ........ ........ ........ */
+ /* .....111 11...... ........ ........ ........ */
+ dst[0] = buf[0] << 3 | buf[1] >> 2;
+
+ /* .....111 11...... ........ ........ ........ */
+ /* ........ ..22222. ........ ........ ........ */
+ /* ........ .......3 3333.... ........ ........ */
+ dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
+
+ /* ........ .......3 3333.... ........ ........ */
+ /* ........ ........ ....4444 4....... ........ */
+ dst[2] = buf[3] << 4 | buf[4] >> 1;
+
+ /* ........ ........ ....4444 4....... ........ */
+ /* ........ ........ ........ .55555.. ........ */
+ /* ........ ........ ........ ......66 666..... */
+ dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
+
+ /* ........ ........ ........ ......66 666..... */
+ /* ........ ........ ........ ........ ...77777 */
+ dst[4] = buf[6] << 5 | buf[7];
+
+ dst += 5;
+ dst_sz -= 5;
+ }
+ /* Not ending on a eight byte boundary? */
+ if (i > 0 && i < 8) {
+
+ /* Enough space available at the destination? */
+ if (dst_sz < (i + 1) / 2)
+ return -1;
+
+ switch (i) {
+ case 7: /* ........ ........ ........ ......66 666..... */
+ /* ........ ........ ........ .55555.. ........ */
+ /* ........ ........ ....4444 4....... ........ */
+ dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
+
+ case 5: /* ........ ........ ....4444 4....... ........ */
+ /* ........ .......3 3333.... ........ ........ */
+ dst[2] = buf[3] << 4 | buf[4] >> 1;
+
+ case 4: /* ........ .......3 3333.... ........ ........ */
+ /* ........ ..22222. ........ ........ ........ */
+ /* .....111 11...... ........ ........ ........ */
+ dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
+
+ case 2: /* .....111 11...... ........ ........ ........ */
+ /* 00000... ........ ........ ........ ........ */
+ dst[0] = buf[0] << 3 | buf[1] >> 2;
+
+ break;
+
+ default:
+ return -1;
+ }
+ dst += (i + 1) / 2;
+
+ if (check_padding) {
+ /* Check remaining padding characters */
+ if (ch != '=')
+ return -1;
+
+ /* One down, 8 - i - 1 more to come... */
+ for (i = 8 - i - 1; i > 0; i--) {
+
+ do {
+ if (src_sz == 0)
+ return -1;
+ ch = *src++;
+ src_sz--;
+
+ } while (isspace((unsigned char)ch));
+
+ if (ch != '=')
+ return -1;
+ }
+ }
+ }
+ return dst - start;
+}
+
+int
+sldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz)
+{
+ return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1);
+}
+
+int
+sldns_b32_pton_extended_hex(const char* src, size_t src_sz,
+ uint8_t* dst, size_t dst_sz)
+{
+ return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1);
+}
+
+size_t sldns_b64_ntop_calculate_size(size_t srcsize)
+{
+ return ((((srcsize + 2) / 3) * 4) + 1);
+}
+
+/* RFC 1521, section 5.2.
+ *
+ * The encoding process represents 24-bit groups of input bits as output
+ * strings of 4 encoded characters. Proceeding from left to right, a
+ * 24-bit input group is formed by concatenating 3 8-bit input groups.
+ * These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ * of which is translated into a single digit in the base64 alphabet.
+ *
+ * This routine does not insert spaces or linebreaks after 76 characters.
+ */
+int sldns_b64_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize)
+{
+ const char* b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const char pad64 = '=';
+ size_t i = 0, o = 0;
+ if(targsize < sldns_b64_ntop_calculate_size(srclength))
+ return -1;
+ /* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */
+ while(i+3 <= srclength) {
+ if(o+4 > targsize) return -1;
+ target[o] = b64[src[i] >> 2];
+ target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
+ target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ];
+ target[o+3] = b64[ (src[i+2]&0x3f) ];
+ i += 3;
+ o += 4;
+ }
+ /* remainder */
+ switch(srclength - i) {
+ case 2:
+ /* two at end, converted into A B C = */
+ target[o] = b64[src[i] >> 2];
+ target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ];
+ target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ];
+ target[o+3] = pad64;
+ i += 2;
+ o += 4;
+ break;
+ case 1:
+ /* one at end, converted into A B = = */
+ target[o] = b64[src[i] >> 2];
+ target[o+1] = b64[ ((src[i]&0x03)<<4) ];
+ target[o+2] = pad64;
+ target[o+3] = pad64;
+ i += 1;
+ o += 4;
+ break;
+ case 0:
+ default:
+ /* nothing */
+ break;
+ }
+ /* assert: i == srclength */
+ if(o+1 > targsize) return -1;
+ target[o] = 0;
+ return (int)o;
+}
+
+size_t sldns_b64_pton_calculate_size(size_t srcsize)
+{
+ return (((((srcsize + 3) / 4) * 3)) + 1);
+}
+
+int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ const uint8_t pad64 = 64; /* is 64th in the b64 array */
+ const char* s = src;
+ uint8_t in[4];
+ size_t o = 0, incount = 0;
+
+ while(*s) {
+ /* skip any character that is not base64 */
+ /* conceptually we do:
+ const char* b64 = pad'=' is appended to array
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ const char* d = strchr(b64, *s++);
+ and use d-b64;
+ */
+ char d = *s++;
+ if(d <= 'Z' && d >= 'A')
+ d -= 'A';
+ else if(d <= 'z' && d >= 'a')
+ d = d - 'a' + 26;
+ else if(d <= '9' && d >= '0')
+ d = d - '0' + 52;
+ else if(d == '+')
+ d = 62;
+ else if(d == '/')
+ d = 63;
+ else if(d == '=')
+ d = 64;
+ else continue;
+ in[incount++] = (uint8_t)d;
+ if(incount != 4)
+ continue;
+ /* process whole block of 4 characters into 3 output bytes */
+ if(in[3] == pad64 && in[2] == pad64) { /* A B = = */
+ if(o+1 > targsize)
+ return -1;
+ target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+ o += 1;
+ break; /* we are done */
+ } else if(in[3] == pad64) { /* A B C = */
+ if(o+2 > targsize)
+ return -1;
+ target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+ target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
+ o += 2;
+ break; /* we are done */
+ } else {
+ if(o+3 > targsize)
+ return -1;
+ /* write xxxxxxyy yyyyzzzz zzwwwwww */
+ target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
+ target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
+ target[o+2]= ((in[2]&0x03)<<6) | in[3];
+ o += 3;
+ }
+ incount = 0;
+ }
+ return (int)o;
+}
diff --git a/sldns/parseutil.h b/sldns/parseutil.h
new file mode 100644
index 000000000000..dfa1c2a2b14b
--- /dev/null
+++ b/sldns/parseutil.h
@@ -0,0 +1,148 @@
+/*
+ * parseutil.h - parse utilities for string and wire conversion
+ *
+ * (c) NLnet Labs, 2004
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Utility functions for parsing, base32(DNS variant) and base64 encoding
+ * and decoding, Hex, Time units, Escape codes.
+ */
+
+#ifndef LDNS_PARSEUTIL_H
+#define LDNS_PARSEUTIL_H
+struct tm;
+
+/**
+ * A general purpose lookup table
+ *
+ * Lookup tables are arrays of (id, name) pairs,
+ * So you can for instance lookup the RCODE 3, which is "NXDOMAIN",
+ * and vice versa. The lookup tables themselves are defined wherever needed,
+ * for instance in host2str.c
+ */
+struct sldns_struct_lookup_table {
+ int id;
+ const char *name;
+};
+typedef struct sldns_struct_lookup_table sldns_lookup_table;
+
+/**
+ * Looks up the table entry by name, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] name what to search for
+ * \return the item found
+ */
+sldns_lookup_table *sldns_lookup_by_name(sldns_lookup_table table[],
+ const char *name);
+/**
+ * Looks up the table entry by id, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] id what to search for
+ * \return the item found
+ */
+sldns_lookup_table *sldns_lookup_by_id(sldns_lookup_table table[], int id);
+
+/**
+ * Convert TM to seconds since epoch (midnight, January 1st, 1970).
+ * Like timegm(3), which is not always available.
+ * \param[in] tm a struct tm* with the date
+ * \return the seconds since epoch
+ */
+time_t sldns_mktime_from_utc(const struct tm *tm);
+
+/**
+ * The function interprets time as the number of seconds since epoch
+ * with respect to now using serial arithmitics (rfc1982).
+ * That number of seconds is then converted to broken-out time information.
+ * This is especially usefull when converting the inception and expiration
+ * fields of RRSIG records.
+ *
+ * \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
+ * to be intepreted as a serial arithmitics number relative to now.
+ * \param[in] now number of seconds since epoch (midnight, January 1st, 1970)
+ * to which the time value is compared to determine the final value.
+ * \param[out] result the struct with the broken-out time information
+ * \return result on success or NULL on error
+ */
+struct tm * sldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/**
+ * converts a ttl value (like 5d2h) to a long.
+ * \param[in] nptr the start of the string
+ * \param[out] endptr points to the last char in case of error
+ * \return the convert duration value
+ */
+uint32_t sldns_str2period(const char *nptr, const char **endptr);
+
+/**
+ * Returns the int value of the given (hex) digit
+ * \param[in] ch the hex char to convert
+ * \return the converted decimal value
+ */
+int sldns_hexdigit_to_int(char ch);
+
+/**
+ * calculates the size needed to store the result of b64_ntop
+ */
+size_t sldns_b64_ntop_calculate_size(size_t srcsize);
+
+int sldns_b64_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+
+/**
+ * calculates the size needed to store the result of sldns_b64_pton
+ */
+size_t sldns_b64_pton_calculate_size(size_t srcsize);
+
+int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize);
+
+/**
+ * calculates the size needed to store the result of b32_ntop
+ */
+size_t sldns_b32_ntop_calculate_size(size_t src_data_length);
+
+size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length);
+
+int sldns_b32_ntop(const uint8_t* src_data, size_t src_data_length,
+ char* target_text_buffer, size_t target_text_buffer_size);
+
+int sldns_b32_ntop_extended_hex(const uint8_t* src_data, size_t src_data_length,
+ char* target_text_buffer, size_t target_text_buffer_size);
+
+/**
+ * calculates the size needed to store the result of b32_pton
+ */
+size_t sldns_b32_pton_calculate_size(size_t src_text_length);
+
+int sldns_b32_pton(const char* src_text, size_t src_text_length,
+ uint8_t* target_data_buffer, size_t target_data_buffer_size);
+
+int sldns_b32_pton_extended_hex(const char* src_text, size_t src_text_length,
+ uint8_t* target_data_buffer, size_t target_data_buffer_size);
+
+/*
+ * Checks whether the escaped value at **s is an octal value or
+ * a 'normally' escaped character (and not eos)
+ *
+ * @param ch_p: the parsed character
+ * @param str_p: the string. moved along for characters read.
+ * The string pointer at *s is increased by either 0 (on error), 1 (on
+ * normal escapes), or 3 (on octals)
+ *
+ * @return 0 on error
+ */
+int sldns_parse_escape(uint8_t *ch_p, const char** str_p);
+
+/**
+ * Parse one character, with escape codes,
+ * @param ch_p: the parsed character
+ * @param str_p: the string. moved along for characters read.
+ * @return 0 on error
+ */
+int sldns_parse_char(uint8_t *ch_p, const char** str_p);
+
+#endif /* LDNS_PARSEUTIL_H */
diff --git a/sldns/pkthdr.h b/sldns/pkthdr.h
new file mode 100644
index 000000000000..de9952ea71f8
--- /dev/null
+++ b/sldns/pkthdr.h
@@ -0,0 +1,158 @@
+/*
+ * pkthdr.h - packet header from wire conversion routines
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions that translate dns data from the wire format (as sent
+ * by servers and clients) to the internal structures for the packet header.
+ */
+
+#ifndef LDNS_PKTHDR_H
+#define LDNS_PKTHDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The length of the header */
+#define LDNS_HEADER_SIZE 12
+
+/* First octet of flags */
+#define LDNS_RD_MASK 0x01U
+#define LDNS_RD_SHIFT 0
+#define LDNS_RD_WIRE(wirebuf) (*(wirebuf+2) & LDNS_RD_MASK)
+#define LDNS_RD_SET(wirebuf) (*(wirebuf+2) |= LDNS_RD_MASK)
+#define LDNS_RD_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_RD_MASK)
+
+#define LDNS_TC_MASK 0x02U
+#define LDNS_TC_SHIFT 1
+#define LDNS_TC_WIRE(wirebuf) (*(wirebuf+2) & LDNS_TC_MASK)
+#define LDNS_TC_SET(wirebuf) (*(wirebuf+2) |= LDNS_TC_MASK)
+#define LDNS_TC_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_TC_MASK)
+
+#define LDNS_AA_MASK 0x04U
+#define LDNS_AA_SHIFT 2
+#define LDNS_AA_WIRE(wirebuf) (*(wirebuf+2) & LDNS_AA_MASK)
+#define LDNS_AA_SET(wirebuf) (*(wirebuf+2) |= LDNS_AA_MASK)
+#define LDNS_AA_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_AA_MASK)
+
+#define LDNS_OPCODE_MASK 0x78U
+#define LDNS_OPCODE_SHIFT 3
+#define LDNS_OPCODE_WIRE(wirebuf) ((*(wirebuf+2) & LDNS_OPCODE_MASK) >> LDNS_OPCODE_SHIFT)
+#define LDNS_OPCODE_SET(wirebuf, opcode) \
+ (*(wirebuf+2) = ((*(wirebuf+2)) & ~LDNS_OPCODE_MASK) | ((opcode) << LDNS_OPCODE_SHIFT))
+
+#define LDNS_QR_MASK 0x80U
+#define LDNS_QR_SHIFT 7
+#define LDNS_QR_WIRE(wirebuf) (*(wirebuf+2) & LDNS_QR_MASK)
+#define LDNS_QR_SET(wirebuf) (*(wirebuf+2) |= LDNS_QR_MASK)
+#define LDNS_QR_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_QR_MASK)
+
+/* Second octet of flags */
+#define LDNS_RCODE_MASK 0x0fU
+#define LDNS_RCODE_SHIFT 0
+#define LDNS_RCODE_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RCODE_MASK)
+#define LDNS_RCODE_SET(wirebuf, rcode) \
+ (*(wirebuf+3) = ((*(wirebuf+3)) & ~LDNS_RCODE_MASK) | (rcode))
+
+#define LDNS_CD_MASK 0x10U
+#define LDNS_CD_SHIFT 4
+#define LDNS_CD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_CD_MASK)
+#define LDNS_CD_SET(wirebuf) (*(wirebuf+3) |= LDNS_CD_MASK)
+#define LDNS_CD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_CD_MASK)
+
+#define LDNS_AD_MASK 0x20U
+#define LDNS_AD_SHIFT 5
+#define LDNS_AD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_AD_MASK)
+#define LDNS_AD_SET(wirebuf) (*(wirebuf+3) |= LDNS_AD_MASK)
+#define LDNS_AD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_AD_MASK)
+
+#define LDNS_Z_MASK 0x40U
+#define LDNS_Z_SHIFT 6
+#define LDNS_Z_WIRE(wirebuf) (*(wirebuf+3) & LDNS_Z_MASK)
+#define LDNS_Z_SET(wirebuf) (*(wirebuf+3) |= LDNS_Z_MASK)
+#define LDNS_Z_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_Z_MASK)
+
+#define LDNS_RA_MASK 0x80U
+#define LDNS_RA_SHIFT 7
+#define LDNS_RA_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RA_MASK)
+#define LDNS_RA_SET(wirebuf) (*(wirebuf+3) |= LDNS_RA_MASK)
+#define LDNS_RA_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_RA_MASK)
+
+/* Query ID */
+#define LDNS_ID_WIRE(wirebuf) (sldns_read_uint16(wirebuf))
+#define LDNS_ID_SET(wirebuf, id) (sldns_write_uint16(wirebuf, id))
+
+/* Counter of the question section */
+#define LDNS_QDCOUNT_OFF 4
+/*
+#define QDCOUNT(wirebuf) (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF)))
+*/
+#define LDNS_QDCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF))
+
+/* Counter of the answer section */
+#define LDNS_ANCOUNT_OFF 6
+#define LDNS_ANCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF))
+
+/* Counter of the authority section */
+#define LDNS_NSCOUNT_OFF 8
+#define LDNS_NSCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF))
+
+/* Counter of the additional section */
+#define LDNS_ARCOUNT_OFF 10
+#define LDNS_ARCOUNT(wirebuf) (sldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF))
+
+/**
+ * The sections of a packet
+ */
+enum sldns_enum_pkt_section {
+ LDNS_SECTION_QUESTION = 0,
+ LDNS_SECTION_ANSWER = 1,
+ LDNS_SECTION_AUTHORITY = 2,
+ LDNS_SECTION_ADDITIONAL = 3,
+ /** bogus section, if not interested */
+ LDNS_SECTION_ANY = 4,
+ /** used to get all non-question rrs from a packet */
+ LDNS_SECTION_ANY_NOQUESTION = 5
+};
+typedef enum sldns_enum_pkt_section sldns_pkt_section;
+
+/* opcodes for pkt's */
+enum sldns_enum_pkt_opcode {
+ LDNS_PACKET_QUERY = 0,
+ LDNS_PACKET_IQUERY = 1,
+ LDNS_PACKET_STATUS = 2, /* there is no 3?? DNS is weird */
+ LDNS_PACKET_NOTIFY = 4,
+ LDNS_PACKET_UPDATE = 5
+};
+typedef enum sldns_enum_pkt_opcode sldns_pkt_opcode;
+
+/* rcodes for pkts */
+enum sldns_enum_pkt_rcode {
+ LDNS_RCODE_NOERROR = 0,
+ LDNS_RCODE_FORMERR = 1,
+ LDNS_RCODE_SERVFAIL = 2,
+ LDNS_RCODE_NXDOMAIN = 3,
+ LDNS_RCODE_NOTIMPL = 4,
+ LDNS_RCODE_REFUSED = 5,
+ LDNS_RCODE_YXDOMAIN = 6,
+ LDNS_RCODE_YXRRSET = 7,
+ LDNS_RCODE_NXRRSET = 8,
+ LDNS_RCODE_NOTAUTH = 9,
+ LDNS_RCODE_NOTZONE = 10
+};
+typedef enum sldns_enum_pkt_rcode sldns_pkt_rcode;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PKTHDR_H */
diff --git a/sldns/rrdef.c b/sldns/rrdef.c
new file mode 100644
index 000000000000..a8c6229b9d2e
--- /dev/null
+++ b/sldns/rrdef.c
@@ -0,0 +1,728 @@
+/* rrdef.c
+ *
+ * access functions to rr definitions list.
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ *
+ * (c) NLnet Labs, 2004-2006
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Defines resource record types and constants.
+ */
+#include "config.h"
+#include "sldns/rrdef.h"
+#include "sldns/parseutil.h"
+
+/* classes */
+static sldns_lookup_table sldns_rr_classes_data[] = {
+ { LDNS_RR_CLASS_IN, "IN" },
+ { LDNS_RR_CLASS_CH, "CH" },
+ { LDNS_RR_CLASS_HS, "HS" },
+ { LDNS_RR_CLASS_NONE, "NONE" },
+ { LDNS_RR_CLASS_ANY, "ANY" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_rr_classes = sldns_rr_classes_data;
+
+/* types */
+static const sldns_rdf_type type_0_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const sldns_rdf_type type_a_wireformat[] = { LDNS_RDF_TYPE_A };
+static const sldns_rdf_type type_ns_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_md_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mf_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_cname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_soa_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD,
+ LDNS_RDF_TYPE_PERIOD
+};
+static const sldns_rdf_type type_mb_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mg_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_mr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_wks_wireformat[] = {
+ LDNS_RDF_TYPE_A, LDNS_RDF_TYPE_WKS
+};
+static const sldns_rdf_type type_ptr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_hinfo_wireformat[] = {
+ LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_minfo_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_mx_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_rp_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_afsdb_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_x25_wireformat[] = { LDNS_RDF_TYPE_STR };
+static const sldns_rdf_type type_isdn_wireformat[] = {
+ LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_rt_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_nsap_wireformat[] = {
+ LDNS_RDF_TYPE_NSAP
+};
+static const sldns_rdf_type type_nsap_ptr_wireformat[] = {
+ LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_sig_wireformat[] = {
+ LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_key_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_px_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_gpos_wireformat[] = {
+ LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const sldns_rdf_type type_aaaa_wireformat[] = { LDNS_RDF_TYPE_AAAA };
+static const sldns_rdf_type type_loc_wireformat[] = { LDNS_RDF_TYPE_LOC };
+static const sldns_rdf_type type_nxt_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_UNKNOWN
+};
+static const sldns_rdf_type type_eid_wireformat[] = {
+ LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_nimloc_wireformat[] = {
+ LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_srv_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_atma_wireformat[] = {
+ LDNS_RDF_TYPE_ATMA
+};
+static const sldns_rdf_type type_naptr_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_kx_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_cert_wireformat[] = {
+ LDNS_RDF_TYPE_CERT_ALG, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_a6_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const sldns_rdf_type type_dname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const sldns_rdf_type type_sink_wireformat[] = { LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_apl_wireformat[] = {
+ LDNS_RDF_TYPE_APL
+};
+static const sldns_rdf_type type_ds_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_sshfp_wireformat[] = {
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_ipseckey_wireformat[] = {
+ LDNS_RDF_TYPE_IPSECKEY
+};
+static const sldns_rdf_type type_rrsig_wireformat[] = {
+ LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_nsec_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_NSEC
+};
+static const sldns_rdf_type type_dhcid_wireformat[] = {
+ LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_talink_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+/* nsec3 is some vars, followed by same type of data of nsec */
+static const sldns_rdf_type type_nsec3_wireformat[] = {
+/* LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC
+};
+
+static const sldns_rdf_type type_nsec3param_wireformat[] = {
+/* LDNS_RDF_TYPE_NSEC3_PARAMS_VARS*/
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_NSEC3_SALT
+};
+
+static const sldns_rdf_type type_dnskey_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_ALG,
+ LDNS_RDF_TYPE_B64
+};
+static const sldns_rdf_type type_tkey_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME,
+ LDNS_RDF_TYPE_TIME,
+ LDNS_RDF_TYPE_TIME,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16_DATA,
+ LDNS_RDF_TYPE_INT16_DATA,
+};
+static const sldns_rdf_type type_tsig_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME,
+ LDNS_RDF_TYPE_TSIGTIME,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16_DATA,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16_DATA
+};
+static const sldns_rdf_type type_tlsa_wireformat[] = {
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_HEX
+};
+static const sldns_rdf_type type_hip_wireformat[] = {
+ LDNS_RDF_TYPE_HIP
+};
+static const sldns_rdf_type type_nid_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_ILNP64
+};
+static const sldns_rdf_type type_l32_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_A
+};
+static const sldns_rdf_type type_l64_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_ILNP64
+};
+static const sldns_rdf_type type_lp_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_DNAME
+};
+static const sldns_rdf_type type_eui48_wireformat[] = {
+ LDNS_RDF_TYPE_EUI48
+};
+static const sldns_rdf_type type_eui64_wireformat[] = {
+ LDNS_RDF_TYPE_EUI64
+};
+static const sldns_rdf_type type_uri_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_LONG_STR
+};
+static const sldns_rdf_type type_caa_wireformat[] = {
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_TAG,
+ LDNS_RDF_TYPE_LONG_STR
+};
+
+/* All RR's defined in 1035 are well known and can thus
+ * be compressed. See RFC3597. These RR's are:
+ * CNAME HINFO MB MD MF MG MINFO MR MX NULL NS PTR SOA TXT
+ */
+static sldns_rr_descriptor rdata_field_descriptors[] = {
+ /* 0 */
+ { 0, NULL, 0, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 1 */
+ {LDNS_RR_TYPE_A, "A", 1, 1, type_a_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 2 */
+ {LDNS_RR_TYPE_NS, "NS", 1, 1, type_ns_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 3 */
+ {LDNS_RR_TYPE_MD, "MD", 1, 1, type_md_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 4 */
+ {LDNS_RR_TYPE_MF, "MF", 1, 1, type_mf_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 5 */
+ {LDNS_RR_TYPE_CNAME, "CNAME", 1, 1, type_cname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 6 */
+ {LDNS_RR_TYPE_SOA, "SOA", 7, 7, type_soa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+ /* 7 */
+ {LDNS_RR_TYPE_MB, "MB", 1, 1, type_mb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 8 */
+ {LDNS_RR_TYPE_MG, "MG", 1, 1, type_mg_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 9 */
+ {LDNS_RR_TYPE_MR, "MR", 1, 1, type_mr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 10 */
+ {LDNS_RR_TYPE_NULL, "NULL", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 11 */
+ {LDNS_RR_TYPE_WKS, "WKS", 2, 2, type_wks_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 12 */
+ {LDNS_RR_TYPE_PTR, "PTR", 1, 1, type_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 13 */
+ {LDNS_RR_TYPE_HINFO, "HINFO", 2, 2, type_hinfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 14 */
+ {LDNS_RR_TYPE_MINFO, "MINFO", 2, 2, type_minfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+ /* 15 */
+ {LDNS_RR_TYPE_MX, "MX", 2, 2, type_mx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 16 */
+ {LDNS_RR_TYPE_TXT, "TXT", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+ /* 17 */
+ {LDNS_RR_TYPE_RP, "RP", 2, 2, type_rp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+ /* 18 */
+ {LDNS_RR_TYPE_AFSDB, "AFSDB", 2, 2, type_afsdb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 19 */
+ {LDNS_RR_TYPE_X25, "X25", 1, 1, type_x25_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 20 */
+ {LDNS_RR_TYPE_ISDN, "ISDN", 1, 2, type_isdn_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 21 */
+ {LDNS_RR_TYPE_RT, "RT", 2, 2, type_rt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 22 */
+ {LDNS_RR_TYPE_NSAP, "NSAP", 1, 1, type_nsap_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 23 */
+ {LDNS_RR_TYPE_NSAP_PTR, "NSAP-PTR", 1, 1, type_nsap_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 24 */
+ {LDNS_RR_TYPE_SIG, "SIG", 9, 9, type_sig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 25 */
+ {LDNS_RR_TYPE_KEY, "KEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 26 */
+ {LDNS_RR_TYPE_PX, "PX", 3, 3, type_px_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+ /* 27 */
+ {LDNS_RR_TYPE_GPOS, "GPOS", 3, 3, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 28 */
+ {LDNS_RR_TYPE_AAAA, "AAAA", 1, 1, type_aaaa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 29 */
+ {LDNS_RR_TYPE_LOC, "LOC", 1, 1, type_loc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 30 */
+ {LDNS_RR_TYPE_NXT, "NXT", 2, 2, type_nxt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 31 */
+ {LDNS_RR_TYPE_EID, "EID", 1, 1, type_eid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 32 */
+ {LDNS_RR_TYPE_NIMLOC, "NIMLOC", 1, 1, type_nimloc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 33 */
+ {LDNS_RR_TYPE_SRV, "SRV", 4, 4, type_srv_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 34 */
+ {LDNS_RR_TYPE_ATMA, "ATMA", 1, 1, type_atma_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 35 */
+ {LDNS_RR_TYPE_NAPTR, "NAPTR", 6, 6, type_naptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 36 */
+ {LDNS_RR_TYPE_KX, "KX", 2, 2, type_kx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 37 */
+ {LDNS_RR_TYPE_CERT, "CERT", 4, 4, type_cert_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 38 */
+ {LDNS_RR_TYPE_A6, "A6", 1, 1, type_a6_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 39 */
+ {LDNS_RR_TYPE_DNAME, "DNAME", 1, 1, type_dname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 40 */
+ {LDNS_RR_TYPE_SINK, "SINK", 1, 1, type_sink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 41 */
+ {LDNS_RR_TYPE_OPT, "OPT", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 42 */
+ {LDNS_RR_TYPE_APL, "APL", 0, 0, type_apl_wireformat, LDNS_RDF_TYPE_APL, LDNS_RR_NO_COMPRESS, 0 },
+ /* 43 */
+ {LDNS_RR_TYPE_DS, "DS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 44 */
+ {LDNS_RR_TYPE_SSHFP, "SSHFP", 3, 3, type_sshfp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 45 */
+ {LDNS_RR_TYPE_IPSECKEY, "IPSECKEY", 1, 1, type_ipseckey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 46 */
+ {LDNS_RR_TYPE_RRSIG, "RRSIG", 9, 9, type_rrsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 47 */
+ {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 48 */
+ {LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 49 */
+ {LDNS_RR_TYPE_DHCID, "DHCID", 1, 1, type_dhcid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 50 */
+ {LDNS_RR_TYPE_NSEC3, "NSEC3", 5, 6, type_nsec3_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 51 */
+ {LDNS_RR_TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, type_nsec3param_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 52 */
+ {LDNS_RR_TYPE_TLSA, "TLSA", 4, 4, type_tlsa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+{LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 55
+ * Hip ends with 0 or more Rendezvous Servers represented as dname's.
+ * Hence the LDNS_RDF_TYPE_DNAME _variable field and the _maximum field
+ * set to 0.
+ */
+ {LDNS_RR_TYPE_HIP, "HIP", 1, 1, type_hip_wireformat, LDNS_RDF_TYPE_DNAME, LDNS_RR_NO_COMPRESS, 0 },
+
+#ifdef DRAFT_RRTYPES
+ /* 56 */
+ {LDNS_RR_TYPE_NINFO, "NINFO", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+ /* 57 */
+ {LDNS_RR_TYPE_RKEY, "RKEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
+{LDNS_RR_TYPE_NULL, "TYPE56", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE57", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#endif
+ /* 58 */
+ {LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+
+ /* 59 */
+ {LDNS_RR_TYPE_CDS, "CDS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 60 */
+ {LDNS_RR_TYPE_CDNSKEY, "CDNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE63", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE64", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE65", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE66", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE67", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE68", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE69", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE70", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE71", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE72", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE73", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE74", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE75", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE76", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE77", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE78", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE79", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE80", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE81", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE82", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE83", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE84", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE85", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE86", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE87", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE88", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE89", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE90", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE91", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE92", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE93", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE94", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE95", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE96", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE97", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE98", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+ /* 99 */
+ {LDNS_RR_TYPE_SPF, "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+
+ /* UINFO [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE100", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* UID [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE101", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* GID [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE102", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* UNSPEC [IANA-Reserved] */
+{LDNS_RR_TYPE_NULL, "TYPE103", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+ /* 104 */
+ {LDNS_RR_TYPE_NID, "NID", 2, 2, type_nid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 105 */
+ {LDNS_RR_TYPE_L32, "L32", 2, 2, type_l32_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 106 */
+ {LDNS_RR_TYPE_L64, "L64", 2, 2, type_l64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 107 */
+ {LDNS_RR_TYPE_LP, "LP", 2, 2, type_lp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+
+ /* 108 */
+ {LDNS_RR_TYPE_EUI48, "EUI48", 1, 1, type_eui48_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 109 */
+ {LDNS_RR_TYPE_EUI64, "EUI64", 1, 1, type_eui64_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+{LDNS_RR_TYPE_NULL, "TYPE110", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE111", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE112", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE113", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE114", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE115", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE116", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE117", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE118", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE119", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE120", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE121", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE122", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE123", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE124", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE125", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE126", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE127", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE128", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE129", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE130", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE131", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE132", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE133", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE134", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE135", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE136", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE137", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE138", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE139", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE140", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE141", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE142", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE143", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE144", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE145", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE146", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE147", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE148", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE149", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE150", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE151", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE152", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE153", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE154", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE155", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE156", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE157", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE158", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE159", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE160", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE161", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE162", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE163", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE164", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE165", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE166", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE167", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE168", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE169", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE170", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE171", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE172", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE173", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE174", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE175", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE176", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE177", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE178", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE179", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE180", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE181", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE182", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE183", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE184", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE185", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE186", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE187", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE188", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE189", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE190", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE191", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE192", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE193", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE194", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE195", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE196", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE197", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE198", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE199", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE200", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE201", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE202", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE203", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE204", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE205", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE206", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE207", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE208", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE209", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE210", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE211", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE212", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE213", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE214", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE215", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE216", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE217", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE218", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE219", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE220", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE221", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE222", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE223", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE224", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE225", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE226", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE227", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE228", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE229", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE230", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE231", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE232", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE233", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE234", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE235", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE236", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE237", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE238", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE239", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE240", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE241", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE242", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE243", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE244", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE245", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE246", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+ /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one.
+ * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9.
+ */
+ /* 249 */
+ {LDNS_RR_TYPE_TKEY, "TKEY", 7, 7, type_tkey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* LDNS_RDF_TYPE_INT16_DATA takes two fields (length and data) as one.
+ * So, unlike RFC 2930 spec, we have 7 min/max rdf's i.s.o. 8/9.
+ */
+ /* 250 */
+ {LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+
+ /* IXFR: A request for a transfer of an incremental zone transfer */
+{LDNS_RR_TYPE_IXFR, "IXFR", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* AXFR: A request for a transfer of an entire zone */
+{LDNS_RR_TYPE_AXFR, "AXFR", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* MAILB: A request for mailbox-related records (MB, MG or MR) */
+{LDNS_RR_TYPE_MAILB, "MAILB", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* MAILA: A request for mail agent RRs (Obsolete - see MX) */
+{LDNS_RR_TYPE_MAILA, "MAILA", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* ANY: A request for all (available) records */
+{LDNS_RR_TYPE_ANY, "ANY", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+ /* 256 */
+ {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 257 */
+ {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+
+/* split in array, no longer contiguous */
+
+#ifdef DRAFT_RRTYPES
+ /* 32768 */
+ {LDNS_RR_TYPE_TA, "TA", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
+{LDNS_RR_TYPE_NULL, "TYPE32768", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#endif
+ /* 32769 */
+ {LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }
+};
+
+/**
+ * \def LDNS_RDATA_FIELD_DESCRIPTORS_COUNT
+ * computes the number of rdata fields
+ */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \
+ (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0]))
+
+const sldns_rr_descriptor *
+sldns_rr_descript(uint16_t type)
+{
+ size_t i;
+ if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) {
+ return &rdata_field_descriptors[type];
+ } else {
+ /* because not all array index equals type code */
+ for (i = LDNS_RDATA_FIELD_DESCRIPTORS_COMMON;
+ i < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT;
+ i++) {
+ if (rdata_field_descriptors[i]._type == type) {
+ return &rdata_field_descriptors[i];
+ }
+ }
+ return &rdata_field_descriptors[0];
+ }
+}
+
+size_t
+sldns_rr_descriptor_minimum(const sldns_rr_descriptor *descriptor)
+{
+ if (descriptor) {
+ return descriptor->_minimum;
+ } else {
+ return 0;
+ }
+}
+
+size_t
+sldns_rr_descriptor_maximum(const sldns_rr_descriptor *descriptor)
+{
+ if (descriptor) {
+ if (descriptor->_variable != LDNS_RDF_TYPE_NONE) {
+ return 65535; /* cannot be more than 64k */
+ } else {
+ return descriptor->_maximum;
+ }
+ } else {
+ return 0;
+ }
+}
+
+sldns_rdf_type
+sldns_rr_descriptor_field_type(const sldns_rr_descriptor *descriptor,
+ size_t index)
+{
+ assert(descriptor != NULL);
+ assert(index < descriptor->_maximum
+ || descriptor->_variable != LDNS_RDF_TYPE_NONE);
+ if (index < descriptor->_maximum) {
+ return descriptor->_wireformat[index];
+ } else {
+ return descriptor->_variable;
+ }
+}
+
+sldns_rr_type
+sldns_get_rr_type_by_name(const char *name)
+{
+ unsigned int i;
+ const char *desc_name;
+ const sldns_rr_descriptor *desc;
+
+ /* TYPEXX representation */
+ if (strlen(name) > 4 && strncasecmp(name, "TYPE", 4) == 0) {
+ return atoi(name + 4);
+ }
+
+ /* Normal types */
+ for (i = 0; i < (unsigned int) LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) {
+ desc = &rdata_field_descriptors[i];
+ desc_name = desc->_name;
+ if(desc_name &&
+ strlen(name) == strlen(desc_name) &&
+ strncasecmp(name, desc_name, strlen(desc_name)) == 0) {
+ /* because not all array index equals type code */
+ return desc->_type;
+ }
+ }
+
+ /* special cases for query types */
+ if (strlen(name) == 4 && strncasecmp(name, "IXFR", 4) == 0) {
+ return 251;
+ } else if (strlen(name) == 4 && strncasecmp(name, "AXFR", 4) == 0) {
+ return 252;
+ } else if (strlen(name) == 5 && strncasecmp(name, "MAILB", 5) == 0) {
+ return 253;
+ } else if (strlen(name) == 5 && strncasecmp(name, "MAILA", 5) == 0) {
+ return 254;
+ } else if (strlen(name) == 3 && strncasecmp(name, "ANY", 3) == 0) {
+ return 255;
+ }
+
+ return 0;
+}
+
+sldns_rr_class
+sldns_get_rr_class_by_name(const char *name)
+{
+ sldns_lookup_table *lt;
+
+ /* CLASSXX representation */
+ if (strlen(name) > 5 && strncasecmp(name, "CLASS", 5) == 0) {
+ return atoi(name + 5);
+ }
+
+ /* Normal types */
+ lt = sldns_lookup_by_name(sldns_rr_classes, name);
+ if (lt) {
+ return lt->id;
+ }
+ return 0;
+}
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
new file mode 100644
index 000000000000..678d2bc791e2
--- /dev/null
+++ b/sldns/rrdef.h
@@ -0,0 +1,502 @@
+/*
+ * rrdef.h
+ *
+ * RR definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Defines resource record types and constants.
+ */
+
+#ifndef LDNS_RRDEF_H
+#define LDNS_RRDEF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum length of a dname label */
+#define LDNS_MAX_LABELLEN 63
+/** Maximum length of a complete dname */
+#define LDNS_MAX_DOMAINLEN 255
+/** Maximum number of pointers in 1 dname */
+#define LDNS_MAX_POINTERS 65535
+/** The bytes TTL, CLASS and length use up in an rr */
+#define LDNS_RR_OVERHEAD 10
+
+#define LDNS_DNSSEC_KEYPROTO 3
+#define LDNS_KEY_ZONE_KEY 0x0100 /* set for ZSK&KSK, rfc 4034 */
+#define LDNS_KEY_SEP_KEY 0x0001 /* set for KSK, rfc 4034 */
+#define LDNS_KEY_REVOKE_KEY 0x0080 /* used to revoke KSK, rfc 5011 */
+
+/* The first fields are contiguous and can be referenced instantly */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 258
+
+/** lookuptable for rr classes */
+extern struct sldns_struct_lookup_table* sldns_rr_classes;
+
+/**
+ * The different RR classes.
+ */
+enum sldns_enum_rr_class
+{
+ /** the Internet */
+ LDNS_RR_CLASS_IN = 1,
+ /** Chaos class */
+ LDNS_RR_CLASS_CH = 3,
+ /** Hesiod (Dyer 87) */
+ LDNS_RR_CLASS_HS = 4,
+ /** None class, dynamic update */
+ LDNS_RR_CLASS_NONE = 254,
+ /** Any class */
+ LDNS_RR_CLASS_ANY = 255,
+
+ LDNS_RR_CLASS_FIRST = 0,
+ LDNS_RR_CLASS_LAST = 65535,
+ LDNS_RR_CLASS_COUNT = LDNS_RR_CLASS_LAST - LDNS_RR_CLASS_FIRST + 1
+};
+typedef enum sldns_enum_rr_class sldns_rr_class;
+
+/**
+ * Used to specify whether compression is allowed.
+ */
+enum sldns_enum_rr_compress
+{
+ /** compression is allowed */
+ LDNS_RR_COMPRESS,
+ LDNS_RR_NO_COMPRESS
+};
+typedef enum sldns_enum_rr_compress sldns_rr_compress;
+
+/**
+ * The different RR types.
+ */
+enum sldns_enum_rr_type
+{
+ /** a host address */
+ LDNS_RR_TYPE_A = 1,
+ /** an authoritative name server */
+ LDNS_RR_TYPE_NS = 2,
+ /** a mail destination (Obsolete - use MX) */
+ LDNS_RR_TYPE_MD = 3,
+ /** a mail forwarder (Obsolete - use MX) */
+ LDNS_RR_TYPE_MF = 4,
+ /** the canonical name for an alias */
+ LDNS_RR_TYPE_CNAME = 5,
+ /** marks the start of a zone of authority */
+ LDNS_RR_TYPE_SOA = 6,
+ /** a mailbox domain name (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MB = 7,
+ /** a mail group member (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MG = 8,
+ /** a mail rename domain name (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MR = 9,
+ /** a null RR (EXPERIMENTAL) */
+ LDNS_RR_TYPE_NULL = 10,
+ /** a well known service description */
+ LDNS_RR_TYPE_WKS = 11,
+ /** a domain name pointer */
+ LDNS_RR_TYPE_PTR = 12,
+ /** host information */
+ LDNS_RR_TYPE_HINFO = 13,
+ /** mailbox or mail list information */
+ LDNS_RR_TYPE_MINFO = 14,
+ /** mail exchange */
+ LDNS_RR_TYPE_MX = 15,
+ /** text strings */
+ LDNS_RR_TYPE_TXT = 16,
+ /** RFC1183 */
+ LDNS_RR_TYPE_RP = 17,
+ /** RFC1183 */
+ LDNS_RR_TYPE_AFSDB = 18,
+ /** RFC1183 */
+ LDNS_RR_TYPE_X25 = 19,
+ /** RFC1183 */
+ LDNS_RR_TYPE_ISDN = 20,
+ /** RFC1183 */
+ LDNS_RR_TYPE_RT = 21,
+ /** RFC1706 */
+ LDNS_RR_TYPE_NSAP = 22,
+ /** RFC1348 */
+ LDNS_RR_TYPE_NSAP_PTR = 23,
+ /** 2535typecode */
+ LDNS_RR_TYPE_SIG = 24,
+ /** 2535typecode */
+ LDNS_RR_TYPE_KEY = 25,
+ /** RFC2163 */
+ LDNS_RR_TYPE_PX = 26,
+ /** RFC1712 */
+ LDNS_RR_TYPE_GPOS = 27,
+ /** ipv6 address */
+ LDNS_RR_TYPE_AAAA = 28,
+ /** LOC record RFC1876 */
+ LDNS_RR_TYPE_LOC = 29,
+ /** 2535typecode */
+ LDNS_RR_TYPE_NXT = 30,
+ /** draft-ietf-nimrod-dns-01.txt */
+ LDNS_RR_TYPE_EID = 31,
+ /** draft-ietf-nimrod-dns-01.txt */
+ LDNS_RR_TYPE_NIMLOC = 32,
+ /** SRV record RFC2782 */
+ LDNS_RR_TYPE_SRV = 33,
+ /** http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
+ LDNS_RR_TYPE_ATMA = 34,
+ /** RFC2915 */
+ LDNS_RR_TYPE_NAPTR = 35,
+ /** RFC2230 */
+ LDNS_RR_TYPE_KX = 36,
+ /** RFC2538 */
+ LDNS_RR_TYPE_CERT = 37,
+ /** RFC2874 */
+ LDNS_RR_TYPE_A6 = 38,
+ /** RFC2672 */
+ LDNS_RR_TYPE_DNAME = 39,
+ /** dnsind-kitchen-sink-02.txt */
+ LDNS_RR_TYPE_SINK = 40,
+ /** Pseudo OPT record... */
+ LDNS_RR_TYPE_OPT = 41,
+ /** RFC3123 */
+ LDNS_RR_TYPE_APL = 42,
+ /** RFC4034, RFC3658 */
+ LDNS_RR_TYPE_DS = 43,
+ /** SSH Key Fingerprint */
+ LDNS_RR_TYPE_SSHFP = 44, /* RFC 4255 */
+ /** IPsec Key */
+ LDNS_RR_TYPE_IPSECKEY = 45, /* RFC 4025 */
+ /** DNSSEC */
+ LDNS_RR_TYPE_RRSIG = 46, /* RFC 4034 */
+ LDNS_RR_TYPE_NSEC = 47, /* RFC 4034 */
+ LDNS_RR_TYPE_DNSKEY = 48, /* RFC 4034 */
+
+ LDNS_RR_TYPE_DHCID = 49, /* RFC 4701 */
+ /* NSEC3 */
+ LDNS_RR_TYPE_NSEC3 = 50, /* RFC 5155 */
+ LDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */
+ LDNS_RR_TYPE_NSEC3PARAMS = 51,
+ LDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */
+
+ LDNS_RR_TYPE_HIP = 55, /* RFC 5205 */
+
+ /** draft-reid-dnsext-zs */
+ LDNS_RR_TYPE_NINFO = 56,
+ /** draft-reid-dnsext-rkey */
+ LDNS_RR_TYPE_RKEY = 57,
+ /** draft-ietf-dnsop-trust-history */
+ LDNS_RR_TYPE_TALINK = 58,
+ LDNS_RR_TYPE_CDS = 59, /** RFC 7344 */
+ LDNS_RR_TYPE_CDNSKEY = 60, /** RFC 7344 */
+
+ LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */
+
+ LDNS_RR_TYPE_UINFO = 100,
+ LDNS_RR_TYPE_UID = 101,
+ LDNS_RR_TYPE_GID = 102,
+ LDNS_RR_TYPE_UNSPEC = 103,
+
+ LDNS_RR_TYPE_NID = 104, /* RFC 6742 */
+ LDNS_RR_TYPE_L32 = 105, /* RFC 6742 */
+ LDNS_RR_TYPE_L64 = 106, /* RFC 6742 */
+ LDNS_RR_TYPE_LP = 107, /* RFC 6742 */
+
+ /** draft-jabley-dnsext-eui48-eui64-rrtypes */
+ LDNS_RR_TYPE_EUI48 = 108,
+ LDNS_RR_TYPE_EUI64 = 109,
+
+ LDNS_RR_TYPE_TKEY = 249, /* RFC 2930 */
+ LDNS_RR_TYPE_TSIG = 250,
+ LDNS_RR_TYPE_IXFR = 251,
+ LDNS_RR_TYPE_AXFR = 252,
+ /** A request for mailbox-related records (MB, MG or MR) */
+ LDNS_RR_TYPE_MAILB = 253,
+ /** A request for mail agent RRs (Obsolete - see MX) */
+ LDNS_RR_TYPE_MAILA = 254,
+ /** any type (wildcard) */
+ LDNS_RR_TYPE_ANY = 255,
+ LDNS_RR_TYPE_URI = 256, /* RFC 7553 */
+ LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */
+
+ /** DNSSEC Trust Authorities */
+ LDNS_RR_TYPE_TA = 32768,
+ /* RFC 4431, 5074, DNSSEC Lookaside Validation */
+ LDNS_RR_TYPE_DLV = 32769,
+
+ /* type codes from nsec3 experimental phase
+ LDNS_RR_TYPE_NSEC3 = 65324,
+ LDNS_RR_TYPE_NSEC3PARAMS = 65325, */
+ LDNS_RR_TYPE_FIRST = 0,
+ LDNS_RR_TYPE_LAST = 65535,
+ LDNS_RR_TYPE_COUNT = LDNS_RR_TYPE_LAST - LDNS_RR_TYPE_FIRST + 1
+};
+typedef enum sldns_enum_rr_type sldns_rr_type;
+
+/* RDATA */
+#define LDNS_MAX_RDFLEN 65535
+
+#define LDNS_RDF_SIZE_BYTE 1
+#define LDNS_RDF_SIZE_WORD 2
+#define LDNS_RDF_SIZE_DOUBLEWORD 4
+#define LDNS_RDF_SIZE_6BYTES 6
+#define LDNS_RDF_SIZE_8BYTES 8
+#define LDNS_RDF_SIZE_16BYTES 16
+
+#define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01
+
+#define LDNS_APL_IP4 1
+#define LDNS_APL_IP6 2
+#define LDNS_APL_MASK 0x7f
+#define LDNS_APL_NEGATION 0x80
+
+/**
+ * The different types of RDATA fields.
+ */
+enum sldns_enum_rdf_type
+{
+ /** none */
+ LDNS_RDF_TYPE_NONE,
+ /** domain name */
+ LDNS_RDF_TYPE_DNAME,
+ /** 8 bits */
+ LDNS_RDF_TYPE_INT8,
+ /** 16 bits */
+ LDNS_RDF_TYPE_INT16,
+ /** 32 bits */
+ LDNS_RDF_TYPE_INT32,
+ /** A record */
+ LDNS_RDF_TYPE_A,
+ /** AAAA record */
+ LDNS_RDF_TYPE_AAAA,
+ /** txt string */
+ LDNS_RDF_TYPE_STR,
+ /** apl data */
+ LDNS_RDF_TYPE_APL,
+ /** b32 string */
+ LDNS_RDF_TYPE_B32_EXT,
+ /** b64 string */
+ LDNS_RDF_TYPE_B64,
+ /** hex string */
+ LDNS_RDF_TYPE_HEX,
+ /** nsec type codes */
+ LDNS_RDF_TYPE_NSEC,
+ /** a RR type */
+ LDNS_RDF_TYPE_TYPE,
+ /** a class */
+ LDNS_RDF_TYPE_CLASS,
+ /** certificate algorithm */
+ LDNS_RDF_TYPE_CERT_ALG,
+ /** a key algorithm */
+ LDNS_RDF_TYPE_ALG,
+ /** unknown types */
+ LDNS_RDF_TYPE_UNKNOWN,
+ /** time (32 bits) */
+ LDNS_RDF_TYPE_TIME,
+ /** period */
+ LDNS_RDF_TYPE_PERIOD,
+ /** tsig time 48 bits */
+ LDNS_RDF_TYPE_TSIGTIME,
+ /** Represents the Public Key Algorithm, HIT and Public Key fields
+ for the HIP RR types. A HIP specific rdf type is used because of
+ the unusual layout in wireformat (see RFC 5205 Section 5) */
+ LDNS_RDF_TYPE_HIP,
+ /** variable length any type rdata where the length
+ is specified by the first 2 bytes */
+ LDNS_RDF_TYPE_INT16_DATA,
+ /** protocol and port bitmaps */
+ LDNS_RDF_TYPE_SERVICE,
+ /** location data */
+ LDNS_RDF_TYPE_LOC,
+ /** well known services */
+ LDNS_RDF_TYPE_WKS,
+ /** NSAP */
+ LDNS_RDF_TYPE_NSAP,
+ /** ATMA */
+ LDNS_RDF_TYPE_ATMA,
+ /** IPSECKEY */
+ LDNS_RDF_TYPE_IPSECKEY,
+ /** nsec3 hash salt */
+ LDNS_RDF_TYPE_NSEC3_SALT,
+ /** nsec3 base32 string (with length byte on wire */
+ LDNS_RDF_TYPE_NSEC3_NEXT_OWNER,
+
+ /** 4 shorts represented as 4 * 16 bit hex numbers
+ * seperated by colons. For NID and L64.
+ */
+ LDNS_RDF_TYPE_ILNP64,
+
+ /** 6 * 8 bit hex numbers seperated by dashes. For EUI48. */
+ LDNS_RDF_TYPE_EUI48,
+ /** 8 * 8 bit hex numbers seperated by dashes. For EUI64. */
+ LDNS_RDF_TYPE_EUI64,
+
+ /** A non-zero sequence of US-ASCII letters and numbers in lower case.
+ * For CAA.
+ */
+ LDNS_RDF_TYPE_TAG,
+
+ /** A <character-string> encoding of the value field as specified
+ * [RFC1035], Section 5.1., encoded as remaining rdata.
+ * For CAA.
+ */
+ LDNS_RDF_TYPE_LONG_STR,
+
+ /* Aliases */
+ LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC
+};
+typedef enum sldns_enum_rdf_type sldns_rdf_type;
+
+/**
+ * Algorithms used in dns
+ */
+enum sldns_enum_algorithm
+{
+ LDNS_RSAMD5 = 1, /* RFC 4034,4035 */
+ LDNS_DH = 2,
+ LDNS_DSA = 3,
+ LDNS_ECC = 4,
+ LDNS_RSASHA1 = 5,
+ LDNS_DSA_NSEC3 = 6,
+ LDNS_RSASHA1_NSEC3 = 7,
+ LDNS_RSASHA256 = 8, /* RFC 5702 */
+ LDNS_RSASHA512 = 10, /* RFC 5702 */
+ LDNS_ECC_GOST = 12, /* RFC 5933 */
+ LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */
+ LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */
+ LDNS_INDIRECT = 252,
+ LDNS_PRIVATEDNS = 253,
+ LDNS_PRIVATEOID = 254
+};
+typedef enum sldns_enum_algorithm sldns_algorithm;
+
+/**
+ * Hashing algorithms used in the DS record
+ */
+enum sldns_enum_hash
+{
+ LDNS_SHA1 = 1, /* RFC 4034 */
+ LDNS_SHA256 = 2, /* RFC 4509 */
+ LDNS_HASH_GOST = 3, /* RFC 5933 */
+ LDNS_SHA384 = 4 /* RFC 6605 */
+};
+typedef enum sldns_enum_hash sldns_hash;
+
+/**
+ * algorithms used in CERT rrs
+ */
+enum sldns_enum_cert_algorithm
+{
+ LDNS_CERT_PKIX = 1,
+ LDNS_CERT_SPKI = 2,
+ LDNS_CERT_PGP = 3,
+ LDNS_CERT_IPKIX = 4,
+ LDNS_CERT_ISPKI = 5,
+ LDNS_CERT_IPGP = 6,
+ LDNS_CERT_ACPKIX = 7,
+ LDNS_CERT_IACPKIX = 8,
+ LDNS_CERT_URI = 253,
+ LDNS_CERT_OID = 254
+};
+typedef enum sldns_enum_cert_algorithm sldns_cert_algorithm;
+
+/**
+ * EDNS option codes
+ */
+enum sldns_enum_edns_option
+{
+ LDNS_EDNS_LLQ = 1, /* http://files.dns-sd.org/draft-sekar-dns-llq.txt */
+ LDNS_EDNS_UL = 2, /* http://files.dns-sd.org/draft-sekar-dns-ul.txt */
+ LDNS_EDNS_NSID = 3, /* RFC5001 */
+ /* 4 draft-cheshire-edns0-owner-option */
+ LDNS_EDNS_DAU = 5, /* RFC6975 */
+ LDNS_EDNS_DHU = 6, /* RFC6975 */
+ LDNS_EDNS_N3U = 7, /* RFC6975 */
+ LDNS_EDNS_CLIENT_SUBNET = 8 /* draft-vandergaast-edns-client-subnet */
+};
+typedef enum sldns_enum_edns_option sldns_edns_option;
+
+#define LDNS_EDNS_MASK_DO_BIT 0x8000
+
+/**
+ * Contains all information about resource record types.
+ *
+ * This structure contains, for all rr types, the rdata fields that are defined.
+ */
+struct sldns_struct_rr_descriptor
+{
+ /** Type of the RR that is described here */
+ sldns_rr_type _type;
+ /** Textual name of the RR type. */
+ const char *_name;
+ /** Minimum number of rdata fields in the RRs of this type. */
+ uint8_t _minimum;
+ /** Maximum number of rdata fields in the RRs of this type. */
+ uint8_t _maximum;
+ /** Wireformat specification for the rr, i.e. the types of rdata fields in their respective order. */
+ const sldns_rdf_type *_wireformat;
+ /** Special rdf types */
+ sldns_rdf_type _variable;
+ /** Specifies whether compression can be used for dnames in this RR type. */
+ sldns_rr_compress _compress;
+ /** The number of DNAMEs in the _wireformat string, for parsing. */
+ uint8_t _dname_count;
+};
+typedef struct sldns_struct_rr_descriptor sldns_rr_descriptor;
+
+/**
+ * returns the resource record descriptor for the given rr type.
+ *
+ * \param[in] type the type value of the rr type
+ *\return the sldns_rr_descriptor for this type
+ */
+const sldns_rr_descriptor *sldns_rr_descript(uint16_t type);
+
+/**
+ * returns the minimum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in] descriptor for an rr type
+ * \return the minimum number of rdata fields
+ */
+size_t sldns_rr_descriptor_minimum(const sldns_rr_descriptor *descriptor);
+
+/**
+ * returns the maximum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in] descriptor for an rr type
+ * \return the maximum number of rdata fields
+ */
+size_t sldns_rr_descriptor_maximum(const sldns_rr_descriptor *descriptor);
+
+/**
+ * returns the rdf type for the given rdata field number of the rr type for the given descriptor.
+ *
+ * \param[in] descriptor for an rr type
+ * \param[in] field the field number
+ * \return the rdf type for the field
+ */
+sldns_rdf_type sldns_rr_descriptor_field_type(const sldns_rr_descriptor *descriptor, size_t field);
+
+/**
+ * retrieves a rrtype by looking up its name.
+ * \param[in] name a string with the name
+ * \return the type which corresponds with the name
+ */
+sldns_rr_type sldns_get_rr_type_by_name(const char *name);
+
+/**
+ * retrieves a class by looking up its name.
+ * \param[in] name string with the name
+ * \return the cass which corresponds with the name
+ */
+sldns_rr_class sldns_get_rr_class_by_name(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RRDEF_H */
diff --git a/sldns/sbuffer.c b/sldns/sbuffer.c
new file mode 100644
index 000000000000..a7fe53aa0278
--- /dev/null
+++ b/sldns/sbuffer.c
@@ -0,0 +1,178 @@
+/*
+ * buffer.c -- generic memory buffer .
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+/**
+ * \file
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+#include "config.h"
+#include "sldns/sbuffer.h"
+#include <stdarg.h>
+
+sldns_buffer *
+sldns_buffer_new(size_t capacity)
+{
+ sldns_buffer *buffer = (sldns_buffer*)malloc(sizeof(sldns_buffer));
+
+ if (!buffer) {
+ return NULL;
+ }
+
+ buffer->_data = (uint8_t *) malloc(capacity);
+ if (!buffer->_data) {
+ free(buffer);
+ return NULL;
+ }
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity = capacity;
+ buffer->_fixed = 0;
+ buffer->_status_err = 0;
+
+ sldns_buffer_invariant(buffer);
+
+ return buffer;
+}
+
+void
+sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+ assert(data != NULL);
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity = size;
+ buffer->_fixed = 0;
+ buffer->_data = malloc(size);
+ if(!buffer->_data) {
+ buffer->_status_err = 1;
+ return;
+ }
+ memcpy(buffer->_data, data, size);
+ buffer->_status_err = 0;
+
+ sldns_buffer_invariant(buffer);
+}
+
+void
+sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+ memset(buffer, 0, sizeof(*buffer));
+ buffer->_data = data;
+ buffer->_capacity = buffer->_limit = size;
+ buffer->_fixed = 1;
+}
+
+int
+sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity)
+{
+ void *data;
+
+ sldns_buffer_invariant(buffer);
+ assert(buffer->_position <= capacity);
+
+ data = (uint8_t *) realloc(buffer->_data, capacity);
+ if (!data) {
+ buffer->_status_err = 1;
+ return 0;
+ } else {
+ buffer->_data = data;
+ buffer->_limit = buffer->_capacity = capacity;
+ return 1;
+ }
+}
+
+int
+sldns_buffer_reserve(sldns_buffer *buffer, size_t amount)
+{
+ sldns_buffer_invariant(buffer);
+ assert(!buffer->_fixed);
+ if (buffer->_capacity < buffer->_position + amount) {
+ size_t new_capacity = buffer->_capacity * 3 / 2;
+
+ if (new_capacity < buffer->_position + amount) {
+ new_capacity = buffer->_position + amount;
+ }
+ if (!sldns_buffer_set_capacity(buffer, new_capacity)) {
+ buffer->_status_err = 1;
+ return 0;
+ }
+ }
+ buffer->_limit = buffer->_capacity;
+ return 1;
+}
+
+int
+sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+{
+ va_list args;
+ int written = 0;
+ size_t remaining;
+
+ if (sldns_buffer_status_ok(buffer)) {
+ sldns_buffer_invariant(buffer);
+ assert(buffer->_limit == buffer->_capacity);
+
+ remaining = sldns_buffer_remaining(buffer);
+ va_start(args, format);
+ written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
+ format, args);
+ va_end(args);
+ if (written == -1) {
+ buffer->_status_err = 1;
+ return -1;
+ } else if ((size_t) written >= remaining) {
+ if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
+ buffer->_status_err = 1;
+ return -1;
+ }
+ va_start(args, format);
+ written = vsnprintf((char *) sldns_buffer_current(buffer),
+ sldns_buffer_remaining(buffer), format, args);
+ va_end(args);
+ if (written == -1) {
+ buffer->_status_err = 1;
+ return -1;
+ }
+ }
+ buffer->_position += written;
+ }
+ return written;
+}
+
+void
+sldns_buffer_free(sldns_buffer *buffer)
+{
+ if (!buffer) {
+ return;
+ }
+
+ if (!buffer->_fixed)
+ free(buffer->_data);
+
+ free(buffer);
+}
+
+void *
+sldns_buffer_export(sldns_buffer *buffer)
+{
+ buffer->_fixed = 1;
+ return buffer->_data;
+}
+
+void
+sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
+{
+ size_t tocopy = sldns_buffer_limit(from);
+
+ if(tocopy > sldns_buffer_capacity(result))
+ tocopy = sldns_buffer_capacity(result);
+ sldns_buffer_clear(result);
+ sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
+ sldns_buffer_flip(result);
+}
diff --git a/sldns/sbuffer.h b/sldns/sbuffer.h
new file mode 100644
index 000000000000..3ce874fc7f76
--- /dev/null
+++ b/sldns/sbuffer.h
@@ -0,0 +1,706 @@
+/*
+ * buffer.h -- generic memory buffer.
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ *
+ * The buffer module implements a generic buffer. The API is based on
+ * the java.nio.Buffer interface.
+ */
+
+#ifndef LDNS_SBUFFER_H
+#define LDNS_SBUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef S_SPLINT_S
+# define INLINE
+#else
+# ifdef SWIG
+# define INLINE static
+# else
+# define INLINE static inline
+# endif
+#endif
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE uint16_t
+sldns_read_uint16(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohs(*(const uint16_t *) src);
+#else
+ const uint8_t *p = (const uint8_t *) src;
+ return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+#endif
+}
+
+INLINE uint32_t
+sldns_read_uint32(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohl(*(const uint32_t *) src);
+#else
+ const uint8_t *p = (const uint8_t *) src;
+ return ( ((uint32_t) p[0] << 24)
+ | ((uint32_t) p[1] << 16)
+ | ((uint32_t) p[2] << 8)
+ | (uint32_t) p[3]);
+#endif
+}
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE void
+sldns_write_uint16(void *dst, uint16_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint16_t *) dst = htons(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 8) & 0xff);
+ p[1] = (uint8_t) (data & 0xff);
+#endif
+}
+
+INLINE void
+sldns_write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint32_t *) dst = htonl(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 24) & 0xff);
+ p[1] = (uint8_t) ((data >> 16) & 0xff);
+ p[2] = (uint8_t) ((data >> 8) & 0xff);
+ p[3] = (uint8_t) (data & 0xff);
+#endif
+}
+
+
+/**
+ * \file sbuffer.h
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+
+/**
+ * implementation of buffers to ease operations
+ *
+ * sldns_buffers can contain arbitrary information, per octet. You can write
+ * to the current end of a buffer, read from the current position, and
+ * access any data within it.
+ */
+struct sldns_buffer
+{
+ /** The current position used for reading/writing */
+ size_t _position;
+
+ /** The read/write limit */
+ size_t _limit;
+
+ /** The amount of data the buffer can contain */
+ size_t _capacity;
+
+ /** The data contained in the buffer */
+ uint8_t *_data;
+
+ /** If the buffer is fixed it cannot be resized */
+ unsigned _fixed : 1;
+
+ /** The current state of the buffer. If writing to the buffer fails
+ * for any reason, this value is changed. This way, you can perform
+ * multiple writes in sequence and check for success afterwards. */
+ unsigned _status_err : 1;
+};
+typedef struct sldns_buffer sldns_buffer;
+
+#ifdef NDEBUG
+INLINE void
+sldns_buffer_invariant(sldns_buffer *ATTR_UNUSED(buffer))
+{
+}
+#else
+INLINE void
+sldns_buffer_invariant(sldns_buffer *buffer)
+{
+ assert(buffer != NULL);
+ assert(buffer->_position <= buffer->_limit);
+ assert(buffer->_limit <= buffer->_capacity);
+ assert(buffer->_data != NULL);
+}
+#endif
+
+/**
+ * creates a new buffer with the specified capacity.
+ *
+ * \param[in] capacity the size (in bytes) to allocate for the buffer
+ * \return the created buffer
+ */
+sldns_buffer *sldns_buffer_new(size_t capacity);
+
+/**
+ * creates a buffer with the specified data. The data IS copied
+ * and MEMORY allocations are done. The buffer is not fixed and can
+ * be resized using buffer_reserve().
+ *
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * Setup a buffer with the data pointed to. No data copied, no memory allocs.
+ * The buffer is fixed.
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * clears the buffer and make it ready for writing. The buffer's limit
+ * is set to the capacity and the position is set to 0.
+ * \param[in] buffer the buffer to clear
+ */
+INLINE void sldns_buffer_clear(sldns_buffer *buffer)
+{
+ sldns_buffer_invariant(buffer);
+
+ /* reset status here? */
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity;
+}
+
+/**
+ * makes the buffer ready for reading the data that has been written to
+ * the buffer. The buffer's limit is set to the current position and
+ * the position is set to 0.
+ *
+ * \param[in] buffer the buffer to flip
+ * \return void
+ */
+INLINE void sldns_buffer_flip(sldns_buffer *buffer)
+{
+ sldns_buffer_invariant(buffer);
+
+ buffer->_limit = buffer->_position;
+ buffer->_position = 0;
+}
+
+/**
+ * make the buffer ready for re-reading the data. The buffer's
+ * position is reset to 0.
+ * \param[in] buffer the buffer to rewind
+ */
+INLINE void sldns_buffer_rewind(sldns_buffer *buffer)
+{
+ sldns_buffer_invariant(buffer);
+
+ buffer->_position = 0;
+}
+
+/**
+ * returns the current position in the buffer (as a number of bytes)
+ * \param[in] buffer the buffer
+ * \return the current position
+ */
+INLINE size_t
+sldns_buffer_position(sldns_buffer *buffer)
+{
+ return buffer->_position;
+}
+
+/**
+ * sets the buffer's position to MARK. The position must be less than
+ * or equal to the buffer's limit.
+ * \param[in] buffer the buffer
+ * \param[in] mark the mark to use
+ */
+INLINE void
+sldns_buffer_set_position(sldns_buffer *buffer, size_t mark)
+{
+ assert(mark <= buffer->_limit);
+ buffer->_position = mark;
+}
+
+/**
+ * changes the buffer's position by COUNT bytes. The position must not
+ * be moved behind the buffer's limit or before the beginning of the
+ * buffer.
+ * \param[in] buffer the buffer
+ * \param[in] count the count to use
+ */
+INLINE void
+sldns_buffer_skip(sldns_buffer *buffer, ssize_t count)
+{
+ assert(buffer->_position + count <= buffer->_limit);
+ buffer->_position += count;
+}
+
+/**
+ * returns the maximum size of the buffer
+ * \param[in] buffer
+ * \return the size
+ */
+INLINE size_t
+sldns_buffer_limit(sldns_buffer *buffer)
+{
+ return buffer->_limit;
+}
+
+/**
+ * changes the buffer's limit. If the buffer's position is greater
+ * than the new limit the position is set to the limit.
+ * \param[in] buffer the buffer
+ * \param[in] limit the new limit
+ */
+INLINE void
+sldns_buffer_set_limit(sldns_buffer *buffer, size_t limit)
+{
+ assert(limit <= buffer->_capacity);
+ buffer->_limit = limit;
+ if (buffer->_position > buffer->_limit)
+ buffer->_position = buffer->_limit;
+}
+
+/**
+ * returns the number of bytes the buffer can hold.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_capacity(sldns_buffer *buffer)
+{
+ return buffer->_capacity;
+}
+
+/**
+ * changes the buffer's capacity. The data is reallocated so any
+ * pointers to the data may become invalid. The buffer's limit is set
+ * to the buffer's new capacity.
+ * \param[in] buffer the buffer
+ * \param[in] capacity the capacity to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity);
+
+/**
+ * ensures BUFFER can contain at least AMOUNT more bytes. The buffer's
+ * capacity is increased if necessary using buffer_set_capacity().
+ *
+ * The buffer's limit is always set to the (possibly increased)
+ * capacity.
+ * \param[in] buffer the buffer
+ * \param[in] amount amount to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount);
+
+/**
+ * returns a pointer to the data at the indicated position.
+ * \param[in] buffer the buffer
+ * \param[in] at position
+ * \return the pointer to the data
+ */
+INLINE uint8_t *
+sldns_buffer_at(const sldns_buffer *buffer, size_t at)
+{
+ assert(at <= buffer->_limit);
+ return buffer->_data + at;
+}
+
+/**
+ * returns a pointer to the beginning of the buffer (the data at
+ * position 0).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_begin(const sldns_buffer *buffer)
+{
+ return sldns_buffer_at(buffer, 0);
+}
+
+/**
+ * returns a pointer to the end of the buffer (the data at the buffer's
+ * limit).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_end(sldns_buffer *buffer)
+{
+ return sldns_buffer_at(buffer, buffer->_limit);
+}
+
+/**
+ * returns a pointer to the data at the buffer's current position.
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_current(sldns_buffer *buffer)
+{
+ return sldns_buffer_at(buffer, buffer->_position);
+}
+
+/**
+ * returns the number of bytes remaining between the indicated position and
+ * the limit.
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \return number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining_at(sldns_buffer *buffer, size_t at)
+{
+ sldns_buffer_invariant(buffer);
+ assert(at <= buffer->_limit);
+ return buffer->_limit - at;
+}
+
+/**
+ * returns the number of bytes remaining between the buffer's position and
+ * limit.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining(sldns_buffer *buffer)
+{
+ return sldns_buffer_remaining_at(buffer, buffer->_position);
+}
+
+/**
+ * checks if the buffer has at least COUNT more bytes available.
+ * Before reading or writing the caller needs to ensure enough space
+ * is available!
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available_at(sldns_buffer *buffer, size_t at, size_t count)
+{
+ return count <= sldns_buffer_remaining_at(buffer, at);
+}
+
+/**
+ * checks if the buffer has count bytes available at the current position
+ * \param[in] buffer the buffer
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available(sldns_buffer *buffer, size_t count)
+{
+ return sldns_buffer_available_at(buffer, buffer->_position, count);
+}
+
+/**
+ * writes the given data to the buffer at the specified position
+ * \param[in] buffer the buffer
+ * \param[in] at the position (in number of bytes) to write the data at
+ * \param[in] data pointer to the data to write to the buffer
+ * \param[in] count the number of bytes of data to write
+ */
+INLINE void
+sldns_buffer_write_at(sldns_buffer *buffer, size_t at, const void *data, size_t count)
+{
+ assert(sldns_buffer_available_at(buffer, at, count));
+ memcpy(buffer->_data + at, data, count);
+}
+
+/**
+ * writes count bytes of data to the current position of the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the data to write
+ * \param[in] count the lenght of the data to write
+ */
+INLINE void
+sldns_buffer_write(sldns_buffer *buffer, const void *data, size_t count)
+{
+ sldns_buffer_write_at(buffer, buffer->_position, data, count);
+ buffer->_position += count;
+}
+
+/**
+ * copies the given (null-delimited) string to the specified position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string_at(sldns_buffer *buffer, size_t at, const char *str)
+{
+ sldns_buffer_write_at(buffer, at, str, strlen(str));
+}
+
+/**
+ * copies the given (null-delimited) string to the current position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string(sldns_buffer *buffer, const char *str)
+{
+ sldns_buffer_write(buffer, str, strlen(str));
+}
+
+/**
+ * writes the given byte of data at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8_at(sldns_buffer *buffer, size_t at, uint8_t data)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+ buffer->_data[at] = data;
+}
+
+/**
+ * writes the given byte of data at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8(sldns_buffer *buffer, uint8_t data)
+{
+ sldns_buffer_write_u8_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 2 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16_at(sldns_buffer *buffer, size_t at, uint16_t data)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+ sldns_write_uint16(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 2 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16(sldns_buffer *buffer, uint16_t data)
+{
+ sldns_buffer_write_u16_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 4 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32_at(sldns_buffer *buffer, size_t at, uint32_t data)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+ sldns_write_uint32(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 4 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32(sldns_buffer *buffer, uint32_t data)
+{
+ sldns_buffer_write_u32_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * copies count bytes of data at the given position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer to start
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read_at(sldns_buffer *buffer, size_t at, void *data, size_t count)
+{
+ assert(sldns_buffer_available_at(buffer, at, count));
+ memcpy(data, buffer->_data + at, count);
+}
+
+/**
+ * copies count bytes of data at the current position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read(sldns_buffer *buffer, void *data, size_t count)
+{
+ sldns_buffer_read_at(buffer, buffer->_position, data, count);
+ buffer->_position += count;
+}
+
+/**
+ * returns the byte value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8_at(sldns_buffer *buffer, size_t at)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
+ return buffer->_data[at];
+}
+
+/**
+ * returns the byte value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8(sldns_buffer *buffer)
+{
+ uint8_t result = sldns_buffer_read_u8_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint8_t);
+ return result;
+}
+
+/**
+ * returns the 2-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16_at(sldns_buffer *buffer, size_t at)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
+ return sldns_read_uint16(buffer->_data + at);
+}
+
+/**
+ * returns the 2-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16(sldns_buffer *buffer)
+{
+ uint16_t result = sldns_buffer_read_u16_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint16_t);
+ return result;
+}
+
+/**
+ * returns the 4-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32_at(sldns_buffer *buffer, size_t at)
+{
+ assert(sldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
+ return sldns_read_uint32(buffer->_data + at);
+}
+
+/**
+ * returns the 4-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32(sldns_buffer *buffer)
+{
+ uint32_t result = sldns_buffer_read_u32_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint32_t);
+ return result;
+}
+
+/**
+ * returns the status of the buffer
+ * \param[in] buffer
+ * \return the status
+ */
+INLINE int
+sldns_buffer_status(sldns_buffer *buffer)
+{
+ return (int)buffer->_status_err;
+}
+
+/**
+ * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise
+ * \param[in] buffer the buffer
+ * \return true or false
+ */
+INLINE int
+sldns_buffer_status_ok(sldns_buffer *buffer)
+{
+ if (buffer) {
+ return sldns_buffer_status(buffer) == 0;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * prints to the buffer, increasing the capacity if required using
+ * buffer_reserve(). The buffer's position is set to the terminating '\\0'
+ * Returns the number of characters written (not including the
+ * terminating '\\0') or -1 on failure.
+ */
+int sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+ ATTR_FORMAT(printf, 2, 3);
+
+/**
+ * frees the buffer.
+ * \param[in] *buffer the buffer to be freed
+ * \return void
+ */
+void sldns_buffer_free(sldns_buffer *buffer);
+
+/**
+ * Makes the buffer fixed and returns a pointer to the data. The
+ * caller is responsible for free'ing the result.
+ * \param[in] *buffer the buffer to be exported
+ * \return void
+ */
+void *sldns_buffer_export(sldns_buffer *buffer);
+
+/**
+ * Copy contents of the from buffer to the result buffer and then flips
+ * the result buffer. Data will be silently truncated if the result buffer is
+ * too small.
+ * \param[out] *result resulting buffer which is copied to.
+ * \param[in] *from what to copy to result.
+ */
+void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_SBUFFER_H */
diff --git a/sldns/str2wire.c b/sldns/str2wire.c
new file mode 100644
index 000000000000..8cda8c750fb9
--- /dev/null
+++ b/sldns/str2wire.c
@@ -0,0 +1,2023 @@
+/**
+ * str2wire.c - read txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Parses text to wireformat.
+ */
+#include "config.h"
+#include "sldns/str2wire.h"
+#include "sldns/wire2str.h"
+#include "sldns/sbuffer.h"
+#include "sldns/parse.h"
+#include "sldns/parseutil.h"
+#include <ctype.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+/** return an error */
+#define RET_ERR(e, off) ((int)((e)|((off)<<LDNS_WIREPARSE_SHIFT)))
+/** Move parse error but keep its ID */
+#define RET_ERR_SHIFT(e, move) RET_ERR(LDNS_WIREPARSE_ERROR(e), LDNS_WIREPARSE_OFFSET(e)+(move));
+#define LDNS_IP6ADDRLEN (128/8)
+
+/*
+ * No special care is taken, all dots are translated into
+ * label separators.
+ * @param rel: true if the domain is not absolute (not terminated in .).
+ * The output is then still terminated with a '0' rootlabel.
+ */
+static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
+ size_t* olen, int* rel)
+{
+ size_t len;
+
+ const char *s;
+ uint8_t *q, *pq, label_len;
+
+ if(rel) *rel = 0;
+ len = strlen((char*)str);
+ /* octet representation can make strings a lot longer than actual length */
+ if (len > LDNS_MAX_DOMAINLEN * 4) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 0);
+ }
+ if (0 == len) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, 0);
+ }
+
+ /* root label */
+ if (1 == len && *str == '.') {
+ if(*olen < 1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
+ buf[0] = 0;
+ *olen = 1;
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ /* get on with the rest */
+
+ /* s is on the current character in the string
+ * pq points to where the labellength is going to go
+ * label_len keeps track of the current label's length
+ * q builds the dname inside the buf array
+ */
+ len = 0;
+ if(*olen < 1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0);
+ q = buf+1;
+ pq = buf;
+ label_len = 0;
+ for (s = str; *s; s++, q++) {
+ if (q >= buf + *olen)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
+ if (q > buf + LDNS_MAX_DOMAINLEN)
+ return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
+ switch (*s) {
+ case '.':
+ if (label_len > LDNS_MAX_LABELLEN) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
+ }
+ if (label_len == 0) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
+ }
+ len += label_len + 1;
+ *q = 0;
+ *pq = label_len;
+ label_len = 0;
+ pq = q;
+ break;
+ case '\\':
+ /* octet value or literal char */
+ s += 1;
+ if (!sldns_parse_escape(q, &s)) {
+ *q = 0;
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, q-buf);
+ }
+ s -= 1;
+ label_len++;
+ break;
+ default:
+ *q = (uint8_t)*s;
+ label_len++;
+ }
+ }
+
+ /* add root label if last char was not '.' */
+ if(label_len != 0) {
+ if(rel) *rel = 1;
+ if (q >= buf + *olen)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
+ if (q > buf + LDNS_MAX_DOMAINLEN) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
+ }
+ if (label_len > LDNS_MAX_LABELLEN) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf);
+ }
+ if (label_len == 0) { /* label_len 0 but not . at end? */
+ return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf);
+ }
+ len += label_len + 1;
+ *pq = label_len;
+ *q = 0;
+ }
+ len++;
+ *olen = len;
+
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len)
+{
+ return sldns_str2wire_dname_buf_rel(str, buf, len, NULL);
+}
+
+int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
+ uint8_t* origin, size_t origin_len)
+{
+ size_t dlen = *len;
+ int rel = 0;
+ int s = sldns_str2wire_dname_buf_rel(str, buf, &dlen, &rel);
+ if(s) return s;
+
+ if(rel && origin && dlen > 0) {
+ if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN)
+ return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW,
+ LDNS_MAX_DOMAINLEN);
+ if(dlen + origin_len - 1 > *len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ *len);
+ memmove(buf+dlen-1, origin, origin_len);
+ *len = dlen + origin_len - 1;
+ } else
+ *len = dlen;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+uint8_t* sldns_str2wire_dname(const char* str, size_t* len)
+{
+ uint8_t dname[LDNS_MAX_DOMAINLEN+1];
+ *len = sizeof(dname);
+ if(sldns_str2wire_dname_buf(str, dname, len) == 0) {
+ uint8_t* r = (uint8_t*)malloc(*len);
+ if(r) return memcpy(r, dname, *len);
+ }
+ *len = 0;
+ return NULL;
+}
+
+/** read owner name */
+static int
+rrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+ size_t prev_len, char* token, size_t token_len)
+{
+ /* split the rr in its parts -1 signals trouble */
+ if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+ sldns_buffer_position(strbuf));
+ }
+
+ if(strcmp(token, "@") == 0) {
+ uint8_t* tocopy;
+ if (origin) {
+ *dname_len = origin_len;
+ tocopy = origin;
+ } else if (prev) {
+ *dname_len = prev_len;
+ tocopy = prev;
+ } else {
+ /* default to root */
+ *dname_len = 1;
+ tocopy = (uint8_t*)"\0";
+ }
+ if(*len < *dname_len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ memmove(rr, tocopy, *dname_len);
+ } else if(strlen(token) == 0) {
+ /* no ownername was given, try prev, if that fails
+ * origin, else default to root */
+ uint8_t* tocopy;
+ if(prev) {
+ *dname_len = prev_len;
+ tocopy = prev;
+ } else if(origin) {
+ *dname_len = origin_len;
+ tocopy = origin;
+ } else {
+ *dname_len = 1;
+ tocopy = (uint8_t*)"\0";
+ }
+ if(*len < *dname_len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ memmove(rr, tocopy, *dname_len);
+ } else {
+ size_t dlen = *len;
+ int s = sldns_str2wire_dname_buf_origin(token, rr, &dlen,
+ origin, origin_len);
+ if(s) return RET_ERR_SHIFT(s,
+ sldns_buffer_position(strbuf)-strlen(token));
+ *dname_len = dlen;
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read ttl */
+static int
+rrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len,
+ int* not_there, uint32_t* ttl, uint32_t default_ttl)
+{
+ const char* endptr;
+ if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL,
+ sldns_buffer_position(strbuf));
+ }
+ *ttl = (uint32_t) sldns_str2period(token, &endptr);
+
+ if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) {
+ *not_there = 1;
+ /* ah, it's not there or something */
+ if (default_ttl == 0) {
+ *ttl = LDNS_DEFAULT_TTL;
+ } else {
+ *ttl = default_ttl;
+ }
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read class */
+static int
+rrinternal_get_class(sldns_buffer* strbuf, char* token, size_t token_len,
+ int* not_there, uint16_t* cl)
+{
+ /* if 'not_there' then we got token from previous parse routine */
+ if(!*not_there) {
+ /* parse new token for class */
+ if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_CLASS,
+ sldns_buffer_position(strbuf));
+ }
+ } else *not_there = 0;
+ *cl = sldns_get_rr_class_by_name(token);
+ /* class can be left out too, assume IN, current token must be type */
+ if(*cl == 0 && strcmp(token, "CLASS0") != 0) {
+ *not_there = 1;
+ *cl = LDNS_RR_CLASS_IN;
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read type */
+static int
+rrinternal_get_type(sldns_buffer* strbuf, char* token, size_t token_len,
+ int* not_there, uint16_t* tp)
+{
+ /* if 'not_there' then we got token from previous parse routine */
+ if(!*not_there) {
+ /* parse new token for type */
+ if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+ sldns_buffer_position(strbuf));
+ }
+ }
+ *tp = sldns_get_rr_type_by_name(token);
+ if(*tp == 0 && strcmp(token, "TYPE0") != 0) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+ sldns_buffer_position(strbuf));
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** put type, class, ttl into rr buffer */
+static int
+rrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len,
+ size_t dname_len, uint16_t tp, uint16_t cl, uint32_t ttl, int question)
+{
+ if(question) {
+ /* question is : name, type, class */
+ if(dname_len + 4 > len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ sldns_write_uint16(rr+dname_len, tp);
+ sldns_write_uint16(rr+dname_len+2, cl);
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ /* type(2), class(2), ttl(4), rdatalen(2 (later)) = 10 */
+ if(dname_len + 10 > len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ sldns_write_uint16(rr+dname_len, tp);
+ sldns_write_uint16(rr+dname_len+2, cl);
+ sldns_write_uint32(rr+dname_len+4, ttl);
+ sldns_write_uint16(rr+dname_len+8, 0); /* rdatalen placeholder */
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** find delimiters for type */
+static const char*
+rrinternal_get_delims(sldns_rdf_type rdftype, uint16_t r_cnt, uint16_t r_max)
+{
+ switch(rdftype) {
+ case LDNS_RDF_TYPE_B64 :
+ case LDNS_RDF_TYPE_HEX : /* These rdf types may con- */
+ case LDNS_RDF_TYPE_LOC : /* tain whitespace, only if */
+ case LDNS_RDF_TYPE_WKS : /* it is the last rd field. */
+ case LDNS_RDF_TYPE_IPSECKEY :
+ case LDNS_RDF_TYPE_NSEC : if (r_cnt == r_max - 1) {
+ return "\n";
+ }
+ break;
+ default : break;
+ }
+ return "\n\t ";
+}
+
+/* Syntactic sugar for sldns_rr_new_frm_str_internal */
+static int
+sldns_rdf_type_maybe_quoted(sldns_rdf_type rdf_type)
+{
+ return rdf_type == LDNS_RDF_TYPE_STR ||
+ rdf_type == LDNS_RDF_TYPE_LONG_STR;
+}
+
+/** see if rdata is quoted */
+static int
+rrinternal_get_quoted(sldns_buffer* strbuf, const char** delimiters,
+ sldns_rdf_type rdftype)
+{
+ if(sldns_rdf_type_maybe_quoted(rdftype) &&
+ sldns_buffer_remaining(strbuf) > 0) {
+
+ /* skip spaces */
+ while(sldns_buffer_remaining(strbuf) > 0 &&
+ *(sldns_buffer_current(strbuf)) == ' ') {
+ sldns_buffer_skip(strbuf, 1);
+ }
+
+ if(sldns_buffer_remaining(strbuf) > 0 &&
+ *(sldns_buffer_current(strbuf)) == '\"') {
+ *delimiters = "\"\0";
+ sldns_buffer_skip(strbuf, 1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** spool hex data into rdata */
+static int
+rrinternal_spool_hex(char* token, uint8_t* rr, size_t rr_len,
+ size_t rr_cur_len, size_t* cur_hex_data_size, size_t hex_data_size)
+{
+ char* p = token;
+ while(*p) {
+ if(isspace((unsigned char)*p)) {
+ p++;
+ continue;
+ }
+ if(!isxdigit((unsigned char)*p))
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+ p-token);
+ if(*cur_hex_data_size >= hex_data_size)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+ p-token);
+ /* extra robust check */
+ if(rr_cur_len+(*cur_hex_data_size)/2 >= rr_len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ p-token);
+ /* see if 16s or 1s */
+ if( ((*cur_hex_data_size)&1) == 0) {
+ rr[rr_cur_len+(*cur_hex_data_size)/2] =
+ (uint8_t)sldns_hexdigit_to_int(*p)*16;
+ } else {
+ rr[rr_cur_len+(*cur_hex_data_size)/2] +=
+ (uint8_t)sldns_hexdigit_to_int(*p);
+ }
+ p++;
+ (*cur_hex_data_size)++;
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read unknown rr type format */
+static int
+rrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len,
+ uint8_t* rr, size_t* rr_len, size_t* rr_cur_len, size_t pre_data_pos)
+{
+ const char* delim = "\n\t ";
+ size_t hex_data_size, cur_hex_data_size;
+ /* go back to before \#
+ * and skip it while setting delimiters better
+ */
+ sldns_buffer_set_position(strbuf, pre_data_pos);
+ if(sldns_bget_token(strbuf, token, delim, token_len) == -1)
+ return LDNS_WIREPARSE_ERR_GENERAL; /* should not fail */
+ /* read rdata octet length */
+ if(sldns_bget_token(strbuf, token, delim, token_len) == -1) {
+ /* something goes very wrong here */
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+ sldns_buffer_position(strbuf));
+ }
+ hex_data_size = (size_t)atoi(token);
+ if(hex_data_size > LDNS_MAX_RDFLEN ||
+ *rr_cur_len + hex_data_size > *rr_len) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ }
+ /* copy hex chars into hex str (2 chars per byte) */
+ hex_data_size *= 2;
+ cur_hex_data_size = 0;
+ while(cur_hex_data_size < hex_data_size) {
+ int status;
+ ssize_t c = sldns_bget_token(strbuf, token, delim, token_len);
+ if((status = rrinternal_spool_hex(token, rr, *rr_len,
+ *rr_cur_len, &cur_hex_data_size, hex_data_size)) != 0)
+ return RET_ERR_SHIFT(status,
+ sldns_buffer_position(strbuf)-strlen(token));
+ if(c == -1) {
+ if(cur_hex_data_size != hex_data_size)
+ return RET_ERR(
+ LDNS_WIREPARSE_ERR_SYNTAX_RDATA,
+ sldns_buffer_position(strbuf));
+ break;
+ }
+ }
+ *rr_cur_len += hex_data_size/2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** parse normal RR rdata element */
+static int
+rrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len,
+ uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype,
+ uint16_t rr_type, uint16_t r_cnt, uint16_t r_max, size_t dname_len,
+ uint8_t* origin, size_t origin_len)
+{
+ size_t len;
+ int status;
+
+ switch(rdftype) {
+ case LDNS_RDF_TYPE_DNAME:
+ /* check if the origin should be used or concatenated */
+ if(strcmp(token, "@") == 0) {
+ uint8_t* tocopy;
+ size_t copylen;
+ if(origin) {
+ copylen = origin_len;
+ tocopy = origin;
+ } else if(rr_type == LDNS_RR_TYPE_SOA) {
+ copylen = dname_len;
+ tocopy = rr; /* copy rr owner name */
+ } else {
+ copylen = 1;
+ tocopy = (uint8_t*)"\0";
+ }
+ if((*rr_cur_len) + copylen > rr_len)
+ return RET_ERR(
+ LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+ memmove(rr+*rr_cur_len, tocopy, copylen);
+ (*rr_cur_len) += copylen;
+ } else {
+ size_t dlen = rr_len - (*rr_cur_len);
+ int s = sldns_str2wire_dname_buf_origin(token,
+ rr+*rr_cur_len, &dlen, origin, origin_len);
+ if(s) return RET_ERR_SHIFT(s,
+ sldns_buffer_position(strbuf)-strlen(token));
+ (*rr_cur_len) += dlen;
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+
+ case LDNS_RDF_TYPE_HEX:
+ case LDNS_RDF_TYPE_B64:
+ /* When this is the last rdata field, then the
+ * rest should be read in (cause then these
+ * rdf types may contain spaces). */
+ if(r_cnt == r_max - 1) {
+ size_t tlen = strlen(token);
+ (void)sldns_bget_token(strbuf, token+tlen, "\n",
+ token_len - tlen);
+ }
+ break;
+ default:
+ break;
+ }
+
+ len = rr_len - (*rr_cur_len);
+ if((status=sldns_str2wire_rdf_buf(token, rr+(*rr_cur_len), &len,
+ rdftype)) != 0)
+ return RET_ERR_SHIFT(status,
+ sldns_buffer_position(strbuf)-strlen(token));
+ *rr_cur_len += len;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/**
+ * Parse one rdf token. Takes care of quotes and parenthesis.
+ */
+static int
+sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len,
+ int* quoted, int* parens, size_t* pre_data_pos,
+ const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
+{
+ size_t slen;
+
+ /* skip spaces */
+ while(sldns_buffer_remaining(strbuf) > 0 && !*quoted &&
+ *(sldns_buffer_current(strbuf)) == ' ') {
+ sldns_buffer_skip(strbuf, 1);
+ }
+
+ *pre_data_pos = sldns_buffer_position(strbuf);
+ if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters,
+ token_len, parens, (*quoted)?NULL:" \t") == -1) {
+ return 0;
+ }
+ slen = strlen(token);
+ /* check if not quoted yet, and we have encountered quotes */
+ if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
+ slen >= 2 &&
+ (token[0] == '"' || token[0] == '\'') &&
+ (token[slen-1] == '"' || token[slen-1] == '\'')) {
+ /* move token two smaller (quotes) with endnull */
+ memmove(token, token+1, slen-2);
+ token[slen-2] = 0;
+ slen -= 2;
+ *quoted = 1;
+ } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) &&
+ slen >= 2 &&
+ (token[0] == '"' || token[0] == '\'')) {
+ /* got the start quote (remove it) but read remainder
+ * of quoted string as well into remainder of token */
+ memmove(token, token+1, slen-1);
+ token[slen-1] = 0;
+ slen -= 1;
+ *quoted = 1;
+ /* rewind buffer over skipped whitespace */
+ while(sldns_buffer_position(strbuf) > 0 &&
+ (sldns_buffer_current(strbuf)[-1] == ' ' ||
+ sldns_buffer_current(strbuf)[-1] == '\t')) {
+ sldns_buffer_skip(strbuf, -1);
+ }
+ if(sldns_bget_token_par(strbuf, token+slen,
+ "\"", token_len-slen,
+ parens, NULL) == -1) {
+ return 0;
+ }
+ slen = strlen(token);
+ }
+ *token_strlen = slen;
+ return 1;
+}
+
+/** Add space and one more rdf token onto the existing token string. */
+static int
+sldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len,
+ int* quoted, int* parens, size_t* pre_data_pos,
+ const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen)
+{
+ size_t addlen = *token_len - *token_strlen;
+ size_t addstrlen = 0;
+
+ /* add space */
+ if(addlen < 1) return 0;
+ token[*token_strlen] = ' ';
+ token[++(*token_strlen)] = 0;
+
+ /* read another token */
+ addlen = *token_len - *token_strlen;
+ if(!sldns_parse_rdf_token(strbuf, token+*token_strlen, addlen, quoted,
+ parens, pre_data_pos, delimiters, rdftype, &addstrlen))
+ return 0;
+ (*token_strlen) += addstrlen;
+ return 1;
+}
+
+/** parse rdata from string into rr buffer(-remainder after dname). */
+static int
+rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
+ uint8_t* rr, size_t* rr_len, size_t dname_len, uint16_t rr_type,
+ uint8_t* origin, size_t origin_len)
+{
+ const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type);
+ uint16_t r_cnt, r_min, r_max;
+ size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen;
+ int was_unknown_rr_format = 0, parens = 0, status, quoted;
+ const char* delimiters;
+ sldns_rdf_type rdftype;
+ /* a desc is always returned */
+ if(!desc) return LDNS_WIREPARSE_ERR_GENERAL;
+ r_max = sldns_rr_descriptor_maximum(desc);
+ r_min = sldns_rr_descriptor_minimum(desc);
+ /* robust check */
+ if(rr_cur_len > *rr_len)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(strbuf));
+
+ /* because number of fields can be variable, we can't rely on
+ * _maximum() only */
+ for(r_cnt=0; r_cnt < r_max; r_cnt++) {
+ rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
+ delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max);
+ quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype);
+
+ if(!sldns_parse_rdf_token(strbuf, token, token_len, &quoted,
+ &parens, &pre_data_pos, delimiters, rdftype,
+ &token_strlen))
+ break;
+
+ /* rfc3597 specifies that any type can be represented
+ * with \# method, which can contain spaces...
+ * it does specify size though... */
+
+ /* unknown RR data */
+ if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 &&
+ !quoted && (token_strlen == 2 || token[2]==' ')) {
+ was_unknown_rr_format = 1;
+ if((status=rrinternal_parse_unknown(strbuf, token,
+ token_len, rr, rr_len, &rr_cur_len,
+ pre_data_pos)) != 0)
+ return status;
+ } else if(token_strlen > 0 || quoted) {
+ if(rdftype == LDNS_RDF_TYPE_HIP) {
+ /* affix the HIT and PK fields, with a space */
+ if(!sldns_affix_token(strbuf, token,
+ &token_len, &quoted, &parens,
+ &pre_data_pos, delimiters,
+ rdftype, &token_strlen))
+ break;
+ if(!sldns_affix_token(strbuf, token,
+ &token_len, &quoted, &parens,
+ &pre_data_pos, delimiters,
+ rdftype, &token_strlen))
+ break;
+ }
+
+ /* normal RR */
+ if((status=rrinternal_parse_rdf(strbuf, token,
+ token_len, rr, *rr_len, &rr_cur_len, rdftype,
+ rr_type, r_cnt, r_max, dname_len, origin,
+ origin_len)) != 0) {
+ return status;
+ }
+ }
+ }
+ if(!was_unknown_rr_format && r_cnt+1 < r_min) {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE,
+ sldns_buffer_position(strbuf));
+ }
+ while(parens != 0) {
+ /* read remainder, must be "" */
+ if(sldns_bget_token_par(strbuf, token, "\n", token_len,
+ &parens, " \t") == -1) {
+ if(parens != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
+ sldns_buffer_position(strbuf));
+ break;
+ }
+ if(strcmp(token, "") != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS,
+ sldns_buffer_position(strbuf));
+ }
+ /* write rdata length */
+ sldns_write_uint16(rr+dname_len+8, rr_cur_len-dname_len-10);
+ *rr_len = rr_cur_len;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/*
+ * trailing spaces are allowed
+ * leading spaces are not allowed
+ * allow ttl to be optional
+ * class is optional too
+ * if ttl is missing, and default_ttl is 0, use DEF_TTL
+ * allow ttl to be written as 1d3h
+ * So the RR should look like. e.g.
+ * miek.nl. 3600 IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. 1h IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. IN MX 10 elektron.atoom.net
+ */
+static int
+sldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+ size_t origin_len, uint8_t* prev, size_t prev_len, int question)
+{
+ int status;
+ int not_there = 0;
+ char token[LDNS_MAX_RDFLEN+1];
+ uint32_t ttl = 0;
+ uint16_t tp = 0, cl = 0;
+ size_t ddlen = 0;
+
+ /* string in buffer */
+ sldns_buffer strbuf;
+ sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+ if(!dname_len) dname_len = &ddlen;
+
+ /* parse the owner */
+ if((status=rrinternal_get_owner(&strbuf, rr, len, dname_len, origin,
+ origin_len, prev, prev_len, token, sizeof(token))) != 0)
+ return status;
+
+ /* parse the [ttl] [class] <type> */
+ if((status=rrinternal_get_ttl(&strbuf, token, sizeof(token),
+ &not_there, &ttl, default_ttl)) != 0)
+ return status;
+ if((status=rrinternal_get_class(&strbuf, token, sizeof(token),
+ &not_there, &cl)) != 0)
+ return status;
+ if((status=rrinternal_get_type(&strbuf, token, sizeof(token),
+ &not_there, &tp)) != 0)
+ return status;
+ /* put ttl, class, type into the rr result */
+ if((status=rrinternal_write_typeclassttl(&strbuf, rr, *len, *dname_len, tp, cl,
+ ttl, question)) != 0)
+ return status;
+ /* for a question-RR we are done, no rdata */
+ if(question) {
+ *len = *dname_len + 4;
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ /* rdata */
+ if((status=rrinternal_parse_rdata(&strbuf, token, sizeof(token),
+ rr, len, *dname_len, tp, origin, origin_len)) != 0)
+ return status;
+
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+ size_t origin_len, uint8_t* prev, size_t prev_len)
+{
+ return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
+ default_ttl, origin, origin_len, prev, prev_len, 0);
+}
+
+int sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+ size_t prev_len)
+{
+ return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len,
+ 0, origin, origin_len, prev, prev_len, 1);
+}
+
+uint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+2)
+ return 0;
+ return sldns_read_uint16(rr+dname_len);
+}
+
+uint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+4)
+ return 0;
+ return sldns_read_uint16(rr+dname_len+2);
+}
+
+uint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+8)
+ return 0;
+ return sldns_read_uint32(rr+dname_len+4);
+}
+
+uint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+10)
+ return 0;
+ return sldns_read_uint16(rr+dname_len+8);
+}
+
+uint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+10)
+ return NULL;
+ return rr+dname_len+10;
+}
+
+uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len)
+{
+ if(len < dname_len+10)
+ return NULL;
+ return rr+dname_len+8;
+}
+
+const char* sldns_get_errorstr_parse(int e)
+{
+ sldns_lookup_table *lt;
+ lt = sldns_lookup_by_id(sldns_wireparse_errors, LDNS_WIREPARSE_ERROR(e));
+ return lt?lt->name:"unknown error";
+}
+
+/* Strip whitespace from the start and the end of <line>. */
+static char *
+sldns_strip_ws(char *line)
+{
+ char *s = line, *e;
+
+ for (s = line; *s && isspace((unsigned char)*s); s++)
+ ;
+ for (e = strchr(s, 0); e > s+2 && isspace((unsigned char)e[-1]) && e[-2] != '\\'; e--)
+ ;
+ *e = 0;
+ return s;
+}
+
+int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
+ struct sldns_file_parse_state* parse_state)
+{
+ char line[LDNS_RR_BUF_SIZE+1];
+ ssize_t size;
+
+ /* read an entire line in from the file */
+ if((size = sldns_fget_token_l(in, line, LDNS_PARSE_SKIP_SPACE,
+ LDNS_RR_BUF_SIZE, parse_state?&parse_state->lineno:NULL))
+ == -1) {
+ /* if last line was empty, we are now at feof, which is not
+ * always a parse error (happens when for instance last line
+ * was a comment)
+ */
+ return LDNS_WIREPARSE_ERR_SYNTAX;
+ }
+
+ /* we can have the situation, where we've read ok, but still got
+ * no bytes to play with, in this case size is 0 */
+ if(size == 0) {
+ *len = 0;
+ *dname_len = 0;
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ if(strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) {
+ int s;
+ *len = 0;
+ *dname_len = 0;
+ if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
+ parse_state->origin_len = sizeof(parse_state->origin);
+ s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8),
+ parse_state->origin, &parse_state->origin_len);
+ if(s) parse_state->origin_len = 0;
+ return s;
+ } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) {
+ const char* end = NULL;
+ *len = 0;
+ *dname_len = 0;
+ if(!parse_state) return LDNS_WIREPARSE_ERR_OK;
+ parse_state->default_ttl = sldns_str2period(
+ sldns_strip_ws(line+5), &end);
+ } else if (strncmp(line, "$INCLUDE", 8) == 0) {
+ *len = 0;
+ *dname_len = 0;
+ return LDNS_WIREPARSE_ERR_INCLUDE;
+ } else {
+ return sldns_str2wire_rr_buf(line, rr, len, dname_len,
+ parse_state?parse_state->default_ttl:0,
+ (parse_state&&parse_state->origin_len)?
+ parse_state->origin:NULL,
+ parse_state->origin_len,
+ (parse_state&&parse_state->prev_rr_len)?
+ parse_state->prev_rr:NULL,
+ parse_state->prev_rr_len);
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
+ sldns_rdf_type rdftype)
+{
+ switch (rdftype) {
+ case LDNS_RDF_TYPE_DNAME:
+ return sldns_str2wire_dname_buf(str, rd, len);
+ case LDNS_RDF_TYPE_INT8:
+ return sldns_str2wire_int8_buf(str, rd, len);
+ case LDNS_RDF_TYPE_INT16:
+ return sldns_str2wire_int16_buf(str, rd, len);
+ case LDNS_RDF_TYPE_INT32:
+ return sldns_str2wire_int32_buf(str, rd, len);
+ case LDNS_RDF_TYPE_A:
+ return sldns_str2wire_a_buf(str, rd, len);
+ case LDNS_RDF_TYPE_AAAA:
+ return sldns_str2wire_aaaa_buf(str, rd, len);
+ case LDNS_RDF_TYPE_STR:
+ return sldns_str2wire_str_buf(str, rd, len);
+ case LDNS_RDF_TYPE_APL:
+ return sldns_str2wire_apl_buf(str, rd, len);
+ case LDNS_RDF_TYPE_B64:
+ return sldns_str2wire_b64_buf(str, rd, len);
+ case LDNS_RDF_TYPE_B32_EXT:
+ return sldns_str2wire_b32_ext_buf(str, rd, len);
+ case LDNS_RDF_TYPE_HEX:
+ return sldns_str2wire_hex_buf(str, rd, len);
+ case LDNS_RDF_TYPE_NSEC:
+ return sldns_str2wire_nsec_buf(str, rd, len);
+ case LDNS_RDF_TYPE_TYPE:
+ return sldns_str2wire_type_buf(str, rd, len);
+ case LDNS_RDF_TYPE_CLASS:
+ return sldns_str2wire_class_buf(str, rd, len);
+ case LDNS_RDF_TYPE_CERT_ALG:
+ return sldns_str2wire_cert_alg_buf(str, rd, len);
+ case LDNS_RDF_TYPE_ALG:
+ return sldns_str2wire_alg_buf(str, rd, len);
+ case LDNS_RDF_TYPE_TIME:
+ return sldns_str2wire_time_buf(str, rd, len);
+ case LDNS_RDF_TYPE_PERIOD:
+ return sldns_str2wire_period_buf(str, rd, len);
+ case LDNS_RDF_TYPE_LOC:
+ return sldns_str2wire_loc_buf(str, rd, len);
+ case LDNS_RDF_TYPE_WKS:
+ return sldns_str2wire_wks_buf(str, rd, len);
+ case LDNS_RDF_TYPE_NSAP:
+ return sldns_str2wire_nsap_buf(str, rd, len);
+ case LDNS_RDF_TYPE_ATMA:
+ return sldns_str2wire_atma_buf(str, rd, len);
+ case LDNS_RDF_TYPE_IPSECKEY:
+ return sldns_str2wire_ipseckey_buf(str, rd, len);
+ case LDNS_RDF_TYPE_NSEC3_SALT:
+ return sldns_str2wire_nsec3_salt_buf(str, rd, len);
+ case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+ return sldns_str2wire_b32_ext_buf(str, rd, len);
+ case LDNS_RDF_TYPE_ILNP64:
+ return sldns_str2wire_ilnp64_buf(str, rd, len);
+ case LDNS_RDF_TYPE_EUI48:
+ return sldns_str2wire_eui48_buf(str, rd, len);
+ case LDNS_RDF_TYPE_EUI64:
+ return sldns_str2wire_eui64_buf(str, rd, len);
+ case LDNS_RDF_TYPE_TAG:
+ return sldns_str2wire_tag_buf(str, rd, len);
+ case LDNS_RDF_TYPE_LONG_STR:
+ return sldns_str2wire_long_str_buf(str, rd, len);
+ case LDNS_RDF_TYPE_HIP:
+ return sldns_str2wire_hip_buf(str, rd, len);
+ case LDNS_RDF_TYPE_INT16_DATA:
+ return sldns_str2wire_int16_data_buf(str, rd, len);
+ case LDNS_RDF_TYPE_UNKNOWN:
+ case LDNS_RDF_TYPE_SERVICE:
+ return LDNS_WIREPARSE_ERR_NOT_IMPL;
+ case LDNS_RDF_TYPE_NONE:
+ default:
+ break;
+ }
+ return LDNS_WIREPARSE_ERR_GENERAL;
+}
+
+int sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ char* end;
+ uint8_t r = (uint8_t)strtol((char*)str, &end, 10);
+ if(*end != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+ if(*len < 1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[0] = r;
+ *len = 1;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ char* end;
+ uint16_t r = (uint16_t)strtol((char*)str, &end, 10);
+ if(*end != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+ if(*len < 2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ sldns_write_uint16(rd, r);
+ *len = 2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ char* end;
+ uint32_t r;
+ errno = 0; /* must set to zero before call,
+ note race condition on errno */
+ if(*str == '-')
+ r = (uint32_t)strtol((char*)str, &end, 10);
+ else r = (uint32_t)strtoul((char*)str, &end, 10);
+ if(*end != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str);
+ if(errno == ERANGE)
+ return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW;
+ if(*len < 4)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ sldns_write_uint32(rd, r);
+ *len = 4;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ struct in_addr address;
+ if(inet_pton(AF_INET, (char*)str, &address) != 1)
+ return LDNS_WIREPARSE_ERR_SYNTAX_IP4;
+ if(*len < sizeof(address))
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ memmove(rd, &address, sizeof(address));
+ *len = sizeof(address);
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len)
+{
+#ifdef AF_INET6
+ uint8_t address[LDNS_IP6ADDRLEN + 1];
+ if(inet_pton(AF_INET6, (char*)str, address) != 1)
+ return LDNS_WIREPARSE_ERR_SYNTAX_IP6;
+ if(*len < LDNS_IP6ADDRLEN)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ memmove(rd, address, LDNS_IP6ADDRLEN);
+ *len = LDNS_IP6ADDRLEN;
+ return LDNS_WIREPARSE_ERR_OK;
+#else
+ return LDNS_WIREPARSE_ERR_NOT_IMPL;
+#endif
+}
+
+int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ uint8_t ch = 0;
+ size_t sl = 0;
+ const char* s = str;
+ /* skip length byte */
+ if(*len < 1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+ /* read characters */
+ while(sldns_parse_char(&ch, &s)) {
+ if(sl >= 255)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str);
+ if(*len < sl+1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ s-str);
+ rd[++sl] = ch;
+ }
+ if(!s)
+ return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
+ rd[0] = (uint8_t)sl;
+ *len = sl+1;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char *my_str = str;
+
+ char my_ip_str[64];
+ size_t ip_str_len;
+
+ uint16_t family;
+ int negation;
+ size_t adflength = 0;
+ uint8_t data[16+4];
+ uint8_t prefix;
+ size_t i;
+
+ if(strlen(my_str) == 0) {
+ /* empty APL element, no data, no string */
+ *len = 0;
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ /* [!]afi:address/prefix */
+ if (strlen(my_str) < 2
+ || strchr(my_str, ':') == NULL
+ || strchr(my_str, '/') == NULL
+ || strchr(my_str, ':') > strchr(my_str, '/')) {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ if (my_str[0] == '!') {
+ negation = 1;
+ my_str += 1;
+ } else {
+ negation = 0;
+ }
+
+ family = (uint16_t) atoi(my_str);
+
+ my_str = strchr(my_str, ':') + 1;
+
+ /* need ip addr and only ip addr for inet_pton */
+ ip_str_len = (size_t) (strchr(my_str, '/') - my_str);
+ if(ip_str_len+1 > sizeof(my_ip_str))
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ (void)strlcpy(my_ip_str, my_str, sizeof(my_ip_str));
+ my_ip_str[ip_str_len] = 0;
+
+ if (family == 1) {
+ /* ipv4 */
+ if(inet_pton(AF_INET, my_ip_str, data+4) == 0)
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ for (i = 0; i < 4; i++) {
+ if (data[i+4] != 0) {
+ adflength = i + 1;
+ }
+ }
+ } else if (family == 2) {
+ /* ipv6 */
+ if (inet_pton(AF_INET6, my_ip_str, data+4) == 0)
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ for (i = 0; i < 16; i++) {
+ if (data[i+4] != 0) {
+ adflength = i + 1;
+ }
+ }
+ } else {
+ /* unknown family */
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ my_str = strchr(my_str, '/') + 1;
+ prefix = (uint8_t) atoi(my_str);
+
+ sldns_write_uint16(data, family);
+ data[2] = prefix;
+ data[3] = (uint8_t)adflength;
+ if (negation) {
+ /* set bit 1 of byte 3 */
+ data[3] = data[3] | 0x80;
+ }
+
+ if(*len < 4+adflength)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ memmove(rd, data, 4+adflength);
+ *len = 4+adflength;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ size_t sz = sldns_b64_pton_calculate_size(strlen(str));
+ int n;
+ if(*len < sz)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ n = sldns_b64_pton(str, rd, *len);
+ if(n < 0)
+ return LDNS_WIREPARSE_ERR_SYNTAX_B64;
+ *len = (size_t)n;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ size_t slen = strlen(str);
+ size_t sz = sldns_b32_pton_calculate_size(slen);
+ int n;
+ if(*len < 1+sz)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[0] = (uint8_t)sz;
+ n = sldns_b32_pton_extended_hex(str, slen, rd+1, *len-1);
+ if(n < 0)
+ return LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT;
+ *len = (size_t)n+1;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char* s = str;
+ size_t dlen = 0; /* number of hexdigits parsed */
+ while(*s) {
+ if(isspace((unsigned char)*s)) {
+ s++;
+ continue;
+ }
+ if(!isxdigit((unsigned char)*s))
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ if(*len < dlen/2 + 1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ s-str);
+ if((dlen&1)==0)
+ rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+ else rd[dlen/2] += (uint8_t)sldns_hexdigit_to_int(*s++);
+ dlen++;
+ }
+ if((dlen&1)!=0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ *len = dlen/2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char *delim = "\n\t ";
+ char token[64]; /* for a type name */
+ size_t type_count = 0;
+ int block;
+ size_t used = 0;
+ uint16_t maxtype = 0;
+ uint8_t typebits[8192]; /* 65536 bits */
+ uint8_t window_in_use[256];
+
+ /* string in buffer */
+ sldns_buffer strbuf;
+ sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+
+ /* parse the types */
+ memset(typebits, 0, sizeof(typebits));
+ memset(window_in_use, 0, sizeof(window_in_use));
+ while(sldns_buffer_remaining(&strbuf) > 0 &&
+ sldns_bget_token(&strbuf, token, delim, sizeof(token)) != -1) {
+ uint16_t t = sldns_get_rr_type_by_name(token);
+ if(token[0] == 0)
+ continue;
+ if(t == 0 && strcmp(token, "TYPE0") != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE,
+ sldns_buffer_position(&strbuf));
+ typebits[t/8] |= (0x80>>(t%8));
+ window_in_use[t/256] = 1;
+ type_count++;
+ if(t > maxtype) maxtype = t;
+ }
+
+ /* empty NSEC bitmap */
+ if(type_count == 0) {
+ *len = 0;
+ return LDNS_WIREPARSE_ERR_OK;
+ }
+
+ /* encode windows {u8 windowblock, u8 bitmaplength, 0-32u8 bitmap},
+ * block is 0-255 upper octet of types, length if 0-32. */
+ for(block = 0; block <= (int)maxtype/256; block++) {
+ int i, blocklen = 0;
+ if(!window_in_use[block])
+ continue;
+ for(i=0; i<32; i++) {
+ if(typebits[block*32+i] != 0)
+ blocklen = i+1;
+ }
+ if(blocklen == 0)
+ continue; /* empty window should have been !in_use */
+ if(used+blocklen+2 > *len)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[used+0] = (uint8_t)block;
+ rd[used+1] = (uint8_t)blocklen;
+ for(i=0; i<blocklen; i++) {
+ rd[used+2+i] = typebits[block*32+i];
+ }
+ used += blocklen+2;
+ }
+ *len = used;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ uint16_t t = sldns_get_rr_type_by_name(str);
+ if(t == 0 && strcmp(str, "TYPE0") != 0)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TYPE;
+ if(*len < 2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ sldns_write_uint16(rd, t);
+ *len = 2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ uint16_t c = sldns_get_rr_class_by_name(str);
+ if(c == 0 && strcmp(str, "CLASS0") != 0)
+ return LDNS_WIREPARSE_ERR_SYNTAX_CLASS;
+ if(*len < 2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ sldns_write_uint16(rd, c);
+ *len = 2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/* An certificate alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both */
+int sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_name(sldns_cert_algorithms,
+ str);
+ if(*len < 2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ if(lt) {
+ sldns_write_uint16(rd, (uint16_t)lt->id);
+ } else {
+ int s = sldns_str2wire_int16_buf(str, rd, len);
+ if(s) return s;
+ if(sldns_read_uint16(rd) == 0)
+ return LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM;
+ }
+ *len = 2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/* An alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both */
+int sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_name(sldns_algorithms, str);
+ if(*len < 1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ if(lt) {
+ rd[0] = (uint8_t)lt->id;
+ *len = 1;
+ } else {
+ /* try as-is (a number) */
+ return sldns_str2wire_int8_buf(str, rd, len);
+ }
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ /* convert a time YYYYDDMMHHMMSS to wireformat */
+ struct tm tm;
+ if(*len < 4)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+ /* Try to scan the time... */
+ memset(&tm, 0, sizeof(tm));
+ if (strlen(str) == 14 && sscanf(str, "%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) {
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+ /* Check values */
+ if (tm.tm_year < 70)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+ if (tm.tm_mon < 0 || tm.tm_mon > 11)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+ if (tm.tm_mday < 1 || tm.tm_mday > 31)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+ if (tm.tm_hour < 0 || tm.tm_hour > 23)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+ if (tm.tm_min < 0 || tm.tm_min > 59)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+ if (tm.tm_sec < 0 || tm.tm_sec > 59)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TIME;
+
+ sldns_write_uint32(rd, sldns_mktime_from_utc(&tm));
+ } else {
+ /* handle it as 32 bits timestamp */
+ char *end;
+ uint32_t l = (uint32_t)strtol((char*)str, &end, 10);
+ if(*end != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME,
+ end-(char*)str);
+ sldns_write_uint32(rd, l);
+ }
+ *len = 4;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char* end;
+ uint32_t p = sldns_str2period(str, &end);
+ if(*end != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str);
+ if(*len < 4)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ sldns_write_uint32(rd, p);
+ *len = 4;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+/** read "<digits>[.<digits>][mM]" into mantissa exponent format for LOC type */
+static int
+loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e)
+{
+ uint32_t meters = 0, cm = 0, val;
+ while (isblank((unsigned char)*my_str)) {
+ my_str++;
+ }
+ meters = (uint32_t)strtol(my_str, &my_str, 10);
+ if (*my_str == '.') {
+ my_str++;
+ cm = (uint32_t)strtol(my_str, &my_str, 10);
+ }
+ if (meters >= 1) {
+ *e = 2;
+ val = meters;
+ } else {
+ *e = 0;
+ val = cm;
+ }
+ while(val >= 10) {
+ (*e)++;
+ val /= 10;
+ }
+ *m = (uint8_t)val;
+
+ if (*e > 9)
+ return 0;
+ if (*my_str == 'm' || *my_str == 'M') {
+ my_str++;
+ }
+ *endstr = my_str;
+ return 1;
+}
+
+int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ uint32_t latitude = 0;
+ uint32_t longitude = 0;
+ uint32_t altitude = 0;
+
+ uint32_t equator = (uint32_t)1<<31; /* 2**31 */
+
+ /* only support version 0 */
+ uint32_t h = 0;
+ uint32_t m = 0;
+ uint8_t size_b = 1, size_e = 2;
+ uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
+ uint8_t vert_pre_b = 1, vert_pre_e = 3;
+
+ double s = 0.0;
+ int northerness;
+ int easterness;
+
+ char *my_str = (char *) str;
+
+ if (isdigit((unsigned char) *my_str)) {
+ h = (uint32_t) strtol(my_str, &my_str, 10);
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ while (isblank((unsigned char) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((unsigned char) *my_str)) {
+ m = (uint32_t) strtol(my_str, &my_str, 10);
+ } else if (*my_str == 'N' || *my_str == 'S') {
+ goto north;
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ while (isblank((unsigned char) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((unsigned char) *my_str)) {
+ s = strtod(my_str, &my_str);
+ }
+
+ /* skip blanks before norterness */
+ while (isblank((unsigned char) *my_str)) {
+ my_str++;
+ }
+
+north:
+ if (*my_str == 'N') {
+ northerness = 1;
+ } else if (*my_str == 'S') {
+ northerness = 0;
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ my_str++;
+
+ /* store number */
+ s = 1000.0 * s;
+ /* add a little to make floor in conversion a round */
+ s += 0.0005;
+ latitude = (uint32_t) s;
+ latitude += 1000 * 60 * m;
+ latitude += 1000 * 60 * 60 * h;
+ if (northerness) {
+ latitude = equator + latitude;
+ } else {
+ latitude = equator - latitude;
+ }
+ while (isblank((unsigned char)*my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((unsigned char) *my_str)) {
+ h = (uint32_t) strtol(my_str, &my_str, 10);
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ while (isblank((unsigned char) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((unsigned char) *my_str)) {
+ m = (uint32_t) strtol(my_str, &my_str, 10);
+ } else if (*my_str == 'E' || *my_str == 'W') {
+ goto east;
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ while (isblank((unsigned char)*my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((unsigned char) *my_str)) {
+ s = strtod(my_str, &my_str);
+ }
+
+ /* skip blanks before easterness */
+ while (isblank((unsigned char)*my_str)) {
+ my_str++;
+ }
+
+east:
+ if (*my_str == 'E') {
+ easterness = 1;
+ } else if (*my_str == 'W') {
+ easterness = 0;
+ } else {
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ my_str++;
+
+ /* store number */
+ s *= 1000.0;
+ /* add a little to make floor in conversion a round */
+ s += 0.0005;
+ longitude = (uint32_t) s;
+ longitude += 1000 * 60 * m;
+ longitude += 1000 * 60 * 60 * h;
+
+ if (easterness) {
+ longitude += equator;
+ } else {
+ longitude = equator - longitude;
+ }
+
+ altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
+ 10000000.0 + 0.5);
+ if (*my_str == 'm' || *my_str == 'M') {
+ my_str++;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ }
+
+ if(*len < 16)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[0] = 0;
+ rd[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
+ rd[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
+ rd[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
+ sldns_write_uint32(rd + 4, latitude);
+ sldns_write_uint32(rd + 8, longitude);
+ sldns_write_uint32(rd + 12, altitude);
+ *len = 16;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+static void
+ldns_tolower_str(char* s)
+{
+ if(s) {
+ while(*s) {
+ *s = (char)tolower((unsigned char)*s);
+ s++;
+ }
+ }
+}
+
+int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ int rd_len = 1;
+ int have_proto = 0;
+ char token[50], proto_str[50];
+ sldns_buffer strbuf;
+ sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+ proto_str[0]=0;
+
+ /* check we have one byte for proto */
+ if(*len < 1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+ while(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) > 0) {
+ ldns_tolower_str(token);
+ if(!have_proto) {
+ struct protoent *p = getprotobyname(token);
+ have_proto = 1;
+ if(p) rd[0] = (uint8_t)p->p_proto;
+ else rd[0] = (uint8_t)atoi(token);
+ (void)strlcpy(proto_str, token, sizeof(proto_str));
+ } else {
+ int serv_port;
+ struct servent *serv = getservbyname(token, proto_str);
+ if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port);
+ else {
+ serv_port = atoi(token);
+ if(serv_port == 0 && strcmp(token, "0") != 0) {
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+ sldns_buffer_position(&strbuf));
+ }
+ if(serv_port < 0 || serv_port > 65535) {
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX,
+ sldns_buffer_position(&strbuf));
+ }
+ }
+ if(rd_len < 1+serv_port/8+1) {
+ /* bitmap is larger, init new bytes at 0 */
+ if(*len < 1+(size_t)serv_port/8+1) {
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+ return RET_ERR(
+ LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(&strbuf));
+ }
+ memset(rd+rd_len, 0, 1+(size_t)serv_port/8+1-rd_len);
+ rd_len = 1+serv_port/8+1;
+ }
+ rd[1+ serv_port/8] |= (1 << (7 - serv_port % 8));
+ }
+ }
+ *len = (size_t)rd_len;
+
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char* s = str;
+ size_t slen;
+ size_t dlen = 0; /* number of hexdigits parsed */
+
+ /* just a hex string with optional dots? */
+ if (s[0] != '0' || s[1] != 'x')
+ return LDNS_WIREPARSE_ERR_INVALID_STR;
+ s += 2;
+ slen = strlen(s);
+ if(slen > LDNS_MAX_RDFLEN*2)
+ return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+ while(*s) {
+ if(isspace((unsigned char)*s) || *s == '.') {
+ s++;
+ continue;
+ }
+ if(!isxdigit((unsigned char)*s))
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ if(*len < dlen/2 + 1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ s-str);
+ if((dlen&1)==0)
+ rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+ else rd[dlen/2] += sldns_hexdigit_to_int(*s++);
+ dlen++;
+ }
+ if((dlen&1)!=0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ *len = dlen/2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ const char* s = str;
+ size_t slen = strlen(str);
+ size_t dlen = 0; /* number of hexdigits parsed */
+
+ /* just a hex string with optional dots? */
+ /* notimpl e.164 format */
+ if(slen > LDNS_MAX_RDFLEN*2)
+ return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+ while(*s) {
+ if(isspace((unsigned char)*s) || *s == '.') {
+ s++;
+ continue;
+ }
+ if(!isxdigit((unsigned char)*s))
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ if(*len < dlen/2 + 1)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ s-str);
+ if((dlen&1)==0)
+ rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16;
+ else rd[dlen/2] += sldns_hexdigit_to_int(*s++);
+ dlen++;
+ }
+ if((dlen&1)!=0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str);
+ *len = dlen/2;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ size_t gwlen = 0, keylen = 0;
+ int s;
+ uint8_t gwtype;
+ char token[512];
+ sldns_buffer strbuf;
+ sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str));
+
+ if(*len < 3)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ /* precedence */
+ if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ rd[0] = (uint8_t)atoi(token);
+ /* gateway_type */
+ if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ rd[1] = (uint8_t)atoi(token);
+ gwtype = rd[1];
+ /* algorithm */
+ if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ rd[2] = (uint8_t)atoi(token);
+
+ /* gateway */
+ if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ if(gwtype == 0) {
+ /* NOGATEWAY */
+ if(strcmp(token, ".") != 0)
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ gwlen = 0;
+ } else if(gwtype == 1) {
+ /* IP4 */
+ gwlen = *len - 3;
+ s = sldns_str2wire_a_buf(token, rd+3, &gwlen);
+ if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+ } else if(gwtype == 2) {
+ /* IP6 */
+ gwlen = *len - 3;
+ s = sldns_str2wire_aaaa_buf(token, rd+3, &gwlen);
+ if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+ } else if(gwtype == 3) {
+ /* DNAME */
+ gwlen = *len - 3;
+ s = sldns_str2wire_dname_buf(token, rd+3, &gwlen);
+ if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+ } else {
+ /* unknown gateway type */
+ return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR,
+ sldns_buffer_position(&strbuf));
+ }
+ /* double check for size */
+ if(*len < 3 + gwlen)
+ return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ sldns_buffer_position(&strbuf));
+
+ /* publickey in remainder of strbuf */
+ keylen = *len - 3 - gwlen;
+ s = sldns_str2wire_b64_buf((const char*)sldns_buffer_current(&strbuf),
+ rd+3+gwlen, &keylen);
+ if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf));
+
+ *len = 3 + gwlen + keylen;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ int i, salt_length_str = (int)strlen(str);
+ if (salt_length_str == 1 && str[0] == '-') {
+ salt_length_str = 0;
+ } else if (salt_length_str % 2 != 0) {
+ return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
+ }
+ if (salt_length_str > 512)
+ return LDNS_WIREPARSE_ERR_SYNTAX_HEX;
+ if(*len < 1+(size_t)salt_length_str / 2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[0] = (uint8_t) (salt_length_str / 2);
+ for (i = 0; i < salt_length_str; i += 2) {
+ if (isxdigit((unsigned char)str[i]) &&
+ isxdigit((unsigned char)str[i+1])) {
+ rd[1+i/2] = (uint8_t)(sldns_hexdigit_to_int(str[i])*16
+ + sldns_hexdigit_to_int(str[i+1]));
+ } else {
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, i);
+ }
+ }
+ *len = 1 + (size_t)rd[0];
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ unsigned int a, b, c, d;
+ uint16_t shorts[4];
+ int l;
+ if(*len < sizeof(shorts))
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+ if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 ||
+ l != (int)strlen(str) || /* more data to read */
+ strpbrk(str, "+-") /* signed hexes */
+ )
+ return LDNS_WIREPARSE_ERR_SYNTAX_ILNP64;
+ shorts[0] = htons(a);
+ shorts[1] = htons(b);
+ shorts[2] = htons(c);
+ shorts[3] = htons(d);
+ memmove(rd, &shorts, sizeof(shorts));
+ *len = sizeof(shorts);
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ unsigned int a, b, c, d, e, f;
+ int l;
+
+ if(*len < 6)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n",
+ &a, &b, &c, &d, &e, &f, &l) != 6 ||
+ l != (int)strlen(str))
+ return LDNS_WIREPARSE_ERR_SYNTAX_EUI48;
+ rd[0] = a;
+ rd[1] = b;
+ rd[2] = c;
+ rd[3] = d;
+ rd[4] = e;
+ rd[5] = f;
+ *len = 6;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ unsigned int a, b, c, d, e, f, g, h;
+ int l;
+
+ if(*len < 8)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n",
+ &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 ||
+ l != (int)strlen(str))
+ return LDNS_WIREPARSE_ERR_SYNTAX_EUI64;
+ rd[0] = a;
+ rd[1] = b;
+ rd[2] = c;
+ rd[3] = d;
+ rd[4] = e;
+ rd[5] = f;
+ rd[6] = g;
+ rd[7] = h;
+ *len = 8;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ size_t slen = strlen(str);
+ const char* ptr;
+
+ if (slen > 255)
+ return LDNS_WIREPARSE_ERR_SYNTAX_TAG;
+ if(*len < slen+1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ for (ptr = str; *ptr; ptr++) {
+ if(!isalnum((unsigned char)*ptr))
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str);
+ }
+ rd[0] = slen;
+ memmove(rd+1, str, slen);
+ *len = slen+1;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ uint8_t ch = 0;
+ const char* pstr = str;
+ size_t length = 0;
+
+ /* Fill data with parsed bytes */
+ while (sldns_parse_char(&ch, &pstr)) {
+ if(*len < length+1)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ rd[length++] = ch;
+ }
+ if(!pstr)
+ return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE;
+ *len = length;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ char* s, *end;
+ int e;
+ size_t hitlen, pklen = 0;
+ /* presentation format:
+ * pk-algo HIThex pubkeybase64
+ * wireformat:
+ * hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */
+ if(*len < 4)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+
+ /* read PK algorithm */
+ rd[1] = (uint8_t)strtol((char*)str, &s, 10);
+ if(*s != ' ')
+ return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str);
+ s++;
+ while(*s == ' ')
+ s++;
+
+ /* read HIT hex tag */
+ /* zero terminate the tag (replace later) */
+ end = strchr(s, ' ');
+ if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str);
+ *end = 0;
+ hitlen = *len - 4;
+ if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) {
+ *end = ' ';
+ return RET_ERR_SHIFT(e, s-(char*)str);
+ }
+ if(hitlen > 255) {
+ *end = ' ';
+ return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2);
+ }
+ rd[0] = (uint8_t)hitlen;
+ *end = ' ';
+ s = end+1;
+
+ /* read pubkey base64 sequence */
+ pklen = *len - 4 - hitlen;
+ if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0)
+ return RET_ERR_SHIFT(e, s-(char*)str);
+ if(pklen > 65535)
+ return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535);
+ sldns_write_uint16(rd+2, pklen);
+
+ *len = 4 + hitlen + pklen;
+ return LDNS_WIREPARSE_ERR_OK;
+}
+
+int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len)
+{
+ size_t sz = sldns_b64_pton_calculate_size(strlen(str));
+ int n;
+ if(*len < sz+2)
+ return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ if(sz > 65535)
+ return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW;
+ n = sldns_b64_pton(str, rd+2, (*len)-2);
+ if(n < 0)
+ return LDNS_WIREPARSE_ERR_SYNTAX_B64;
+ sldns_write_uint16(rd, (uint16_t)n);
+ *len = (size_t)n;
+ return LDNS_WIREPARSE_ERR_OK;
+}
diff --git a/sldns/str2wire.h b/sldns/str2wire.h
new file mode 100644
index 000000000000..527074a15b81
--- /dev/null
+++ b/sldns/str2wire.h
@@ -0,0 +1,541 @@
+/**
+ * str2wire.h - read txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Parses text to wireformat.
+ */
+
+#ifndef LDNS_STR2WIRE_H
+#define LDNS_STR2WIRE_H
+
+/* include rrdef for MAX_DOMAINLEN constant */
+#include <sldns/rrdef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct sldns_struct_lookup_table;
+
+/** buffer to read an RR, cannot be larger than 64K because of packet size */
+#define LDNS_RR_BUF_SIZE 65535 /* bytes */
+#define LDNS_DEFAULT_TTL 3600
+
+/*
+ * To convert class and type to string see
+ * sldns_get_rr_class_by_name(str)
+ * sldns_get_rr_type_by_name(str)
+ * from rrdef.h
+ */
+
+/**
+ * Convert text string into dname wireformat, mallocless, with user buffer.
+ * @param str: the text string with the domain name.
+ * @param buf: the result buffer, suggested size LDNS_MAX_DOMAINLEN+1
+ * @param len: length of the buffer on input, length of the result on output.
+ * @return 0 on success, otherwise an error.
+ */
+int sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len);
+
+/**
+ * Same as sldns_str2wire_dname_buf, but concatenates origin if the domain
+ * name is relative (does not end in '.').
+ * @param str: the text string with the domain name.
+ * @param buf: the result buffer, suggested size LDNS_MAX_DOMAINLEN+1
+ * @param len: length of the buffer on input, length of the result on output.
+ * @param origin: the origin to append or NULL (nothing is appended).
+ * @param origin_len: length of origin.
+ * @return 0 on success, otherwise an error.
+ */
+int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
+ uint8_t* origin, size_t origin_len);
+
+/**
+ * Convert text string into dname wireformat
+ * @param str: the text string with the domain name.
+ * @param len: returned length of wireformat.
+ * @return wireformat dname (malloced) or NULL on failure.
+ */
+uint8_t* sldns_str2wire_dname(const char* str, size_t* len);
+
+/**
+ * Convert text RR to wireformat, with user buffer.
+ * @param str: the RR data in text presentation format.
+ * @param rr: the buffer where the result is stored into. This buffer has
+ * the wire-dname(uncompressed), type, class, ttl, rdatalen, rdata.
+ * These values are probably not aligned, and in network format.
+ * Use the sldns_wirerr_get_xxx functions to access them safely.
+ * buffer size LDNS_RR_BUF_SIZE is suggested.
+ * @param len: on input the length of the buffer, on output the amount of
+ * the buffer used for the rr.
+ * @param dname_len: if non-NULL, filled with the dname length as result.
+ * Because after the dname you find the type, class, ttl, rdatalen, rdata.
+ * @param default_ttl: TTL used if no TTL available.
+ * @param origin: used for origin dname (if not NULL)
+ * @param origin_len: length of origin.
+ * @param prev: used for prev_rr dname (if not NULL)
+ * @param prev_len: length of prev.
+ * @return 0 on success, an error on failure.
+ */
+int sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint32_t default_ttl, uint8_t* origin,
+ size_t origin_len, uint8_t* prev, size_t prev_len);
+
+/**
+ * Same as sldns_str2wire_rr_buf, but there is no rdata, it returns an RR
+ * with zero rdata and no ttl. It has name, type, class.
+ * You can access those with the sldns_wirerr_get_type and class functions.
+ * @param str: the RR data in text presentation format.
+ * @param rr: the buffer where the result is stored into.
+ * @param len: on input the length of the buffer, on output the amount of
+ * the buffer used for the rr.
+ * @param dname_len: if non-NULL, filled with the dname length as result.
+ * Because after the dname you find the type, class, ttl, rdatalen, rdata.
+ * @param origin: used for origin dname (if not NULL)
+ * @param origin_len: length of origin.
+ * @param prev: used for prev_rr dname (if not NULL)
+ * @param prev_len: length of prev.
+ * @return 0 on success, an error on failure.
+ */
+int sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len,
+ size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev,
+ size_t prev_len);
+
+/**
+ * Get the type of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return type in host byteorder
+ */
+uint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the class of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return class in host byteorder
+ */
+uint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the ttl of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return ttl in host byteorder
+ */
+uint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata length of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return rdata length in host byteorder
+ * If the rdata length is larger than the rr-len allows, it is truncated.
+ * So, that it is safe to read the data length returned
+ * from this function from the rdata pointer of sldns_wirerr_get_rdata.
+ */
+uint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata pointer of the RR.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return rdata pointer
+ */
+uint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Get the rdata pointer of the RR. prefixed with rdata length.
+ * @param rr: the RR in wire format.
+ * @param len: rr length.
+ * @param dname_len: dname length to skip.
+ * @return pointer to rdatalength, followed by the rdata.
+ */
+uint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len);
+
+/**
+ * Parse result codes
+ */
+#define LDNS_WIREPARSE_MASK 0x0fff
+#define LDNS_WIREPARSE_SHIFT 12
+#define LDNS_WIREPARSE_ERROR(e) ((e)&LDNS_WIREPARSE_MASK)
+#define LDNS_WIREPARSE_OFFSET(e) (((e)&~LDNS_WIREPARSE_MASK)>>LDNS_WIREPARSE_SHIFT)
+/* use lookuptable to get error string, sldns_wireparse_errors */
+#define LDNS_WIREPARSE_ERR_OK 0
+#define LDNS_WIREPARSE_ERR_GENERAL 342
+#define LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW 343
+#define LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW 344
+#define LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL 345
+#define LDNS_WIREPARSE_ERR_LABEL_OVERFLOW 346
+#define LDNS_WIREPARSE_ERR_EMPTY_LABEL 347
+#define LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE 348
+#define LDNS_WIREPARSE_ERR_SYNTAX 349
+#define LDNS_WIREPARSE_ERR_SYNTAX_TTL 350
+#define LDNS_WIREPARSE_ERR_SYNTAX_TYPE 351
+#define LDNS_WIREPARSE_ERR_SYNTAX_CLASS 352
+#define LDNS_WIREPARSE_ERR_SYNTAX_RDATA 353
+#define LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE 354
+#define LDNS_WIREPARSE_ERR_INVALID_STR 355
+#define LDNS_WIREPARSE_ERR_SYNTAX_B64 356
+#define LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT 357
+#define LDNS_WIREPARSE_ERR_SYNTAX_HEX 358
+#define LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM 359
+#define LDNS_WIREPARSE_ERR_SYNTAX_TIME 360
+#define LDNS_WIREPARSE_ERR_SYNTAX_PERIOD 361
+#define LDNS_WIREPARSE_ERR_SYNTAX_ILNP64 362
+#define LDNS_WIREPARSE_ERR_SYNTAX_EUI48 363
+#define LDNS_WIREPARSE_ERR_SYNTAX_EUI64 364
+#define LDNS_WIREPARSE_ERR_SYNTAX_TAG 365
+#define LDNS_WIREPARSE_ERR_NOT_IMPL 366
+#define LDNS_WIREPARSE_ERR_SYNTAX_INT 367
+#define LDNS_WIREPARSE_ERR_SYNTAX_IP4 368
+#define LDNS_WIREPARSE_ERR_SYNTAX_IP6 369
+#define LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW 370
+#define LDNS_WIREPARSE_ERR_INCLUDE 371
+#define LDNS_WIREPARSE_ERR_PARENTHESIS 372
+
+/**
+ * Get reference to a constant string for the (parse) error.
+ * @param e: error return value
+ * @return string.
+ */
+const char* sldns_get_errorstr_parse(int e);
+
+/**
+ * wire parse state for parsing files
+ */
+struct sldns_file_parse_state {
+ /** the origin domain name, if len!=0. uncompressed wireformat */
+ uint8_t origin[LDNS_MAX_DOMAINLEN+1];
+ /** length of origin domain name, in bytes. 0 if not set. */
+ size_t origin_len;
+ /** the previous domain name, if len!=0. uncompressed wireformat*/
+ uint8_t prev_rr[LDNS_MAX_DOMAINLEN+1];
+ /** length of the previous domain name, in bytes. 0 if not set. */
+ size_t prev_rr_len;
+ /** default TTL, this is used if the text does not specify a TTL,
+ * host byteorder */
+ uint32_t default_ttl;
+ /** line number information */
+ int lineno;
+};
+
+/**
+ * Read one RR from zonefile with buffer for the data.
+ * @param in: file that is read from (one RR, multiple lines if it spans them).
+ * @param rr: this is malloced by the user and the result is stored here,
+ * if an RR is read. If no RR is read this is signalled with the
+ * return len set to 0 (for ORIGIN, TTL directives).
+ * @param len: on input, the length of the rr buffer. on output the rr len.
+ * Buffer size of 64k should be enough.
+ * @param dname_len: returns the length of the dname initial part of the rr.
+ * @param parse_state: pass a pointer to user-allocated struct.
+ * Contents are maintained by this function.
+ * If you pass NULL then ORIGIN and TTL directives are not honored.
+ * You can start out with a particular origin by pre-filling it.
+ * otherwise, zero the structure before passing it.
+ * lineno is incremented when a newline is passed by the parser,
+ * you should initialize it at 1 at the start of the file.
+ * @return 0 on success, error on failure.
+ */
+int sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
+ struct sldns_file_parse_state* parse_state);
+
+/**
+ * Convert one rdf in rdata to wireformat and parse from string.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @param rdftype: the type of the rdf.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len,
+ sldns_rdf_type rdftype);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT8 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT16 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT32 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_A from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_AAAA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_STR from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_APL from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_B64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_B32_EXT from string to wireformat.
+ * And also LDNS_RDF_TYPE_NSEC3_NEXT_OWNER.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_HEX from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSEC from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TYPE from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_CLASS from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_CERT_ALG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ALG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TIME from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_PERIOD from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_LOC from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_WKS from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSAP from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ATMA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_IPSECKEY from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_NSEC3_SALT from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_ILNP64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_EUI48 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_EUI64 from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_TAG from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_LONG_STR from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_HIP from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len);
+
+/**
+ * Convert rdf of type LDNS_RDF_TYPE_INT16_DATA from string to wireformat.
+ * @param str: the text to convert for this rdata element.
+ * @param rd: rdata buffer for the wireformat.
+ * @param len: length of rd buffer on input, used length on output.
+ * @return 0 on success, error on failure.
+ */
+int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_STR2WIRE_H */
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
new file mode 100644
index 000000000000..cec3bc7b08da
--- /dev/null
+++ b/sldns/wire2str.c
@@ -0,0 +1,1967 @@
+/*
+ * wire2str.c
+ *
+ * conversion routines from the wire format
+ * to the presentation format (strings)
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+/**
+ * \file
+ *
+ * Contains functions to translate the wireformat to text
+ * representation, as well as functions to print them.
+ */
+#include "config.h"
+#include "sldns/wire2str.h"
+#include "sldns/str2wire.h"
+#include "sldns/rrdef.h"
+#include "sldns/pkthdr.h"
+#include "sldns/parseutil.h"
+#include "sldns/sbuffer.h"
+#include "sldns/keyraw.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+/* lookup tables for standard DNS stuff */
+/* Taken from RFC 2535, section 7. */
+static sldns_lookup_table sldns_algorithms_data[] = {
+ { LDNS_RSAMD5, "RSAMD5" },
+ { LDNS_DH, "DH" },
+ { LDNS_DSA, "DSA" },
+ { LDNS_ECC, "ECC" },
+ { LDNS_RSASHA1, "RSASHA1" },
+ { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" },
+ { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
+ { LDNS_RSASHA256, "RSASHA256"},
+ { LDNS_RSASHA512, "RSASHA512"},
+ { LDNS_ECC_GOST, "ECC-GOST"},
+ { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
+ { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
+ { LDNS_INDIRECT, "INDIRECT" },
+ { LDNS_PRIVATEDNS, "PRIVATEDNS" },
+ { LDNS_PRIVATEOID, "PRIVATEOID" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
+
+/* hash algorithms in DS record */
+static sldns_lookup_table sldns_hashes_data[] = {
+ { LDNS_SHA1, "SHA1" },
+ { LDNS_SHA256, "SHA256" },
+ { LDNS_HASH_GOST, "HASH-GOST" },
+ { LDNS_SHA384, "SHA384" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_hashes = sldns_hashes_data;
+
+/* Taken from RFC 4398 */
+static sldns_lookup_table sldns_cert_algorithms_data[] = {
+ { LDNS_CERT_PKIX, "PKIX" },
+ { LDNS_CERT_SPKI, "SPKI" },
+ { LDNS_CERT_PGP, "PGP" },
+ { LDNS_CERT_IPKIX, "IPKIX" },
+ { LDNS_CERT_ISPKI, "ISPKI" },
+ { LDNS_CERT_IPGP, "IPGP" },
+ { LDNS_CERT_ACPKIX, "ACPKIX" },
+ { LDNS_CERT_IACPKIX, "IACPKIX" },
+ { LDNS_CERT_URI, "URI" },
+ { LDNS_CERT_OID, "OID" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_cert_algorithms = sldns_cert_algorithms_data;
+
+/* if these are used elsewhere */
+static sldns_lookup_table sldns_rcodes_data[] = {
+ { LDNS_RCODE_NOERROR, "NOERROR" },
+ { LDNS_RCODE_FORMERR, "FORMERR" },
+ { LDNS_RCODE_SERVFAIL, "SERVFAIL" },
+ { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" },
+ { LDNS_RCODE_NOTIMPL, "NOTIMPL" },
+ { LDNS_RCODE_REFUSED, "REFUSED" },
+ { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" },
+ { LDNS_RCODE_YXRRSET, "YXRRSET" },
+ { LDNS_RCODE_NXRRSET, "NXRRSET" },
+ { LDNS_RCODE_NOTAUTH, "NOTAUTH" },
+ { LDNS_RCODE_NOTZONE, "NOTZONE" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_rcodes = sldns_rcodes_data;
+
+static sldns_lookup_table sldns_opcodes_data[] = {
+ { LDNS_PACKET_QUERY, "QUERY" },
+ { LDNS_PACKET_IQUERY, "IQUERY" },
+ { LDNS_PACKET_STATUS, "STATUS" },
+ { LDNS_PACKET_NOTIFY, "NOTIFY" },
+ { LDNS_PACKET_UPDATE, "UPDATE" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_opcodes = sldns_opcodes_data;
+
+static sldns_lookup_table sldns_wireparse_errors_data[] = {
+ { LDNS_WIREPARSE_ERR_OK, "no parse error" },
+ { LDNS_WIREPARSE_ERR_GENERAL, "parse error" },
+ { LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, "Domainname length overflow" },
+ { LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" },
+ { LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, "buffer too small" },
+ { LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, "Label length overflow" },
+ { LDNS_WIREPARSE_ERR_EMPTY_LABEL, "Empty label" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" },
+ { LDNS_WIREPARSE_ERR_SYNTAX, "Syntax error, could not parse the RR" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_TTL, "Syntax error, could not parse the RR's TTL" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_TYPE, "Syntax error, could not parse the RR's type" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_CLASS, "Syntax error, could not parse the RR's class" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_RDATA, "Syntax error, could not parse the RR's rdata" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, "Syntax error, value expected" },
+ { LDNS_WIREPARSE_ERR_INVALID_STR, "Conversion error, string expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_B64, "Conversion error, b64 encoding expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT, "Conversion error, b32 ext encoding expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_HEX, "Conversion error, hex encoding expected" },
+ { LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_TIME, "Conversion error, time encoding expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, "Conversion error, time period encoding expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_ILNP64, "Conversion error, 4 colon separated hex numbers expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_EUI48,
+ "Conversion error, 6 two character hex numbers "
+ "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_EUI64,
+ "Conversion error, 8 two character hex numbers "
+ "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_TAG,
+ "Conversion error, a non-zero sequence of US-ASCII letters "
+ "and numbers in lower case expected" },
+ { LDNS_WIREPARSE_ERR_NOT_IMPL, "not implemented" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_INT, "Conversion error, integer expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_IP4, "Conversion error, ip4 addr expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_IP6, "Conversion error, ip6 addr expected" },
+ { LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer overflow" },
+ { LDNS_WIREPARSE_ERR_INCLUDE, "$INCLUDE directive was seen in the zone" },
+ { LDNS_WIREPARSE_ERR_PARENTHESIS, "Parse error, parenthesis mismatch" },
+ { 0, NULL }
+};
+sldns_lookup_table* sldns_wireparse_errors = sldns_wireparse_errors_data;
+
+static sldns_lookup_table sldns_edns_flags_data[] = {
+ { 3600, "do"},
+ { 0, NULL}
+};
+sldns_lookup_table* sldns_edns_flags = sldns_edns_flags_data;
+
+static sldns_lookup_table sldns_edns_options_data[] = {
+ { 1, "LLQ" },
+ { 2, "UL" },
+ { 3, "NSID" },
+ /* 4 draft-cheshire-edns0-owner-option */
+ { 5, "DAU" },
+ { 6, "DHU" },
+ { 7, "N3U" },
+ { 8, "edns-client-subnet" },
+ { 0, NULL}
+};
+sldns_lookup_table* sldns_edns_options = sldns_edns_options_data;
+
+char* sldns_wire2str_pkt(uint8_t* data, size_t len)
+{
+ size_t slen = (size_t)sldns_wire2str_pkt_buf(data, len, NULL, 0);
+ char* result = (char*)malloc(slen+1);
+ if(!result) return NULL;
+ sldns_wire2str_pkt_buf(data, len, result, slen+1);
+ return result;
+}
+
+char* sldns_wire2str_rr(uint8_t* rr, size_t len)
+{
+ size_t slen = (size_t)sldns_wire2str_rr_buf(rr, len, NULL, 0);
+ char* result = (char*)malloc(slen+1);
+ if(!result) return NULL;
+ sldns_wire2str_rr_buf(rr, len, result, slen+1);
+ return result;
+}
+
+char* sldns_wire2str_type(uint16_t rrtype)
+{
+ char buf[16];
+ sldns_wire2str_type_buf(rrtype, buf, sizeof(buf));
+ return strdup(buf);
+}
+
+char* sldns_wire2str_class(uint16_t rrclass)
+{
+ char buf[16];
+ sldns_wire2str_class_buf(rrclass, buf, sizeof(buf));
+ return strdup(buf);
+}
+
+char* sldns_wire2str_dname(uint8_t* dname, size_t dname_len)
+{
+ size_t slen=(size_t)sldns_wire2str_dname_buf(dname, dname_len, NULL, 0);
+ char* result = (char*)malloc(slen+1);
+ if(!result) return NULL;
+ sldns_wire2str_dname_buf(dname, dname_len, result, slen+1);
+ return result;
+}
+
+char* sldns_wire2str_rcode(int rcode)
+{
+ char buf[16];
+ sldns_wire2str_rcode_buf(rcode, buf, sizeof(buf));
+ return strdup(buf);
+}
+
+int sldns_wire2str_pkt_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_pkt_scan(&d, &dlen, &s, &slen);
+}
+
+int sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
+ size_t str_len, uint16_t rrtype)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_rdata_scan(&rdata, &rdata_len, &str, &str_len,
+ rrtype, NULL, 0);
+}
+
+int sldns_wire2str_rr_unknown_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rrlen, size_t dname_len,
+ char* s, size_t slen)
+{
+ uint16_t rrtype = sldns_wirerr_get_type(rr, rrlen, dname_len);
+ return sldns_wire2str_rr_comment_print(&s, &slen, rr, rrlen, dname_len,
+ rrtype);
+}
+
+int sldns_wire2str_type_buf(uint16_t rrtype, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_type_print(&s, &slen, rrtype);
+}
+
+int sldns_wire2str_class_buf(uint16_t rrclass, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_class_print(&s, &slen, rrclass);
+}
+
+int sldns_wire2str_rcode_buf(int rcode, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_rcode_print(&s, &slen, rcode);
+}
+
+int sldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
+{
+ /* use arguments as temporary variables */
+ return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0);
+}
+
+int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args)
+{
+ int w = vsnprintf(*str, *slen, format, args);
+ if(w < 0) {
+ /* error in printout */
+ return 0;
+ } else if((size_t)w >= *slen) {
+ *str = NULL; /* we do not want str to point outside of buffer*/
+ *slen = 0;
+ } else {
+ *str += w;
+ *slen -= w;
+ }
+ return w;
+}
+
+int sldns_str_print(char** str, size_t* slen, const char* format, ...)
+{
+ int w;
+ va_list args;
+ va_start(args, format);
+ w = sldns_str_vprint(str, slen, format, args);
+ va_end(args);
+ return w;
+}
+
+/** print hex format into text buffer for specified length */
+static int print_hex_buf(char** s, size_t* slen, uint8_t* buf, size_t len)
+{
+ const char* hex = "0123456789ABCDEF";
+ size_t i;
+ for(i=0; i<len; i++) {
+ (void)sldns_str_print(s, slen, "%c%c", hex[(buf[i]&0xf0)>>4],
+ hex[buf[i]&0x0f]);
+ }
+ return (int)len*2;
+}
+
+/** print remainder of buffer in hex format with prefixed text */
+static int print_remainder_hex(const char* pref, uint8_t** d, size_t* dlen,
+ char** s, size_t* slen)
+{
+ int w = 0;
+ w += sldns_str_print(s, slen, "%s", pref);
+ w += print_hex_buf(s, slen, *d, *dlen);
+ *d += *dlen;
+ *dlen = 0;
+ return w;
+}
+
+int sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+ int w = 0;
+ unsigned qdcount, ancount, nscount, arcount, i;
+ uint8_t* pkt = *d;
+ size_t pktlen = *dlen;
+ if(*dlen >= LDNS_HEADER_SIZE) {
+ qdcount = (unsigned)LDNS_QDCOUNT(*d);
+ ancount = (unsigned)LDNS_ANCOUNT(*d);
+ nscount = (unsigned)LDNS_NSCOUNT(*d);
+ arcount = (unsigned)LDNS_ARCOUNT(*d);
+ } else {
+ qdcount = ancount = nscount = arcount = 0;
+ }
+ w += sldns_wire2str_header_scan(d, dlen, s, slen);
+ w += sldns_str_print(s, slen, "\n");
+ w += sldns_str_print(s, slen, ";; QUESTION SECTION:\n");
+ for(i=0; i<qdcount; i++) {
+ w += sldns_wire2str_rrquestion_scan(d, dlen, s, slen,
+ pkt, pktlen);
+ if(!*dlen) break;
+ }
+ w += sldns_str_print(s, slen, "\n");
+ w += sldns_str_print(s, slen, ";; ANSWER SECTION:\n");
+ for(i=0; i<ancount; i++) {
+ w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+ if(!*dlen) break;
+ }
+ w += sldns_str_print(s, slen, "\n");
+ w += sldns_str_print(s, slen, ";; AUTHORITY SECTION:\n");
+ for(i=0; i<nscount; i++) {
+ w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+ if(!*dlen) break;
+ }
+ w += sldns_str_print(s, slen, "\n");
+ w += sldns_str_print(s, slen, ";; ADDITIONAL SECTION:\n");
+ for(i=0; i<arcount; i++) {
+ w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+ if(!*dlen) break;
+ }
+ /* other fields: WHEN(time), SERVER(IP) not available here. */
+ w += sldns_str_print(s, slen, ";; MSG SIZE rcvd: %d\n", (int)pktlen);
+ if(*dlen > 0) {
+ w += print_remainder_hex(";; trailing garbage 0x",
+ d, dlen, s, slen);
+ w += sldns_str_print(s, slen, "\n");
+ }
+ return w;
+}
+
+/** scan type, class and ttl and printout, for rr */
+static int sldns_rr_tcttl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w = 0;
+ uint16_t t, c;
+ uint32_t ttl;
+ if(*dl < 8) {
+ if(*dl < 4)
+ return w + print_remainder_hex("; Error malformed 0x",
+ d, dl, s, sl);
+ /* these print values or 0x.. if none left */
+ t = sldns_read_uint16(*d);
+ c = sldns_read_uint16((*d)+2);
+ (*d)+=4;
+ (*dl)-=4;
+ w += sldns_wire2str_class_print(s, sl, c);
+ w += sldns_str_print(s, sl, "\t");
+ w += sldns_wire2str_type_print(s, sl, t);
+ if(*dl == 0)
+ return w + sldns_str_print(s, sl, "; Error no ttl");
+ return w + print_remainder_hex(
+ "; Error malformed ttl 0x", d, dl, s, sl);
+ }
+ t = sldns_read_uint16(*d);
+ c = sldns_read_uint16((*d)+2);
+ ttl = sldns_read_uint32((*d)+4);
+ (*d)+=8;
+ (*dl)-=8;
+ w += sldns_str_print(s, sl, "%lu\t", (unsigned long)ttl);
+ w += sldns_wire2str_class_print(s, sl, c);
+ w += sldns_str_print(s, sl, "\t");
+ w += sldns_wire2str_type_print(s, sl, t);
+ return w;
+}
+
+int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+ uint8_t* pkt, size_t pktlen)
+{
+ int w = 0;
+ uint8_t* rr = *d;
+ size_t rrlen = *dlen, dname_off, rdlen, ordlen;
+ uint16_t rrtype = 0;
+
+ if(*dlen >= 3 && (*d)[0]==0 &&
+ sldns_read_uint16((*d)+1)==LDNS_RR_TYPE_OPT) {
+ /* perform EDNS OPT processing */
+ return sldns_wire2str_edns_scan(d, dlen, s, slen, pkt, pktlen);
+ }
+
+ /* try to scan the rdata with pretty-printing, but if that fails, then
+ * scan the rdata as an unknown RR type */
+ w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+ w += sldns_str_print(s, slen, "\t");
+ dname_off = rrlen-(*dlen);
+ if(*dlen == 4) {
+ /* like a question-RR */
+ uint16_t t = sldns_read_uint16(*d);
+ uint16_t c = sldns_read_uint16((*d)+2);
+ (*d)+=4;
+ (*dlen)-=4;
+ w += sldns_wire2str_class_print(s, slen, c);
+ w += sldns_str_print(s, slen, "\t");
+ w += sldns_wire2str_type_print(s, slen, t);
+ w += sldns_str_print(s, slen, " ; Error no ttl,rdata\n");
+ return w;
+ }
+ if(*dlen < 8) {
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, ";Error missing RR\n");
+ w += print_remainder_hex(";Error partial RR 0x", d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ rrtype = sldns_read_uint16(*d);
+ w += sldns_rr_tcttl_scan(d, dlen, s, slen);
+ w += sldns_str_print(s, slen, "\t");
+
+ /* rdata */
+ if(*dlen < 2) {
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
+ w += print_remainder_hex(";Error missing rdatalen 0x",
+ d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ rdlen = sldns_read_uint16(*d);
+ ordlen = rdlen;
+ (*d)+=2;
+ (*dlen)-=2;
+ if(*dlen < rdlen) {
+ w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, ";Error missing rdata\n");
+ w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen);
+ (*dlen) -= (ordlen-rdlen);
+
+ /* default comment */
+ w += sldns_wire2str_rr_comment_print(s, slen, rr, rrlen, dname_off,
+ rrtype);
+ w += sldns_str_print(s, slen, "\n");
+ return w;
+}
+
+int sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s,
+ size_t* slen, uint8_t* pkt, size_t pktlen)
+{
+ int w = 0;
+ uint16_t t, c;
+ w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+ w += sldns_str_print(s, slen, "\t");
+ if(*dlen < 4) {
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, "Error malformed\n");
+ w += print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ t = sldns_read_uint16(*d);
+ c = sldns_read_uint16((*d)+2);
+ (*d)+=4;
+ (*dlen)-=4;
+ w += sldns_wire2str_class_print(s, slen, c);
+ w += sldns_str_print(s, slen, "\t");
+ w += sldns_wire2str_type_print(s, slen, t);
+ w += sldns_str_print(s, slen, "\n");
+ return w;
+}
+
+int sldns_wire2str_rr_unknown_scan(uint8_t** d, size_t* dlen, char** s,
+ size_t* slen, uint8_t* pkt, size_t pktlen)
+{
+ size_t rdlen, ordlen;
+ int w = 0;
+ w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+ w += sldns_str_print(s, slen, "\t");
+ w += sldns_rr_tcttl_scan(d, dlen, s, slen);
+ w += sldns_str_print(s, slen, "\t");
+ if(*dlen < 2) {
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, ";Error missing rdatalen\n");
+ w += print_remainder_hex(";Error missing rdatalen 0x",
+ d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ rdlen = sldns_read_uint16(*d);
+ ordlen = rdlen;
+ (*d) += 2;
+ (*dlen) -= 2;
+ if(*dlen < rdlen) {
+ w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen);
+ if(*dlen == 0)
+ return w + sldns_str_print(s, slen, ";Error missing rdata\n");
+ w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
+ return w + sldns_str_print(s, slen, "\n");
+ }
+ w += sldns_wire2str_rdata_unknown_scan(d, &rdlen, s, slen);
+ (*dlen) -= (ordlen-rdlen);
+ w += sldns_str_print(s, slen, "\n");
+ return w;
+}
+
+/** print rr comment for type DNSKEY */
+static int rr_comment_dnskey(char** s, size_t* slen, uint8_t* rr,
+ size_t rrlen, size_t dname_off)
+{
+ size_t rdlen;
+ uint8_t* rdata;
+ int flags, w = 0;
+ if(rrlen < dname_off + 10) return 0;
+ rdlen = sldns_read_uint16(rr+dname_off+8);
+ if(rrlen < dname_off + 10 + rdlen) return 0;
+ rdata = rr + dname_off + 10;
+ flags = (int)sldns_read_uint16(rdata);
+ w += sldns_str_print(s, slen, " ;{");
+
+ /* id */
+ w += sldns_str_print(s, slen, "id = %u",
+ sldns_calc_keytag_raw(rdata, rdlen));
+
+ /* flags */
+ if((flags&LDNS_KEY_ZONE_KEY)) {
+ if((flags&LDNS_KEY_SEP_KEY))
+ w += sldns_str_print(s, slen, " (ksk)");
+ else w += sldns_str_print(s, slen, " (zsk)");
+ }
+
+ /* keysize */
+ if(rdlen > 4) {
+ w += sldns_str_print(s, slen, ", ");
+ w += sldns_str_print(s, slen, "size = %db",
+ (int)sldns_rr_dnskey_key_size_raw(
+ (unsigned char*)rdata+4, rdlen-4, (int)(rdata[3])));
+ }
+
+ w += sldns_str_print(s, slen, "}");
+ return w;
+}
+
+/** print rr comment for type RRSIG */
+static int rr_comment_rrsig(char** s, size_t* slen, uint8_t* rr,
+ size_t rrlen, size_t dname_off)
+{
+ size_t rdlen;
+ uint8_t* rdata;
+ if(rrlen < dname_off + 10) return 0;
+ rdlen = sldns_read_uint16(rr+dname_off+8);
+ if(rrlen < dname_off + 10 + rdlen) return 0;
+ rdata = rr + dname_off + 10;
+ if(rdlen < 18) return 0;
+ return sldns_str_print(s, slen, " ;{id = %d}",
+ (int)sldns_read_uint16(rdata+16));
+}
+
+/** print rr comment for type NSEC3 */
+static int rr_comment_nsec3(char** s, size_t* slen, uint8_t* rr,
+ size_t rrlen, size_t dname_off)
+{
+ size_t rdlen;
+ uint8_t* rdata;
+ int w = 0;
+ if(rrlen < dname_off + 10) return 0;
+ rdlen = sldns_read_uint16(rr+dname_off+8);
+ if(rrlen < dname_off + 10 + rdlen) return 0;
+ rdata = rr + dname_off + 10;
+ if(rdlen < 2) return 0;
+ if((rdata[1] & LDNS_NSEC3_VARS_OPTOUT_MASK))
+ w += sldns_str_print(s, slen, " ;{flags: optout}");
+ return w;
+}
+
+int sldns_wire2str_rr_comment_print(char** s, size_t* slen, uint8_t* rr,
+ size_t rrlen, size_t dname_off, uint16_t rrtype)
+{
+ if(rrtype == LDNS_RR_TYPE_DNSKEY) {
+ return rr_comment_dnskey(s, slen, rr, rrlen, dname_off);
+ } else if(rrtype == LDNS_RR_TYPE_RRSIG) {
+ return rr_comment_rrsig(s, slen, rr, rrlen, dname_off);
+ } else if(rrtype == LDNS_RR_TYPE_NSEC3) {
+ return rr_comment_nsec3(s, slen, rr, rrlen, dname_off);
+ }
+ return 0;
+}
+
+int sldns_wire2str_header_scan(uint8_t** d, size_t* dlen, char** s,
+ size_t* slen)
+{
+ int w = 0;
+ int opcode, rcode;
+ w += sldns_str_print(s, slen, ";; ->>HEADER<<- ");
+ if(*dlen == 0)
+ return w+sldns_str_print(s, slen, "Error empty packet");
+ if(*dlen < 4)
+ return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
+ opcode = (int)LDNS_OPCODE_WIRE(*d);
+ rcode = (int)LDNS_RCODE_WIRE(*d);
+ w += sldns_str_print(s, slen, "opcode: ");
+ w += sldns_wire2str_opcode_print(s, slen, opcode);
+ w += sldns_str_print(s, slen, ", ");
+ w += sldns_str_print(s, slen, "rcode: ");
+ w += sldns_wire2str_rcode_print(s, slen, rcode);
+ w += sldns_str_print(s, slen, ", ");
+ w += sldns_str_print(s, slen, "id: %d\n", (int)LDNS_ID_WIRE(*d));
+ w += sldns_str_print(s, slen, ";; flags:");
+ if(LDNS_QR_WIRE(*d)) w += sldns_str_print(s, slen, " qr");
+ if(LDNS_AA_WIRE(*d)) w += sldns_str_print(s, slen, " aa");
+ if(LDNS_TC_WIRE(*d)) w += sldns_str_print(s, slen, " tc");
+ if(LDNS_RD_WIRE(*d)) w += sldns_str_print(s, slen, " rd");
+ if(LDNS_CD_WIRE(*d)) w += sldns_str_print(s, slen, " cd");
+ if(LDNS_RA_WIRE(*d)) w += sldns_str_print(s, slen, " ra");
+ if(LDNS_AD_WIRE(*d)) w += sldns_str_print(s, slen, " ad");
+ if(LDNS_Z_WIRE(*d)) w += sldns_str_print(s, slen, " z");
+ w += sldns_str_print(s, slen, " ; ");
+ if(*dlen < LDNS_HEADER_SIZE)
+ return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen);
+ w += sldns_str_print(s, slen, "QUERY: %d, ", (int)LDNS_QDCOUNT(*d));
+ w += sldns_str_print(s, slen, "ANSWER: %d, ", (int)LDNS_ANCOUNT(*d));
+ w += sldns_str_print(s, slen, "AUTHORITY: %d, ", (int)LDNS_NSCOUNT(*d));
+ w += sldns_str_print(s, slen, "ADDITIONAL: %d ", (int)LDNS_ARCOUNT(*d));
+ *d += LDNS_HEADER_SIZE;
+ *dlen -= LDNS_HEADER_SIZE;
+ return w;
+}
+
+int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s,
+ size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen)
+{
+ /* try to prettyprint, but if that fails, use unknown format */
+ uint8_t* origd = *d;
+ char* origs = *s;
+ size_t origdlen = *dlen, origslen = *slen;
+ uint16_t r_cnt, r_max;
+ sldns_rdf_type rdftype;
+ int w = 0, n;
+
+ const sldns_rr_descriptor *desc = sldns_rr_descript(rrtype);
+ if(!desc) /* unknown format */
+ return sldns_wire2str_rdata_unknown_scan(d, dlen, s, slen);
+ /* dlen equals the rdatalen for the rdata */
+
+ r_max = sldns_rr_descriptor_maximum(desc);
+ for(r_cnt=0; r_cnt < r_max; r_cnt++) {
+ if(*dlen == 0) {
+ if(r_cnt < sldns_rr_descriptor_minimum(desc))
+ goto failed;
+ break; /* nothing more to print */
+ }
+ rdftype = sldns_rr_descriptor_field_type(desc, r_cnt);
+ if(r_cnt != 0)
+ w += sldns_str_print(s, slen, " ");
+ n = sldns_wire2str_rdf_scan(d, dlen, s, slen, rdftype,
+ pkt, pktlen);
+ if(n == -1) {
+ failed:
+ /* failed, use unknown format */
+ *d = origd; *s = origs;
+ *dlen = origdlen; *slen = origslen;
+ return sldns_wire2str_rdata_unknown_scan(d, dlen,
+ s, slen);
+ }
+ w += n;
+ }
+ return w;
+}
+
+int sldns_wire2str_rdata_unknown_scan(uint8_t** d, size_t* dlen, char** s,
+ size_t* slen)
+{
+ int w = 0;
+
+ /* print length */
+ w += sldns_str_print(s, slen, "\\# %u", (unsigned)*dlen);
+
+ /* print rdlen in hex */
+ if(*dlen != 0)
+ w += sldns_str_print(s, slen, " ");
+ w += print_hex_buf(s, slen, *d, *dlen);
+ (*d) += *dlen;
+ (*dlen) = 0;
+ return w;
+}
+
+/** print and escape one character for a domain dname */
+static int dname_char_print(char** s, size_t* slen, uint8_t c)
+{
+ if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\')
+ return sldns_str_print(s, slen, "\\%c", c);
+ else if(!(isascii((unsigned char)c) && isgraph((unsigned char)c)))
+ return sldns_str_print(s, slen, "\\%03u", (unsigned)c);
+ /* plain printout */
+ if(*slen) {
+ **s = (char)c;
+ (*s)++;
+ (*slen)--;
+ }
+ return 1;
+}
+
+int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+ uint8_t* pkt, size_t pktlen)
+{
+ int w = 0;
+ /* spool labels onto the string, use compression if its there */
+ uint8_t* pos = *d;
+ unsigned i, counter=0;
+ const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
+ int in_buf = 1;
+ if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
+ if(*pos == 0) {
+ (*d)++;
+ (*dlen)--;
+ return sldns_str_print(s, slen, ".");
+ }
+ while(*pos) {
+ /* read label length */
+ uint8_t labellen = *pos++;
+ if(in_buf) { (*d)++; (*dlen)--; }
+
+ /* find out what sort of label we have */
+ if((labellen&0xc0) == 0xc0) {
+ /* compressed */
+ uint16_t target = 0;
+ if(in_buf && *dlen == 0)
+ return w + sldns_str_print(s, slen,
+ "ErrorPartialDname");
+ else if(!in_buf && pos+1 > pkt+pktlen)
+ return w + sldns_str_print(s, slen,
+ "ErrorPartialDname");
+ target = ((labellen&0x3f)<<8) | *pos;
+ if(in_buf) { (*d)++; (*dlen)--; }
+ /* move to target, if possible */
+ if(!pkt || target >= pktlen)
+ return w + sldns_str_print(s, slen,
+ "ErrorComprPtrOutOfBounds");
+ if(counter++ > maxcompr)
+ return w + sldns_str_print(s, slen,
+ "ErrorComprPtrLooped");
+ in_buf = 0;
+ pos = pkt+target;
+ continue;
+ } else if((labellen&0xc0)) {
+ /* notimpl label type */
+ w += sldns_str_print(s, slen,
+ "ErrorLABELTYPE%xIsUnknown",
+ (int)(labellen&0xc0));
+ return w;
+ }
+
+ /* spool label characters, end with '.' */
+ if(in_buf && *dlen < labellen) labellen = *dlen;
+ else if(!in_buf && pos+labellen > pkt+pktlen)
+ labellen = (uint8_t)(pkt + pktlen - pos);
+ for(i=0; i<(unsigned)labellen; i++) {
+ w += dname_char_print(s, slen, *pos++);
+ }
+ if(in_buf) {
+ (*d) += labellen;
+ (*dlen) -= labellen;
+ if(*dlen == 0) break;
+ }
+ w += sldns_str_print(s, slen, ".");
+ }
+ /* skip over final root label */
+ if(in_buf && *dlen > 0) { (*d)++; (*dlen)--; }
+ /* in case we printed no labels, terminate dname */
+ if(w == 0) w += sldns_str_print(s, slen, ".");
+ return w;
+}
+
+int sldns_wire2str_opcode_print(char** s, size_t* slen, int opcode)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_id(sldns_opcodes, opcode);
+ if (lt && lt->name) {
+ return sldns_str_print(s, slen, "%s", lt->name);
+ }
+ return sldns_str_print(s, slen, "OPCODE%u", (unsigned)opcode);
+}
+
+int sldns_wire2str_rcode_print(char** s, size_t* slen, int rcode)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rcodes, rcode);
+ if (lt && lt->name) {
+ return sldns_str_print(s, slen, "%s", lt->name);
+ }
+ return sldns_str_print(s, slen, "RCODE%u", (unsigned)rcode);
+}
+
+int sldns_wire2str_class_print(char** s, size_t* slen, uint16_t rrclass)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rr_classes,
+ (int)rrclass);
+ if (lt && lt->name) {
+ return sldns_str_print(s, slen, "%s", lt->name);
+ }
+ return sldns_str_print(s, slen, "CLASS%u", (unsigned)rrclass);
+}
+
+int sldns_wire2str_type_print(char** s, size_t* slen, uint16_t rrtype)
+{
+ const sldns_rr_descriptor *descriptor = sldns_rr_descript(rrtype);
+ if (descriptor && descriptor->_name) {
+ return sldns_str_print(s, slen, "%s", descriptor->_name);
+ }
+ return sldns_str_print(s, slen, "TYPE%u", (unsigned)rrtype);
+}
+
+int sldns_wire2str_edns_option_code_print(char** s, size_t* slen,
+ uint16_t opcode)
+{
+ sldns_lookup_table *lt = sldns_lookup_by_id(sldns_edns_options,
+ (int)opcode);
+ if (lt && lt->name) {
+ return sldns_str_print(s, slen, "%s", lt->name);
+ }
+ return sldns_str_print(s, slen, "OPT%u", (unsigned)opcode);
+}
+
+int sldns_wire2str_class_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+ uint16_t c;
+ if(*dlen == 0) return 0;
+ if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+ c = sldns_read_uint16(*d);
+ (*d)+=2;
+ (*dlen)-=2;
+ return sldns_wire2str_class_print(s, slen, c);
+}
+
+int sldns_wire2str_type_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+ uint16_t t;
+ if(*dlen == 0) return 0;
+ if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+ t = sldns_read_uint16(*d);
+ (*d)+=2;
+ (*dlen)-=2;
+ return sldns_wire2str_type_print(s, slen, t);
+}
+
+int sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
+{
+ uint32_t ttl;
+ if(*dlen == 0) return 0;
+ if(*dlen < 4) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen);
+ ttl = sldns_read_uint32(*d);
+ (*d)+=4;
+ (*dlen)-=4;
+ return sldns_str_print(s, slen, "%u", (unsigned)ttl);
+}
+
+int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+ int rdftype, uint8_t* pkt, size_t pktlen)
+{
+ if(*dlen == 0) return 0;
+ switch(rdftype) {
+ case LDNS_RDF_TYPE_NONE:
+ return 0;
+ case LDNS_RDF_TYPE_DNAME:
+ return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+ case LDNS_RDF_TYPE_INT8:
+ return sldns_wire2str_int8_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_INT16:
+ return sldns_wire2str_int16_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_INT32:
+ return sldns_wire2str_int32_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_PERIOD:
+ return sldns_wire2str_period_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_TSIGTIME:
+ return sldns_wire2str_tsigtime_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_A:
+ return sldns_wire2str_a_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_AAAA:
+ return sldns_wire2str_aaaa_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_STR:
+ return sldns_wire2str_str_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_APL:
+ return sldns_wire2str_apl_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_B32_EXT:
+ return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_B64:
+ return sldns_wire2str_b64_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_HEX:
+ return sldns_wire2str_hex_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_NSEC:
+ return sldns_wire2str_nsec_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_NSEC3_SALT:
+ return sldns_wire2str_nsec3_salt_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_TYPE:
+ return sldns_wire2str_type_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_CLASS:
+ return sldns_wire2str_class_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_CERT_ALG:
+ return sldns_wire2str_cert_alg_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_ALG:
+ return sldns_wire2str_alg_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_UNKNOWN:
+ return sldns_wire2str_unknown_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_TIME:
+ return sldns_wire2str_time_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_LOC:
+ return sldns_wire2str_loc_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_WKS:
+ case LDNS_RDF_TYPE_SERVICE:
+ return sldns_wire2str_wks_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_NSAP:
+ return sldns_wire2str_nsap_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_ATMA:
+ return sldns_wire2str_atma_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_IPSECKEY:
+ return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt,
+ pktlen);
+ case LDNS_RDF_TYPE_HIP:
+ return sldns_wire2str_hip_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_INT16_DATA:
+ return sldns_wire2str_int16_data_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+ return sldns_wire2str_b32_ext_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_ILNP64:
+ return sldns_wire2str_ilnp64_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_EUI48:
+ return sldns_wire2str_eui48_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_EUI64:
+ return sldns_wire2str_eui64_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_TAG:
+ return sldns_wire2str_tag_scan(d, dlen, s, slen);
+ case LDNS_RDF_TYPE_LONG_STR:
+ return sldns_wire2str_long_str_scan(d, dlen, s, slen);
+ }
+ /* unknown rdf type */
+ return -1;
+}
+
+int sldns_wire2str_int8_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 1) return -1;
+ w = sldns_str_print(s, sl, "%u", (unsigned)**d);
+ (*d)++;
+ (*dl)--;
+ return w;
+}
+
+int sldns_wire2str_int16_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 2) return -1;
+ w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint16(*d));
+ (*d)+=2;
+ (*dl)-=2;
+ return w;
+}
+
+int sldns_wire2str_int32_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 4) return -1;
+ w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint32(*d));
+ (*d)+=4;
+ (*dl)-=4;
+ return w;
+}
+
+int sldns_wire2str_period_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 4) return -1;
+ w = sldns_str_print(s, sl, "%u", (unsigned)sldns_read_uint32(*d));
+ (*d)+=4;
+ (*dl)-=4;
+ return w;
+}
+
+int sldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ /* tsigtime is 48 bits network order unsigned integer */
+ int w;
+ uint64_t tsigtime = 0;
+ uint64_t d0, d1, d2, d3, d4, d5;
+ if(*dl < 6) return -1;
+ d0 = (*d)[0]; /* cast to uint64 for shift operations */
+ d1 = (*d)[1];
+ d2 = (*d)[2];
+ d3 = (*d)[3];
+ d4 = (*d)[4];
+ d5 = (*d)[5];
+ tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5;
+#ifndef USE_WINSOCK
+ w = sldns_str_print(s, sl, "%llu", (long long)tsigtime);
+#else
+ w = sldns_str_print(s, sl, "%I64u", (long long)tsigtime);
+#endif
+ (*d)+=6;
+ (*dl)-=6;
+ return w;
+}
+
+int sldns_wire2str_a_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ char buf[32];
+ int w;
+ if(*dl < 4) return -1;
+ if(!inet_ntop(AF_INET, *d, buf, (socklen_t)sizeof(buf)))
+ return -1;
+ w = sldns_str_print(s, sl, "%s", buf);
+ (*d)+=4;
+ (*dl)-=4;
+ return w;
+}
+
+int sldns_wire2str_aaaa_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+#ifdef AF_INET6
+ char buf[64];
+ int w;
+ if(*dl < 16) return -1;
+ if(!inet_ntop(AF_INET6, *d, buf, (socklen_t)sizeof(buf)))
+ return -1;
+ w = sldns_str_print(s, sl, "%s", buf);
+ (*d)+=16;
+ (*dl)-=16;
+ return w;
+#else
+ return -1;
+#endif
+}
+
+/** printout escaped TYPE_STR character */
+static int str_char_print(char** s, size_t* sl, uint8_t c)
+{
+ if(isprint((unsigned char)c) || c == '\t') {
+ if(c == '\"' || c == '\\')
+ return sldns_str_print(s, sl, "\\%c", c);
+ if(*sl) {
+ **s = (char)c;
+ (*s)++;
+ (*sl)--;
+ }
+ return 1;
+ }
+ return sldns_str_print(s, sl, "\\%03u", (unsigned)c);
+}
+
+int sldns_wire2str_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w = 0;
+ size_t i, len;
+ if(*dl < 1) return -1;
+ len = **d;
+ if(*dl < 1+len) return -1;
+ (*d)++;
+ (*dl)--;
+ w += sldns_str_print(s, sl, "\"");
+ for(i=0; i<len; i++)
+ w += str_char_print(s, sl, (*d)[i]);
+ w += sldns_str_print(s, sl, "\"");
+ (*d)+=len;
+ (*dl)-=len;
+ return w;
+}
+
+int sldns_wire2str_apl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int i, w = 0;
+ uint16_t family;
+ uint8_t negation, prefix, adflength;
+ if(*dl < 4) return -1;
+ family = sldns_read_uint16(*d);
+ prefix = (*d)[2];
+ negation = ((*d)[3] & LDNS_APL_NEGATION);
+ adflength = ((*d)[3] & LDNS_APL_MASK);
+ if(*dl < 4+(size_t)adflength) return -1;
+ if(family != LDNS_APL_IP4 && family != LDNS_APL_IP6)
+ return -1; /* unknown address family */
+ if(negation)
+ w += sldns_str_print(s, sl, "!");
+ w += sldns_str_print(s, sl, "%u:", (unsigned)family);
+ if(family == LDNS_APL_IP4) {
+ /* check if prefix <32 ? */
+ /* address is variable length 0 - 4 */
+ for(i=0; i<4; i++) {
+ if(i > 0)
+ w += sldns_str_print(s, sl, ".");
+ if(i < (int)adflength)
+ w += sldns_str_print(s, sl, "%d", (*d)[4+i]);
+ else w += sldns_str_print(s, sl, "0");
+ }
+ } else if(family == LDNS_APL_IP6) {
+ /* check if prefix <128 ? */
+ /* address is variable length 0 - 16 */
+ for(i=0; i<16; i++) {
+ if(i%2 == 0 && i>0)
+ w += sldns_str_print(s, sl, ":");
+ if(i < (int)adflength)
+ w += sldns_str_print(s, sl, "%02x", (*d)[4+i]);
+ else w += sldns_str_print(s, sl, "00");
+ }
+ }
+ w += sldns_str_print(s, sl, "/%u", (unsigned)prefix);
+ (*d) += 4+adflength;
+ (*dl) -= 4+adflength;
+ return w;
+}
+
+int sldns_wire2str_b32_ext_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ size_t datalen;
+ size_t sz;
+ if(*dl < 1) return -1;
+ datalen = (*d)[0];
+ if(*dl < 1+datalen) return -1;
+ sz = sldns_b32_ntop_calculate_size(datalen);
+ if(*sl < sz+1) {
+ (*d) += datalen+1;
+ (*dl) -= (datalen+1);
+ return (int)sz; /* out of space really, but would need buffer
+ in order to truncate the output */
+ }
+ sldns_b32_ntop_extended_hex((*d)+1, datalen, *s, *sl);
+ (*d) += datalen+1;
+ (*dl) -= (datalen+1);
+ (*s) += sz;
+ (*sl) -= sz;
+ return (int)sz;
+}
+
+/** scan number of bytes from wire into b64 presentation format */
+static int sldns_wire2str_b64_scan_num(uint8_t** d, size_t* dl, char** s,
+ size_t* sl, size_t num)
+{
+ /* b64_ntop_calculate size includes null at the end */
+ size_t sz = sldns_b64_ntop_calculate_size(num)-1;
+ if(*sl < sz+1) {
+ (*d) += num;
+ (*dl) -= num;
+ return (int)sz; /* out of space really, but would need buffer
+ in order to truncate the output */
+ }
+ sldns_b64_ntop(*d, num, *s, *sl);
+ (*d) += num;
+ (*dl) -= num;
+ (*s) += sz;
+ (*sl) -= sz;
+ return (int)sz;
+}
+
+int sldns_wire2str_b64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ return sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
+}
+
+int sldns_wire2str_hex_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ return print_remainder_hex("", d, dl, s, sl);
+}
+
+int sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ uint8_t* p = *d;
+ size_t pl = *dl;
+ unsigned i, bit, window, block_len;
+ uint16_t t;
+ int w = 0;
+
+ /* check for errors */
+ while(pl) {
+ if(pl < 2) return -1;
+ block_len = (unsigned)p[1];
+ if(pl < 2+block_len) return -1;
+ p += block_len+2;
+ pl -= block_len+2;
+ }
+
+ /* do it */
+ p = *d;
+ pl = *dl;
+ while(pl) {
+ if(pl < 2) return -1; /* cannot happen */
+ window = (unsigned)p[0];
+ block_len = (unsigned)p[1];
+ if(pl < 2+block_len) return -1; /* cannot happen */
+ p += 2;
+ for(i=0; i<block_len; i++) {
+ if(p[i] == 0) continue;
+ /* base type number for this octet */
+ t = ((window)<<8) | (i << 3);
+ for(bit=0; bit<8; bit++) {
+ if((p[i]&(0x80>>bit))) {
+ if(w) w += sldns_str_print(s, sl, " ");
+ w += sldns_wire2str_type_print(s, sl,
+ t+bit);
+ }
+ }
+ }
+ p += block_len;
+ pl -= block_len+2;
+ }
+ (*d) += *dl;
+ (*dl) = 0;
+ return w;
+}
+
+int sldns_wire2str_nsec3_salt_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ size_t salt_len;
+ int w;
+ if(*dl < 1) return -1;
+ salt_len = (size_t)(*d)[0];
+ if(*dl < 1+salt_len) return -1;
+ (*d)++;
+ (*dl)--;
+ if(salt_len == 0) {
+ return sldns_str_print(s, sl, "-");
+ }
+ w = print_hex_buf(s, sl, *d, salt_len);
+ (*dl)-=salt_len;
+ (*d)+=salt_len;
+ return w;
+}
+
+int sldns_wire2str_cert_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ sldns_lookup_table *lt;
+ int data, w;
+ if(*dl < 2) return -1;
+ data = (int)sldns_read_uint16(*d);
+ lt = sldns_lookup_by_id(sldns_cert_algorithms, data);
+ if(lt && lt->name)
+ w = sldns_str_print(s, sl, "%s", lt->name);
+ else w = sldns_str_print(s, sl, "%d", data);
+ (*dl)-=2;
+ (*d)+=2;
+ return w;
+}
+
+int sldns_wire2str_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ /* don't use algorithm mnemonics in the presentation format
+ * this kind of got sneaked into the rfc's */
+ return sldns_wire2str_int8_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_unknown_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ return sldns_wire2str_rdata_unknown_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ /* create a YYYYMMDDHHMMSS string if possible */
+ struct tm tm;
+ char date_buf[16];
+ uint32_t t;
+ memset(&tm, 0, sizeof(tm));
+ if(*dl < 4) return -1;
+ t = sldns_read_uint32(*d);
+ date_buf[15]=0;
+ if(sldns_serial_arithmitics_gmtime_r(t, time(NULL), &tm) &&
+ strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
+ (*d) += 4;
+ (*dl) -= 4;
+ return sldns_str_print(s, sl, "%s", date_buf);
+ }
+ return -1;
+}
+
+static int
+loc_cm_print(char** str, size_t* sl, uint8_t mantissa, uint8_t exponent)
+{
+ int w = 0;
+ uint8_t i;
+ /* is it 0.<two digits> ? */
+ if(exponent < 2) {
+ if(exponent == 1)
+ mantissa *= 10;
+ return sldns_str_print(str, sl, "0.%02ld", (long)mantissa);
+ }
+ /* always <digit><string of zeros> */
+ w += sldns_str_print(str, sl, "%d", (int)mantissa);
+ for(i=0; i<exponent-2; i++)
+ w += sldns_str_print(str, sl, "0");
+ return w;
+}
+
+int sldns_wire2str_loc_scan(uint8_t** d, size_t* dl, char** str, size_t* sl)
+{
+ /* we could do checking (ie degrees < 90 etc)? */
+ uint8_t version;
+ uint8_t size;
+ uint8_t horizontal_precision;
+ uint8_t vertical_precision;
+ uint32_t longitude;
+ uint32_t latitude;
+ uint32_t altitude;
+ char northerness;
+ char easterness;
+ uint32_t h;
+ uint32_t m;
+ double s;
+ uint32_t equator = (uint32_t)1 << 31; /* 2**31 */
+ int w = 0;
+
+ if(*dl < 16) return -1;
+ version = (*d)[0];
+ if(version != 0)
+ return sldns_wire2str_hex_scan(d, dl, str, sl);
+ size = (*d)[1];
+ horizontal_precision = (*d)[2];
+ vertical_precision = (*d)[3];
+
+ latitude = sldns_read_uint32((*d)+4);
+ longitude = sldns_read_uint32((*d)+8);
+ altitude = sldns_read_uint32((*d)+12);
+
+ if (latitude > equator) {
+ northerness = 'N';
+ latitude = latitude - equator;
+ } else {
+ northerness = 'S';
+ latitude = equator - latitude;
+ }
+ h = latitude / (1000 * 60 * 60);
+ latitude = latitude % (1000 * 60 * 60);
+ m = latitude / (1000 * 60);
+ latitude = latitude % (1000 * 60);
+ s = (double) latitude / 1000.0;
+ w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
+ h, m, s, northerness);
+
+ if (longitude > equator) {
+ easterness = 'E';
+ longitude = longitude - equator;
+ } else {
+ easterness = 'W';
+ longitude = equator - longitude;
+ }
+ h = longitude / (1000 * 60 * 60);
+ longitude = longitude % (1000 * 60 * 60);
+ m = longitude / (1000 * 60);
+ longitude = longitude % (1000 * 60);
+ s = (double) longitude / (1000.0);
+ w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ",
+ h, m, s, easterness);
+
+ s = ((double) altitude) / 100;
+ s -= 100000;
+
+ if(altitude%100 != 0)
+ w += sldns_str_print(str, sl, "%.2f", s);
+ else
+ w += sldns_str_print(str, sl, "%.0f", s);
+
+ w += sldns_str_print(str, sl, "m ");
+
+ w += loc_cm_print(str, sl, (size & 0xf0) >> 4, size & 0x0f);
+ w += sldns_str_print(str, sl, "m ");
+
+ w += loc_cm_print(str, sl, (horizontal_precision & 0xf0) >> 4,
+ horizontal_precision & 0x0f);
+ w += sldns_str_print(str, sl, "m ");
+
+ w += loc_cm_print(str, sl, (vertical_precision & 0xf0) >> 4,
+ vertical_precision & 0x0f);
+ w += sldns_str_print(str, sl, "m");
+
+ (*d)+=16;
+ (*dl)-=16;
+ return w;
+}
+
+int sldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ /* protocol, followed by bitmap of services */
+ const char* proto_name = NULL;
+ struct protoent *protocol;
+ struct servent *service;
+ uint8_t protocol_nr;
+ int bit, port, w = 0;
+ size_t i;
+ /* we cannot print with strings because they
+ * are not portable, the presentation format may
+ * not be able to be read in on another computer. */
+ int print_symbols = 0;
+
+ /* protocol */
+ if(*dl < 1) return -1;
+ protocol_nr = (*d)[0];
+ (*d)++;
+ (*dl)--;
+ protocol = getprotobynumber((int)protocol_nr);
+ if(protocol && (protocol->p_name != NULL)) {
+ w += sldns_str_print(s, sl, "%s", protocol->p_name);
+ proto_name = protocol->p_name;
+ } else {
+ w += sldns_str_print(s, sl, "%u", (unsigned)protocol_nr);
+ }
+
+ for(i=0; i<*dl; i++) {
+ if((*d)[i] == 0)
+ continue;
+ for(bit=0; bit<8; bit++) {
+ if(!(((*d)[i])&(0x80>>bit)))
+ continue;
+ port = (int)i*8 + bit;
+
+ if(!print_symbols)
+ service = NULL;
+ else
+ service = getservbyport(
+ (int)htons((uint16_t)port), proto_name);
+ if(service && service->s_name)
+ w += sldns_str_print(s, sl, " %s",
+ service->s_name);
+ else w += sldns_str_print(s, sl, " %u",
+ (unsigned)port);
+ }
+ }
+
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+ (*d) += *dl;
+ (*dl) = 0;
+ return w;
+}
+
+int sldns_wire2str_nsap_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ return print_remainder_hex("0x", d, dl, s, sl);
+}
+
+int sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ return print_remainder_hex("", d, dl, s, sl);
+}
+
+/* internal scan routine that can modify arguments on failure */
+static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
+ char** s, size_t* sl, uint8_t* pkt, size_t pktlen)
+{
+ /* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/
+ uint8_t precedence, gateway_type, algorithm;
+ int w = 0;
+
+ if(*dl < 3) return -1;
+ precedence = (*d)[0];
+ gateway_type = (*d)[1];
+ algorithm = (*d)[2];
+ if(gateway_type > 3)
+ return -1; /* unknown */
+ (*d)+=3;
+ (*dl)-=3;
+ w += sldns_str_print(s, sl, "%d %d %d ",
+ (int)precedence, (int)gateway_type, (int)algorithm);
+
+ switch(gateway_type) {
+ case 0: /* no gateway */
+ w += sldns_str_print(s, sl, ".");
+ break;
+ case 1: /* ip4 */
+ w += sldns_wire2str_a_scan(d, dl, s, sl);
+ break;
+ case 2: /* ip6 */
+ w += sldns_wire2str_aaaa_scan(d, dl, s, sl);
+ break;
+ case 3: /* dname */
+ w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen);
+ break;
+ default: /* unknown */
+ return -1;
+ }
+
+ if(*dl < 1)
+ return -1;
+ w += sldns_str_print(s, sl, " ");
+ w += sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl);
+ return w;
+}
+
+int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl,
+ uint8_t* pkt, size_t pktlen)
+{
+ uint8_t* od = *d;
+ char* os = *s;
+ size_t odl = *dl, osl = *sl;
+ int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen);
+ if(w == -1) {
+ *d = od;
+ *s = os;
+ *dl = odl;
+ *sl = osl;
+ return -1;
+ }
+ return w;
+}
+
+int sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ uint8_t algo, hitlen;
+ uint16_t pklen;
+
+ /* read lengths */
+ if(*dl < 4)
+ return -1;
+ hitlen = (*d)[0];
+ algo = (*d)[1];
+ pklen = sldns_read_uint16((*d)+2);
+ if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen)
+ return -1;
+
+ /* write: algo hit pubkey */
+ w = sldns_str_print(s, sl, "%u ", (unsigned)algo);
+ w += print_hex_buf(s, sl, (*d)+4, hitlen);
+ w += sldns_str_print(s, sl, " ");
+ (*d)+=4+hitlen;
+ (*dl)-= (4+hitlen);
+ w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen);
+ return w;
+}
+
+int sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ uint16_t n;
+ if(*dl < 2)
+ return -1;
+ n = sldns_read_uint16(*d);
+ if(*dl < 2+(size_t)n)
+ return -1;
+ (*d)+=2;
+ (*dl)-=2;
+ return sldns_wire2str_b64_scan_num(d, dl, s, sl, n);
+}
+
+int sldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s,
+ size_t* sl)
+{
+ return sldns_wire2str_b32_ext_scan(d, dl, s, sl);
+}
+
+int sldns_wire2str_ilnp64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 8)
+ return -1;
+ w = sldns_str_print(s, sl, "%.4x:%.4x:%.4x:%.4x",
+ sldns_read_uint16(*d), sldns_read_uint16((*d)+2),
+ sldns_read_uint16((*d)+4), sldns_read_uint16((*d)+6));
+ (*d)+=8;
+ (*dl)-=8;
+ return w;
+}
+
+int sldns_wire2str_eui48_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 6)
+ return -1;
+ w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
+ (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5]);
+ (*d)+=6;
+ (*dl)-=6;
+ return w;
+}
+
+int sldns_wire2str_eui64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ int w;
+ if(*dl < 8)
+ return -1;
+ w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
+ (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5],
+ (*d)[6], (*d)[7]);
+ (*d)+=8;
+ (*dl)-=8;
+ return w;
+}
+
+int sldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ size_t i, n;
+ int w = 0;
+ if(*dl < 1)
+ return -1;
+ n = (size_t)((*d)[0]);
+ if(*dl < 1+n)
+ return -1;
+ for(i=0; i<n; i++)
+ if(!isalnum((unsigned char)(*d)[i]))
+ return -1;
+ for(i=0; i<n; i++)
+ w += sldns_str_print(s, sl, "%c", (char)(*d)[i]);
+ (*d)+=n+1;
+ (*dl)-=(n+1);
+ return w;
+}
+
+int sldns_wire2str_long_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
+{
+ size_t i;
+ int w = 0;
+ w += sldns_str_print(s, sl, "\"");
+ for(i=0; i<*dl; i++)
+ w += str_char_print(s, sl, (*d)[i]);
+ w += sldns_str_print(s, sl, "\"");
+ (*d)+=*dl;
+ (*dl)=0;
+ return w;
+}
+
+int sldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ /* LLQ constants */
+ const char* llq_errors[] = {"NO-ERROR", "SERV-FULL", "STATIC",
+ "FORMAT-ERR", "NO-SUCH-LLQ", "BAD-VERS", "UNKNOWN_ERR"};
+ const unsigned int llq_errors_num = 7;
+ const char* llq_opcodes[] = {"LLQ-SETUP", "LLQ-REFRESH", "LLQ-EVENT"};
+ const unsigned int llq_opcodes_num = 3;
+ uint16_t version, llq_opcode, error_code;
+ uint64_t llq_id;
+ uint32_t lease_life; /* Requested or granted life of LLQ, in seconds */
+ int w = 0;
+
+ /* read the record */
+ if(len != 18) {
+ w += sldns_str_print(s, sl, "malformed LLQ ");
+ w += print_hex_buf(s, sl, data, len);
+ return w;
+ }
+ version = sldns_read_uint16(data);
+ llq_opcode = sldns_read_uint16(data+2);
+ error_code = sldns_read_uint16(data+4);
+ memmove(&llq_id, data+6, sizeof(llq_id));
+ lease_life = sldns_read_uint32(data+14);
+
+ /* print it */
+ w += sldns_str_print(s, sl, "v%d ", (int)version);
+ if(llq_opcode < llq_opcodes_num)
+ w += sldns_str_print(s, sl, "%s", llq_opcodes[llq_opcode]);
+ else w += sldns_str_print(s, sl, "opcode %d", (int)llq_opcode);
+ if(error_code < llq_errors_num)
+ w += sldns_str_print(s, sl, " %s", llq_errors[error_code]);
+ else w += sldns_str_print(s, sl, " error %d", (int)error_code);
+#ifndef USE_WINSOCK
+ w += sldns_str_print(s, sl, " id %llx lease-life %lu",
+ (unsigned long long)llq_id, (unsigned long)lease_life);
+#else
+ w += sldns_str_print(s, sl, " id %I64x lease-life %lu",
+ (unsigned long long)llq_id, (unsigned long)lease_life);
+#endif
+ return w;
+}
+
+int sldns_wire2str_edns_ul_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ uint32_t lease;
+ int w = 0;
+ if(len != 4) {
+ w += sldns_str_print(s, sl, "malformed UL ");
+ w += print_hex_buf(s, sl, data, len);
+ return w;
+ }
+ lease = sldns_read_uint32(data);
+ w += sldns_str_print(s, sl, "lease %lu", (unsigned long)lease);
+ return w;
+}
+
+int sldns_wire2str_edns_nsid_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ int w = 0;
+ size_t i, printed=0;
+ w += print_hex_buf(s, sl, data, len);
+ for(i=0; i<len; i++) {
+ if(isprint((unsigned char)data[i]) || data[i] == '\t') {
+ if(!printed) {
+ w += sldns_str_print(s, sl, " (");
+ printed = 1;
+ }
+ w += sldns_str_print(s, sl, "%c", (char)data[i]);
+ }
+ }
+ if(printed)
+ w += sldns_str_print(s, sl, ")");
+ return w;
+}
+
+int sldns_wire2str_edns_dau_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ sldns_lookup_table *lt;
+ size_t i;
+ int w = 0;
+ for(i=0; i<len; i++) {
+ lt = sldns_lookup_by_id(sldns_algorithms, (int)data[i]);
+ if(lt && lt->name)
+ w += sldns_str_print(s, sl, " %s", lt->name);
+ else w += sldns_str_print(s, sl, " %d", (int)data[i]);
+ }
+ return w;
+}
+
+int sldns_wire2str_edns_dhu_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ sldns_lookup_table *lt;
+ size_t i;
+ int w = 0;
+ for(i=0; i<len; i++) {
+ lt = sldns_lookup_by_id(sldns_hashes, (int)data[i]);
+ if(lt && lt->name)
+ w += sldns_str_print(s, sl, " %s", lt->name);
+ else w += sldns_str_print(s, sl, " %d", (int)data[i]);
+ }
+ return w;
+}
+
+int sldns_wire2str_edns_n3u_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ size_t i;
+ int w = 0;
+ for(i=0; i<len; i++) {
+ if(data[i] == 1)
+ w += sldns_str_print(s, sl, " SHA1");
+ else w += sldns_str_print(s, sl, " %d", (int)data[i]);
+ }
+ return w;
+}
+
+int sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data,
+ size_t len)
+{
+ int w = 0;
+ uint16_t family;
+ uint8_t source, scope;
+ if(len < 4) {
+ w += sldns_str_print(s, sl, "malformed subnet ");
+ w += print_hex_buf(s, sl, data, len);
+ return w;
+ }
+ family = sldns_read_uint16(data);
+ source = data[2];
+ scope = data[3];
+ if(family == 1) {
+ /* IP4 */
+ char buf[64];
+ uint8_t ip4[4];
+ memset(ip4, 0, sizeof(ip4));
+ if(len-4 > 4) {
+ w += sldns_str_print(s, sl, "trailingdata:");
+ w += print_hex_buf(s, sl, data+4+4, len-4-4);
+ w += sldns_str_print(s, sl, " ");
+ len = 4+4;
+ }
+ memmove(ip4, data+4, len-4);
+ if(!inet_ntop(AF_INET, ip4, buf, (socklen_t)sizeof(buf))) {
+ w += sldns_str_print(s, sl, "ip4ntoperror ");
+ w += print_hex_buf(s, sl, data+4+4, len-4-4);
+ } else {
+ w += sldns_str_print(s, sl, "%s", buf);
+ }
+ } else if(family == 2) {
+ /* IP6 */
+ char buf[64];
+ uint8_t ip6[16];
+ memset(ip6, 0, sizeof(ip6));
+ if(len-4 > 16) {
+ w += sldns_str_print(s, sl, "trailingdata:");
+ w += print_hex_buf(s, sl, data+4+16, len-4-16);
+ w += sldns_str_print(s, sl, " ");
+ len = 4+16;
+ }
+ memmove(ip6, data+4, len-4);
+#ifdef AF_INET6
+ if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t)sizeof(buf))) {
+ w += sldns_str_print(s, sl, "ip6ntoperror ");
+ w += print_hex_buf(s, sl, data+4+4, len-4-4);
+ } else {
+ w += sldns_str_print(s, sl, "%s", buf);
+ }
+#else
+ w += print_hex_buf(s, sl, data+4+4, len-4-4);
+#endif
+ } else {
+ /* unknown */
+ w += sldns_str_print(s, sl, "family %d ",
+ (int)family);
+ w += print_hex_buf(s, sl, data, len);
+ }
+ w += sldns_str_print(s, sl, "/%d scope /%d", (int)source, (int)scope);
+ return w;
+}
+
+int sldns_wire2str_edns_option_print(char** s, size_t* sl,
+ uint16_t option_code, uint8_t* optdata, size_t optlen)
+{
+ int w = 0;
+ w += sldns_wire2str_edns_option_code_print(s, sl, option_code);
+ w += sldns_str_print(s, sl, ": ");
+ switch(option_code) {
+ case LDNS_EDNS_LLQ:
+ w += sldns_wire2str_edns_llq_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_UL:
+ w += sldns_wire2str_edns_ul_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_NSID:
+ w += sldns_wire2str_edns_nsid_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_DAU:
+ w += sldns_wire2str_edns_dau_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_DHU:
+ w += sldns_wire2str_edns_dhu_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_N3U:
+ w += sldns_wire2str_edns_n3u_print(s, sl, optdata, optlen);
+ break;
+ case LDNS_EDNS_CLIENT_SUBNET:
+ w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen);
+ break;
+ default:
+ /* unknown option code */
+ w += print_hex_buf(s, sl, optdata, optlen);
+ break;
+ }
+ return w;
+}
+
+/** print the edns options to string */
+static int
+print_edns_opts(char** s, size_t* sl, uint8_t* rdata, size_t rdatalen)
+{
+ uint16_t option_code, option_len;
+ int w = 0;
+ while(rdatalen > 0) {
+ /* option name */
+ if(rdatalen < 4) {
+ w += sldns_str_print(s, sl, " ; malformed: ");
+ w += print_hex_buf(s, sl, rdata, rdatalen);
+ return w;
+ }
+ option_code = sldns_read_uint16(rdata);
+ option_len = sldns_read_uint16(rdata+2);
+ rdata += 4;
+ rdatalen -= 4;
+
+ /* option value */
+ if(rdatalen < (size_t)option_len) {
+ w += sldns_str_print(s, sl, " ; malformed ");
+ w += sldns_wire2str_edns_option_code_print(s, sl,
+ option_code);
+ w += sldns_str_print(s, sl, ": ");
+ w += print_hex_buf(s, sl, rdata, rdatalen);
+ return w;
+ }
+ w += sldns_str_print(s, sl, " ; ");
+ w += sldns_wire2str_edns_option_print(s, sl, option_code,
+ rdata, option_len);
+ rdata += option_len;
+ rdatalen -= option_len;
+ }
+ return w;
+}
+
+int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen)
+{
+ int w = 0;
+ uint8_t ext_rcode, edns_version;
+ uint16_t udpsize, edns_bits, rdatalen;
+ w += sldns_str_print(str, str_len, "; EDNS:");
+
+ /* some input checks, domain name */
+ if(*data_len < 1+10)
+ return w + print_remainder_hex("Error malformed 0x",
+ data, data_len, str, str_len);
+ if(*data[0] != 0) {
+ return w + print_remainder_hex("Error nonrootdname 0x",
+ data, data_len, str, str_len);
+ }
+ (*data)++;
+ (*data_len)--;
+
+ /* check type and read fixed contents */
+ if(sldns_read_uint16((*data)) != LDNS_RR_TYPE_OPT) {
+ return w + print_remainder_hex("Error nottypeOPT 0x",
+ data, data_len, str, str_len);
+ }
+ udpsize = sldns_read_uint16((*data)+2);
+ ext_rcode = (*data)[4];
+ edns_version = (*data)[5];
+ edns_bits = sldns_read_uint16((*data)+6);
+ rdatalen = sldns_read_uint16((*data)+8);
+ (*data)+=10;
+ (*data_len)-=10;
+
+ w += sldns_str_print(str, str_len, " version: %u;",
+ (unsigned)edns_version);
+ w += sldns_str_print(str, str_len, " flags:");
+ if((edns_bits & LDNS_EDNS_MASK_DO_BIT))
+ w += sldns_str_print(str, str_len, " do");
+ /* the extended rcode is the value set, shifted four bits,
+ * and or'd with the original rcode */
+ if(ext_rcode) {
+ int rc = ((int)ext_rcode)<<4;
+ if(pkt && pktlen >= LDNS_HEADER_SIZE)
+ rc |= LDNS_RCODE_WIRE(pkt);
+ w += sldns_str_print(str, str_len, " ; ext-rcode: %d", rc);
+ }
+ w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize);
+
+ if(rdatalen) {
+ if(*data_len < rdatalen) {
+ w += sldns_str_print(str, str_len,
+ " ; Error EDNS rdata too short; ");
+ rdatalen = *data_len;
+ }
+ w += print_edns_opts(str, str_len, *data, rdatalen);
+ (*data) += rdatalen;
+ (*data_len) -= rdatalen;
+ }
+ w += sldns_str_print(str, str_len, "\n");
+ return w;
+}
diff --git a/sldns/wire2str.h b/sldns/wire2str.h
new file mode 100644
index 000000000000..67f543566267
--- /dev/null
+++ b/sldns/wire2str.h
@@ -0,0 +1,984 @@
+/**
+ * wire2str.h - txt presentation of RRs
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions to translate the wireformat to text
+ * representation, as well as functions to print them.
+ */
+
+#ifndef LDNS_WIRE2STR_H
+#define LDNS_WIRE2STR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct sldns_struct_lookup_table;
+
+/* lookup tables for standard DNS stuff */
+/** Taken from RFC 2535, section 7. */
+extern struct sldns_struct_lookup_table* sldns_algorithms;
+/** DS record hash algorithms */
+extern struct sldns_struct_lookup_table* sldns_hashes;
+/** Taken from RFC 2538, section 2.1. */
+extern struct sldns_struct_lookup_table* sldns_cert_algorithms;
+/** Response codes */
+extern struct sldns_struct_lookup_table* sldns_rcodes;
+/** Operation codes */
+extern struct sldns_struct_lookup_table* sldns_opcodes;
+/** EDNS flags */
+extern struct sldns_struct_lookup_table* sldns_edns_flags;
+/** EDNS option codes */
+extern struct sldns_struct_lookup_table* sldns_edns_options;
+/** error string from wireparse */
+extern struct sldns_struct_lookup_table* sldns_wireparse_errors;
+
+/**
+ * Convert wireformat packet to a string representation
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param len: length of packet.
+ * @return string(malloced) or NULL on failure.
+ */
+char* sldns_wire2str_pkt(uint8_t* data, size_t len);
+
+/**
+ * Convert wireformat RR to a string representation.
+ * @param rr: the wireformat RR, in uncompressed form. Starts at the domain
+ * name start, ends with the rdata of the RR.
+ * @param len: length of the rr wireformat.
+ * @return string(malloced) or NULL on failure.
+ */
+char* sldns_wire2str_rr(uint8_t* rr, size_t len);
+
+/**
+ * Conver wire dname to a string.
+ * @param dname: the dname in uncompressed wireformat.
+ * @param dname_len: length of the dname.
+ * @return string or NULL on failure.
+ */
+char* sldns_wire2str_dname(uint8_t* dname, size_t dname_len);
+
+/**
+ * Convert wire RR type to a string, 'MX', 'TYPE1234'...
+ * @param rrtype: the RR type in host order.
+ * @return malloced string with the RR type or NULL on malloc failure.
+ */
+char* sldns_wire2str_type(uint16_t rrtype);
+
+/**
+ * Convert wire RR class to a string, 'IN', 'CLASS1'.
+ * @param rrclass: the RR class in host order.
+ * @return malloced string with the RR class or NULL on malloc failure.
+ */
+char* sldns_wire2str_class(uint16_t rrclass);
+
+/**
+ * Convert wire packet rcode to a string, 'NOERROR', 'NXDOMAIN'...
+ * @param rcode: as integer, host order
+ * @return malloced string with the rcode or NULL on malloc failure.
+ */
+char* sldns_wire2str_rcode(int rcode);
+
+/**
+ * Print to string, move string along for next content. With va_list.
+ * @param str: string buffer. Adjusted at end to after the output.
+ * @param slen: length of the string buffer. Adjusted at end.
+ * @param format: printf format string.
+ * @param args: arguments for printf.
+ * @return number of characters needed. Can be larger than slen.
+ */
+int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args);
+
+/**
+ * Print to string, move string along for next content.
+ * @param str: string buffer. Adjusted at end to after the output.
+ * @param slen: length of the string buffer. Adjusted at end.
+ * @param format: printf format string and arguments for it.
+ * @return number of characters needed. Can be larger than slen.
+ */
+int sldns_str_print(char** str, size_t* slen, const char* format, ...)
+ ATTR_FORMAT(printf, 3, 4);
+
+/**
+ * Convert wireformat packet to a string representation with user buffer
+ * It appends every RR with default comments.
+ * For more formatter options use the function: TBD(TODO)
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param data_len: length of packet.
+ * @param str: the string buffer for the output.
+ * If you pass NULL as the str the return value of the function is
+ * the str_len you need for the entire packet. It does not include
+ * the 0 byte at the end.
+ * @param str_len: the size of the string buffer. If more is needed, it'll
+ * silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_pkt_buf(uint8_t* data, size_t data_len, char* str,
+ size_t str_len);
+
+/**
+ * Scan wireformat packet to a string representation with user buffer
+ * It appends every RR with default comments.
+ * For more formatter options use the function: TBD(TODO)
+ * @param data: wireformat packet data (starting at ID bytes).
+ * @param data_len: length of packet.
+ * @param str: the string buffer for the output.
+ * @param str_len: the size of the string buffer.
+ * @return number of characters for string.
+ * returns the number of characters that are needed (except terminating null),
+ * so it may return a value larger than str_len.
+ * On error you get less output (i.e. shorter output in str (null terminated))
+ * On exit the data, data_len, str and str_len values are adjusted to move them
+ * from their original position along the input and output for the content
+ * that has been consumed (and produced) by this function. If the end of the
+ * output string is reached, *str_len is set to 0. The output string is null
+ * terminated (shortening the output if necessary). If the end of the input
+ * is reached *data_len is set to 0.
+ */
+int sldns_wire2str_pkt_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat rr to string, with user buffers. It shifts the arguments
+ * to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat question rr to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rrquestion_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat RR to string in unknown RR format, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_unknown_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Print to string the RR-information comment in default format,
+ * with user buffers. Moves string along.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rr: wireformat data.
+ * @param rrlen: length of data buffer.
+ * @param dname_off: offset in buffer behind owner dname, the compressed size
+ * of the owner name.
+ * @param rrtype: type of the RR, host format.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rr_comment_print(char** str, size_t* str_len, uint8_t* rr,
+ size_t rrlen, size_t dname_off, uint16_t rrtype);
+
+/**
+ * Scan wireformat packet header to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_header_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat rdata to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer. The length of the rdata in the
+ * buffer. The rdatalen itself has already been scanned, the data
+ * points to the rdata after the rdatalen.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrtype: RR type of Rdata, host format.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rdata_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint16_t rrtype, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat rdata to string in unknown format, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer, the length of the rdata in buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rdata_unknown_scan(uint8_t** data, size_t* data_len,
+ char** str, size_t* str_len);
+
+/**
+ * Scan wireformat domain name to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_dname_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat rr type to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_type_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat rr class to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_class_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat rr ttl to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_ttl_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+
+/**
+ * Print host format rr type to string. Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrtype: host format rr type.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_type_print(char** str, size_t* str_len, uint16_t rrtype);
+
+/**
+ * Print host format rr class to string. Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rrclass: host format rr class.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_class_print(char** str, size_t* str_len, uint16_t rrclass);
+
+/**
+ * Print host format rcode to string. Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rcode: host format rcode number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_rcode_print(char** str, size_t* str_len, int rcode);
+
+/**
+ * Print host format opcode to string. Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param opcode: host format opcode number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_opcode_print(char** str, size_t* str_len, int opcode);
+
+/**
+ * Print host format EDNS0 option to string. Moves string along, user buffers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param opcode: host format option number.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_option_code_print(char** str, size_t* str_len,
+ uint16_t opcode);
+
+/**
+ * Convert RR to string presentation format, on one line. User buffer.
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ * If you pass NULL as the str, the return value of the function is
+ * the str_len you need for the entire packet. It does not include
+ * the 0 byte at the end.
+ * @param str_len: the size of the string buffer. If more is needed, it'll
+ * silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str,
+ size_t str_len);
+
+/**
+ * 3597 printout of an RR in unknown rr format.
+ * There are more format and comment options available for printout
+ * with the function: TBD(TODO)
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ * If you pass NULL as the str, the return value of the function is
+ * the str_len you need for the entire rr. It does not include
+ * the 0 byte at the end.
+ * @param str_len: the size of the string buffer. If more is needed, it'll
+ * silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_unknown_buf(uint8_t* rr, size_t rr_len, char* str,
+ size_t str_len);
+
+/**
+ * This creates the comment to print after the RR. ; keytag=... , and other
+ * basic comments for RRs.
+ * There are more format and comment options available for printout
+ * with the function: TBD(TODO)
+ * @param rr: wireformat RR data
+ * @param rr_len: length of the rr wire data.
+ * @param dname_len: length of the dname in front of the RR.
+ * @param str: the string buffer to write to.
+ * If you pass NULL as the str, the return value of the function is
+ * the str_len you need for the entire comment. It does not include
+ * the 0 byte at the end.
+ * @param str_len: the size of the string buffer. If more is needed, it'll
+ * silently truncate the output to fit in the buffer.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rr_len, size_t dname_len,
+ char* str, size_t str_len);
+
+/**
+ * Convert RDATA to string presentation format, on one line. User buffer.
+ * @param rdata: wireformat rdata part of an RR.
+ * @param rdata_len: length of the rr wire data.
+ * @param str: the string buffer to write to.
+ * If you pass NULL as the str, the return value of the function is
+ * the str_len you need for the entire packet. It does not include
+ * the 0 byte at the end.
+ * @param str_len: the size of the string buffer. If more is needed, it'll
+ * silently truncate the output to fit in the buffer.
+ * @param rrtype: rr type of the data
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
+ size_t str_len, uint16_t rrtype);
+
+/**
+ * Convert wire RR type to a string, 'MX', 'TYPE12'. With user buffer.
+ * @param rrtype: the RR type in host order.
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_type_buf(uint16_t rrtype, char* str, size_t len);
+
+/**
+ * Convert wire RR class to a string, 'IN', 'CLASS12'. With user buffer.
+ * @param rrclass: the RR class in host order.
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_class_buf(uint16_t rrclass, char* str, size_t len);
+
+/**
+ * Convert wire RR rcode to a string, 'NOERROR', 'NXDOMAIN'. With user buffer.
+ * @param rcode: rcode as integer in host order
+ * @param str: the string to write to.
+ * @param len: length of str.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_rcode_buf(int rcode, char* str, size_t len);
+
+/**
+ * Convert wire dname to a string, "example.com.". With user buffer.
+ * @param dname: the dname in uncompressed wireformat.
+ * @param dname_len: length of the dname.
+ * @param str: the string to write to.
+ * @param len: length of string.
+ * @return the number of characters for this element, excluding zerobyte.
+ * Is larger than str_len if output was truncated.
+ */
+int sldns_wire2str_dname_buf(uint8_t* dname, size_t dname_len, char* str,
+ size_t len);
+
+/**
+ * Scan wireformat rdf field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param rdftype: the type of the rdata field, enum sldns_rdf_type.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_rdf_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, int rdftype, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat int8 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_int8_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat int16 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_int16_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat int32 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_int32_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat period field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_period_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat tsigtime field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_tsigtime_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat ip4 A field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_a_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat ip6 AAAA field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_aaaa_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat str field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_str_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat apl field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_apl_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat b32_ext field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_b32_ext_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat b64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_b64_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat hex field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_hex_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat nsec bitmap field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_nsec_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat nsec3_salt field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_nsec3_salt_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat cert_alg field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_cert_alg_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat alg field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_alg_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat type unknown field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_unknown_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat time field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_time_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat LOC field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_loc_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat WKS field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_wks_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat NSAP field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_nsap_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat ATMA field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_atma_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat IPSECKEY field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet for decompression, if NULL no decompression.
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_ipseckey_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+/**
+ * Scan wireformat HIP (algo, HIT, pubkey) field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_hip_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat int16_data field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_int16_data_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat nsec3_next_owner field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_nsec3_next_owner_scan(uint8_t** data, size_t* data_len,
+ char** str, size_t* str_len);
+
+/**
+ * Scan wireformat ILNP64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_ilnp64_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat EUI48 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_eui48_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat EUI64 field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_eui64_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat TAG field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_tag_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Scan wireformat long_str field to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @return number of characters (except null) needed to print.
+ * Can return -1 on failure.
+ */
+int sldns_wire2str_long_str_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len);
+
+/**
+ * Print EDNS LLQ option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_llq_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS UL option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_ul_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS NSID option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_nsid_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS DAU option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_dau_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS DHU option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_dhu_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS N3U option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_n3u_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print EDNS SUBNET option data to string. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_subnet_print(char** str, size_t* str_len,
+ uint8_t* option_data, size_t option_len);
+
+/**
+ * Print an EDNS option as OPT: VALUE. User buffers, moves string pointers.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param option_code: host format EDNS option code.
+ * @param option_data: buffer with EDNS option code data.
+ * @param option_len: length of the data for this option.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_option_print(char** str, size_t* str_len,
+ uint16_t option_code, uint8_t* option_data, size_t option_len);
+
+/**
+ * Scan wireformat EDNS OPT to string, with user buffers.
+ * It shifts the arguments to move along (see sldns_wire2str_pkt_scan).
+ * @param data: wireformat data.
+ * @param data_len: length of data buffer.
+ * @param str: string buffer.
+ * @param str_len: length of string buffer.
+ * @param pkt: packet with header and other info (may be NULL)
+ * @param pktlen: length of packet buffer.
+ * @return number of characters (except null) needed to print.
+ */
+int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
+ size_t* str_len, uint8_t* pkt, size_t pktlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_WIRE2STR_H */