diff --git a/Makefile_upgrade.inc b/Makefile_upgrade.inc
index ae95002cf7..89d562c904 100644
--- a/Makefile_upgrade.inc
+++ b/Makefile_upgrade.inc
@@ -2275,6 +2275,7 @@ TO_REMOVE+=/usr/lib/libedit.so
 TO_REMOVE+=/usr/lib/profile/libedit.a
 TO_REMOVE+=/lib/libedit.so.5
 TO_REMOVE+=/usr/lib/libprivate_ldns.so.1
+TO_REMOVE+=/usr/lib/libprivate_ldns.so.2
 TO_REMOVE+=/usr/lib/profile/libprivate_ldns.a
 TO_REMOVE+=/usr/lib/libprivate_ssh.so.4
 TO_REMOVE+=/usr/lib/profile/libprivate_ssh.a
diff --git a/contrib/ldns/README.DELETED b/contrib/ldns/README.DELETED
index a0801db0b5..f76fa91088 100644
--- a/contrib/ldns/README.DELETED
+++ b/contrib/ldns/README.DELETED
@@ -5,6 +5,7 @@ Makefile.in
 README
 README.git
 README.snapshots
+README-Travis.md
 aclocal.m4
 acx_nlnetlabs.m4
 ax_pkg_swig.m4
@@ -45,6 +46,7 @@ ldns/net.h.in
 ldns/util.h.in
 libdns.doxygen
 libdns.vim
+libdns.doxygen.in
 linktest.c
 ltmain.sh
 m4/
diff --git a/contrib/ldns/README.DRAGONFLY b/contrib/ldns/README.DRAGONFLY
index a8315a1c51..d5e94b384c 100644
--- a/contrib/ldns/README.DRAGONFLY
+++ b/contrib/ldns/README.DRAGONFLY
@@ -4,10 +4,10 @@ LDNS
 Original source can be downloaded from:
 http://www.nlnetlabs.nl/downloads/ldns/
 
-file = ldns-1.7.1.tar.gz
-date = 26 July 2019
-size = 1244394
-sha1 = d075a08972c0f573101fb4a6250471daaa53cb3e
+file = ldns-1.8.3.tar.gz
+date = 15 August 2022
+size = 1299856
+sha1 = 2796cc49636f68260c9662b60d5a7c9e6eed195c
 
 A list of files and directories removed is in README.DELETED
 
diff --git a/contrib/ldns/buffer.c b/contrib/ldns/buffer.c
index e008831fcc..8f6aab59ea 100644
--- a/contrib/ldns/buffer.c
+++ b/contrib/ldns/buffer.c
@@ -63,6 +63,7 @@ ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity)
 	
 	ldns_buffer_invariant(buffer);
 	assert(buffer->_position <= capacity);
+	assert(!buffer->_fixed);
 
 	data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity);
 	if (!data) {
@@ -79,7 +80,6 @@ bool
 ldns_buffer_reserve(ldns_buffer *buffer, size_t amount)
 {
 	ldns_buffer_invariant(buffer);
-	assert(!buffer->_fixed);
 	if (buffer->_capacity < buffer->_position + amount) {
 		size_t new_capacity = buffer->_capacity * 3 / 2;
 
diff --git a/contrib/ldns/dane.c b/contrib/ldns/dane.c
index 30dc1f7005..b8487b53a8 100644
--- a/contrib/ldns/dane.c
+++ b/contrib/ldns/dane.c
@@ -1,7 +1,7 @@
 /*
  * Verify or create TLS authentication with DANE (RFC6698)
  *
- * (c) NLnetLabs 2012
+ * (c) NLnetLabs 2012-2020
  *
  * See the file LICENSE for the license.
  *
@@ -29,6 +29,63 @@
 #include <openssl/x509v3.h>
 #endif
 
+/* OpenSSL context options. At the moment, disable SSLv2, SSLv3
+ * and Compression, if available. TLSv1.0 is allowed at the moment.
+ * TLSv1.1 is the first to provide elliptic curves, so it is usually
+ * allowed in a TLS stack. TLSv1.2 is the first to provide authentication
+ * modes of operation, like GCM. The defines below are a moving
+ * target based on OpenSSL library version. Grep is useful to find
+ * the defines: grep -IR SSL_OP_NO_ /usr/include/openssl.
+ */
+#ifdef HAVE_SSL
+# ifdef SSL_OP_NO_SSLv2
+	const long NoOpenSSLv2 = SSL_OP_NO_SSLv2;
+# else
+	const long NoOpenSSLv2 = 0L;
+# endif
+# ifdef SSL_OP_NO_SSLv3
+	const long NoOpenSSLv3 = SSL_OP_NO_SSLv3;
+# else
+	const long NoOpenSSLv3 = 0L;
+# endif
+# ifdef SSL_OP_NO_TLSv1
+	const long NoOpenTLSv1 = SSL_OP_NO_TLSv1;
+# else
+	const long NoOpenTLSv1 = 0L;
+# endif
+# ifdef SSL_OP_NO_DTLSv1
+	const long NoOpenDTLSv1 = SSL_OP_NO_DTLSv1;
+# else
+	const long NoOpenDTLSv1 = 0L;
+# endif
+# ifdef SSL_OP_NO_COMPRESSION
+	const long NoOpenSSLCompression = SSL_OP_NO_COMPRESSION;
+# else
+	const long NoOpenSSLCompression = 0L;
+# endif
+#endif
+
+#if defined(USE_DANE_VERIFY) && defined(USE_DANE_TA_USAGE)
+static SSL_CTX*
+ldns_dane_new_ssl_context(void)
+{
+	SSL_CTX* ssl_ctx;
+
+	ssl_ctx = SSL_CTX_new(TLS_client_method());
+	if (ssl_ctx != NULL)
+	{
+		/* ldns allows TLS and DTLS v1.0 at the moment. Some may disagree.
+		 * Sometime in the future they may be disabled, too. Maybe
+		 * --disable-tlsv1 and --disable-dtlsv1 should be configure options.
+		 */
+		long flags = NoOpenSSLv2 | NoOpenSSLv3 | NoOpenSSLCompression;
+		SSL_CTX_set_options(ssl_ctx, flags);
+	}
+
+	return ssl_ctx;
+}
+#endif
+
 ldns_status
 ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name,
 		uint16_t port, ldns_dane_transport transport)
@@ -193,7 +250,7 @@ ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs,
 }
 
 
-/* Orinary PKIX validation of cert (with extra_certs to help)
+/* Ordinary PKIX validation of cert (with extra_certs to help)
  * against the CA's in store, but also return the validation chain.
  */
 static ldns_status
@@ -641,7 +698,7 @@ ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
 	 * verification.  We use these undocumented means with the ldns
 	 * dane function prototypes which did only offline dane verification.
 	 */
-	if (!(ssl_ctx = SSL_CTX_new(TLS_client_method())))
+	if (!(ssl_ctx = ldns_dane_new_ssl_context()))
 		s = LDNS_STATUS_MEM_ERR;
 
 	else if (SSL_CTX_dane_enable(ssl_ctx) <= 0)
@@ -841,7 +898,7 @@ ldns_dane_verify(const ldns_rr_list* tlsas,
 	 * verification.  We use these undocumented means with the ldns
 	 * dane function prototypes which did only offline dane verification.
 	 */
-	if (!(ssl_ctx = SSL_CTX_new(TLS_client_method())))
+	if (!(ssl_ctx = ldns_dane_new_ssl_context()))
 		s = LDNS_STATUS_MEM_ERR;
 
 	else if (SSL_CTX_dane_enable(ssl_ctx) <= 0)
diff --git a/contrib/ldns/dname.c b/contrib/ldns/dname.c
index 17afe1d333..4f311ee298 100644
--- a/contrib/ldns/dname.c
+++ b/contrib/ldns/dname.c
@@ -3,7 +3,7 @@
  *
  * dname specific rdata implementations
  * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
- * It is not a /real/ type! All function must therefor check
+ * It is not a /real/ type! All function must therefore check
  * for LDNS_RDF_TYPE_DNAME.
  *
  * a Net::DNS like library for C
diff --git a/contrib/ldns/dnssec.c b/contrib/ldns/dnssec.c
index 52c35ee760..fbaa518a8c 100644
--- a/contrib/ldns/dnssec.c
+++ b/contrib/ldns/dnssec.c
@@ -332,6 +332,7 @@ uint16_t ldns_calc_keytag_raw(const uint8_t* key, size_t keysize)
 }
 
 #ifdef HAVE_SSL
+#ifdef USE_DSA
 DSA *
 ldns_key_buf2dsa(const ldns_buffer *key)
 {
@@ -380,7 +381,7 @@ ldns_key_buf2dsa_raw(const unsigned char* key, size_t len)
 		BN_free(Y);
 		return NULL;
 	}
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 #ifndef S_SPLINT_S
 	dsa->p = P;
 	dsa->q = Q;
@@ -407,6 +408,7 @@ ldns_key_buf2dsa_raw(const unsigned char* key, size_t len)
 #endif /* OPENSSL_VERSION_NUMBER */
 	return dsa;
 }
+#endif /* USE_DSA */
 
 RSA *
 ldns_key_buf2rsa(const ldns_buffer *key)
@@ -432,7 +434,7 @@ ldns_key_buf2rsa_raw(const unsigned char* key, size_t len)
 			return NULL;
 		/* need some smart comment here XXX*/
 		/* the exponent is too large so it's places
-		 * futher...???? */
+		 * further...???? */
 		memmove(&int16, key+1, 2);
 		exp = ntohs(int16);
 		offset = 3;
@@ -466,7 +468,7 @@ ldns_key_buf2rsa_raw(const unsigned char* key, size_t len)
 		BN_free(modulus);
 		return NULL;
 	}
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 #ifndef S_SPLINT_S
 	rsa->n = modulus;
 	rsa->e = exponent;
@@ -910,7 +912,7 @@ ldns_dnssec_create_nsec3(const ldns_dnssec_name *from,
 	cur_rrsets = from->rrsets;
 	while (cur_rrsets) {
 		/* Do not include non-authoritative rrsets on the delegation point
-		 * in the type bitmap. Potentionally not skipping insecure
+		 * in the type bitmap. Potentially not skipping insecure
 		 * delegation should have been done earlier, in function
 		 * ldns_dnssec_zone_create_nsec3s, or even earlier in:
 		 * ldns_dnssec_zone_sign_nsec3_flg .
@@ -1332,6 +1334,8 @@ ldns_nsec3_salt_data(const ldns_rr *nsec3_rr)
 	ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
 	if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
 	    	salt_length = ldns_rdf_data(salt_rdf)[0];
+		if((size_t)salt_length+1 > ldns_rdf_size(salt_rdf))
+			return NULL;
 		salt = LDNS_XMALLOC(uint8_t, salt_length);
                 if(!salt) return NULL;
 		memcpy(salt, &ldns_rdf_data(salt_rdf)[1], salt_length);
@@ -1904,7 +1908,7 @@ ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
         const ldns_rdf *sig_rdf)
 {
         /* convert from two BIGNUMs in the rdata buffer, to ASN notation.
-	 * ASN preable:  30440220 <R 32bytefor256> 0220 <S 32bytefor256>
+	 * ASN preamble:  30440220 <R 32bytefor256> 0220 <S 32bytefor256>
 	 * the '20' is the length of that field (=bnsize).
 	 * the '44' is the total remaining length.
 	 * if negative, start with leading zero.
diff --git a/contrib/ldns/dnssec_sign.c b/contrib/ldns/dnssec_sign.c
index c6d1dd2f34..41d845f3fa 100644
--- a/contrib/ldns/dnssec_sign.c
+++ b/contrib/ldns/dnssec_sign.c
@@ -24,6 +24,9 @@
 #endif
 #endif /* HAVE_SSL */
 
+#define LDNS_SIGN_WITH_ZONEMD ( LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA384 \
+                              | LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA512 )
+
 ldns_rr *
 ldns_create_empty_rrsig(const ldns_rr_list *rrset,
                         const ldns_key *current_key)
@@ -325,14 +328,6 @@ ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys)
 	return signatures;
 }
 
-/**
- * Sign data with DSA
- *
- * \param[in] to_sign The ldns_buffer containing raw data that is
- *                    to be signed
- * \param[in] key The DSA key structure to sign with
- * \return ldns_rdf for the RRSIG ldns_rr
- */
 ldns_rdf *
 ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key)
 {
@@ -413,11 +408,14 @@ ldns_pkey_is_ecdsa(EVP_PKEY* pkey)
 {
         EC_KEY* ec;
         const EC_GROUP* g;
-#ifdef HAVE_EVP_PKEY_BASE_ID
+#ifdef HAVE_EVP_PKEY_GET_BASE_ID
+        if(EVP_PKEY_get_base_id(pkey) != EVP_PKEY_EC)
+                return 0;
+#elif defined(HAVE_EVP_PKEY_BASE_ID)
         if(EVP_PKEY_base_id(pkey) != EVP_PKEY_EC)
                 return 0;
 #else
-        if(EVP_PKEY_type(key->type) != EVP_PKEY_EC)
+        if(EVP_PKEY_type(pkey->type) != EVP_PKEY_EC)
                 return 0;
 #endif
         ec = EVP_PKEY_get1_EC_KEY(pkey);
@@ -529,7 +527,9 @@ ldns_sign_public_evp(ldns_buffer *to_sign,
 #ifdef USE_DSA
 #ifndef S_SPLINT_S
 	/* unfortunately, OpenSSL output is different from DNS DSA format */
-# ifdef HAVE_EVP_PKEY_BASE_ID
+# ifdef HAVE_EVP_PKEY_GET_BASE_ID
+	if (EVP_PKEY_get_base_id(key) == EVP_PKEY_DSA) {
+# elif defined(HAVE_EVP_PKEY_BASE_ID)
 	if (EVP_PKEY_base_id(key) == EVP_PKEY_DSA) {
 # else
 	if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) {
@@ -541,7 +541,9 @@ ldns_sign_public_evp(ldns_buffer *to_sign,
 #endif
 #if defined(USE_ECDSA)
 	if(
-#  ifdef HAVE_EVP_PKEY_BASE_ID
+#  ifdef HAVE_EVP_PKEY_GET_BASE_ID
+		EVP_PKEY_get_base_id(key)
+#  elif defined(HAVE_EVP_PKEY_BASE_ID)
 		EVP_PKEY_base_id(key)
 #  else
 		EVP_PKEY_type(key->type)
@@ -655,7 +657,7 @@ ldns_dnssec_addresses_on_glue_list(
 						/* ldns_rr_list_push_rr()
 						 * returns false when unable
 						 * to increase the capacity
-						 * of the ldsn_rr_list
+						 * of the ldns_rr_list
 						 */
 					}
 				}
@@ -666,20 +668,6 @@ ldns_dnssec_addresses_on_glue_list(
 	return LDNS_STATUS_OK;
 }
 
-/**
- * Marks the names in the zone that are occluded. Those names will be skipped
- * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
- * function. But watch out! Names that are partially occluded (like glue with
- * the same name as the delegation) will not be marked and should specifically 
- * be taken into account separately.
- *
- * When glue_list is given (not NULL), in the process of marking the names, all
- * glue resource records will be pushed to that list, even glue at delegation names.
- *
- * \param[in] zone the zone in which to mark the names
- * \param[in] glue_list the list to which to push the glue rrs
- * \return LDNS_STATUS_OK on success, an error code otherwise
- */
 ldns_status
 ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone, 
 	ldns_rr_list *glue_list)
@@ -691,7 +679,7 @@ ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
 	/* When the cut is caused by a delegation, below_delegation will be 1.
 	 * When caused by a DNAME, below_delegation will be 0.
 	 */
-	int below_delegation = -1; /* init suppresses comiler warning */
+	int below_delegation = -1; /* init suppresses compiler warning */
 	ldns_status s;
 
 	if (!zone || !zone->names) {
@@ -713,7 +701,7 @@ ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
 			 * FIXME! If there are labels in between the SOA and
 			 * the cut, going from the authoritative space (below
 			 * the SOA) up into occluded space again, will not be
-			 * detected with the contruct below!
+			 * detected with the construct below!
 			 */
 			if (ldns_dname_is_subdomain(owner, cut) &&
 					!ldns_dnssec_rrsets_contains_type(
@@ -759,16 +747,6 @@ ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
 	return LDNS_STATUS_OK;
 }
 
-/**
- * Marks the names in the zone that are occluded. Those names will be skipped
- * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
- * function. But watch out! Names that are partially occluded (like glue with
- * the same name as the delegation) will not be marked and should specifically 
- * be taken into account separately.
- *
- * \param[in] zone the zone in which to mark the names
- * \return LDNS_STATUS_OK on success, an error code otherwise
- */
 ldns_status
 ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone)
 {
@@ -812,17 +790,24 @@ ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
 	uint32_t nsec_ttl;
 	ldns_dnssec_rrsets *soa;
 
-	/* the TTL of NSEC rrs should be set to the minimum TTL of
-	 * the zone SOA (RFC4035 Section 2.3)
+	/* The TTL value for any NSEC RR SHOULD be the same TTL value as the
+	 * lesser of the MINIMUM field of the SOA record and the TTL of the SOA
+	 * itself. This matches the definition of the TTL for negative
+	 * responses in [RFC2308]. (draft-ietf-dnsop-nsec-ttl-01 update of
+	 * RFC4035 Section 2.3)
 	 */
 	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
 
 	/* did the caller actually set it? if not,
 	 * fall back to default ttl
 	 */
-	if (soa && soa->rrs && soa->rrs->rr
-			&& (ldns_rr_rdf(soa->rrs->rr, 6) != NULL)) {
-		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
+	if (soa && soa->rrs && soa->rrs->rr) {
+		ldns_rr  *soa_rr  = soa->rrs->rr;
+		ldns_rdf *min_rdf = ldns_rr_rdf(soa_rr, 6);
+
+		nsec_ttl = min_rdf == NULL
+		       || ldns_rr_ttl(soa_rr) < ldns_rdf2native_int32(min_rdf)
+		        ? ldns_rr_ttl(soa_rr) : ldns_rdf2native_int32(min_rdf);
 	} else {
 		nsec_ttl = LDNS_DEFAULT_TTL;
 	}
@@ -906,17 +891,24 @@ ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone,
 		return LDNS_STATUS_ERR;
 	}
 
-	/* the TTL of NSEC rrs should be set to the minimum TTL of
-	 * the zone SOA (RFC4035 Section 2.3)
+	/* The TTL value for any NSEC RR SHOULD be the same TTL value as the
+	 * lesser of the MINIMUM field of the SOA record and the TTL of the SOA
+	 * itself. This matches the definition of the TTL for negative
+	 * responses in [RFC2308]. (draft-ietf-dnsop-nsec-ttl-01 update of
+	 * RFC4035 Section 2.3)
 	 */
 	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
 
 	/* did the caller actually set it? if not,
 	 * fall back to default ttl
 	 */
-	if (soa && soa->rrs && soa->rrs->rr
-			&& ldns_rr_rdf(soa->rrs->rr, 6) != NULL) {
-		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
+	if (soa && soa->rrs && soa->rrs->rr) {
+		ldns_rr  *soa_rr  = soa->rrs->rr;
+		ldns_rdf *min_rdf = ldns_rr_rdf(soa_rr, 6);
+
+		nsec_ttl = min_rdf == NULL
+		       || ldns_rr_ttl(soa_rr) < ldns_rdf2native_int32(min_rdf)
+		        ? ldns_rr_ttl(soa_rr) : ldns_rdf2native_int32(min_rdf);
 	} else {
 		nsec_ttl = LDNS_DEFAULT_TTL;
 	}
@@ -1141,17 +1133,22 @@ ldns_key_list_filter_for_dnskey(ldns_key_list *key_list, int flags)
 	if (!ldns_key_list_key_count(key_list))
 		return;
 
+	/* Mark all KSKs */
 	for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
 		key = ldns_key_list_key(key_list, i);
-		if ((ldns_key_flags(key) & LDNS_KEY_SEP_KEY) && !saw_ksk)
-			saw_ksk = ldns_key_algorithm(key);
-		algos[ldns_key_algorithm(key)] = true;
+		if ((ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
+			if (!saw_ksk)
+				saw_ksk = ldns_key_algorithm(key);
+			algos[ldns_key_algorithm(key)] = true;
+		}
 	}
 	if (!saw_ksk)
-		return;
-	else
-		algos[saw_ksk] = 0;
+		return; /* No KSKs means sign using all ZSKs */
 
+	/* Deselect the ZSKs so they do not sign DNSKEY RRs.
+	 * Except with the LDNS_SIGN_WITH_ALL_ALGORITHMS flag, then use it,
+	 * but only if it has an algorithm for which there is no KSK
+	 */
 	for (i =0; i < ldns_key_list_key_count(key_list); i++) {
 		key = ldns_key_list_key(key_list, i);
 		if (!(ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
@@ -1159,15 +1156,15 @@ ldns_key_list_filter_for_dnskey(ldns_key_list *key_list, int flags)
 			 * Still use it if it has a unique algorithm though!
 			 */
 			if ((flags & LDNS_SIGN_WITH_ALL_ALGORITHMS) &&
-			    algos[ldns_key_algorithm(key)])
-				algos[ldns_key_algorithm(key)] = false;
+			    !algos[ldns_key_algorithm(key)])
+				algos[ldns_key_algorithm(key)] = true;
 			else
 				ldns_key_set_use(key, 0);
 		}
 	}
 }
 
-/** If there are no ZSKs use KSK as ZSK */
+/** If there are no ZSKs use KSKs as ZSK too */
 static void
 ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list, int flags)
 {
@@ -1183,17 +1180,22 @@ ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list, int flags)
 	if (!ldns_key_list_key_count(key_list))
 		return;
 
+	/* Mark all ZSKs */
 	for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
 		key = ldns_key_list_key(key_list, i);
-		if (!(ldns_key_flags(key) & LDNS_KEY_SEP_KEY) && !saw_zsk)
-			saw_zsk = ldns_key_algorithm(key);
-		algos[ldns_key_algorithm(key)] = true;
+		if (!(ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
+			if (!saw_zsk)
+				saw_zsk = ldns_key_algorithm(key);
+			algos[ldns_key_algorithm(key)] = true;
+		}
 	}
 	if (!saw_zsk)
-		return;
-	else
-		algos[saw_zsk] = 0;
+		return; /* No ZSKs means sign using all KSKs */
 
+	/* Deselect the KSKs so they do not sign non DNSKEY RRs.
+	 * Except with the LDNS_SIGN_WITH_ALL_ALGORITHMS flag, then use it,
+	 * but only if it has an algorithm for which there is no ZSK
+	 */
 	for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
 		key = ldns_key_list_key(key_list, i);
 		if((ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
@@ -1201,8 +1203,8 @@ ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list, int flags)
 			 * Still use it if it has a unique algorithm though!
 			 */
 			if ((flags & LDNS_SIGN_WITH_ALL_ALGORITHMS) &&
-			    algos[ldns_key_algorithm(key)])
-				algos[ldns_key_algorithm(key)] = false;
+			    !algos[ldns_key_algorithm(key)])
+				algos[ldns_key_algorithm(key)] = true;
 			else
 				ldns_key_set_use(key, 0);
 		}
@@ -1365,6 +1367,8 @@ ldns_dnssec_zone_sign(ldns_dnssec_zone *zone,
 	return ldns_dnssec_zone_sign_flg(zone, new_rrs, key_list, func, arg, 0);
 }
 
+ldns_status dnssec_zone_equip_zonemd(ldns_dnssec_zone *zone,
+		ldns_rr_list *new_rrs, ldns_key_list *key_list, int flags);
 ldns_status
 ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
 				  ldns_rr_list *new_rrs,
@@ -1374,25 +1378,46 @@ ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
 				  int flags)
 {
 	ldns_status result = LDNS_STATUS_OK;
+	ldns_dnssec_rrsets zonemd_rrset;
+	bool zonemd_added = false;
 
 	if (!zone || !new_rrs || !key_list) {
 		return LDNS_STATUS_ERR;
 	}
-
+	if (flags & LDNS_SIGN_WITH_ZONEMD) {
+		ldns_dnssec_rrsets **rrsets_ref = &zone->soa->rrsets;
+
+		while (*rrsets_ref
+		   && (*rrsets_ref)->type < LDNS_RR_TYPE_ZONEMD)
+			rrsets_ref = &(*rrsets_ref)->next;
+		if (!*rrsets_ref
+		||  (*rrsets_ref)->type > LDNS_RR_TYPE_ZONEMD) {
+			zonemd_rrset.rrs = NULL;
+			zonemd_rrset.type = LDNS_RR_TYPE_ZONEMD;
+			zonemd_rrset.signatures = NULL;
+			zonemd_rrset.next = *rrsets_ref;
+			*rrsets_ref = &zonemd_rrset;
+			zonemd_added = true;
+		}
+	}
 	/* zone is already sorted */
 	result = ldns_dnssec_zone_mark_glue(zone);
 	if (result != LDNS_STATUS_OK) {
 		return result;
 	}
-
 	/* check whether we need to add nsecs */
-	if (zone->names && !((ldns_dnssec_name *)zone->names->root->data)->nsec) {
+	if ((flags & LDNS_SIGN_NO_KEYS_NO_NSECS)
+	&&  ldns_key_list_key_count(key_list) < 1)
+		; /* pass */
+
+	else if (zone->names
+	     && !((ldns_dnssec_name *)zone->names->root->data)->nsec) {
+
 		result = ldns_dnssec_zone_create_nsecs(zone, new_rrs);
 		if (result != LDNS_STATUS_OK) {
 			return result;
 		}
 	}
-
 	result = ldns_dnssec_zone_create_rrsigs_flg(zone,
 					new_rrs,
 					key_list,
@@ -1400,7 +1425,18 @@ ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
 					arg,
 					flags);
 
-	return result;
+	if (zonemd_added) {
+		ldns_dnssec_rrsets **rrsets_ref
+		    = &zone->soa->rrsets;
+
+		while (*rrsets_ref
+		   && (*rrsets_ref)->type < LDNS_RR_TYPE_ZONEMD)
+			rrsets_ref = &(*rrsets_ref)->next;
+		*rrsets_ref = zonemd_rrset.next;
+	}
+	return flags & LDNS_SIGN_WITH_ZONEMD
+	     ? dnssec_zone_equip_zonemd(zone, new_rrs, key_list, flags)
+	     : result;
 }
 
 ldns_status
@@ -1436,6 +1472,8 @@ ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
 {
 	ldns_rr *nsec3, *nsec3param;
 	ldns_status result = LDNS_STATUS_OK;
+	bool zonemd_added = false;
+	ldns_dnssec_rrsets zonemd_rrset;
 
 	/* zone is already sorted */
 	result = ldns_dnssec_zone_mark_glue(zone);
@@ -1454,7 +1492,13 @@ ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
 		}
 
 		nsec3 = ((ldns_dnssec_name *)zone->names->root->data)->nsec;
-		if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) {
+
+		/* check whether we need to add nsecs */
+		if ((signflags & LDNS_SIGN_NO_KEYS_NO_NSECS)
+		&&  ldns_key_list_key_count(key_list) < 1)
+			; /* pass */
+
+		else if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) {
 			/* no need to recreate */
 		} else {
 			if (!ldns_dnssec_zone_find_rrset(zone,
@@ -1481,6 +1525,23 @@ ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
 				}
 				ldns_rr_list_push_rr(new_rrs, nsec3param);
 			}
+			if (signflags & LDNS_SIGN_WITH_ZONEMD) {
+				ldns_dnssec_rrsets **rrsets_ref
+				    = &zone->soa->rrsets;
+
+				while (*rrsets_ref
+				   && (*rrsets_ref)->type < LDNS_RR_TYPE_ZONEMD)
+					rrsets_ref = &(*rrsets_ref)->next;
+				if (!*rrsets_ref
+				||  (*rrsets_ref)->type > LDNS_RR_TYPE_ZONEMD) {
+					zonemd_rrset.rrs = NULL;
+					zonemd_rrset.type = LDNS_RR_TYPE_ZONEMD;
+					zonemd_rrset.signatures = NULL;
+					zonemd_rrset.next = *rrsets_ref;
+					*rrsets_ref = &zonemd_rrset;
+					zonemd_added = true;
+				}
+			}
 			result = ldns_dnssec_zone_create_nsec3s_mkmap(zone,
 											new_rrs,
 											algorithm,
@@ -1489,6 +1550,15 @@ ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
 											salt_length,
 											salt,
 											map);
+			if (zonemd_added) {
+				ldns_dnssec_rrsets **rrsets_ref
+				    = &zone->soa->rrsets;
+
+				while (*rrsets_ref
+				   && (*rrsets_ref)->type < LDNS_RR_TYPE_ZONEMD)
+					rrsets_ref = &(*rrsets_ref)->next;
+				*rrsets_ref = zonemd_rrset.next;
+			}
 			if (result != LDNS_STATUS_OK) {
 				return result;
 			}
@@ -1501,8 +1571,12 @@ ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
 						arg,
 						signflags);
 	}
+	if (result || !zone->names)
+		return result;
 
-	return result;
+	return signflags & LDNS_SIGN_WITH_ZONEMD
+	     ? dnssec_zone_equip_zonemd(zone, new_rrs, key_list, signflags)
+	     : result;
 }
 
 ldns_status
diff --git a/contrib/ldns/dnssec_verify.c b/contrib/ldns/dnssec_verify.c
index d22962eb90..d76f32eba7 100644
--- a/contrib/ldns/dnssec_verify.c
+++ b/contrib/ldns/dnssec_verify.c
@@ -21,7 +21,7 @@ ldns_dnssec_data_chain_new(void)
 	ldns_dnssec_data_chain *nc = LDNS_CALLOC(ldns_dnssec_data_chain, 1);
         if(!nc) return NULL;
 	/* 
-	 * not needed anymore because CALLOC initalizes everything to zero.
+	 * not needed anymore because CALLOC initializes everything to zero.
 
 	nc->rrset = NULL;
 	nc->parent_type = 0;
@@ -597,7 +597,9 @@ ldns_dnssec_trust_tree_print_sm_fmt(FILE *out,
 						if (tree->parent_status[i]
 						    == LDNS_STATUS_SSL_ERR) {
 							printf("; SSL Error: ");
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(HAVE_LIBRESSL)
 							ERR_load_crypto_strings();
+#endif
 							ERR_print_errors_fp(stdout);
 							printf("\n");
 						}
@@ -1501,7 +1503,7 @@ ldns_dnssec_verify_denial(ldns_rr *rr,
                           ldns_rr_list *rrsigs)
 {
 	ldns_rdf *rr_name;
-	ldns_rdf *wildcard_name;
+	ldns_rdf *wildcard_name = NULL;
 	ldns_rdf *chopped_dname;
 	ldns_rr *cur_nsec;
 	size_t i;
@@ -1512,14 +1514,19 @@ ldns_dnssec_verify_denial(ldns_rr *rr,
 	bool type_covered = false;
 	bool wildcard_covered = false;
 	bool wildcard_type_covered = false;
+	bool rr_name_is_root = false;
 
-	wildcard_name = ldns_dname_new_frm_str("*");
 	rr_name = ldns_rr_owner(rr);
-	chopped_dname = ldns_dname_left_chop(rr_name);
-	result = ldns_dname_cat(wildcard_name, chopped_dname);
-	ldns_rdf_deep_free(chopped_dname);
-	if (result != LDNS_STATUS_OK) {
-		return result;
+	rr_name_is_root =     ldns_rdf_size(rr_name) == 1
+	                  && *ldns_rdf_data(rr_name) == 0;
+	if (!rr_name_is_root) {
+		wildcard_name = ldns_dname_new_frm_str("*");
+		chopped_dname = ldns_dname_left_chop(rr_name);
+		result = ldns_dname_cat(wildcard_name, chopped_dname);
+		ldns_rdf_deep_free(chopped_dname);
+		if (result != LDNS_STATUS_OK) {
+			return result;
+		}
 	}
 	
 	for  (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
@@ -1546,6 +1553,9 @@ ldns_dnssec_verify_denial(ldns_rr *rr,
 			name_covered = true;
 		}
 		
+		if (rr_name_is_root)
+			continue;
+
 		if (ldns_dname_compare(wildcard_name,
 						   ldns_rr_owner(cur_nsec)) == 0) {
 			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(cur_nsec),
@@ -1566,6 +1576,9 @@ ldns_dnssec_verify_denial(ldns_rr *rr,
 		return LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
 	}
 	
+	if (rr_name_is_root)
+		return LDNS_STATUS_OK;
+
 	if (wildcard_type_covered || !wildcard_covered) {
 		return LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED;
 	}
@@ -2390,8 +2403,12 @@ ldns_verify_rrsig_keylist_time(
 		ldns_rr_list *good_keys)
 {
 	ldns_status result;
-	ldns_rr_list *valid = ldns_rr_list_new();
-	if (!valid)
+	ldns_rr_list *valid;
+
+	if (!good_keys)
+		valid = NULL;
+
+	else if (!(valid = ldns_rr_list_new()))
 		return LDNS_STATUS_MEM_ERR;
 
 	result = ldns_verify_rrsig_keylist_notime(rrset, rrsig, keys, valid);
diff --git a/contrib/ldns/dnssec_zone.c b/contrib/ldns/dnssec_zone.c
index e089754ddb..7be6791e7f 100644
--- a/contrib/ldns/dnssec_zone.c
+++ b/contrib/ldns/dnssec_zone.c
@@ -323,7 +323,7 @@ ldns_dnssec_name_new(void)
 		return NULL;
 	}
 	/*
-	 * not needed anymore because CALLOC initalizes everything to zero.
+	 * not needed anymore because CALLOC initializes everything to zero.
 
 	new_name->name = NULL;
 	new_name->rrsets = NULL;
@@ -370,9 +370,10 @@ ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
 			ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
 		}
 		if (name->hashed_name) {
-			if (deep) {
-				ldns_rdf_deep_free(name->hashed_name);
-			}
+			/* Hashed name is always allocated when signing,
+			 * so always deep free
+			 */
+			ldns_rdf_deep_free(name->hashed_name);
 		}
 		LDNS_FREE(name);
 	}
@@ -588,7 +589,7 @@ rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
 /* When the zone is first read into an list and then inserted into an
  * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
  * to each other. Because ldns-verify-zone (the only program that uses this
- * function) uses the rbtree mostly for sequentual walking, this results
+ * function) uses the rbtree mostly for sequential walking, this results
  * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
  */
 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
@@ -604,9 +605,13 @@ ldns_todo_nsec3_ents_node_free(ldns_rbnode_t *node, void *arg) {
 	LDNS_FREE(node);
 }
 
+ldns_status _ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+		uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+		int *line_nr, bool *explicit_ttl);
+
 ldns_status
 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
-	       	uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
+		uint32_t default_ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
 {
 	ldns_rr* cur_rr;
 	size_t i;
@@ -626,7 +631,7 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* or
 	   nsec3_ents (where ent is e.n.t.; i.e. empty non terminal) will
 	   hold the NSEC3s that still didn't have a matching name in the
 	   zone tree, even after all names were read.  They can only match
-	   after the zone is equiped with all the empty non terminals. */
+	   after the zone is equipped with all the empty non terminals. */
 	ldns_rbtree_t todo_nsec3_ents;
 	ldns_rbnode_t *new_node;
 	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
@@ -636,13 +641,19 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* or
 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
 	ldns_zone* zone = NULL;
 #else
-	uint32_t  my_ttl = ttl;
+	ldns_rr  *prev_rr = NULL;
+	uint32_t   my_ttl = default_ttl;
+	/* RFC 1035 Section 5.1, says 'Omitted class and TTL values are default
+	 * to the last explicitly stated values.'
+	 */
+	bool ttl_from_TTL = false;
+	bool explicit_ttl = false;
 #endif
 
 	ldns_rbtree_init(&todo_nsec3_ents, ldns_dname_compare_v);
 
 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
-	status = ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr);
+	status = ldns_zone_new_frm_fp_l(&zone, fp, origin, default_ttl, c, line_nr);
 	if (status != LDNS_STATUS_OK)
 		goto error;
 #endif
@@ -672,13 +683,61 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* or
 		status = LDNS_STATUS_OK;
 #else
 	while (!feof(fp)) {
+		/* If ttl came from $TTL line, then it should be the default.
+		 * (RFC 2308 Section 4)
+		 * Otherwise it "defaults to the last explicitly stated value"
+		 * (RFC 1035 Section 5.1)
+		 */
+		if (ttl_from_TTL)
+			my_ttl = default_ttl;
 		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
-				&my_prev, line_nr);
-
+				&my_prev, line_nr, &explicit_ttl);
 #endif
 		switch (status) {
 		case LDNS_STATUS_OK:
+#ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
+			if (explicit_ttl) {
+				if (!ttl_from_TTL) {
+					/* No $TTL, so ttl "defaults to the
+					 * last explicitly stated value"
+					 * (RFC 1035 Section 5.1)
+					 */
+					my_ttl = ldns_rr_ttl(cur_rr);
+				}
+			/* When ttl is implicit, try to adhere to the rules as
+			 * much as possible. (also for compatibility with bind)
+			 * This was changed when fixing an issue with ZONEMD
+			 * which hashes the TTL too.
+			 */
+			} else if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SIG
+			       ||  ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_RRSIG) {
+				if (ldns_rr_rd_count(cur_rr) >= 4
+				&&  ldns_rdf_get_type(ldns_rr_rdf(cur_rr, 3)) == LDNS_RDF_TYPE_INT32)
+
+					/* SIG without explicit ttl get ttl
+					 * from the original_ttl field
+					 * (RFC 2535 Section 7.2)
+					 *
+					 * Similarly for RRSIG, but stated less
+					 * specifically in the spec.
+					 * (RFC 4034 Section 3)
+					 */
+					ldns_rr_set_ttl(cur_rr,
+					    ldns_rdf2native_int32(
+					        ldns_rr_rdf(rr, 3)));
+
+			} else if (prev_rr
+			       &&  ldns_rr_get_type(prev_rr) == ldns_rr_get_type(cur_rr)
+			       &&  ldns_dname_compare( ldns_rr_owner(prev_rr)
+			                             , ldns_rr_owner(cur_rr)) == 0)
+
+				/* "TTLs of all RRs in an RRSet must be the same"
+				 * (RFC 2881 Section 5.2)
+				 */
+				ldns_rr_set_ttl(cur_rr, ldns_rr_ttl(prev_rr));
 
+			prev_rr = cur_rr;
+#endif
 			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
 			if (status ==
 				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
@@ -698,9 +757,16 @@ ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* or
 
 			break;
 
+		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
+#ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
+			default_ttl = my_ttl;
+			ttl_from_TTL = true;
+#endif
+			status = LDNS_STATUS_OK;
+			break;
+
 
 		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
-		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
 		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
 			status = LDNS_STATUS_OK;
 			break;
@@ -793,10 +859,21 @@ ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
 	LDNS_FREE(node);
 }
 
+static void
+ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
+	(void) arg;
+	LDNS_FREE(node);
+}
+
 void
 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
 {
 	if (zone) {
+		if (zone->hashed_names) {
+			ldns_traverse_postorder(zone->hashed_names,
+					ldns_hashed_names_node_free, NULL);
+			LDNS_FREE(zone->hashed_names);
+		}
 		if (zone->names) {
 			/* destroy all name structures within the tree */
 			ldns_traverse_postorder(zone->names,
@@ -812,6 +889,11 @@ void
 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
 {
 	if (zone) {
+		if (zone->hashed_names) {
+			ldns_traverse_postorder(zone->hashed_names,
+					ldns_hashed_names_node_free, NULL);
+			LDNS_FREE(zone->hashed_names);
+		}
 		if (zone->names) {
 			/* destroy all name structures within the tree */
 			ldns_traverse_postorder(zone->names,
@@ -833,12 +915,6 @@ static void
 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
 		ldns_dnssec_name* name, ldns_rr* nsec3rr);
 
-static void
-ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
-	(void) arg;
-	LDNS_FREE(node);
-}
-
 static void
 ldns_dnssec_zone_hashed_names_from_nsec3(
 		ldns_dnssec_zone* zone, ldns_rr* nsec3rr)
@@ -908,20 +984,22 @@ ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
 static ldns_rbnode_t *
 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) {
 	ldns_rdf *hashed_name;
+	ldns_rbnode_t *to_return;
 
-	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
-	if (hashed_name == NULL) {
-		return NULL;
-	}
 	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){
 
 		ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr);
 	}
 	if (zone->hashed_names == NULL) {
-		ldns_rdf_deep_free(hashed_name);
 		return NULL;
 	}
-	return  ldns_rbtree_search(zone->hashed_names, hashed_name);
+	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
+	if (hashed_name == NULL) {
+		return NULL;
+	}
+	to_return = ldns_rbtree_search(zone->hashed_names, hashed_name);
+	ldns_rdf_deep_free(hashed_name);
+	return to_return;
 }
 
 ldns_status
@@ -1127,6 +1205,7 @@ ldns_dnssec_zone_add_empty_nonterminals_nsec3(
 					}
 					node = ldns_rbtree_search(nsec3s, 
 							ent_hashed_name);
+					ldns_rdf_deep_free(ent_hashed_name);
 					if (!node) {
 						ldns_rdf_deep_free(l1);
 						ldns_rdf_deep_free(l2);
@@ -1201,3 +1280,706 @@ ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone)
 	}
 	return false;
 }
+
+/*
+ * Stuff for calculating and verifying zone digests
+ */
+typedef enum dnssec_zone_rr_iter_state {
+	  DNSSEC_ZONE_RR_ITER_LT_RRSIG
+	, DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
+	, DNSSEC_ZONE_RR_ITER_REST
+	, DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC
+	, DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST
+	, DNSSEC_ZONE_RR_ITER_NSEC3
+	, DNSSEC_ZONE_RR_ITER_FINI
+} dnssec_zone_rr_iter_state;
+
+typedef struct dnssec_zone_rr_iter {
+	ldns_dnssec_zone         *zone;
+	ldns_rbnode_t            *node;
+	ldns_dnssec_name         *name;
+	ldns_dnssec_rrsets       *rrsets;
+	ldns_dnssec_rrs          *rrs;
+	ldns_dnssec_rrsets       *rrsets4rrsigs;
+	ldns_rbnode_t            *nsec3_node;
+	ldns_dnssec_name         *nsec3_name;
+	dnssec_zone_rr_iter_state state;
+	ldns_rdf                 *apex_name;
+	uint8_t                   apex_labs;
+} dnssec_zone_rr_iter;
+
+INLINE void
+dnssec_zone_rr_iter_set_state_for_next_name(dnssec_zone_rr_iter *i)
+{
+	/* Make sure the i->name is "in zone" (i.e. below the apex) */
+	if (i->apex_name) {
+		ldns_rdf *name = (ldns_rdf *)i->node->key;
+
+		while (i->name && name != i->apex_name        /* not apex */
+
+		&& (  ldns_dname_label_count(name) != i->apex_labs
+		   || ldns_dname_compare(name, i->apex_name)) /* not apex */
+
+		&& !ldns_dname_is_subdomain(name, i->apex_name) /* no sub */) {
+
+			/* next name */
+			i->node = ldns_rbtree_next(i->node);
+			if (i->node == LDNS_RBTREE_NULL)
+				i->name = NULL;
+			else {
+				i->name = (ldns_dnssec_name *)i->node->data;
+				name = (ldns_rdf *)i->node->key;
+			}
+		}
+	}
+	/* determine state */
+	if (!i->name) {
+		if (!i->nsec3_name)
+			i->state = DNSSEC_ZONE_RR_ITER_FINI;
+		else {
+			i->rrs = i->nsec3_name->nsec_signatures;
+			i->state = DNSSEC_ZONE_RR_ITER_NSEC3;
+		}
+	} else if (!i->nsec3_name) {
+		i->rrsets = i->name->rrsets;
+		i->state = DNSSEC_ZONE_RR_ITER_LT_RRSIG;
+
+	} else if (ldns_dname_compare( ldns_rr_owner(i->nsec3_name->nsec)
+	                             , (ldns_rdf *)i->node->key) < 0) {
+		i->rrs = i->nsec3_name->nsec_signatures;
+		i->state = DNSSEC_ZONE_RR_ITER_NSEC3;
+	} else {
+		i->rrsets = i->name->rrsets;
+		i->state = DNSSEC_ZONE_RR_ITER_LT_RRSIG;
+	}
+}
+
+/**
+ * Iterate over the RR's in the ldns_dnssec_zone in canonical order.
+ * There are three possible paths through the RR's in a ldns_dnssec_name.
+ * 
+ * 1. There is no NSEC:
+ *
+ *    1.1. All the RRs in the name->rrsets with type < RRSIG,
+ *         state: DNSSEC_ZONE_RR_ITER_LT_RRSIG
+ *
+ *    1.2. Then all the RRSIGs from name->rrsets (likely none)
+ *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
+ *
+ *    1.3. Finally the remaining RRs in name->rrsets (type > RRSIG)
+ *         state: DNSSEC_ZONE_RR_ITER_REST
+ *
+ *
+ * 2. There is a NSEC of type NSEC with this name:
+ *
+ *    2.1. All the RRs in the name->rrsets with type < RRSIG,
+ *         state: DNSSEC_ZONE_RR_ITER_LT_RRSIG
+ *
+ *    2.2. Then all the RRSIGs from name->rrsets with type < NSEC
+ *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
+ *
+ *    2.3. Then the signatures of the NSEC RR, followed by
+ *         the signatures of the remaining name->rrsets (type > NSEC),
+ *         followed by the NSEC rr.
+ *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
+ *
+ *    2.4. Finally the remaining RRs in name->rrsets (type > RRSIG)
+ *         state: DNSSEC_ZONE_RR_ITER_REST
+ *
+ *
+ * 3. There is a NSEC of type NSEC3 for this name:
+ *
+ *    3.1. If the NSEC3 name is before the name for other RRsets in the zone,
+ *         Then all signatures of the NSEC3 RR, followed by the NSEC3
+ *         state: DNSSEC_ZONE_RR_ITER_NSEC3
+ *
+ *         otherwise follow path for "no NSEC" for the name for other RRsets
+ */
+static ldns_rr *
+dnssec_zone_rr_iter_next(dnssec_zone_rr_iter *i)
+{
+	ldns_rr *nsec3;
+
+	for (;;) {
+		if (i->rrs) {
+			ldns_rr *rr = i->rrs->rr;
+			i->rrs = i->rrs->next;
+			return rr;
+		}
+		switch (i->state) {
+		case DNSSEC_ZONE_RR_ITER_LT_RRSIG:
+			if (i->rrsets
+			&&  i->rrsets->type < LDNS_RR_TYPE_RRSIG) {
+
+				i->rrs = i->rrsets->rrs;
+				i->rrsets = i->rrsets->next;
+				break;
+			}
+			i->rrsets4rrsigs = i->name->rrsets;
+			if (i->name->nsec && ldns_rr_get_type(i->name->nsec)
+			                               == LDNS_RR_TYPE_NSEC) {
+
+				i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC;
+				break;
+			}
+			i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC;
+			/* fallthrough */
+
+		case DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC:
+			if (i->rrsets4rrsigs) {
+				i->rrs = i->rrsets4rrsigs->signatures;
+				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
+				break;
+			}
+			i->state = DNSSEC_ZONE_RR_ITER_REST;
+			/* fallthrough */
+
+		case DNSSEC_ZONE_RR_ITER_REST:
+			if (i->rrsets) {
+				i->rrs = i->rrsets->rrs;
+				i->rrsets = i->rrsets->next;
+				break;
+			}
+			/* next name */
+			i->node = ldns_rbtree_next(i->node);
+			i->name = i->node == LDNS_RBTREE_NULL ? NULL
+				: (ldns_dnssec_name *)i->node->data;
+
+			dnssec_zone_rr_iter_set_state_for_next_name(i);
+			break;
+
+		case DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC:
+			if (i->rrsets4rrsigs
+			&&  i->rrsets4rrsigs->type < LDNS_RR_TYPE_NSEC) {
+
+				i->rrs = i->rrsets4rrsigs->signatures;
+				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
+				break;
+			}
+			i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST;
+			i->rrs = i->name->nsec_signatures;
+			break;
+
+		case DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST:
+			if (i->rrsets4rrsigs) {
+				i->rrs = i->rrsets4rrsigs->signatures;
+				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
+				break;
+			}
+			i->state = DNSSEC_ZONE_RR_ITER_REST;
+			return i->name->nsec;
+
+		case DNSSEC_ZONE_RR_ITER_NSEC3:
+			nsec3 = i->nsec3_name->nsec;
+
+			/* next nsec3 */
+			do {
+				i->nsec3_node
+				    = ldns_rbtree_next(i->nsec3_node);
+				i->nsec3_name
+				    = i->nsec3_node == LDNS_RBTREE_NULL ? NULL
+				    : (ldns_dnssec_name*)i->nsec3_node->data;
+
+				/* names for glue can be in the hashed_names 
+				 * tree, but will not have a NSEC3 
+				 */
+			} while (i->nsec3_name && !i->nsec3_name->nsec);
+
+			dnssec_zone_rr_iter_set_state_for_next_name(i);
+			return nsec3;
+
+		case DNSSEC_ZONE_RR_ITER_FINI:
+			return NULL;
+		}
+	}
+}
+
+static ldns_rr *
+dnssec_zone_rr_iter_first(dnssec_zone_rr_iter *i, ldns_dnssec_zone *zone)
+{
+	if (!i || !zone)
+		return NULL;
+
+	memset(i, 0, sizeof(*i));
+	i->zone = zone;
+	if (zone->soa && zone->soa->name) {
+		i->apex_name = zone->soa->name;
+		i->apex_labs = ldns_dname_label_count(i->apex_name);
+	} else
+		i->apex_name = NULL;
+
+
+	i->node = ldns_rbtree_first(zone->names);
+	i->name = i->node == LDNS_RBTREE_NULL ? NULL
+		: (ldns_dnssec_name *)i->node->data;
+
+	if (zone->hashed_names) {
+		do {
+			i->nsec3_node = ldns_rbtree_first(zone->hashed_names);
+			i->nsec3_name = i->nsec3_node == LDNS_RBTREE_NULL ?NULL
+				      : (ldns_dnssec_name*)i->nsec3_node->data;
+		} while (i->nsec3_name && !i->nsec3_name->nsec);
+	}
+	dnssec_zone_rr_iter_set_state_for_next_name(i);
+	return dnssec_zone_rr_iter_next(i);
+}
+
+enum enum_zonemd_scheme {
+        ZONEMD_SCHEME_FIRST  = 1,
+        ZONEMD_SCHEME_SIMPLE = 1,
+        ZONEMD_SCHEME_LAST   = 1
+};
+typedef enum enum_zonemd_scheme zonemd_scheme;
+
+enum enum_zonemd_hash {
+        ZONEMD_HASH_FIRST  = 1,
+        ZONEMD_HASH_SHA384 = 1,
+        ZONEMD_HASH_SHA512 = 2,
+        ZONEMD_HASH_LAST   = 2
+};
+typedef enum enum_zonemd_hash zonemd_hash;
+
+struct struct_zone_digester {
+        ldns_sha384_CTX sha384_CTX;
+        ldns_sha512_CTX sha512_CTX;
+        unsigned simple_sha384 : 1;
+        unsigned simple_sha512 : 1;
+        unsigned double_sha384 : 1;
+        unsigned double_sha512 : 1;
+};
+typedef struct struct_zone_digester zone_digester;
+
+INLINE bool zone_digester_set(zone_digester *zd)
+{ return zd && (zd->simple_sha384 || zd->simple_sha512); }
+
+INLINE void zone_digester_init(zone_digester *zd)
+{ memset(zd, 0, sizeof(*zd)); }
+
+static ldns_status
+zone_digester_add(zone_digester *zd, zonemd_scheme scheme, zonemd_hash hash)
+{
+	if (!zd)
+		return LDNS_STATUS_NULL;
+
+	switch (scheme) {
+	case ZONEMD_SCHEME_SIMPLE:
+		switch (hash) {
+		case ZONEMD_HASH_SHA384:
+			if (zd->double_sha384)
+				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
+
+			else if (zd->simple_sha384) {
+				zd->simple_sha384 = 0;
+				zd->double_sha384 = 1;
+				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
+			}
+			ldns_sha384_init(&zd->sha384_CTX);
+			zd->simple_sha384 = 1;
+			break;
+
+		case ZONEMD_HASH_SHA512:
+			if (zd->double_sha512)
+				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
+
+			else if (zd->simple_sha512) {
+				zd->simple_sha512 = 0;
+				zd->double_sha512 = 1;
+				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
+			}
+			ldns_sha512_init(&zd->sha512_CTX);
+			zd->simple_sha512 = 1;
+			break;
+		default:
+			return LDNS_STATUS_ZONEMD_UNKNOWN_HASH;
+		}
+		break;
+	default:
+		return LDNS_STATUS_ZONEMD_UNKNOWN_SCHEME;
+	}
+	return LDNS_STATUS_OK;
+}
+
+static ldns_status
+zone_digester_update(zone_digester *zd, ldns_rr *rr)
+{
+	uint8_t data[65536];
+	ldns_buffer buf;
+	ldns_status st;
+	
+	buf._data = data;
+	buf._position = 0;
+	buf._limit = sizeof(data);
+	buf._capacity = sizeof(data);
+	buf._fixed = 1;
+	buf._status = LDNS_STATUS_OK;
+
+	if ((st = ldns_rr2buffer_wire_canonical(&buf, rr, LDNS_SECTION_ANSWER)))
+		return st;
+
+	if (zd->simple_sha384)
+		ldns_sha384_update(&zd->sha384_CTX, data, buf._position);
+
+	if (zd->simple_sha512)
+		ldns_sha512_update(&zd->sha512_CTX, data, buf._position);
+
+	return LDNS_STATUS_OK;
+}
+
+INLINE ldns_rr *
+new_zonemd(ldns_rr *soa, zonemd_hash hash)
+{
+	ldns_rr  *rr     = NULL;
+	uint8_t  *data   = NULL;
+	ldns_rdf *rdf;
+	size_t    md_len = hash == ZONEMD_HASH_SHA384
+	                 ? LDNS_SHA384_DIGEST_LENGTH
+	                 : LDNS_SHA512_DIGEST_LENGTH;
+
+	if (!(rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_ZONEMD)))
+		return NULL;
+
+	if (!(rdf = ldns_rdf_clone(ldns_rr_owner(soa))))
+		goto error;
+
+	ldns_rr_set_owner(rr, rdf);
+	ldns_rr_set_class(rr, ldns_rr_get_class(soa));
+	ldns_rr_set_ttl(rr, ldns_rr_ttl(soa));
+
+	if (!(rdf = ldns_rdf_clone(ldns_rr_rdf(soa, 2))))
+		goto error;
+	ldns_rr_set_rdf(rr, rdf, 0);
+
+	if (!(rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, 1)))
+		goto error;
+	ldns_rr_set_rdf(rr, rdf, 1);
+
+	if (!(rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, hash)))
+		goto error;
+	ldns_rr_set_rdf(rr, rdf, 2);
+
+	if (!(data = LDNS_XMALLOC(uint8_t, md_len)))
+		goto error;
+
+	if (!(rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, md_len, data)))
+		goto error;
+	ldns_rr_set_rdf(rr, rdf, 3);
+
+	return rr;
+error:
+	if (data)
+		LDNS_FREE(data);
+	ldns_rr_free(rr);
+	return NULL;
+}
+
+static ldns_rr_list *
+zone_digester_export(
+		zone_digester *zd, ldns_rr *soa, ldns_status *ret_st)
+{
+	ldns_status st = LDNS_STATUS_OK;
+	ldns_rr_list *rr_list = NULL;
+	ldns_rr *sha384 = NULL;
+	ldns_rr *sha512 = NULL;
+
+	if (!zd || !soa)
+		st = LDNS_STATUS_NULL;
+
+	else if (ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA
+	     ||  ldns_rr_rd_count(soa) < 3)
+		st = LDNS_STATUS_ZONEMD_INVALID_SOA;
+
+	else if (!(rr_list = ldns_rr_list_new()))
+		st = LDNS_STATUS_MEM_ERR;
+
+	else if (zd->simple_sha384
+	     && !(sha384 = new_zonemd(soa, ZONEMD_HASH_SHA384)))
+		st = LDNS_STATUS_MEM_ERR;
+
+	else if (zd->simple_sha512
+	     && !(sha512 = new_zonemd(soa, ZONEMD_HASH_SHA512)))
+		st = LDNS_STATUS_MEM_ERR;
+
+	else if (zd->simple_sha384
+	     && !ldns_rr_list_push_rr(rr_list, sha384))
+		st = LDNS_STATUS_MEM_ERR;
+
+	else if (zd->simple_sha512
+	     && !ldns_rr_list_push_rr(rr_list, sha512)) {
+		if (zd->simple_sha384)
+			sha384 = NULL; /* deleted by ldns_rr_list_deep_free */
+		st = LDNS_STATUS_MEM_ERR;
+
+	} else {
+		if (sha384)
+			ldns_sha384_final( ldns_rdf_data(ldns_rr_rdf(sha384,3))
+			                 , &zd->sha384_CTX);
+		if (sha512)
+			ldns_sha512_final( ldns_rdf_data(ldns_rr_rdf(sha512,3))
+			                 , &zd->sha512_CTX);
+		return rr_list;
+	}
+	if (ret_st)
+		*ret_st = st;
+	if (sha384)
+		ldns_rr_free(sha384);
+	if (sha512)
+		ldns_rr_free(sha512);
+	if (rr_list)
+		ldns_rr_list_deep_free(rr_list);
+	return NULL;
+}
+
+static ldns_status
+ldns_digest_zone(ldns_dnssec_zone *zone, zone_digester *zd)
+{
+	ldns_status st = LDNS_STATUS_OK;
+	dnssec_zone_rr_iter rr_iter;
+	ldns_rr *rr;
+	ldns_rdf *apex_name; /* name of zone apex */
+
+	if (!zone || !zd || !zone->soa || !zone->soa->name)
+		return LDNS_STATUS_NULL;
+
+	apex_name = zone->soa->name;
+	for ( rr = dnssec_zone_rr_iter_first(&rr_iter, zone)
+	    ; rr && !st
+	    ; rr = dnssec_zone_rr_iter_next(&rr_iter)) {
+		/* Skip apex ZONEMD RRs */
+		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_ZONEMD
+		&& !ldns_dname_compare(ldns_rr_owner(rr), apex_name))
+			continue;
+		/* Skip RRSIGs for apex ZONEMD RRs */
+		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
+		&&  LDNS_RR_TYPE_ZONEMD == ldns_rdf2rr_type(
+				ldns_rr_rrsig_typecovered(rr))
+		&& !ldns_dname_compare(ldns_rr_owner(rr), apex_name))
+			continue;
+		st = zone_digester_update(zd, rr);
+	}
+	return st;
+}
+
+ldns_status
+ldns_dnssec_zone_verify_zonemd(ldns_dnssec_zone *zone)
+{
+	ldns_dnssec_rrsets *zonemd, *soa;
+	zone_digester zd;
+	ldns_dnssec_rrs *rrs;
+	ldns_rr *soa_rr;
+	ldns_status st;
+	uint8_t simple_sha384[LDNS_SHA384_DIGEST_LENGTH];
+	uint8_t simple_sha512[LDNS_SHA512_DIGEST_LENGTH];
+	size_t valid_zonemds;
+
+	if (!zone)
+		return LDNS_STATUS_NULL;
+
+	zonemd = ldns_dnssec_zone_find_rrset(
+			zone, zone->soa->name, LDNS_RR_TYPE_ZONEMD);
+	if (!zonemd) {
+		ldns_rbnode_t *nsec3_node;
+
+		/* we need proof of non-existence for ZONEMD at the apex */
+		if (zone->soa->nsec) {
+			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(
+							zone->soa->nsec),
+					       	LDNS_RR_TYPE_ZONEMD))
+				return LDNS_STATUS_NO_ZONEMD;
+
+		} else if (!zone->soa->hashed_name || !zone->hashed_names)
+			return LDNS_STATUS_NO_ZONEMD;
+
+		else if (LDNS_RBTREE_NULL == 
+		    (nsec3_node = ldns_rbtree_search( zone->hashed_names
+						    , zone->soa->hashed_name)))
+			return LDNS_STATUS_NO_ZONEMD;
+		else {
+			ldns_dnssec_name *nsec3
+				= (ldns_dnssec_name *)nsec3_node->data;
+			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(
+							nsec3->nsec),
+						LDNS_RR_TYPE_ZONEMD))
+				return LDNS_STATUS_NO_ZONEMD;
+		}
+		/* ZONEMD at apex does really not exist */
+		return LDNS_STATUS_OK;
+	}
+	soa = ldns_dnssec_zone_find_rrset(
+			zone, zone->soa->name, LDNS_RR_TYPE_SOA);
+	if (!soa || !soa->rrs || !soa->rrs->rr)
+		return LDNS_STATUS_ZONEMD_INVALID_SOA;
+
+	soa_rr = soa->rrs->rr;
+	if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
+	||  ldns_rr_rd_count(soa_rr) < 3)
+		return LDNS_STATUS_ZONEMD_INVALID_SOA;
+
+	zone_digester_init(&zd);
+	for (rrs = zonemd->rrs; rrs; rrs = rrs->next) {
+		if (!rrs->rr
+		||  ldns_rr_get_type(rrs->rr) != LDNS_RR_TYPE_ZONEMD
+		||  ldns_rr_rd_count(rrs->rr) < 4)
+			continue;
+
+		/* serial should match SOA's serial */
+		if (ldns_rdf2native_int32(ldns_rr_rdf(soa_rr, 2))
+		    != ldns_rdf2native_int32(ldns_rr_rdf(rrs->rr, 0)))
+			continue;
+		
+		/* Add (scheme, hash) to digester */
+		zone_digester_add(&zd,
+				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 1)),
+				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 2)));
+	}
+	if (!zone_digester_set(&zd))
+		return LDNS_STATUS_NO_VALID_ZONEMD;
+
+	if ((st = ldns_digest_zone(zone, &zd)))
+		return st;
+
+	if (zd.simple_sha384)
+		ldns_sha384_final(simple_sha384, &zd.sha384_CTX);
+	if (zd.simple_sha512)
+		ldns_sha512_final(simple_sha512, &zd.sha512_CTX);
+
+	valid_zonemds = 0;
+	for (rrs = zonemd->rrs; rrs; rrs = rrs->next) {
+		if (!rrs->rr
+		||  ldns_rr_get_type(rrs->rr) != LDNS_RR_TYPE_ZONEMD
+		||  ldns_rr_rd_count(rrs->rr) < 4)
+			continue;
+
+		/* serial should match SOA's serial */
+		if (ldns_rdf2native_int32(ldns_rr_rdf(soa_rr, 2))
+		    != ldns_rdf2native_int32(ldns_rr_rdf(rrs->rr, 0)))
+			continue;
+		
+		if (ZONEMD_SCHEME_SIMPLE !=
+				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 1)))
+			continue;
+
+		if (ZONEMD_HASH_SHA384
+				== ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr,2))
+		&&  LDNS_SHA384_DIGEST_LENGTH
+				== ldns_rdf_size(ldns_rr_rdf(rrs->rr, 3))
+		&&  memcmp( simple_sha384
+			  , ldns_rdf_data(ldns_rr_rdf(rrs->rr, 3))
+		          , LDNS_SHA384_DIGEST_LENGTH) == 0)
+
+			valid_zonemds += 1;
+
+		if (ZONEMD_HASH_SHA512
+				== ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr,2))
+		&&  LDNS_SHA512_DIGEST_LENGTH
+				== ldns_rdf_size(ldns_rr_rdf(rrs->rr, 3))
+		&&  memcmp( simple_sha512
+			  , ldns_rdf_data(ldns_rr_rdf(rrs->rr, 3))
+		          , LDNS_SHA512_DIGEST_LENGTH) == 0)
+
+			valid_zonemds += 1;
+	}
+	return valid_zonemds ? LDNS_STATUS_OK : LDNS_STATUS_NO_VALID_ZONEMD;
+}
+
+#ifdef HAVE_SSL
+static ldns_status
+rr_list2dnssec_rrs(ldns_rr_list *rr_list, ldns_dnssec_rrs **rrs,
+		ldns_rr_list *new_rrs)
+{
+	ldns_rr *rr = NULL;
+
+	if (!rr_list || !rrs)
+		return LDNS_STATUS_NULL;
+
+	if (ldns_rr_list_rr_count(rr_list) == 0)
+		return LDNS_STATUS_OK;
+
+	if (!*rrs) {
+		if (!(*rrs = ldns_dnssec_rrs_new()))
+			return LDNS_STATUS_MEM_ERR;
+		(*rrs)->rr = ldns_rr_list_pop_rr(rr_list);
+		if (new_rrs)
+			ldns_rr_list_push_rr(new_rrs, (*rrs)->rr);
+	}
+	while ((rr = ldns_rr_list_pop_rr(rr_list))) {
+		ldns_status st;
+	       
+		if ((st = ldns_dnssec_rrs_add_rr(*rrs, rr))) {
+			ldns_rr_list_push_rr(rr_list, rr);
+			return st;
+		} else if (new_rrs)
+			ldns_rr_list_push_rr(new_rrs, rr);
+	}
+	return LDNS_STATUS_OK;
+}
+
+
+ldns_status
+dnssec_zone_equip_zonemd(ldns_dnssec_zone *zone,
+		ldns_rr_list *new_rrs, ldns_key_list *key_list, int signflags)
+{
+	ldns_status st = LDNS_STATUS_OK;
+	zone_digester zd;
+	ldns_rr_list *zonemd_rr_list = NULL;
+	ldns_rr_list *zonemd_rrsigs = NULL;
+	ldns_dnssec_rrsets *soa_rrset;
+	ldns_rr *soa_rr = NULL;
+	ldns_dnssec_rrsets **rrset_ref;
+	ldns_dnssec_rrsets *zonemd_rrset;
+
+	zone_digester_init(&zd);
+	if (signflags & LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA384)
+		zone_digester_add(&zd, ZONEMD_SCHEME_SIMPLE
+		                     , ZONEMD_HASH_SHA384);
+
+	if (signflags & LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA512)
+		zone_digester_add(&zd, ZONEMD_SCHEME_SIMPLE
+		                     , ZONEMD_HASH_SHA512);
+
+	if ((st = ldns_digest_zone(zone, &zd)))
+		return st;
+
+	soa_rrset = ldns_dnssec_zone_find_rrset(
+			zone, zone->soa->name, LDNS_RR_TYPE_SOA);
+	if (!soa_rrset || !soa_rrset->rrs || !soa_rrset->rrs->rr)
+		return LDNS_STATUS_ZONEMD_INVALID_SOA;
+	soa_rr = soa_rrset->rrs->rr;
+
+	if (!(zonemd_rr_list = zone_digester_export(&zd, soa_rr, &st)))
+		return st;
+	
+	/* - replace or add ZONEMD rrset */
+	rrset_ref = &zone->soa->rrsets; /* scan rrsets at apex */
+	while (*rrset_ref && (*rrset_ref)->type < LDNS_RR_TYPE_ZONEMD)
+		rrset_ref = &(*rrset_ref)->next;
+	if (*rrset_ref && (*rrset_ref)->type == LDNS_RR_TYPE_ZONEMD) {
+		/* reuse zonemd rrset */
+		zonemd_rrset = *rrset_ref;
+		ldns_dnssec_rrs_free(zonemd_rrset->rrs);
+		zonemd_rrset->rrs = NULL;
+		ldns_dnssec_rrs_free(zonemd_rrset->signatures);
+		zonemd_rrset->signatures = NULL;
+	} else {
+		/* insert zonemd rrset */
+		zonemd_rrset = ldns_dnssec_rrsets_new();
+		if (!zonemd_rrset) {
+			ldns_rr_list_deep_free(zonemd_rr_list);
+			return LDNS_STATUS_MEM_ERR;
+		}
+		zonemd_rrset->type = LDNS_RR_TYPE_ZONEMD;
+		zonemd_rrset->next = *rrset_ref;
+		*rrset_ref = zonemd_rrset;
+	}
+	if ((zonemd_rrsigs = ldns_sign_public(zonemd_rr_list, key_list)))
+		st = rr_list2dnssec_rrs(  zonemd_rrsigs
+		                       , &zonemd_rrset->signatures, new_rrs);
+	if (!st)
+		st = rr_list2dnssec_rrs(  zonemd_rr_list
+		                       , &zonemd_rrset->rrs, new_rrs);
+	ldns_rr_list_deep_free(zonemd_rr_list);
+	ldns_rr_list_deep_free(zonemd_rrsigs);
+	return st;
+}
+
+#endif /* HAVE_SSL */
+
diff --git a/contrib/ldns/drill/chasetrace.c b/contrib/ldns/drill/chasetrace.c
index dd495db5a9..3bd59563c5 100644
--- a/contrib/ldns/drill/chasetrace.c
+++ b/contrib/ldns/drill/chasetrace.c
@@ -171,7 +171,7 @@ do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
         }
 
 	/* transfer some properties of local_res to res,
-	 * because they were given on the commandline */
+	 * because they were given on the command line */
 	ldns_resolver_set_ip6(res, 
 			ldns_resolver_ip6(local_res));
 	ldns_resolver_set_port(res, 
diff --git a/contrib/ldns/drill/dnssec.c b/contrib/ldns/drill/dnssec.c
index d41704925d..687cfe55a5 100644
--- a/contrib/ldns/drill/dnssec.c
+++ b/contrib/ldns/drill/dnssec.c
@@ -180,7 +180,20 @@ ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_lis
 
 	ldns_rr_list *nsecs;
 	ldns_status result;
-	
+	const ldns_rr_descriptor *descriptor;
+
+	if (!pkt) {
+		descriptor = ldns_rr_descript(type);
+
+		printf("NETWORk ERROR! Cannot verify denial for: ");
+		ldns_rdf_print(stdout, name);
+		printf(" type ");
+		if (descriptor && descriptor->_name)
+			printf("%s", descriptor->_name);
+		else
+			printf("TYPE%u", type);
+		return LDNS_STATUS_CRYPTO_NO_RRSIG;
+	}
 	if (verbosity >= 5) {
 		printf("VERIFY DENIAL FROM:\n");
 		ldns_pkt_print(stdout, pkt);
diff --git a/contrib/ldns/drill/drill.c b/contrib/ldns/drill/drill.c
index 6efd29a5ca..611c81f3a8 100644
--- a/contrib/ldns/drill/drill.c
+++ b/contrib/ldns/drill/drill.c
@@ -59,7 +59,7 @@ usage(FILE *stream, const char *progname)
 	fprintf(stream, "\t-6\t\tstay on ip6\n");
 	fprintf(stream, "\t-a\t\tfallback to EDNS0 and TCP if the answer is truncated\n");
 	fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n");
-	fprintf(stream, "\t-c <file>\tuse file for rescursive nameserver configuration"
+	fprintf(stream, "\t-c <file>\tuse file for recursive nameserver configuration"
 			"\n\t\t\t(/etc/resolv.conf)\n");
 	fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n");
 	fprintf(stream, "\t\t\tUsed to verify any signatures in the current answer.\n");
@@ -173,6 +173,8 @@ main(int argc, char *argv[])
 	int r;
 	WSADATA wsa_data;
 #endif
+	ldns_output_format_storage fmt_storage;
+	ldns_output_format* fmt = ldns_output_format_init(&fmt_storage);
 
 	int_type = -1; serv = NULL; type = 0; 
 	int_clas = -1; name = NULL; clas = 0;
@@ -201,6 +203,7 @@ main(int argc, char *argv[])
 	qusevc = false;
 	qrandom = true;
 	key_verified = NULL;
+	ldns_edns_option_list* edns_list = NULL;
 
 	ldns_init_random(NULL, 0);
 
@@ -247,6 +250,7 @@ main(int argc, char *argv[])
 				verbosity = atoi(optarg);
 				break;
 			case 'Q':
+				fmt->flags |= LDNS_FMT_SHORT;
 				verbosity = -1;
 				break;
 			case 'f':
@@ -454,6 +458,31 @@ main(int argc, char *argv[])
 			serv = argv[i] + 1;
 			continue;
 		}
+		/* if ^+ then it's an EDNS option */
+		if (argv[i][0] == '+') {
+			if (!strcmp(argv[i]+1, "nsid")) {
+				ldns_edns_option *edns;
+				edns_list = ldns_edns_option_list_new();
+
+				/* create NSID EDNS*/
+				edns = ldns_edns_new_from_data(LDNS_EDNS_NSID, 0, NULL);
+
+				if (edns_list == NULL || edns == NULL) {
+					error("EDNS option could not be allocated");
+					break;
+				}
+
+				if (!(ldns_edns_option_list_push(edns_list, edns))) {
+					error("EDNS option NSID could not be attached");
+					break;
+				}
+				continue;
+			}
+			else {
+				error("Unsupported argument after '+'");
+				break;
+			}
+		}
 		/* if has a dot, it's a name */
 		if (strchr(argv[i], '.')) {
 			name = argv[i];
@@ -793,7 +822,7 @@ main(int argc, char *argv[])
 			}
 			status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags);
 			if(status != LDNS_STATUS_OK) {
-				error("%s", "making query: %s", 
+				error("%s", "making query: %s",
 					ldns_get_errorstr_by_id(status));
 			}
 			dump_hex(qpkt, query_file);
@@ -864,9 +893,22 @@ main(int argc, char *argv[])
 				} else {
 					/* create a packet and set the RD flag on it */
 					pkt = NULL;
-					status = ldns_resolver_query_status(
-							&pkt, res, qname,
-							type, clas, qflags);
+
+					status = ldns_resolver_prepare_query_pkt(&qpkt,
+						res, qname, type, clas, qflags);
+					if(status != LDNS_STATUS_OK) {
+						error("%s", "making query: %s", 
+							ldns_get_errorstr_by_id(status));
+					}
+
+					if (edns_list) {
+						/* attach the structed EDNS options */
+						ldns_pkt_set_edns_option_list(qpkt, edns_list);
+					}
+
+					status = ldns_resolver_send_pkt(&pkt, res, qpkt);
+					ldns_pkt_free(qpkt);
+
 					if (status != LDNS_STATUS_OK) {
 						error("error sending query: %s"
 						     , ldns_get_errorstr_by_id(
@@ -875,12 +917,13 @@ main(int argc, char *argv[])
 				}
 			}
 			
-			if (!pkt)  {
+			/* now handling the response message/packet */
+			if (!pkt) {
 				mesg("No packet received");
 				result = EXIT_FAILURE;
 			} else {
+				ldns_pkt_print_fmt(stdout, fmt, pkt);
 				if (verbosity != -1) {
-					ldns_pkt_print(stdout, pkt);
 					if (ldns_pkt_tc(pkt)) {
 						fprintf(stdout,
 							"\n;; WARNING: The answer packet was truncated; you might want to\n");
@@ -994,9 +1037,17 @@ main(int argc, char *argv[])
 	xfree(tsig_algorithm);
 
 #ifdef HAVE_SSL
-	CRYPTO_cleanup_all_ex_data();
-	ERR_free_strings();
-	EVP_cleanup();
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(HAVE_LIBRESSL)
+#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+	CRYPTO_cleanup_all_ex_data ();
+#endif
+#ifdef HAVE_ERR_FREE_STRINGS
+	ERR_free_strings ();
+#endif
+#ifdef HAVE_EVP_CLEANUP
+	EVP_cleanup ();
+#endif
+#endif
 #endif
 #ifdef USE_WINSOCK
 	WSACleanup();
diff --git a/contrib/ldns/drill/securetrace.c b/contrib/ldns/drill/securetrace.c
index 6967265de5..90014b4e30 100644
--- a/contrib/ldns/drill/securetrace.c
+++ b/contrib/ldns/drill/securetrace.c
@@ -137,7 +137,7 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
 	ldns_rr_list *correct_key_list;
 	ldns_rr_list *trusted_ds_rrs;
 	bool new_keys_trusted = false;
-	ldns_rr_list *current_correct_keys;
+	ldns_rr_list *current_correct_keys = NULL;
 	ldns_rr_list *dataset;
 
 	ldns_rr_list *nsec_rrs = NULL;
@@ -520,8 +520,8 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
 							labels[i-1]);
 						printf(", but valid CNAME");
 					} else {
-						printf("[B] Unable to verify de"
-						       "nial of existence for ");
+						printf(BOGUS " Unable to verify "
+						       "denial of existence for ");
 						ldns_rdf_print(stdout,
 							labels[i-1]);
 						printf(", because of BOGUS CNAME");
@@ -644,7 +644,7 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
 							printf(";; No DS for ");
 							ldns_rdf_print(stdout, labels[i - 1]);
 						} else {
-							printf("[B] Unable to verify denial of existence for ");
+							printf(BOGUS " Unable to verify denial of existence for ");
 							ldns_rdf_print(stdout, labels[i - 1]);
 							printf(" DS: %s\n", ldns_get_errorstr_by_id(status));
 						}
@@ -748,7 +748,7 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
 						}
 						printf("\n");
 					} else {
-						printf("[B] Unable to verify denial of existence for ");
+						printf(BOGUS " Unable to verify denial of existence for ");
 						ldns_rdf_print(stdout, name);
 						printf(" type ");
 						if (descriptor && descriptor->_name) {
@@ -774,7 +774,7 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
 		ldns_rr_list_deep_free(ds_sig_list);
 		ds_sig_list = NULL;
 	}
-	printf(";;" SELF " self sig OK; " BOGUS " bogus; " TRUST " trusted\n");
+	printf(";;" SELF " self sig OK; " BOGUS " bogus; " TRUST " trusted; " UNSIGNED " unsigned\n");
 	/* verbose mode?
 	printf("Trusted keys:\n");
 	ldns_rr_list_print(stdout, trusted_keys);
diff --git a/contrib/ldns/duration.c b/contrib/ldns/duration.c
index 0a8d79b519..abff9a074f 100644
--- a/contrib/ldns/duration.c
+++ b/contrib/ldns/duration.c
@@ -190,121 +190,51 @@ ldns_duration_create_from_string(const char* str)
 
 
 /**
- * Get the number of digits in a number.
- *
+ * Helper func for ldns_duration2string below. If t > 0,
+ * scan print t and c on buf, forwarding buf. Return 0 on success.
  */
-static size_t
-digits_in_number(time_t duration)
+static inline int dur_scan_print(char **buf, char *eob, char c, time_t t)
 {
-	unsigned int i = (unsigned int) duration;
-	size_t n = 1;
-
-	while (i >= 100000000) {
-		n += 8;
-		i /= 100000000;
+	if (t > 0) {
+		int r = snprintf(*buf, eob - *buf, "%u%c", (unsigned)t, c);
+		if (r < 0 || (*buf += r) >= eob)
+			return -1;
 	}
-	if (i >= 10000) { n += 4; i /= 10000; }
-	if (i >= 100  ) { n += 2; i /= 100; }
-	if (i >= 10   ) { n += 1; }
-	return n;
+	return 0;
 }
 
-
 /**
  * Convert a duration to a string.
  *
  */
 char*
-ldns_duration2string(const ldns_duration_type* duration)
+ldns_duration2string(const ldns_duration_type* d)
 {
-    char* str = NULL;
-    size_t count = 2;
-    int T = 0;
-    char num[sizeof(unsigned int) + 2];
-
-    if (!duration) {
-        return NULL;
-    }
-
-    if (duration->years > 0) {
-        count = count + 1 + digits_in_number(duration->years);
-    }
-    if (duration->months > 0) {
-        count = count + 1 + digits_in_number(duration->months);
-    }
-    if (duration->weeks > 0) {
-        count = count + 1 + digits_in_number(duration->weeks);
-    }
-    if (duration->days > 0) {
-        count = count + 1 + digits_in_number(duration->days);
-    }
-    if (duration->hours > 0) {
-        count = count + 1 + digits_in_number(duration->hours);
-        T = 1;
-    }
-    if (duration->minutes > 0) {
-        count = count + 1 + digits_in_number(duration->minutes);
-        T = 1;
-    }
-    if (duration->seconds > 0) {
-        count = count + 1 + digits_in_number(duration->seconds);
-        T = 1;
-    }
-    if (T) {
-        count++;
-    }
-
-    if (!(str = (char*) calloc(count, sizeof(char))))
-	    return NULL;
-    str[0] = 'P';
-    str[1] = '\0';
-
-    if (duration->years > 0) {
-        count = digits_in_number(duration->years);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uY", (unsigned int) duration->years);
-        str = strncat(str, num, count+2);
-    }
-    if (duration->months > 0) {
-        count = digits_in_number(duration->months);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uM", (unsigned int) duration->months);
-        str = strncat(str, num, count+2);
-    }
-    if (duration->weeks > 0) {
-        count = digits_in_number(duration->weeks);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uW", (unsigned int) duration->weeks);
-        str = strncat(str, num, count+2);
-    }
-    if (duration->days > 0) {
-        count = digits_in_number(duration->days);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uD", (unsigned int) duration->days);
-        str = strncat(str, num, count+2);
-    }
-    if (T) {
-        str = strcat(str, "T");
-    }
-    if (duration->hours > 0) {
-        count = digits_in_number(duration->hours);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uH", (unsigned int) duration->hours);
-        str = strncat(str, num, count+2);
-    }
-    if (duration->minutes > 0) {
-        count = digits_in_number(duration->minutes);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uM", (unsigned int) duration->minutes);
-        str = strncat(str, num, count+2);
-    }
-    if (duration->seconds > 0) {
-        count = digits_in_number(duration->seconds);
-	assert(count <= sizeof(num) - 2);
-        snprintf(num, count+2, "%uS", (unsigned int) duration->seconds);
-        str = strncat(str, num, count+2);
-    }
-    return str;
+ 	/* Max string size should be 7 * 40 + 3 on a 127 bits machine
+	 * So 300 (< 273) is more than enough.
+	 */
+	char buf[300] = "P0D", *eob = buf + sizeof(buf), *p = buf + 1;
+
+	if (!d)
+		return NULL;
+
+	if (dur_scan_print(&p, eob, 'Y', d->years)
+	||  dur_scan_print(&p, eob, 'M', d->months)
+	||  dur_scan_print(&p, eob, 'W', d->weeks)
+	||  dur_scan_print(&p, eob, 'D', d->days))
+		return NULL;
+
+	if (d->hours || d->minutes || d->seconds) {
+		if (p > (eob - 2))
+			return NULL; /* Error; no space left on buf for 'T' */
+
+		*p++ = 'T'; *p = 0;
+		if (dur_scan_print(&p, eob, 'H', d->hours)
+		||  dur_scan_print(&p, eob, 'M', d->minutes)
+		||  dur_scan_print(&p, eob, 'S', d->seconds))
+			return NULL;
+	}
+	return strdup(buf);
 }
 
 
diff --git a/contrib/ldns/edns.c b/contrib/ldns/edns.c
new file mode 100644
index 0000000000..3d002d67ed
--- /dev/null
+++ b/contrib/ldns/edns.c
@@ -0,0 +1,436 @@
+/*
+ * edns.c
+ *
+ * edns implementation
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2022
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/ldns.h>
+
+#define LDNS_OPTIONLIST_INIT 8
+
+/*
+ * Access functions
+ * functions to get and set type checking
+ */
+
+/* read */
+size_t
+ldns_edns_get_size(const ldns_edns_option *edns)
+{
+	assert(edns != NULL);
+	return edns->_size;
+}
+
+ldns_edns_option_code
+ldns_edns_get_code(const ldns_edns_option *edns)
+{
+	assert(edns != NULL);
+	return edns->_code;
+}
+
+uint8_t *
+ldns_edns_get_data(const ldns_edns_option *edns)
+{
+	assert(edns != NULL);
+	return edns->_data;
+}
+
+ldns_buffer *
+ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns)
+{
+	uint16_t option;
+	size_t size;
+	uint8_t* data;
+	ldns_buffer* buffer;
+
+	if (edns == NULL) {
+		return NULL;
+	}
+
+	option = ldns_edns_get_code(edns);
+	size = ldns_edns_get_size(edns);
+	data = ldns_edns_get_data(edns);
+
+	buffer = ldns_buffer_new(size + 4);
+
+	if (buffer == NULL) {
+		return NULL;
+	}
+
+	ldns_buffer_write_u16(buffer, option);
+	ldns_buffer_write_u16(buffer, size);
+	ldns_buffer_write(buffer, data, size);
+
+	ldns_buffer_flip(buffer);
+
+	return buffer;
+}
+
+/* write */
+void
+ldns_edns_set_size(ldns_edns_option *edns, size_t size)
+{
+	assert(edns != NULL);
+	edns->_size = size;
+}
+
+void
+ldns_edns_set_code(ldns_edns_option *edns, ldns_edns_option_code code)
+{
+	assert(edns != NULL);
+	edns->_code = code;
+}
+
+void
+ldns_edns_set_data(ldns_edns_option *edns, void *data)
+{
+	/* only copy the pointer */
+	assert(edns != NULL);
+	edns->_data = data;
+}
+
+/* note: data must be allocated memory */
+ldns_edns_option *
+ldns_edns_new(ldns_edns_option_code code, size_t size, void *data)
+{
+	ldns_edns_option *edns;
+	edns = LDNS_MALLOC(ldns_edns_option);
+	if (!edns) {
+		return NULL;
+	}
+	ldns_edns_set_code(edns, code);
+	ldns_edns_set_size(edns, size);
+	ldns_edns_set_data(edns, data);
+
+	return edns;
+}
+
+ldns_edns_option *
+ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data)
+{
+	ldns_edns_option *edns;
+	edns = LDNS_MALLOC(ldns_edns_option);
+	if (!edns) {
+		return NULL;
+	}
+	edns->_data = LDNS_XMALLOC(uint8_t, size);
+	if (!edns->_data) {
+		LDNS_FREE(edns);
+		return NULL;
+	}
+
+	/* set the values */
+	ldns_edns_set_code(edns, code);
+	ldns_edns_set_size(edns, size);
+	memcpy(edns->_data, data, size);
+
+	return edns;
+}
+
+ldns_edns_option *
+ldns_edns_clone(ldns_edns_option *edns)
+{
+	ldns_edns_option *new_option;
+
+	assert(edns != NULL);
+
+	new_option = ldns_edns_new_from_data(ldns_edns_get_code(edns),
+		ldns_edns_get_size(edns),
+		ldns_edns_get_data(edns));
+
+	return new_option;
+}
+
+void
+ldns_edns_deep_free(ldns_edns_option *edns)
+{
+	if (edns) {
+		if (edns->_data) {
+			LDNS_FREE(edns->_data);
+		}
+		LDNS_FREE(edns);
+	}
+}
+
+void 
+ldns_edns_free(ldns_edns_option *edns)
+{
+	if (edns) {
+		LDNS_FREE(edns);
+	}
+}
+
+ldns_edns_option_list*
+ldns_edns_option_list_new()
+{
+	ldns_edns_option_list *option_list = LDNS_MALLOC(ldns_edns_option_list);
+	if(!option_list) {
+		return NULL;
+	}
+
+	option_list->_option_count = 0;
+	option_list->_option_capacity = 0;
+	option_list->_options_size = 0;
+	option_list->_options = NULL;
+	return option_list;
+}
+
+ldns_edns_option_list *
+ldns_edns_option_list_clone(ldns_edns_option_list *old_list)
+{
+	size_t i;
+	ldns_edns_option_list *new_list;
+
+	if (!old_list) {
+		return NULL;
+	}
+
+	new_list = ldns_edns_option_list_new();
+	if (!new_list) {
+		return NULL;
+	}
+
+	if (old_list->_option_count == 0) {
+		return new_list;
+	}
+
+	/* adding options also updates the total options size */
+	for (i = 0; i < old_list->_option_count; i++) {
+		ldns_edns_option *option = ldns_edns_clone(ldns_edns_option_list_get_option(old_list, i));
+		if (!ldns_edns_option_list_push(new_list, option)) {
+			ldns_edns_deep_free(option);
+			ldns_edns_option_list_deep_free(new_list);
+			return NULL;
+		}
+	}
+	return new_list;
+}
+
+void
+ldns_edns_option_list_free(ldns_edns_option_list *option_list)
+{
+	if (option_list) {
+		LDNS_FREE(option_list->_options);
+		LDNS_FREE(option_list);
+	}
+}
+
+void
+ldns_edns_option_list_deep_free(ldns_edns_option_list *option_list)
+{
+	size_t i;
+
+	if (option_list) {
+		for (i=0; i < ldns_edns_option_list_get_count(option_list); i++) {
+			ldns_edns_deep_free(ldns_edns_option_list_get_option(option_list, i));
+		}
+		ldns_edns_option_list_free(option_list);
+	}
+}
+
+size_t
+ldns_edns_option_list_get_count(const ldns_edns_option_list *option_list)
+{
+	if (option_list) {
+		return option_list->_option_count;
+	} else {
+		return 0;
+	}
+}
+
+ldns_edns_option *
+ldns_edns_option_list_get_option(const ldns_edns_option_list *option_list, size_t index)
+{
+	if (option_list && index < ldns_edns_option_list_get_count(option_list)) {
+		assert(option_list->_options[index]);
+		return option_list->_options[index];
+	} else {
+		return NULL;
+	}
+}
+
+size_t
+ldns_edns_option_list_get_options_size(const ldns_edns_option_list *option_list)
+{
+	if (option_list) {
+		return option_list->_options_size;
+	} else {
+		return 0;
+	}
+}
+
+
+ldns_edns_option *
+ldns_edns_option_list_set_option(ldns_edns_option_list *option_list,
+	ldns_edns_option *option, size_t index)
+{
+	ldns_edns_option* old;
+
+	assert(option_list != NULL);
+
+	if (index > ldns_edns_option_list_get_count(option_list)) {
+		return NULL;
+	}
+
+	if (option == NULL) {
+		return NULL;
+	}
+
+	old = ldns_edns_option_list_get_option(option_list, index);
+
+	/* shrink the total EDNS size if the old EDNS option exists */
+	if (old != NULL) {
+		option_list->_options_size -= (ldns_edns_get_size(old) + 4);
+	}
+
+	option_list->_options_size += (ldns_edns_get_size(option) + 4);
+
+	option_list->_options[index] = option;
+	return old;
+}
+
+bool
+ldns_edns_option_list_push(ldns_edns_option_list *option_list,
+	ldns_edns_option *option)
+{
+	size_t cap;
+	size_t option_count;
+
+	assert(option_list != NULL);
+
+	if (option == NULL) {
+		return false;
+	}
+
+	cap = option_list->_option_capacity;
+	option_count = ldns_edns_option_list_get_count(option_list);
+
+	/* verify we need to grow the array to fit the new option */
+	if (option_count+1 > cap) {
+		ldns_edns_option **new_list;
+
+		/* initialize the capacity if needed, otherwise grow by doubling */
+		if (cap == 0) {
+			cap = LDNS_OPTIONLIST_INIT; /* initial list size */
+		} else {
+			cap *= 2;
+		}
+
+		new_list = LDNS_XREALLOC(option_list->_options,
+			ldns_edns_option *, cap);
+
+		if (!new_list) {
+			return false;
+		}
+
+		option_list->_options = new_list;
+		option_list->_option_capacity = cap;
+	}
+
+	/* add the new option */
+	ldns_edns_option_list_set_option(option_list, option,
+		option_list->_option_count);
+	option_list->_option_count += 1;
+
+	return true;
+}
+
+ldns_edns_option *
+ldns_edns_option_list_pop(ldns_edns_option_list *option_list)
+{
+	ldns_edns_option* pop;
+	size_t count;
+	size_t cap;
+
+	assert(option_list != NULL);
+
+	cap = option_list->_option_capacity;
+	count = ldns_edns_option_list_get_count(option_list);
+
+	if (count == 0) {
+		return NULL;
+	}
+	/* get the last option from the list */
+	pop = ldns_edns_option_list_get_option(option_list, count-1);
+
+	/* shrink the array */
+	if (cap > LDNS_OPTIONLIST_INIT && count-1 <= cap/2) {
+		ldns_edns_option **new_list;
+
+		cap /= 2;
+
+		new_list = LDNS_XREALLOC(option_list->_options,
+			ldns_edns_option *, cap);
+		if (new_list) {
+			option_list->_options = new_list;
+		}
+		/* if the realloc fails, the capacity for the list remains unchanged */
+	}
+
+	/* shrink the total EDNS size of the options if the popped EDNS option exists */
+	if (pop != NULL) {
+		option_list->_options_size -= (ldns_edns_get_size(pop) + 4);
+	}
+
+	option_list->_option_count = count - 1;
+
+	return pop;
+}
+
+ldns_buffer *
+ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list)
+{
+	size_t i, list_size, options_size, option, size;
+	ldns_buffer* buffer;
+	ldns_edns_option *edns;
+	uint8_t* data = NULL;
+
+	if (!option_list) {
+		return NULL;
+	}
+
+	/* get the number of EDNS options in the list*/
+	list_size = ldns_edns_option_list_get_count(option_list);
+
+	/* create buffer the size of the total EDNS wireformat options */
+	options_size = ldns_edns_option_list_get_options_size(option_list);
+	buffer = ldns_buffer_new(options_size);
+	
+	if (!buffer) {
+		return NULL;
+	}
+
+	/* write individual serialized EDNS options to final buffer*/
+	for (i = 0; i < list_size; i++) {
+		edns = ldns_edns_option_list_get_option(option_list, i);
+
+		if (edns == NULL) {
+			/* this shouldn't be possible */
+			return NULL;
+		}
+
+		option = ldns_edns_get_code(edns);
+		size = ldns_edns_get_size(edns);
+		data = ldns_edns_get_data(edns);
+
+		/* make sure the option fits */
+		if (!(ldns_buffer_available(buffer, size + 4))) {
+			ldns_buffer_free(buffer);
+			return NULL;
+		}
+
+		ldns_buffer_write_u16(buffer, option);
+		ldns_buffer_write_u16(buffer, size);
+		ldns_buffer_write(buffer, data, size);
+	}
+
+	ldns_buffer_flip(buffer);
+
+	return buffer;
+}
diff --git a/contrib/ldns/error.c b/contrib/ldns/error.c
index 7943017a90..e3fd121127 100644
--- a/contrib/ldns/error.c
+++ b/contrib/ldns/error.c
@@ -1,6 +1,6 @@
 /*
  * a error2str function to make sense of all the
- * error codes we have laying ardoun
+ * error codes we have laying around
  *
  * a Net::DNS like library for C
  * LibDNS Team @ NLnet Labs
@@ -157,6 +157,33 @@ ldns_lookup_table ldns_error_str[] = {
 		"X509_STORE_CTX_set0_dane() functions within OpenSSL >= 1.1.0 "
 		"to be able to verify the DANE-TA usage type." },
 #endif
+	{ LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE, "A ZONEMD with the same "
+		"<scheme> and hash algorithm occurred more than once." },
+	{ LDNS_STATUS_ZONEMD_UNKNOWN_SCHEME, "Unknown ZONEMD <scheme>" },
+	{ LDNS_STATUS_ZONEMD_UNKNOWN_HASH, "Unknown ZONEMD hash algorithm" },
+	{ LDNS_STATUS_ZONEMD_INVALID_SOA,
+		"Missing or invalid SOA to associate with ZONEMD RR" },
+	{ LDNS_STATUS_NO_ZONEMD,
+		"NSEC(3) RRs indicate that a ZONEMD exists, "
+	        "but it is not found in the zone" },
+	{ LDNS_STATUS_NO_VALID_ZONEMD,
+		"No ZONEMD matching the zone data was found" },
+	{ LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR, "Syntax error in a key in "
+		"the ServiceParam rdata field of SVCB or HTTPS RR" },
+	{ LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR, "Syntax error in a value in "
+		"the ServiceParam rdata field of SVCB or HTTPS RR" },
+	{ LDNS_STATUS_RESERVED_SVCPARAM_KEY,
+		"key65535 is reserved and MUST NOT be used "
+		"in the ServiceParam rdata field of SVCB or HTTPS RR" },
+	{ LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED,
+		"A value was found for a key that SHOULD not have a value "
+		"in the ServiceParam rdata field of SVCB or HTTPS RR" },
+	{ LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE,
+		"A key was found more than once "
+		"in the ServiceParam rdata field of SVCB or HTTPS RR" },
+	{ LDNS_STATUS_INVALID_SVCPARAM_VALUE,
+		"Invalid wireformat of a value "
+		"in the ServiceParam rdata field of SVCB or HTTPS RR" },
 	{ 0, NULL }
 };
 
diff --git a/contrib/ldns/host2str.c b/contrib/ldns/host2str.c
index 3ca23c2017..7282db9ee2 100644
--- a/contrib/ldns/host2str.c
+++ b/contrib/ldns/host2str.c
@@ -43,6 +43,10 @@
 #define INET6_ADDRSTRLEN 46
 #endif
 
+/* Internal helper function */
+ldns_edns_option_list*
+pkt_edns_data2edns_option_list(const ldns_rdf *edns_data);
+
 /* lookup tables for standard DNS stuff  */
 
 /* Taken from RFC 2535, section 7.  */
@@ -54,29 +58,28 @@ ldns_lookup_table ldns_algorithms[] = {
         { LDNS_RSASHA1, "RSASHA1" },
         { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" },
         { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
-#ifdef USE_SHA2
 	{ LDNS_RSASHA256, "RSASHA256"},
 	{ LDNS_RSASHA512, "RSASHA512"},
-#endif
-#ifdef USE_GOST
 	{ LDNS_ECC_GOST, "ECC-GOST"},
-#endif
-#ifdef USE_ECDSA
         { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
         { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
-#endif
-#ifdef USE_ED25519
 	{ LDNS_ED25519, "ED25519"},
-#endif
-#ifdef USE_ED448
 	{ LDNS_ED448, "ED448"},
-#endif
         { LDNS_INDIRECT, "INDIRECT" },
         { LDNS_PRIVATEDNS, "PRIVATEDNS" },
         { LDNS_PRIVATEOID, "PRIVATEOID" },
         { 0, NULL }
 };
 
+/* Hashing algorithms used in the DS record */
+ldns_lookup_table ldns_hashes[] = {
+        {LDNS_SHA1     , "SHA1" },      /* RFC 4034 */
+        {LDNS_SHA256   , "SHA256" },    /* RFC 4509 */
+        {LDNS_HASH_GOST, "HASH-GOST" }, /* RFC 5933 */
+        {LDNS_SHA384   , "SHA384" },    /* RFC 6605 */
+        { 0, NULL }
+};
+
 /* Taken from RFC 4398  */
 ldns_lookup_table ldns_cert_algorithms[] = {
         { LDNS_CERT_PKIX, "PKIX" },
@@ -414,7 +417,7 @@ ldns_rdf2buffer_str_time(ldns_buffer *output, const ldns_rdf *rdf)
 	char date_buf[16];
 
 	memset(&tm, 0, sizeof(tm));
-	if (ldns_serial_arithmitics_gmtime_r(ldns_rdf2native_int32(rdf), time(NULL), &tm)
+	if (ldns_serial_arithmetics_gmtime_r(ldns_rdf2native_int32(rdf), time(NULL), &tm)
 	    && strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
 		ldns_buffer_printf(output, "%s", date_buf);
 	}
@@ -709,8 +712,8 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
 	uint32_t longitude;
 	uint32_t latitude;
 	uint32_t altitude;
-	char northerness;
-	char easterness;
+	char latitude_hemisphere;
+	char longitude_hemisphere;
 	uint32_t h;
 	uint32_t m;
 	double s;
@@ -734,10 +737,10 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
 		altitude = ldns_read_uint32(&ldns_rdf_data(rdf)[12]);
 
 		if (latitude > equator) {
-			northerness = 'N';
+			latitude_hemisphere = 'N';
 			latitude = latitude - equator;
 		} else {
-			northerness = 'S';
+			latitude_hemisphere = 'S';
 			latitude = equator - latitude;
 		}
 		h = latitude / (1000 * 60 * 60);
@@ -746,13 +749,13 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
 		latitude = latitude % (1000 * 60);
 		s = (double) latitude / 1000.0;
 		ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
-			h, m, s, northerness);
+			h, m, s, latitude_hemisphere);
 
 		if (longitude > equator) {
-			easterness = 'E';
+			longitude_hemisphere = 'E';
 			longitude = longitude - equator;
 		} else {
-			easterness = 'W';
+			longitude_hemisphere = 'W';
 			longitude = equator - longitude;
 		}
 		h = longitude / (1000 * 60 * 60);
@@ -761,8 +764,7 @@ ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
 		longitude = longitude % (1000 * 60);
 		s = (double) longitude / (1000.0);
 		ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
-			h, m, s, easterness);
-
+			h, m, s, longitude_hemisphere);
 
 		s = ((double) altitude) / 100;
 		s -= 100000;
@@ -851,6 +853,8 @@ ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf)
 			endservent();
 #endif
 		}
+		/* exit from loop before integer overflow */
+		if(current_service == 65535) { break; }
 	}
 	return ldns_buffer_status(output);
 }
@@ -1281,7 +1285,7 @@ ldns_rdf2buffer_str_hip(ldns_buffer *output, const ldns_rdf *rdf)
 
 		ldns_buffer_printf(output, "%02x", (int) *data);
 	}
-	ldns_buffer_write_u8(output, (uint8_t) ' ');
+	ldns_buffer_write_char(output, (uint8_t) ' ');
 
 	if (ldns_buffer_reserve(output,
 				ldns_b64_ntop_calculate_size(pk_size))) {
@@ -1299,7 +1303,7 @@ ldns_rdf2buffer_str_hip(ldns_buffer *output, const ldns_rdf *rdf)
 	return ldns_buffer_status(output);
 }
 
-/* implementation mimiced from ldns_rdf2buffer_str_ipseckey */
+/* implementation mimicked from ldns_rdf2buffer_str_ipseckey */
 ldns_status
 ldns_rdf2buffer_str_amtrelay(ldns_buffer *output, const ldns_rdf *rdf)
 {
@@ -1386,6 +1390,231 @@ ldns_rdf2buffer_str_amtrelay(ldns_buffer *output, const ldns_rdf *rdf)
 	return ldns_buffer_status(output);
 }
 
+#ifdef RRTYPE_SVCB_HTTPS
+ldns_status svcparam_key2buffer_str(ldns_buffer *output, uint16_t key);
+
+static ldns_status
+svcparam_mandatory2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	if (sz % 2)
+		return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+	svcparam_key2buffer_str(output, ldns_read_uint16(data));
+	for (data += 2, sz -= 2; sz; data += 2, sz -= 2) {
+		ldns_buffer_write_char(output, ',');
+		svcparam_key2buffer_str(output, ldns_read_uint16(data));
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_alpn2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	uint8_t *eod = data + sz, *dp;
+	bool quote = false;
+	size_t i;
+
+	for (dp = data; dp < eod && !quote; dp += 1 + *dp) {
+		if (dp + 1 + *dp > eod)
+			return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+		for (i = 0; i < *dp; i++)
+			if (isspace(dp[i + 1]))
+				break;
+		quote = i < *dp;
+	}
+	if (quote)
+		ldns_buffer_write_char(output, '"');
+	while (data < eod) {
+		uint8_t *eot = data + 1 + *data;
+
+		if (eot > eod)
+			return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+		if (eod - data < (int)sz)
+			ldns_buffer_write_char(output, ',');
+
+		for (data += 1; data < eot; data += 1) {
+			uint8_t ch = *data;
+
+			if (isprint(ch) || ch == '\t') {
+				if (ch == '"' ||  ch == ',' || ch == '\\')
+					ldns_buffer_write_char(output, '\\');
+				ldns_buffer_write_char(output, ch);
+			} else
+				ldns_buffer_printf(output, "\\%03u"
+				                         , (unsigned)ch);
+		}
+	}
+	if (quote)
+		ldns_buffer_write_char(output, '"');
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_port2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	if (sz != 2)
+		return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+	ldns_buffer_printf(output, "%d", (int)ldns_read_uint16(data));
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_ipv4hint2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	char str[INET_ADDRSTRLEN];
+
+	if (sz % 4 || !inet_ntop(AF_INET, data, str, INET_ADDRSTRLEN))
+		return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+	ldns_buffer_write_chars(output, str);
+
+	for (data += 4, sz -= 4; sz ; data += 4, sz -= 4 ) {
+		ldns_buffer_write_char(output, ',');
+		if (!inet_ntop(AF_INET, data, str, INET_ADDRSTRLEN))
+			return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+		ldns_buffer_write_chars(output, str);
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_ech2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	size_t str_sz = ldns_b64_ntop_calculate_size(sz);
+	int written;
+
+	if (!ldns_buffer_reserve(output, str_sz))
+		return LDNS_STATUS_MEM_ERR;
+
+	written = ldns_b64_ntop( data, sz
+	                       , (char *)ldns_buffer_current(output), str_sz);
+	if (written > 0)
+		ldns_buffer_skip(output, written);
+	else
+		return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_ipv6hint2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	char str[INET6_ADDRSTRLEN];
+
+	if (sz % 16 || !inet_ntop(AF_INET6, data, str, INET6_ADDRSTRLEN))
+		return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+	ldns_buffer_write_chars(output, str);
+
+	for (data += 16, sz -= 16; sz ; data += 16, sz -= 16) {
+		ldns_buffer_write_char(output, ',');
+		if (!inet_ntop(AF_INET6, data, str, INET6_ADDRSTRLEN))
+			return LDNS_STATUS_INVALID_SVCPARAM_VALUE;
+
+		ldns_buffer_write_chars(output, str);
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+svcparam_value2buffer_str(ldns_buffer *output, size_t sz, uint8_t *data)
+{
+	uint8_t *eod = data + sz, *dp;
+	bool quote = false;
+
+	for (dp = data; dp < eod && !isspace(*dp); dp++)
+		; /* pass */
+
+	if ((quote = dp < eod))
+		ldns_buffer_write_char(output, '"');
+
+	for (dp = data; dp < eod; dp++) {
+		uint8_t ch = *dp;
+
+		if (isprint(ch) || ch == '\t') {
+			if (ch == '"' ||  ch == '\\')
+				ldns_buffer_write_char(output, '\\');
+			ldns_buffer_write_char(output, ch);
+		} else
+			ldns_buffer_printf(output, "\\%03u", (unsigned)ch);
+	}
+	if (quote)
+		ldns_buffer_write_char(output, '"');
+	return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_svcparams(ldns_buffer *output, const ldns_rdf *rdf)
+{
+	uint8_t    *data, *dp, *next_dp = NULL;
+	size_t      sz;
+	ldns_status st;
+
+	if (!output)
+		return LDNS_STATUS_NULL;
+
+	if (!rdf || !(data = ldns_rdf_data(rdf)) || !(sz = ldns_rdf_size(rdf)))
+		/* No svcparams is just fine. Just nothing to print. */
+		return LDNS_STATUS_OK;
+	
+	for (dp = data; dp + 4 <= data + sz; dp = next_dp) {
+		ldns_svcparam_key key    = ldns_read_uint16(dp);
+		uint16_t          val_sz = ldns_read_uint16(dp + 2);
+
+		if ((next_dp = dp + 4 + val_sz) > data + sz)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+
+		if (dp > data)
+			ldns_buffer_write_char(output, ' ');
+
+		if ((st = svcparam_key2buffer_str(output, key)))
+			return st;
+
+		if (val_sz == 0)
+			continue;
+		dp += 4;
+		ldns_buffer_write_char(output, '=');
+		switch (key) {
+		case LDNS_SVCPARAM_KEY_MANDATORY:
+			st = svcparam_mandatory2buffer_str(output, val_sz, dp);
+			break;
+		case LDNS_SVCPARAM_KEY_ALPN:
+			st = svcparam_alpn2buffer_str(output, val_sz, dp);
+			break;
+		case LDNS_SVCPARAM_KEY_NO_DEFAULT_ALPN:
+			return LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED;
+		case LDNS_SVCPARAM_KEY_PORT:
+			st = svcparam_port2buffer_str(output, val_sz, dp);
+			break;
+		case LDNS_SVCPARAM_KEY_IPV4HINT:
+			st = svcparam_ipv4hint2buffer_str(output, val_sz, dp);
+			break;
+		case LDNS_SVCPARAM_KEY_ECH:
+			st = svcparam_ech2buffer_str(output, val_sz, dp);
+			break;
+		case LDNS_SVCPARAM_KEY_IPV6HINT:
+			st = svcparam_ipv6hint2buffer_str(output, val_sz, dp);
+			break;
+		default:
+			st = svcparam_value2buffer_str(output, val_sz, dp);
+			break;
+		}
+		if (st)
+			return st;
+	}
+	return ldns_buffer_status(output);
+}
+#else	/* #ifdef RRTYPE_SVCB_HTTPS */
+ldns_status
+ldns_rdf2buffer_str_svcparams(ldns_buffer *output, const ldns_rdf *rdf)
+{
+	(void)output; (void)rdf;
+	return LDNS_STATUS_NOT_IMPL;
+}
+#endif	/* #ifdef RRTYPE_SVCB_HTTPS */
 
 static ldns_status
 ldns_rdf2buffer_str_fmt(ldns_buffer *buffer,
@@ -1505,6 +1734,9 @@ ldns_rdf2buffer_str_fmt(ldns_buffer *buffer,
 		case LDNS_RDF_TYPE_AMTRELAY:
 			res = ldns_rdf2buffer_str_amtrelay(buffer, rdf);
 			break;
+		case LDNS_RDF_TYPE_SVCPARAMS:
+			res = ldns_rdf2buffer_str_svcparams(buffer, rdf);
+			break;
 		}
 	} else {
 		/** This will write mangled RRs */
@@ -1584,45 +1816,50 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output,
 		fmt_st = (ldns_output_format_storage*)
 			  ldns_output_format_default;
 	}
-	if (!rr) {
-		if (LDNS_COMMENT_NULLS & fmt_st->flags) {
-			ldns_buffer_printf(output, "; (null)\n");
+	if (!(fmt_st->flags & LDNS_FMT_SHORT)) {
+		if (!rr) {
+			if (LDNS_COMMENT_NULLS & fmt_st->flags) {
+				ldns_buffer_printf(output, "; (null)\n");
+			}
+			return ldns_buffer_status(output);
+		}
+		if (ldns_rr_owner(rr)) {
+			status = ldns_rdf2buffer_str_dname(output, ldns_rr_owner(rr));
+		}
+		if (status != LDNS_STATUS_OK) {
+			return status;
 		}
-		return ldns_buffer_status(output);
-	}
-	if (ldns_rr_owner(rr)) {
-		status = ldns_rdf2buffer_str_dname(output, ldns_rr_owner(rr));
-	}
-	if (status != LDNS_STATUS_OK) {
-		return status;
-	}
 
-	/* TTL should NOT be printed if it is a question */
-	if (!ldns_rr_is_question(rr)) {
-		ldns_buffer_printf(output, "\t%d", ldns_rr_ttl(rr));
-	}
+		/* TTL should NOT be printed if it is a question */
+		if (!ldns_rr_is_question(rr)) {
+			ldns_buffer_printf(output, "\t%u", (unsigned)ldns_rr_ttl(rr));
+		}
 
-	ldns_buffer_printf(output, "\t");
-	status = ldns_rr_class2buffer_str(output, ldns_rr_get_class(rr));
-	if (status != LDNS_STATUS_OK) {
-		return status;
-	}
-	ldns_buffer_printf(output, "\t");
+		ldns_buffer_printf(output, "\t");
+		status = ldns_rr_class2buffer_str(output, ldns_rr_get_class(rr));
+		if (status != LDNS_STATUS_OK) {
+			return status;
+		}
+		ldns_buffer_printf(output, "\t");
 
-	if (ldns_output_format_covers_type(fmt, ldns_rr_get_type(rr))) {
-		return ldns_rr2buffer_str_rfc3597(output, rr);
-	}
-	status = ldns_rr_type2buffer_str(output, ldns_rr_get_type(rr));
-	if (status != LDNS_STATUS_OK) {
-		return status;
-	}
+		if (ldns_output_format_covers_type(fmt, ldns_rr_get_type(rr))) {
+			return ldns_rr2buffer_str_rfc3597(output, rr);
+		}
+		status = ldns_rr_type2buffer_str(output, ldns_rr_get_type(rr));
+		if (status != LDNS_STATUS_OK) {
+			return status;
+		}
 
-	if (ldns_rr_rd_count(rr) > 0) {
-		ldns_buffer_printf(output, "\t");
-	} else if (!ldns_rr_is_question(rr)) {
-		ldns_buffer_printf(output, "\t\\# 0");
-	}
+		if (ldns_rr_rd_count(rr) > 0) {
+			ldns_buffer_printf(output, "\t");
+		} else if (!ldns_rr_is_question(rr)) {
+			ldns_buffer_printf(output, "\t\\# 0");
+		}
+	} else if (ldns_rr_rd_count(rr) == 0) {
+		/* assert(fmt_st->flags & LDNS_FMT_SHORT); */
 
+		ldns_buffer_printf(output, "# 0");
+	}
 	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
 		/* ldns_rdf2buffer_str handles NULL input fine! */
 		if ((fmt_st->flags & LDNS_FMT_ZEROIZE_RRSIGS) &&
@@ -1758,7 +1995,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output,
 							   node->data
 							));
 					}
-					ldns_rdf_free(key);
+					ldns_rdf_deep_free(key);
 				}
 				key = ldns_b32_ext2dname(
 						ldns_nsec3_next_owner(rr));
@@ -1776,7 +2013,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output,
 							   node->data
 							));
 					}
-					ldns_rdf_free(key);
+					ldns_rdf_deep_free(key);
 				}
 			}
 			ldns_buffer_printf(output, "}");
@@ -1869,6 +2106,579 @@ ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt)
 	return ldns_buffer_status(output);
 }
 
+
+/* print EDNS option data in the Dig format: 76 61 6c 69 ... */
+static void
+ldns_edns_hex_data2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t j;
+	for (j = 0; j < len; j++) {
+		ldns_buffer_printf(output, " %02x", data[j]);
+	}
+}
+
+static ldns_status
+ldns_edns_llq2buffer_str(ldns_buffer* output, 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 */
+
+	ldns_buffer_printf(output, "; Long-Lived Query:");
+
+	/* read the record */
+	if(len != 18) {
+		ldns_buffer_printf(output, " malformed LLQ ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+	version = ldns_read_uint16(data);
+	llq_opcode = ldns_read_uint16(data+2);
+	error_code = ldns_read_uint16(data+4);
+	memmove(&llq_id, data+6, sizeof(uint64_t));
+	lease_life = ldns_read_uint32(data+14);
+
+	/* print option field entires */
+	ldns_buffer_printf(output, "v%d ", (int)version);
+
+	if(llq_opcode < llq_opcodes_num) {
+		ldns_buffer_printf(output, "%s", llq_opcodes[llq_opcode]);
+	} else {
+		ldns_buffer_printf(output, "opcode %d", (int)llq_opcode);
+	}
+
+	if(error_code < llq_errors_num)
+		ldns_buffer_printf(output, " %s", llq_errors[error_code]);
+	else {
+		ldns_buffer_printf(output, " error %d", (int)error_code);
+	}
+
+#ifndef USE_WINSOCK
+	ldns_buffer_printf(output, " id %llx lease-life %lu",
+		(unsigned long long)llq_id, (unsigned long)lease_life);
+#else
+	ldns_buffer_printf(output, " id %I64x lease-life %lu",
+		(unsigned long long)llq_id, (unsigned long)lease_life);
+#endif
+	return ldns_buffer_status(output);
+}
+
+
+static ldns_status
+ldns_edns_ul2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	uint32_t lease;
+
+	ldns_buffer_printf(output, "; Update Lease:");
+
+	if(len != 4) {
+		ldns_buffer_printf(output, " malformed UL ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+		return ldns_buffer_status(output);
+	}
+	lease = ldns_read_uint32(data);
+	ldns_buffer_printf(output, "lease %lu", (unsigned long)lease);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_nsid2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i, printed=0;
+
+	ldns_buffer_printf(output, "; NSID:");
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	/* print the human-readable text string */
+	for(i = 0; i < len; i++) {
+		if(isprint((unsigned char)data[i]) || data[i] == '\t') {
+			if(!printed) {
+				ldns_buffer_printf(output, " (");
+				printed = 1;
+			}
+			ldns_buffer_printf(output, "%c", (char)data[i]);
+		}
+	}
+	if(printed)
+		ldns_buffer_printf(output, ")");
+	return ldns_buffer_status(output);
+}
+
+
+static ldns_status
+ldns_edns_dau2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i;
+	ldns_lookup_table *lt;
+
+	ldns_buffer_printf(output, "; DNSSEC Algorithm Understood (DAU):");
+
+	for(i = 0; i <len; i++) {
+		lt = ldns_lookup_by_id(ldns_algorithms, data[i]);
+		if (lt && lt->name) {
+			ldns_buffer_printf(output, " %s", lt->name);
+		} else {
+			ldns_buffer_printf(output, " ALG%u", data[i]);
+		}
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_dhu2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i;
+	ldns_lookup_table *lt;
+
+	ldns_buffer_printf(output, "; DS Hash Understood (DHU):");
+
+	for(i = 0; i < len; i++) {
+		lt = ldns_lookup_by_id(ldns_hashes, data[i]);
+		if (lt && lt->name) {
+			ldns_buffer_printf(output, " %s", lt->name);
+		} else {
+			ldns_buffer_printf(output, " ALG%u", data[i]);
+		}
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_d3u2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i;
+
+	ldns_buffer_printf(output, "; NSEC3 Hash Understood (N3U):");
+
+	for(i=0; i<len; i++) {
+		if(data[i] == 1) {
+			ldns_buffer_printf(output, " SHA1");
+		} else {
+			ldns_buffer_printf(output, " %d", (int)data[i]);
+		}
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_subnet2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	uint16_t family;
+	uint8_t source, scope;
+	if(len < 4) {
+		ldns_buffer_printf(output, "malformed subnet ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+		return ldns_buffer_status(output);
+	}
+	family = ldns_read_uint16(data);
+	source = data[2];
+	scope = data[3];
+	if(family == 1) {
+		/* IPv4 */
+		char buf[64];
+		uint8_t ip4[4];
+		memset(ip4, 0, sizeof(ip4));
+		if(len-4 > 4) {
+			ldns_buffer_printf(output, "trailingdata:");
+			ldns_edns_hex_data2buffer_str(output, data+4+4, len-4-4);
+			ldns_buffer_printf(output, " ");
+			len = 4+4;
+		}
+		memmove(ip4, data+4, len-4);
+		if(!inet_ntop(AF_INET, ip4, buf, (socklen_t) sizeof(buf))) {
+			ldns_buffer_printf(output, "ip4ntoperror ");
+			ldns_edns_hex_data2buffer_str(output, data+4+4, len-4-4);
+		} else {
+			ldns_buffer_printf(output, "%s", buf);
+		}
+	} else if(family == 2) {
+		/* IPv6 */
+		char buf[64];
+		uint8_t ip6[16];
+		memset(ip6, 0, sizeof(ip6));
+		if(len-4 > 16) {
+			ldns_buffer_printf(output, "trailingdata:");
+			ldns_edns_hex_data2buffer_str(output, data+4+16, len-4-16);
+			ldns_buffer_printf(output, " ");
+			len = 4+16;
+		}
+		memmove(ip6, data+4, len-4);
+#ifdef AF_INET6
+		if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t) sizeof(buf))) {
+			ldns_buffer_printf(output, "ip6ntoperror ");
+			ldns_edns_hex_data2buffer_str(output, data+4+4, len-4-4);
+		} else {
+			ldns_buffer_printf(output, "%s", buf);
+		}
+#else
+		ldns_edns_hex_data2buffer_str(output,  data+4+4, len-4-4);
+#endif
+	} else {
+		/* unknown */
+		ldns_buffer_printf(output, "family %d ", (int)family);
+		ldns_edns_hex_data2buffer_str(output, data, len);
+	}
+	ldns_buffer_printf(output, "/%d scope /%d", (int)source, (int)scope);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_expire2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+
+	ldns_buffer_printf(output, "; EXPIRE:");
+
+	if (!(len == 0) || len == 4) {
+		ldns_buffer_printf(output, "malformed expire ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	// TODO can this output be more accurate?
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	return ldns_buffer_status(output);
+}
+
+
+static ldns_status
+ldns_edns_cookie2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	ldns_buffer_printf(output, "; COOKIE:");
+
+	/* the size of an EDNS cookie is restricted by RFC 7873 */
+	if (!(len == 8 || (len >= 16 && len < 40))) {
+		ldns_buffer_printf(output, "malformed cookie ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+	}
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_keepalive2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	uint16_t timeout;
+
+	ldns_buffer_printf(output, "; KEEPALIVE:");
+
+	if(!(len == 0 || len == 2)) {
+		ldns_buffer_printf(output, "malformed keepalive ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	if(len == 0) {
+		ldns_buffer_printf(output, "no timeout value (only valid for client option)");
+	} else {
+		timeout = ldns_read_uint16(data);
+		ldns_buffer_printf(output, "timeout value in units of 100ms %u", (int)timeout);
+	}
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_padding2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	ldns_buffer_printf(output, "; PADDING: ");
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_chain2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	ldns_rdf** temp = NULL;
+
+	ldns_buffer_printf(output, "; CHAIN: ");
+
+	if (ldns_str2rdf_dname(temp, (char*) data) != LDNS_STATUS_OK) {
+		ldns_buffer_printf(output, "malformed chain ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	ldns_characters2buffer_str(output, len, data);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_key_tag2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i;
+
+	ldns_buffer_printf(output, "; KEY TAG: ");
+
+	if(len < 2 || len % 2 != 0) {
+		ldns_buffer_printf(output, "malformed key tag ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	for (i = 0; i < len; i += 2) {
+		uint16_t tag = ldns_read_uint16(data);
+
+		ldns_buffer_printf(output, " %hu", tag);
+	}
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_ede2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	size_t i;
+	uint16_t ede;
+	ldns_buffer_printf(output, "; EDE:");
+
+	if(len < 2) {
+		ldns_buffer_printf(output, "malformed ede ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	ede = ldns_read_uint16(data);
+
+	switch (ede) {
+	case LDNS_EDE_OTHER:
+		ldns_buffer_printf(output, " 0 (Other): ");
+		break;
+	case LDNS_EDE_UNSUPPORTED_DNSKEY_ALG:
+		ldns_buffer_printf(output, " 1 (Unsupported DNSKEY Algorithm)");
+		break;
+	case LDNS_EDE_UNSUPPORTED_DS_DIGEST:
+		ldns_buffer_printf(output, " 2 (Unsupported DS Digest type)");
+		break;
+	case LDNS_EDE_STALE_ANSWER:
+		ldns_buffer_printf(output, " 3 (Stale Answer)");
+		break;
+	case LDNS_EDE_FORGED_ANSWER:
+		ldns_buffer_printf(output, " 4 (Forged Answer)");
+		break;
+	case LDNS_EDE_DNSSEC_INDETERMINATE:
+		ldns_buffer_printf(output, " 5 (DNSSEC Indeterminate)");
+		break;
+	case LDNS_EDE_DNSSEC_BOGUS:
+		ldns_buffer_printf(output, " 6 (DNSSEC Bogus)");
+		break;
+	case LDNS_EDE_SIGNATURE_EXPIRED:
+		ldns_buffer_printf(output, " 7 (Signature Expired)");
+		break;
+	case LDNS_EDE_SIGNATURE_NOT_YET_VALID:
+		ldns_buffer_printf(output, " 8 (Signature Not Yet Valid)");
+		break;
+	case LDNS_EDE_DNSKEY_MISSING:
+		ldns_buffer_printf(output, " 9 (DNSKEY Missing)");
+		break;
+	case LDNS_EDE_RRSIGS_MISSING:
+		ldns_buffer_printf(output, " 10 (RRSIGs Missing)");
+		break;
+	case LDNS_EDE_NO_ZONE_KEY_BIT_SET:
+		ldns_buffer_printf(output, " 11 (No Zone Key Bit Set)");
+		break;
+	case LDNS_EDE_NSEC_MISSING:
+		ldns_buffer_printf(output, " 12 (NSEC Missing)");
+		break;
+	case LDNS_EDE_CACHED_ERROR:
+		ldns_buffer_printf(output, " 13 (Cached Error)");
+		break;
+	case LDNS_EDE_NOT_READY:
+		ldns_buffer_printf(output, " 14 (Not Ready)");
+		break;
+	case LDNS_EDE_BLOCKED:
+		ldns_buffer_printf(output, " 15 (Blocked)");
+		break;
+	case LDNS_EDE_CENSORED:
+		ldns_buffer_printf(output, " 16 (Censored)");
+		break;
+	case LDNS_EDE_FILTERED:
+		ldns_buffer_printf(output, " 17 (Filtered)");
+		break;
+	case LDNS_EDE_PROHIBITED:
+		ldns_buffer_printf(output, " 18 (Prohibited)");
+		break;
+	case LDNS_EDE_STALE_NXDOMAIN_ANSWER:
+		ldns_buffer_printf(output, " 19 (NXDOMAIN Answer)");
+		break;
+	case LDNS_EDE_NOT_AUTHORITATIVE:
+		ldns_buffer_printf(output, " 20 (Not Authoritative)");
+		break;
+	case LDNS_EDE_NOT_SUPPORTED:
+		ldns_buffer_printf(output, " 21 (Not Supported)");
+		break;
+	case LDNS_EDE_NO_REACHABLE_AUTHORITY:
+		ldns_buffer_printf(output, " 22 (No Reachable Authority)");
+		break;
+	case LDNS_EDE_NETWORK_ERROR:
+		ldns_buffer_printf(output, " 23 (Network Error)");
+		break;
+	case LDNS_EDE_INVALID_DATA:
+		ldns_buffer_printf(output, " 24 (Invalid Data)");
+		break;
+	case LDNS_EDE_SIGNATURE_EXPIRED_BEFORE_VALID:
+		ldns_buffer_printf(output, " 25 (Signature Expired Before Valid)");
+		break;
+	case LDNS_EDE_TOO_EARLY:
+		ldns_buffer_printf(output, " 26 (Too Early)");
+		break;
+	default:
+		ldns_buffer_printf(output, " %02x", data[0]);
+		ldns_buffer_printf(output, " %02x", data[1]);
+		break;
+	}
+
+	/* skip the EDE code in the output */
+	data += 2;
+	len -= 2;
+
+	if (len > 2) {
+		/* format the hex bytes */
+		ldns_buffer_printf(output, ":");
+		for (i = 0; i < len; i++) {
+			ldns_buffer_printf(output, " %02x", data[i]);
+		}
+
+		/* format the human-readable string */
+		ldns_buffer_printf(output, " (");
+		ldns_characters2buffer_str(output, len, data);
+		ldns_buffer_printf(output, ")");
+	}
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_client_tag2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	ldns_buffer_printf(output, "; CLIENT-TAG:");
+
+	if (len > 2) {
+		ldns_buffer_printf(output, "malformed client-tag ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	return ldns_buffer_status(output);
+}
+
+static ldns_status
+ldns_edns_server_tag2buffer_str(ldns_buffer* output, uint8_t* data, size_t len)
+{
+	ldns_buffer_printf(output, "; SERVER-TAG:");
+
+	if (len > 2) {
+		ldns_buffer_printf(output, "malformed server-tag ");
+		ldns_edns_hex_data2buffer_str(output, data, len);
+
+		return ldns_buffer_status(output);
+	}
+
+	ldns_edns_hex_data2buffer_str(output, data, len);
+
+	return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_edns_option_list2buffer_str(ldns_buffer *output, ldns_edns_option_list* edns_list)
+{
+	size_t count = ldns_edns_option_list_get_count(edns_list);
+	size_t i, size;
+	uint8_t* data;
+
+	for (i = 0; i < count; i++) {
+		ldns_edns_option_code code;
+		ldns_edns_option* edns = ldns_edns_option_list_get_option(edns_list, i);
+
+		if (!edns) {
+			break;
+		}
+
+		code = ldns_edns_get_code(edns);
+		size = ldns_edns_get_size(edns);
+		data = ldns_edns_get_data(edns);
+
+		switch(code) {
+		case LDNS_EDNS_LLQ:
+			ldns_edns_llq2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_UL:
+			ldns_edns_ul2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_NSID:
+			ldns_edns_nsid2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_DAU:
+			ldns_edns_dau2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_DHU:
+			ldns_edns_dhu2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_N3U:
+			ldns_edns_d3u2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_CLIENT_SUBNET:
+			ldns_edns_subnet2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_EXPIRE:
+			ldns_edns_expire2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_COOKIE:
+			ldns_edns_cookie2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_KEEPALIVE:
+			ldns_edns_keepalive2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_PADDING:
+			ldns_edns_padding2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_CHAIN:
+			ldns_edns_chain2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_KEY_TAG:
+			ldns_edns_key_tag2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_EDE:
+			ldns_edns_ede2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_CLIENT_TAG:
+			ldns_edns_client_tag2buffer_str(output, data, size);
+			break;
+		case LDNS_EDNS_SERVER_TAG:
+			ldns_edns_server_tag2buffer_str(output, data, size);
+			break;
+		default:
+			ldns_buffer_printf(output, "; OPT=%d:", code);
+			ldns_edns_hex_data2buffer_str(output, data, size);
+			break;
+		}
+		ldns_buffer_printf(output, "\n");
+	}
+
+	return ldns_buffer_status(output);
+}
+
+
 ldns_status
 ldns_pkt2buffer_str_fmt(ldns_buffer *output, 
 		const ldns_output_format *fmt, const ldns_pkt *pkt)
@@ -1878,13 +2688,18 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output,
 	char *tmp;
 	struct timeval time;
 	time_t time_tt;
+	int short_fmt = fmt && (fmt->flags & LDNS_FMT_SHORT);
 
 	if (!pkt) {
 		ldns_buffer_printf(output, "null");
 		return LDNS_STATUS_OK;
 	}
 
-	if (ldns_buffer_status_ok(output)) {
+	if (!ldns_buffer_status_ok(output)) {
+		return ldns_buffer_status(output);
+	}
+
+	if (!short_fmt) {
 		status = ldns_pktheader2buffer_str(output, pkt);
 		if (status != LDNS_STATUS_OK) {
 			return status;
@@ -1906,15 +2721,16 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output,
 		ldns_buffer_printf(output, "\n");
 
 		ldns_buffer_printf(output, ";; ANSWER SECTION:\n");
-		for (i = 0; i < ldns_pkt_ancount(pkt); i++) {
-			status = ldns_rr2buffer_str_fmt(output, fmt,
-				       ldns_rr_list_rr(
-					       ldns_pkt_answer(pkt), i));
-			if (status != LDNS_STATUS_OK) {
-				return status;
-			}
-
+	}
+	for (i = 0; i < ldns_pkt_ancount(pkt); i++) {
+		status = ldns_rr2buffer_str_fmt(output, fmt,
+			       ldns_rr_list_rr(
+				       ldns_pkt_answer(pkt), i));
+		if (status != LDNS_STATUS_OK) {
+			return status;
 		}
+	}
+	if (!short_fmt) {
 		ldns_buffer_printf(output, "\n");
 
 		ldns_buffer_printf(output, ";; AUTHORITY SECTION:\n");
@@ -1940,7 +2756,7 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output,
 
 		}
 		ldns_buffer_printf(output, "\n");
-		/* add some futher fields */
+		/* add some further fields */
 		ldns_buffer_printf(output, ";; Query time: %d msec\n",
 				ldns_pkt_querytime(pkt));
 		if (ldns_pkt_edns(pkt)) {
@@ -1959,11 +2775,20 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output,
 			ldns_buffer_printf(output, " ; udp: %u\n",
 					   ldns_pkt_edns_udp_size(pkt));
 
-			if (ldns_pkt_edns_data(pkt)) {
-				ldns_buffer_printf(output, ";; Data: ");
-				(void)ldns_rdf2buffer_str(output,
-							  ldns_pkt_edns_data(pkt));
-				ldns_buffer_printf(output, "\n");
+			if (pkt->_edns_list)
+				ldns_edns_option_list2buffer_str(output, pkt->_edns_list);
+
+			else if (ldns_pkt_edns_data(pkt)) {
+				ldns_edns_option_list* edns_list;
+				/* parse the EDNS data into separate EDNS options
+				 * and add them to the list */
+				if ((edns_list = pkt_edns_data2edns_option_list(ldns_pkt_edns_data(pkt)))) {
+					ldns_edns_option_list2buffer_str(output, edns_list);
+					ldns_edns_option_list_deep_free(edns_list);
+				} else {
+					ldns_buffer_printf(output, ";; Data: ");
+					(void)ldns_rdf2buffer_str(output, ldns_pkt_edns_data(pkt));
+				}
 			}
 		}
 		if (ldns_pkt_tsig(pkt)) {
@@ -1984,8 +2809,6 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output,
 
 		ldns_buffer_printf(output, ";; MSG SIZE  rcvd: %d\n",
 				(int)ldns_pkt_size(pkt));
-	} else {
-		return ldns_buffer_status(output);
 	}
 	return status;
 }
@@ -2133,7 +2956,9 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 	unsigned char  *bignum;
 #ifdef HAVE_SSL
 	RSA *rsa;
+#ifdef USE_DSA
 	DSA *dsa;
+#endif /* USE_DSA */
 #endif /* HAVE_SSL */
 
 	if (!k) {
@@ -2207,7 +3032,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 					const BIGNUM *n=NULL, *e=NULL, *d=NULL,
 						*p=NULL, *q=NULL, *dmp1=NULL,
 						*dmq1=NULL, *iqmp=NULL;
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 					n = rsa->n;
 					e = rsa->e;
 					d = rsa->d;
@@ -2243,6 +3068,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 
 				RSA_free(rsa);
 				break;
+#ifdef USE_DSA
 			case LDNS_SIGN_DSA:
 			case LDNS_SIGN_DSA_NSEC3:
 				dsa = ldns_key_dsa_key(k);
@@ -2259,7 +3085,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 				if(1) {
 					const BIGNUM *p=NULL, *q=NULL, *g=NULL,
 						*priv_key=NULL, *pub_key=NULL;
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 #ifndef S_SPLINT_S
 					p = dsa->p;
 					q = dsa->q;
@@ -2283,6 +3109,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 						goto error;
 				}
 				break;
+#endif /* USE_DSA */
 			case LDNS_SIGN_ECC_GOST:
 				/* no format defined, use blob */
 #if defined(HAVE_SSL) && defined(USE_GOST)
@@ -2407,7 +3234,7 @@ ldns_buffer2str(ldns_buffer *buffer)
 		if (!ldns_buffer_reserve(buffer, 1)) {
 			return NULL;
 		}
-		ldns_buffer_write_u8(buffer, (uint8_t) '\0');
+		ldns_buffer_write_char(buffer, (uint8_t) '\0');
 		if (!ldns_buffer_set_capacity(buffer, ldns_buffer_position(buffer))) {
 			return NULL;
 		}
@@ -2430,7 +3257,7 @@ ldns_buffer_export2str(ldns_buffer *buffer)
 	if (! ldns_buffer_reserve(buffer, 1)) {
 		return NULL;
 	}
-	ldns_buffer_write_u8(buffer, 0);
+	ldns_buffer_write_char(buffer, 0);
 
 	/* reallocate memory to the size of the string and export */
 	ldns_buffer_set_capacity(buffer, ldns_buffer_position(buffer));
diff --git a/contrib/ldns/host2wire.c b/contrib/ldns/host2wire.c
index a12b6b035e..d153921479 100644
--- a/contrib/ldns/host2wire.c
+++ b/contrib/ldns/host2wire.c
@@ -374,6 +374,20 @@ compression_node_free(ldns_rbnode_t *node, void *arg)
 
 ldns_status
 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
+{
+	ldns_status status;
+	ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
+
+	status = ldns_pkt2buffer_wire_compress(buffer, packet, compression_data);
+
+	ldns_traverse_postorder(compression_data,compression_node_free,NULL);
+	ldns_rbtree_free(compression_data);
+
+	return status;
+}
+
+ldns_status
+ldns_pkt2buffer_wire_compress(ldns_buffer *buffer, const ldns_pkt *packet, ldns_rbtree_t *compression_data)
 {
 	ldns_rr_list *rr_list;
 	uint16_t i;
@@ -382,8 +396,9 @@ ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
 	ldns_rr *edns_rr;
 	uint8_t edata[4];
 
-	ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
-	
+	ldns_buffer *edns_buf = NULL;
+	ldns_rdf    *edns_rdf = NULL;
+
 	(void) ldns_hdr2buffer_wire(buffer, packet);
 
 	rr_list = ldns_pkt_question(packet);
@@ -428,11 +443,22 @@ ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
 		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
 		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
 		/* don't forget to add the edns rdata (if any) */
-		if (packet->_edns_data)
-			ldns_rr_push_rdf (edns_rr, packet->_edns_data);
+		if ((edns_buf = ldns_edns_option_list2wireformat_buffer(packet->_edns_list))) {
+			edns_rdf = ldns_rdf_new( LDNS_RDF_TYPE_UNKNOWN
+			                       , ldns_buffer_limit(edns_buf)
+			                       , ldns_buffer_export(edns_buf));
+			ldns_buffer_free(edns_buf);
+		}
+		if (edns_rdf)
+			ldns_rr_push_rdf(edns_rr, edns_rdf);
+		else if (packet->_edns_data)
+			ldns_rr_push_rdf(edns_rr, packet->_edns_data);
 		(void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data);
-		/* take the edns rdata back out of the rr before we free rr */
-		if (packet->_edns_data)
+		/* if the rdata of the OPT came from packet->_edns_data
+		 * we need to take it back out of the edns_rr before we free it
+		 * so packet->_edns_data doesn't get freed
+		 */
+		if (!edns_rdf && packet->_edns_data)
 			(void)ldns_rr_pop_rdf (edns_rr);
 		ldns_rr_free(edns_rr);
 	}
@@ -443,9 +469,6 @@ ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
 		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data);
 	}
 
-	ldns_traverse_postorder(compression_data,compression_node_free,NULL);
-	ldns_rbtree_free(compression_data);
-
 	return LDNS_STATUS_OK;
 }
 
diff --git a/contrib/ldns/keys.c b/contrib/ldns/keys.c
index 016f973111..78bea9721c 100644
--- a/contrib/ldns/keys.c
+++ b/contrib/ldns/keys.c
@@ -15,6 +15,7 @@
 #include <ldns/ldns.h>
 
 #ifdef HAVE_SSL
+#include <openssl/ui.h>
 #include <openssl/ssl.h>
 #include <openssl/rand.h>
 #include <openssl/bn.h>
@@ -83,7 +84,7 @@ ldns_key_new(void)
 	if (!newkey) {
 		return NULL;
 	} else {
-		/* some defaults - not sure wether to do this */
+		/* some defaults - not sure whether to do this */
 		ldns_key_set_use(newkey, true);
 		ldns_key_set_flags(newkey, LDNS_KEY_ZONE_KEY);
 		ldns_key_set_origttl(newkey, 0);
@@ -775,7 +776,7 @@ ldns_key_new_frm_fp_rsa_l(FILE *f, int *line_nr)
 	}
 
 	/* I could use functions again, but that seems an overkill,
-	 * allthough this also looks tedious
+	 * although this also looks tedious
 	 */
 
 	/* Modules, rsa->n */
@@ -860,7 +861,7 @@ ldns_key_new_frm_fp_rsa_l(FILE *f, int *line_nr)
 	}
 #endif /* splint */
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 # ifndef S_SPLINT_S
 	rsa->n = n;
 	rsa->e = e;
@@ -904,6 +905,7 @@ ldns_key_new_frm_fp_rsa_l(FILE *f, int *line_nr)
 	return NULL;
 }
 
+#ifdef USE_DSA
 DSA *
 ldns_key_new_frm_fp_dsa(FILE *f)
 {
@@ -980,7 +982,7 @@ ldns_key_new_frm_fp_dsa_l(FILE *f, ATTR_UNUSED(int *line_nr))
 	}
 #endif /* splint */
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 # ifndef S_SPLINT_S
 	dsa->p = p;
 	dsa->q = q;
@@ -1014,6 +1016,7 @@ ldns_key_new_frm_fp_dsa_l(FILE *f, ATTR_UNUSED(int *line_nr))
 	BN_free(pub_key);
 	return NULL;
 }
+#endif /* USE_DSA */
 
 unsigned char *
 ldns_key_new_frm_fp_hmac(FILE *f, size_t *hmac_size)
@@ -1148,9 +1151,9 @@ ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
 #endif /* HAVE_EVP_PKEY_KEYGEN */
 #endif /* HAVE_SSL */
 			break;
+#ifdef USE_DSA
 		case LDNS_SIGN_DSA:
 		case LDNS_SIGN_DSA_NSEC3:
-#ifdef USE_DSA
 #ifdef HAVE_SSL
 # if OPENSSL_VERSION_NUMBER < 0x00908000L
 			d = DSA_generate_parameters((int)size, NULL, 0, NULL, NULL, NULL, NULL);
@@ -1443,7 +1446,7 @@ ldns_key_set_keytag(ldns_key *k, uint16_t tag)
 size_t
 ldns_key_list_key_count(const ldns_key_list *key_list)
 {
-	        return key_list->_key_count;
+	return key_list ? key_list->_key_count : 0;
 }       
 
 ldns_key *
@@ -1657,7 +1660,7 @@ ldns_key_rsa2bin(unsigned char *data, RSA *k, uint16_t *size)
 	if (!k) {
 		return false;
 	}
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || (defined(HAVE_LIBRESSL) && LIBRESSL_VERSION_NUMBER < 0x20700000)
 	n = k->n;
 	e = k->e;
 #else
@@ -1877,10 +1880,10 @@ ldns_key2rr(const ldns_key *k)
 #endif
 			size++;
 			break;
+#ifdef USE_DSA
 		case LDNS_SIGN_DSA:
 			ldns_rr_push_rdf(pubkey,
 					ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA));
-#ifdef USE_DSA
 #ifdef HAVE_SSL
 			dsa = ldns_key_dsa_key(k);
 			if (dsa) {
@@ -1900,10 +1903,10 @@ ldns_key2rr(const ldns_key *k)
 #endif /* HAVE_SSL */
 #endif /* USE_DSA */
 			break;
+#ifdef USE_DSA
 		case LDNS_SIGN_DSA_NSEC3:
 			ldns_rr_push_rdf(pubkey,
 					ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA_NSEC3));
-#ifdef USE_DSA
 #ifdef HAVE_SSL
 			dsa = ldns_key_dsa_key(k);
 			if (dsa) {
@@ -2164,7 +2167,9 @@ ldns_signing_algorithm ldns_get_signing_algorithm_by_name(const char* name)
         ldns_lookup_table aliases[] = {
                 /* from bind dnssec-keygen */
                 {LDNS_SIGN_HMACMD5, "HMAC-MD5"},
+#ifdef USE_DSA
                 {LDNS_SIGN_DSA_NSEC3, "NSEC3DSA"},
+#endif /* USE_DSA */
                 {LDNS_SIGN_RSASHA1_NSEC3, "NSEC3RSASHA1"},
                 /* old ldns usage, now RFC names */
 #ifdef USE_DSA
diff --git a/contrib/ldns/ldns/buffer.h b/contrib/ldns/ldns/buffer.h
index f49a550bbd..79ae0f5cc1 100644
--- a/contrib/ldns/ldns/buffer.h
+++ b/contrib/ldns/ldns/buffer.h
@@ -399,6 +399,22 @@ ldns_buffer_write_string(ldns_buffer *buffer, const char *str)
 	ldns_buffer_write(buffer, str, strlen(str));
 }
 
+/**
+ * copies the given (null-delimited) string to the current position at the buffer
+ * increasing the capacity if necessary
+ * \param[in] buffer the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+ldns_buffer_write_chars(ldns_buffer *buffer, const char *str)
+{
+	if (!ldns_buffer_reserve(buffer, strlen(str)))
+		buffer->_status = LDNS_STATUS_MEM_ERR;
+	else
+		ldns_buffer_write_string(buffer, str);
+}
+
+
 /**
  * writes the given byte of data at the given position in the buffer
  * \param[in] buffer the buffer
@@ -424,6 +440,21 @@ ldns_buffer_write_u8(ldns_buffer *buffer, uint8_t data)
 	buffer->_position += sizeof(data);
 }
 
+/**
+ * writes the given byte of data at the current position in the buffer
+ * increasing the capacity if necessary
+ * \param[in] buffer the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+ldns_buffer_write_char(ldns_buffer *buffer, uint8_t data)
+{
+	if (!ldns_buffer_reserve(buffer, sizeof(data)))
+		buffer->_status = LDNS_STATUS_MEM_ERR;
+	else
+		ldns_buffer_write_u8(buffer, data);
+}
+
 /**
  * writes the given 2 byte integer at the given position in the buffer
  * \param[in] buffer the buffer
diff --git a/contrib/ldns/ldns/common.h b/contrib/ldns/ldns/common.h
index 9abd9b9396..27f858dd9e 100644
--- a/contrib/ldns/ldns/common.h
+++ b/contrib/ldns/ldns/common.h
@@ -27,6 +27,9 @@
 #define LDNS_BUILD_CONFIG_USE_DANE         1
 #define LDNS_BUILD_CONFIG_HAVE_B32_PTON    0
 #define LDNS_BUILD_CONFIG_HAVE_B32_NTOP    0
+#define LDNS_BUILD_CONFIG_USE_DSA          1
+#define LDNS_BUILD_CONFIG_USE_ED25519      1
+#define LDNS_BUILD_CONFIG_USE_ED448        1
 
 /*
  * HAVE_STDBOOL_H is not available when distributed as a library, but no build 
diff --git a/contrib/ldns/ldns/dane.h b/contrib/ldns/ldns/dane.h
index 3bde546391..b5366e0e5c 100644
--- a/contrib/ldns/ldns/dane.h
+++ b/contrib/ldns/ldns/dane.h
@@ -43,7 +43,7 @@ enum ldns_enum_tlsa_certificate_usage
 	/** CA constraint */
 	LDNS_TLSA_USAGE_PKIX_TA				=   0,
 	LDNS_TLSA_USAGE_CA_CONSTRAINT			=   0,
-	/** Sevice certificate constraint */
+	/** Service certificate constraint */
 	LDNS_TLSA_USAGE_PKIX_EE				=   1,
 	LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT	=   1,
 	/** Trust anchor assertion */
diff --git a/contrib/ldns/ldns/dnssec.h b/contrib/ldns/ldns/dnssec.h
index 9881fda723..6ce305aeb7 100644
--- a/contrib/ldns/ldns/dnssec.h
+++ b/contrib/ldns/ldns/dnssec.h
@@ -355,7 +355,7 @@ uint8_t ldns_nsec3_salt_length(const ldns_rr *nsec3_rr);
 /**
  * Returns the salt bytes used in the given NSEC3 RR
  * \param[in] *nsec3_rr The RR to read from
- * \return The salt in bytes, this is alloced, so you need to free it
+ * \return The salt in bytes, this is alloc'ed, so you need to free it
  */
 uint8_t *ldns_nsec3_salt_data(const ldns_rr *nsec3_rr);
 
diff --git a/contrib/ldns/ldns/dnssec_sign.h b/contrib/ldns/ldns/dnssec_sign.h
index a88a46affa..4523811f1a 100644
--- a/contrib/ldns/ldns/dnssec_sign.h
+++ b/contrib/ldns/ldns/dnssec_sign.h
@@ -12,8 +12,11 @@ extern "C" {
 /* sign functions */
 
 /** Sign flag that makes DNSKEY type signed by all keys, not only by SEP keys*/
-#define LDNS_SIGN_DNSKEY_WITH_ZSK 1
-#define LDNS_SIGN_WITH_ALL_ALGORITHMS 2 
+#define LDNS_SIGN_DNSKEY_WITH_ZSK            1
+#define LDNS_SIGN_WITH_ALL_ALGORITHMS        2 
+#define LDNS_SIGN_NO_KEYS_NO_NSECS           4
+#define LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA384  8
+#define LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA512 16
 
 /**
  * Create an empty RRSIG RR (i.e. without the actual signature data)
@@ -46,9 +49,10 @@ ldns_rr_list *ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys);
 #if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * Sign a buffer with the DSA key (hash with SHA1)
- * \param[in] to_sign buffer with the data
- * \param[in] key the key to use
- * \return a ldns_rdf with the signed data
+ *
+ * \param[in] to_sign The ldns_buffer containing raw data that is to be signed
+ * \param[in] key The DSA key structure to sign with
+ * \return a ldns_rdf for the RRSIG ldns_rr
  */
 ldns_rdf *ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key);
 
@@ -109,7 +113,7 @@ ldns_dnssec_zone_mark_and_get_glue(
  * be taken into account separately.
  *
  * \param[in] zone the zone in which to mark the names
- * \return LDNS_STATUS_OK on succesful completion
+ * \return LDNS_STATUS_OK on successful completion, an error code otherwise
  */
 ldns_status
 ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone);
diff --git a/contrib/ldns/ldns/dnssec_verify.h b/contrib/ldns/ldns/dnssec_verify.h
index 80881c682f..0ce6ec99d2 100644
--- a/contrib/ldns/ldns/dnssec_verify.h
+++ b/contrib/ldns/ldns/dnssec_verify.h
@@ -592,7 +592,7 @@ ldns_status ldns_dnssec_verify_denial_nsec3(ldns_rr *rr,
  * \param[in] packet_qtype The original query RR type
  * \param[in] packet_nodata True if the providing packet had an empty ANSWER
  *                          section
- * \param[in] match On match, the given (reference to a) pointer will be set 
+ * \param[out] match On match, the given (reference to a) pointer will be set 
  *                  to point to the matching nsec resource record.
  * \return LDNS_STATUS_OK if the NSEC3 RRs deny the existence, error code
  *                        containing the reason they do not otherwise
diff --git a/contrib/ldns/ldns/dnssec_zone.h b/contrib/ldns/ldns/dnssec_zone.h
index e97ea30c60..156e391023 100644
--- a/contrib/ldns/ldns/dnssec_zone.h
+++ b/contrib/ldns/ldns/dnssec_zone.h
@@ -53,7 +53,7 @@ struct ldns_struct_dnssec_name
 	 * Usually, the name is a pointer to the owner name of the first rr for
 	 * this name, but sometimes there is no actual data to point to, 
 	 * for instance in
-	 * names representing empty nonterminals. If so, set alloced to true to
+	 * names representing empty nonterminals. If so, set name_alloced to true to
 	 * indicate that this data must also be freed when the name is freed
 	 */
 	bool name_alloced;
@@ -93,7 +93,7 @@ struct ldns_struct_dnssec_zone {
 	ldns_dnssec_name *soa;
 	/** tree of ldns_dnssec_names */
 	ldns_rbtree_t *names;
-	/** tree of ldns_dnssec_names by nsec3 hashes (when applicible) */
+	/** tree of ldns_dnssec_names by nsec3 hashes (when applicable) */
 	ldns_rbtree_t *hashed_names;
 	/** points to the first added NSEC3 rr whose parameters will be 
 	 *  assumed for all subsequent NSEC3 rr's and which will be used
@@ -204,7 +204,7 @@ ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
 ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr);
 
 /**
- * Print the given list of rrsets to the fiven file descriptor
+ * Print the given list of rrsets to the given file descriptor
  * 
  * \param[in] out the file descriptor to print to
  * \param[in] rrsets the list of RRsets to print
@@ -215,7 +215,7 @@ void ldns_dnssec_rrsets_print(FILE *out,
 		bool follow);
 
 /**
- * Print the given list of rrsets to the fiven file descriptor
+ * Print the given list of rrsets to the given file descriptor
  * 
  * \param[in] out the file descriptor to print to
  * \param[in] fmt the format of the textual representation
@@ -297,12 +297,12 @@ void ldns_dnssec_name_set_nsec(ldns_dnssec_name *name, ldns_rr *nsec);
 
 /**
  * Compares the domain names of the two arguments in their
- * canonical ordening.
+ * canonical ordering.
  * 
  * \param[in] a The first dnssec_name to compare
  * \param[in] b The second dnssec_name to compare
  * \return -1 if the domain name of a comes before that of b in canonical
- *            ordening, 1 if it is the other way around, and 0 if they are
+ *            ordering, 1 if it is the other way around, and 0 if they are
  *            equal
  */
 int ldns_dnssec_name_cmp(const void *a, const void *b);
@@ -476,6 +476,8 @@ ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone);
  */
 bool ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone);
 
+ldns_status ldns_dnssec_zone_verify_zonemd(ldns_dnssec_zone *zone);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/contrib/ldns/ldns/edns.h b/contrib/ldns/ldns/edns.h
new file mode 100644
index 0000000000..594fda22f7
--- /dev/null
+++ b/contrib/ldns/ldns/edns.h
@@ -0,0 +1,272 @@
+/*
+ * edns.h
+ *
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2022
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_EDNS_H
+#define LDNS_EDNS_H
+
+#include <ldns/common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * EDNS option codes
+ */
+enum ldns_enum_edns_option
+{
+	LDNS_EDNS_LLQ = 1, /* RFC8764 */
+	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, /* RFC7871 */
+	LDNS_EDNS_EXPIRE = 9, /* RFC7314 */
+	LDNS_EDNS_COOKIE = 10, /* RFC7873 */
+	LDNS_EDNS_KEEPALIVE = 11, /* RFC7828*/
+	LDNS_EDNS_PADDING = 12, /* RFC7830 */
+	LDNS_EDNS_CHAIN = 13, /* RFC7901 */
+	LDNS_EDNS_KEY_TAG = 14, /* RFC8145 */
+	LDNS_EDNS_EDE = 15, /* RFC8914 */
+	LDNS_EDNS_CLIENT_TAG = 16, /* draft-bellis-dnsop-edns-tags-01 */
+	LDNS_EDNS_SERVER_TAG = 17 /* draft-bellis-dnsop-edns-tags-01 */
+};
+typedef enum ldns_enum_edns_option ldns_edns_option_code;
+
+/**
+ * Extended DNS Error (RFC 8914) codes
+ */
+enum ldns_edns_enum_ede_code
+{
+	LDNS_EDE_OTHER = 0,
+	LDNS_EDE_UNSUPPORTED_DNSKEY_ALG = 1,
+	LDNS_EDE_UNSUPPORTED_DS_DIGEST = 2,
+	LDNS_EDE_STALE_ANSWER = 3,
+	LDNS_EDE_FORGED_ANSWER = 4,
+	LDNS_EDE_DNSSEC_INDETERMINATE = 5,
+	LDNS_EDE_DNSSEC_BOGUS = 6,
+	LDNS_EDE_SIGNATURE_EXPIRED = 7,
+	LDNS_EDE_SIGNATURE_NOT_YET_VALID = 8,
+	LDNS_EDE_DNSKEY_MISSING = 9,
+	LDNS_EDE_RRSIGS_MISSING = 10,
+	LDNS_EDE_NO_ZONE_KEY_BIT_SET = 11,
+	LDNS_EDE_NSEC_MISSING = 12,
+	LDNS_EDE_CACHED_ERROR = 13,
+	LDNS_EDE_NOT_READY = 14,
+	LDNS_EDE_BLOCKED = 15,
+	LDNS_EDE_CENSORED = 16,
+	LDNS_EDE_FILTERED = 17,
+	LDNS_EDE_PROHIBITED = 18,
+	LDNS_EDE_STALE_NXDOMAIN_ANSWER = 19,
+	LDNS_EDE_NOT_AUTHORITATIVE = 20,
+	LDNS_EDE_NOT_SUPPORTED = 21,
+	LDNS_EDE_NO_REACHABLE_AUTHORITY = 22,
+	LDNS_EDE_NETWORK_ERROR = 23,
+	LDNS_EDE_INVALID_DATA = 24,
+	LDNS_EDE_SIGNATURE_EXPIRED_BEFORE_VALID = 25,
+	LDNS_EDE_TOO_EARLY = 26
+};
+typedef enum ldns_edns_enum_ede_code ldns_edns_ede_code;
+
+/**
+ * The struct that stores an ordered EDNS option.
+ * An EDNS option is structed as follows:
+  +0 (MSB)                            +1 (LSB)
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  0: |                          OPTION-CODE                          |
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  2: |                         OPTION-LENGTH                         |
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+  4: |                                                               |
+     /                          OPTION-DATA                          /
+     /                                                               /
+     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ */
+struct ldns_struct_edns_option {
+	ldns_edns_option_code _code;
+	size_t                _size;
+	void                 *_data;
+};
+typedef struct ldns_struct_edns_option ldns_edns_option;
+
+
+/* 
+ * Array structure to store multiple EDNS options
+ */
+struct ldns_struct_edns_option_list
+{
+	size_t _option_count; /* the number of EDNS options in the list */
+   size_t _option_capacity; /* the amount of options that fit into the list */
+	size_t _options_size; /* the total size of the options serialized */
+	ldns_edns_option **_options;
+};
+typedef struct ldns_struct_edns_option_list ldns_edns_option_list;
+
+/*
+ * Access functions 
+ * do this as functions to get type checking
+ */
+
+/**
+ * returns the size of the EDNS data.
+ * \param[in] *edns the EDNS struct to read from
+ * \return uint16_t with the size
+ */
+size_t ldns_edns_get_size(const ldns_edns_option *edns);
+
+/**
+ * returns the option code of the EDNS data.
+ * \param[in] *edns the EDNS struct to read from
+ * \return uint16_t with the size
+ */
+ldns_edns_option_code ldns_edns_get_code(const ldns_edns_option *edns);
+
+/**
+ * returns the EDNS option data.
+ * \param[in] *edns the EDNS option to read from
+ * \return uint8_t* pointer to the EDNS option's data
+ */
+uint8_t *ldns_edns_get_data(const ldns_edns_option *edns);
+
+
+/**
+ * serialise the EDNS option into wireformat.
+ * \param[in] *edns the EDNS option to read from
+ * \return ldns_buffer* the buffer containing the data
+ */
+ldns_buffer *ldns_edns_get_wireformat_buffer(const ldns_edns_option *edns);
+
+/* Constructors and destructors*/
+
+/**
+ * allocates a new EDNS structure and fills it. This function *DOES NOT* copy
+ * the contents from the data parameter.
+ * \param[in] code the EDNS code
+ * \param[in] size size of the buffer
+ * \param[in] data pointer to the buffer to be assigned
+ * \return the new EDNS structure or NULL on failure
+ */
+ldns_edns_option *ldns_edns_new(ldns_edns_option_code code, size_t size, void *data);
+
+/**
+ * allocates a new EDNS structure and fills it. This function *DOES* copy
+ * the contents from the data parameter.
+ * \param[in] code the EDNS code
+ * \param[in] size size of the buffer
+ * \param[in] data pointer to the buffer to be assigned
+ * \return the new EDNS structure or NULL on failure
+ */
+ldns_edns_option *ldns_edns_new_from_data(ldns_edns_option_code code, size_t size, const void *data);
+
+/**
+ * clone an EDNS option
+ * \param[in] edns the EDNS option
+ * \return the new EDNS structure
+ */
+ldns_edns_option *ldns_edns_clone(ldns_edns_option *edns);
+
+/**
+ * free the EDNS option. Use deep_free if the _data member is allocated.
+ * \param[in] edns the EDNS option to free
+ */
+void ldns_edns_deep_free(ldns_edns_option *edns);
+void ldns_edns_free(ldns_edns_option *edns);
+
+/**
+ * allocates space for a new list of EDNS options
+ * \return the new EDNS option list or NULL on failure
+ */
+ldns_edns_option_list* ldns_edns_option_list_new(void);
+
+/**
+ * clone the EDNS options list and it's contents
+ * \param[in] options_list  the EDNS options_list to read from
+ * \return the new EDNS option list
+ */
+ldns_edns_option_list *ldns_edns_option_list_clone(ldns_edns_option_list *options_list);
+
+/**
+ * free the EDNS option list. Use deep_free to free the options options
+ * in the list as well.
+ * \param[in] options_list the EDNS option to free
+ */
+void ldns_edns_option_list_free(ldns_edns_option_list *options_list);
+void ldns_edns_option_list_deep_free(ldns_edns_option_list *options_list);
+
+/* edns_option_list functions */
+
+/**
+ * returns the number of options in the EDNS options list.
+ * \param[in] options_list  the EDNS options_list to read from
+ * \return the number of EDNS options
+ */
+size_t ldns_edns_option_list_get_count(const ldns_edns_option_list *options_list);
+
+/**
+ * returns the EDNS option as the specified index in the list of EDNS options.
+ * \param[in] options_list  the EDNS options_list to read from
+ * \param[in] index         the location of the EDNS option to get in the list
+ * \return the EDNS option located at the index or NULL on failure
+ */
+ldns_edns_option* ldns_edns_option_list_get_option(const ldns_edns_option_list *options_list,
+	size_t index);
+
+
+/**
+ * returns the total size of all the individual EDNS options in the EDNS list.
+ * \param[in] options_list  the EDNS options_list to read from
+ * \return the total size of the options combined
+ */
+size_t ldns_edns_option_list_get_options_size(const ldns_edns_option_list *options_list);
+
+/**
+ * adds an EDNS option to the list of options at the specified index. Also
+ * returns the option that was previously at that index.
+ * \param[in] options_list  the EDNS options_list to add to
+ * \param[in] option        the EDNS option to add to the list
+ * \param[in] index         the index in the list where to set the option
+ * \return the EDNS option previously located at the index
+ */
+ldns_edns_option *ldns_edns_option_list_set_option(ldns_edns_option_list *options_list,
+	ldns_edns_option *option, size_t index);
+
+/**
+ * adds an EDNS option at the end of the list of options.
+ * \param[in] options_list  the EDNS options_list to add to
+ * \param[in] option        the (non-NULL) EDNS option to add to the list
+ * \return true on success and false of failure
+ */
+bool ldns_edns_option_list_push(ldns_edns_option_list *options_list,
+	ldns_edns_option *option);
+
+/**
+ * removes and returns the EDNS option at the end of the list of options.
+ * \param[in] options_list  the EDNS options_list to add to
+ * \return the EDNS option at the end of the list, or NULL on failure
+ */
+ldns_edns_option* ldns_edns_option_list_pop(ldns_edns_option_list *options_list);
+
+/**
+ * serializes all the EDNS options into a single wireformat buffer
+ * \param[in] option_list  the EDNS options_list to combine into one wireformat
+ * \return the filled buffer or NULL on failure
+ */
+ldns_buffer *ldns_edns_option_list2wireformat_buffer(const ldns_edns_option_list *option_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_EDNS_H */
diff --git a/contrib/ldns/ldns/error.h b/contrib/ldns/ldns/error.h
index 15f49a28e1..2429b7703d 100644
--- a/contrib/ldns/ldns/error.h
+++ b/contrib/ldns/ldns/error.h
@@ -129,7 +129,19 @@ enum ldns_enum_status {
 	LDNS_STATUS_RDATA_OVERFLOW,
 	LDNS_STATUS_SYNTAX_SUPERFLUOUS_TEXT_ERR,
 	LDNS_STATUS_NSEC3_DOMAINNAME_OVERFLOW,
-	LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA
+	LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA,
+	LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE,
+	LDNS_STATUS_ZONEMD_UNKNOWN_SCHEME,
+	LDNS_STATUS_ZONEMD_UNKNOWN_HASH,
+	LDNS_STATUS_ZONEMD_INVALID_SOA,
+	LDNS_STATUS_NO_ZONEMD,
+	LDNS_STATUS_NO_VALID_ZONEMD,
+	LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR,
+	LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR,
+	LDNS_STATUS_RESERVED_SVCPARAM_KEY,
+	LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED,
+	LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE,
+	LDNS_STATUS_INVALID_SVCPARAM_VALUE
 };
 typedef enum ldns_enum_status ldns_status;
 
diff --git a/contrib/ldns/ldns/host2str.h b/contrib/ldns/ldns/host2str.h
index 4b443d05f4..79f5561a94 100644
--- a/contrib/ldns/ldns/host2str.h
+++ b/contrib/ldns/ldns/host2str.h
@@ -65,6 +65,8 @@ extern "C" {
 #define LDNS_FMT_ZEROIZE_RRSIGS		(1 <<  9)
 #define LDNS_FMT_PAD_SOA_SERIAL		(1 << 10)
 #define LDNS_FMT_RFC3597		(1 << 11)	/* yes */
+/** Prints only answer section of packets and only rdata of RRs **/
+#define LDNS_FMT_SHORT			(1 << 12)
 
 #define LDNS_FMT_FLAGS_WITH_DATA			    2
 
@@ -76,11 +78,11 @@ extern "C" {
 /**
  * Output format specifier
  *
- * Determines how Packets, Resource Records and Resource record data fiels are
+ * Determines how Packets, Resource Records and Resource record data field are
  * formatted when printing or converting to string.
  * Currently it is only used to specify what aspects of a Resource Record are
  * annotated in the comment section of the textual representation the record.
- * This is speciefed with flags and potential exra data (such as for example
+ * This is specified with flags and potential extra data (such as for example
  * a lookup map of hashes to real names for annotation NSEC3 records).
  */
 struct ldns_struct_output_format
@@ -110,7 +112,7 @@ typedef struct ldns_struct_output_format_storage ldns_output_format_storage;
  */
 extern const ldns_output_format *ldns_output_format_nocomments;
 /**
- * Standard output format record that annotated only DNSKEY RR's with commenti
+ * Standard output format record that annotated only DNSKEY RR's with comment
  * text.
  */
 extern const ldns_output_format *ldns_output_format_onlykeyids;
@@ -513,6 +515,17 @@ ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output,
  */
 ldns_status ldns_pkt2buffer_str(ldns_buffer *output, const ldns_pkt *pkt);
 
+/**
+ * Converts the list of EDNS options to presentation
+ * format (as char *) and appends it to the given buffer
+ *
+ * \param[in] output pointer to the buffer to append the data to
+ * \param[in] edns_list the list of EDNS options
+ * \return status
+ */
+ldns_status ldns_edns_option_list2buffer_str(ldns_buffer *output,
+        ldns_edns_option_list* edns_list);
+
 /**
  * Converts the data in the DNS packet to presentation
  * format (as char *) and appends it to the given buffer
@@ -646,6 +659,14 @@ ldns_status ldns_rdf2buffer_str_hip(ldns_buffer *output,
 ldns_status ldns_rdf2buffer_str_amtrelay(ldns_buffer *output,
 		const ldns_rdf *rdf);
 
+/** 
+ * Converts an LDNS_RDF_TYPE_SVCPARAMS rdata element to presentation format.
+ * \param[in] *rdf The rdata to convert
+ * \param[in] *output The buffer to add the data to
+ * \return LDNS_STATUS_OK on success, and error status on failure
+ */
+ldns_status ldns_rdf2buffer_str_svcparams(ldns_buffer *output,
+		const ldns_rdf *rdf);
 
 /**
  * Converts the data in the rdata field to presentation format and
diff --git a/contrib/ldns/ldns/host2wire.h b/contrib/ldns/ldns/host2wire.h
index 94693cda36..4378f3366f 100644
--- a/contrib/ldns/ldns/host2wire.h
+++ b/contrib/ldns/ldns/host2wire.h
@@ -130,7 +130,7 @@ ldns_status ldns_rrsig2buffer_wire(ldns_buffer *output, const ldns_rr *sigrr);
  * Converts an rr's rdata to wireformat, while excluding
  * the ownername and all the stuff before the rdata.
  * This is needed in DNSSEC keytag calculation, the ds
- * calcalution from the key and maybe elsewhere.
+ * calculation from the key and maybe elsewhere.
  *
  * \param[out] *output buffer where to put the result
  * \param[in] *rr rr to operate on
@@ -146,6 +146,15 @@ ldns_status ldns_rr_rdata2buffer_wire(ldns_buffer *output, const ldns_rr *rr);
  */
 ldns_status ldns_pkt2buffer_wire(ldns_buffer *output, const ldns_pkt *pkt);
 
+/**
+ * Copies the packet data to the buffer in wire format
+ * \param[out] *output buffer to append the result to
+ * \param[in] *pkt packet to convert
+ * \param[out] *compression_data data structure holding state for compression
+ * \return ldns_status
+ */
+ldns_status ldns_pkt2buffer_wire_compress(ldns_buffer *output, const ldns_pkt *pkt, ldns_rbtree_t *compression_data);
+
 /**
  * Copies the rr_list data to the buffer in wire format
  * \param[out] *output buffer to append the result to
@@ -187,6 +196,10 @@ ldns_status ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t
  * given packet in that array. The result_size value contains the
  * length of the array, if it succeeds, and 0 otherwise (in which case
  * the function also returns NULL)
+ *
+ * \param[out] dest pointer to the array of bytes to be created
+ * \param[in] p the packet to convert
+ * \param[out] size the size of the converted result
  */
 ldns_status ldns_pkt2wire(uint8_t **dest, const ldns_pkt *p, size_t *size);
 
diff --git a/contrib/ldns/ldns/keys.h b/contrib/ldns/ldns/keys.h
index df4bb22b26..847825e533 100644
--- a/contrib/ldns/ldns/keys.h
+++ b/contrib/ldns/ldns/keys.h
@@ -55,16 +55,8 @@ enum ldns_enum_algorithm
         LDNS_ECC_GOST           = 12,  /* RFC 5933 */
         LDNS_ECDSAP256SHA256    = 13,  /* RFC 6605 */
         LDNS_ECDSAP384SHA384    = 14,  /* RFC 6605 */
-#ifdef USE_ED25519
-	/* this ifdef is internal to ldns, because we do not want to export
-	 * the symbol.  Users can define it if they want access,
-	 * the feature is not fully implemented at this time and openssl
-	 * does not support it fully either (also for ED448). */
-	LDNS_ED25519		= 15,  /* draft-ietf-curdle-dnskey-ed25519 */
-#endif
-#ifdef USE_ED448
-	LDNS_ED448		= 16,  /* draft-ietf-curdle-dnskey-ed448 */
-#endif
+	LDNS_ED25519		= 15,  /* RFC 8080 */
+	LDNS_ED448		= 16,  /* RFC 8080 */
         LDNS_INDIRECT           = 252,
         LDNS_PRIVATEDNS         = 253,
         LDNS_PRIVATEOID         = 254
@@ -90,20 +82,24 @@ enum ldns_enum_signing_algorithm
 {
 	LDNS_SIGN_RSAMD5	 = LDNS_RSAMD5,
 	LDNS_SIGN_RSASHA1	 = LDNS_RSASHA1,
+#if LDNS_BUILD_CONFIG_USE_DSA
 	LDNS_SIGN_DSA		 = LDNS_DSA,
+#endif /* LDNS_BUILD_CONFIG_USE_DSA */
 	LDNS_SIGN_RSASHA1_NSEC3  = LDNS_RSASHA1_NSEC3,
 	LDNS_SIGN_RSASHA256	 = LDNS_RSASHA256,
 	LDNS_SIGN_RSASHA512	 = LDNS_RSASHA512,
+#if LDNS_BUILD_CONFIG_USE_DSA
 	LDNS_SIGN_DSA_NSEC3	 = LDNS_DSA_NSEC3,
+#endif /* LDNS_BUILD_CONFIG_USE_DSA */
 	LDNS_SIGN_ECC_GOST       = LDNS_ECC_GOST,
         LDNS_SIGN_ECDSAP256SHA256 = LDNS_ECDSAP256SHA256,
         LDNS_SIGN_ECDSAP384SHA384 = LDNS_ECDSAP384SHA384,
-#ifdef USE_ED25519
+#if LDNS_BUILD_CONFIG_USE_ED25519
 	LDNS_SIGN_ED25519	 = LDNS_ED25519,
-#endif
-#ifdef USE_ED448
+#endif /* LDNS_BUILD_CONFIG_USE_ED25519 */
+#if LDNS_BUILD_CONFIG_USE_ED448
 	LDNS_SIGN_ED448		 = LDNS_ED448,
-#endif
+#endif /* LDNS_BUILD_CONFIG_USE_ED448 */
 	LDNS_SIGN_HMACMD5	 = 157,	/* not official! This type is for TSIG, not DNSSEC */
 	LDNS_SIGN_HMACSHA1	 = 158,	/* not official! This type is for TSIG, not DNSSEC */
 	LDNS_SIGN_HMACSHA256 = 159,  /* ditto */
@@ -231,8 +227,14 @@ ldns_status ldns_key_new_frm_fp_l(ldns_key **k, FILE *fp, int *line_nr);
 /**
  * Read the key with the given id from the given engine and store it
  * in the given ldns_key structure. The algorithm type is set
+ * 
+ * \param[out] key the new ldns_key structure
+ * \param[in] e the engine from which to read the key
+ * \param[in] key_id the id of the key with which to lookup the key in the engine
+ * \param[in] a the algorithm to set for this key
+ * \return an error or LDNS_STATUS_OK
  */
-ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm);
+ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm a);
 
 
 /**
@@ -242,9 +244,7 @@ ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldn
  * \return NULL on failure otherwise a RSA structure
  */
 RSA *ldns_key_new_frm_fp_rsa(FILE *fp);
-#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
-#if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * frm_fp helper function. This function parses the
  * remainder of the (RSA) priv. key file generated from bind9
@@ -253,9 +253,9 @@ RSA *ldns_key_new_frm_fp_rsa(FILE *fp);
  * \return NULL on failure otherwise a RSA structure
  */
 RSA *ldns_key_new_frm_fp_rsa_l(FILE *fp, int *line_nr);
-#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
-#if LDNS_BUILD_CONFIG_HAVE_SSL
+
+# if LDNS_BUILD_CONFIG_USE_DSA
 /**
  * frm_fp helper function. This function parses the
  * remainder of the (DSA) priv. key file
@@ -263,9 +263,7 @@ RSA *ldns_key_new_frm_fp_rsa_l(FILE *fp, int *line_nr);
  * \return NULL on failure otherwise a RSA structure
  */
 DSA *ldns_key_new_frm_fp_dsa(FILE *fp);
-#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
-#if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * frm_fp helper function. This function parses the
  * remainder of the (DSA) priv. key file
@@ -274,9 +272,8 @@ DSA *ldns_key_new_frm_fp_dsa(FILE *fp);
  * \return NULL on failure otherwise a RSA structure
  */
 DSA *ldns_key_new_frm_fp_dsa_l(FILE *fp, int *line_nr);
-#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+# endif /* LDNS_BUILD_CONFIG_USE_DSA */
 
-#if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * frm_fp helper function. This function parses the
  * remainder of the (HMAC-MD5) key file
@@ -286,9 +283,7 @@ DSA *ldns_key_new_frm_fp_dsa_l(FILE *fp, int *line_nr);
  * \return NULL on failure otherwise a newly allocated char buffer
  */
 unsigned char *ldns_key_new_frm_fp_hmac(FILE *fp, size_t *hmac_size);
-#endif
 
-#if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * frm_fp helper function. This function parses the
  * remainder of the (HMAC-MD5) key file
@@ -301,13 +296,14 @@ unsigned char *ldns_key_new_frm_fp_hmac(FILE *fp, size_t *hmac_size);
 unsigned char *ldns_key_new_frm_fp_hmac_l(FILE *fp, int *line_nr, size_t *hmac_size);
 #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
-/* acces write functions */
+/* access write functions */
 /**
  * Set the key's algorithm
  * \param[in] k the key
  * \param[in] l the algorithm
  */
 void ldns_key_set_algorithm(ldns_key *k, ldns_signing_algorithm l);
+
 #if LDNS_BUILD_CONFIG_HAVE_SSL
 /**
  * Set the key's evp key
@@ -324,6 +320,7 @@ void ldns_key_set_evp_key(ldns_key *k, EVP_PKEY *e);
  */
 void ldns_key_set_rsa_key(ldns_key *k, RSA *r);
 
+# if LDNS_BUILD_CONFIG_USE_DSA
 /**
  * Set the key's dsa data
  * The dsa data should be freed by the user.
@@ -331,6 +328,7 @@ void ldns_key_set_rsa_key(ldns_key *k, RSA *r);
  * \param[in] d the dsa data
  */
 void ldns_key_set_dsa_key(ldns_key *k, DSA *d);
+# endif /* LDNS_BUILD_CONFIG_USE_DSA */
 
 /**
  * Assign the key's rsa data
@@ -340,6 +338,7 @@ void ldns_key_set_dsa_key(ldns_key *k, DSA *d);
  */
 void ldns_key_assign_rsa_key(ldns_key *k, RSA *r);
 
+# if LDNS_BUILD_CONFIG_USE_DSA
 /**
  * Assign the key's dsa data
  * The dsa data will be freed automatically when the key is freed.
@@ -347,6 +346,7 @@ void ldns_key_assign_rsa_key(ldns_key *k, RSA *r);
  * \param[in] d the dsa data
  */
 void ldns_key_assign_dsa_key(ldns_key *k, DSA *d);
+# endif /* LDNS_BUILD_CONFIG_USE_DSA */
 
 /** 
  * Get the PKEY id for GOST, loads GOST into openssl as a side effect.
@@ -423,7 +423,7 @@ void ldns_key_set_flags(ldns_key *k, uint16_t flags);
 /**
  * Set the keylist's key count to count
  * \param[in] key the key
- * \param[in] count the cuont
+ * \param[in] count the count
  */
 void ldns_key_list_set_key_count(ldns_key_list *key, size_t count);
 
@@ -463,13 +463,13 @@ RSA *ldns_key_rsa_key(const ldns_key *k);
  * \return the RSA * structure in the key
  */
 EVP_PKEY *ldns_key_evp_key(const ldns_key *k);
-#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
+# if LDNS_BUILD_CONFIG_USE_DSA
 /**
  * returns the (openssl) DSA struct contained in the key
  */
-#if LDNS_BUILD_CONFIG_HAVE_SSL
 DSA *ldns_key_dsa_key(const ldns_key *k);
+# endif /* LDNS_BUILD_CONFIG_USE_DSA */
 #endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
 
 /**
@@ -523,7 +523,7 @@ uint32_t ldns_key_inception(const ldns_key *k);
 /**
  * return the key's expiration date
  * \param[in] k the key
- * \return the experiration date
+ * \return the expiration date
  */
 uint32_t ldns_key_expiration(const ldns_key *k);
 /**
diff --git a/contrib/ldns/ldns/ldns.h b/contrib/ldns/ldns/ldns.h
index 60663ef95c..9b0bc066b0 100644
--- a/contrib/ldns/ldns/ldns.h
+++ b/contrib/ldns/ldns/ldns.h
@@ -101,6 +101,7 @@ Or you can just use the menu above to browse through the API docs.
 #include <ldns/dnssec_verify.h>
 #include <ldns/dnssec_sign.h>
 #include <ldns/duration.h>
+#include <ldns/edns.h>
 #include <ldns/error.h>
 #include <ldns/higher.h>
 #include <ldns/host2str.h>
diff --git a/contrib/ldns/ldns/net.h b/contrib/ldns/ldns/net.h
index d074f20ace..0fbf1544d5 100644
--- a/contrib/ldns/ldns/net.h
+++ b/contrib/ldns/ldns/net.h
@@ -30,7 +30,7 @@ extern "C" {
  */
 
 /**
- * Sends a buffer to an ip using udp and return the respons as a ldns_pkt
+ * Sends a buffer to an ip using udp and return the response as a ldns_pkt
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] to the ip addr to send to
  * \param[in] tolen length of the ip addr
@@ -90,7 +90,7 @@ int ldns_tcp_bgsend2(ldns_buffer *qbin, const struct sockaddr_storage *to, sockl
 int ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
 
 /**
- * Sends a buffer to an ip using tcp and return the respons as a ldns_pkt
+ * Sends a buffer to an ip using tcp and return the response as a ldns_pkt
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] to the ip addr to send to
@@ -233,7 +233,7 @@ struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, u
  * returns an rdf with the sockaddr info. works for ip4 and ip6
  * \param[in] sock the struct sockaddr_storage to convert
  * \param[in] port what port was used. When NULL this is not set
- * \return ldns_rdf* wth the address
+ * \return ldns_rdf* with the address
  */
 ldns_rdf * ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port);
 
@@ -241,7 +241,7 @@ ldns_rdf * ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16
  * Prepares the resolver for an axfr query
  * The query is sent and the answers can be read with ldns_axfr_next
  * \param[in] resolver the resolver to use
- * \param[in] domain the domain to exfr
+ * \param[in] domain the domain to axfr
  * \param[in] c the class to use
  * \return ldns_status the status of the transfer
  */
diff --git a/contrib/ldns/ldns/packet.h b/contrib/ldns/ldns/packet.h
index 2e5ee8bde1..2c60609fc0 100644
--- a/contrib/ldns/ldns/packet.h
+++ b/contrib/ldns/ldns/packet.h
@@ -35,6 +35,7 @@
 #include <ldns/error.h>
 #include <ldns/common.h>
 #include <ldns/rr.h>
+#include <ldns/edns.h>
 #include <sys/time.h>
 
 #ifdef __cplusplus
@@ -251,12 +252,14 @@ struct ldns_struct_pkt
 	uint8_t _edns_extended_rcode;
 	/** EDNS Version */
 	uint8_t _edns_version;
-        /* OPT pseudo-RR presence flag */
-        uint8_t _edns_present;
+	/* OPT pseudo-RR presence flag */
+	uint8_t _edns_present;
 	/** Reserved EDNS data bits */
 	uint16_t _edns_z;
 	/** Arbitrary EDNS rdata */
 	ldns_rdf *_edns_data;
+	/** Structed EDNS data */
+	ldns_edns_option_list *_edns_list;
 	/**  Question section */
 	ldns_rr_list	*_question;
 	/**  Answer section */
@@ -355,9 +358,9 @@ bool ldns_pkt_ad(const ldns_pkt *p);
  */
 ldns_pkt_opcode ldns_pkt_get_opcode(const ldns_pkt *p);
 /**
- * Return the packet's respons code
+ * Return the packet's response code
  * \param[in] p the packet
- * \return the respons code
+ * \return the response code
  */
 ldns_pkt_rcode ldns_pkt_get_rcode(const ldns_pkt *p);
 /**
@@ -586,7 +589,7 @@ void ldns_pkt_set_ad(ldns_pkt *p, bool b);
  */
 void ldns_pkt_set_opcode(ldns_pkt *p, ldns_pkt_opcode c);
 /**
- * Set the packet's respons code
+ * Set the packet's response code
  * \param[in] p the packet
  * \param[in] c the rcode
  */
@@ -687,7 +690,7 @@ uint8_t ldns_pkt_edns_version(const ldns_pkt *packet);
  */
 uint16_t ldns_pkt_edns_z(const ldns_pkt *packet);
 /**
- * return the packet's edns data
+ * return the packet's EDNS data
  * \param[in] packet the packet
  * \return the data
  */
@@ -729,6 +732,16 @@ void ldns_pkt_set_edns_unassigned(ldns_pkt *packet, uint16_t value);
  */
 bool ldns_pkt_edns(const ldns_pkt *packet);
 
+/**
+ * Returns a list of structured EDNS options. The list will be automatically
+ * freed when the packet is freed. The option list can be manipulated and
+ * will be used when converting the packet to wireformat with ldns_pkt2wire.
+ *
+ * \param[in] packet the packet which contains the EDNS data
+ * \return the list of EDNS options
+ */
+ldns_edns_option_list* ldns_pkt_edns_get_option_list(ldns_pkt *packet);
+
 /**
  * Set the packet's edns udp size
  * \param[in] packet the packet
@@ -754,12 +767,20 @@ void ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v);
  */
 void ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z);
 /**
- * Set the packet's edns data
+ * Set the packet's EDNS data
  * \param[in] packet the packet
  * \param[in] data the data
  */
 void ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data);
 
+/**
+ * Set the packet's structured EDNS data. Once an edns_option_list is set 
+ * (or get), the option list will be used for converting into wireformat. 
+ * \param[in] packet the packet
+ * \param[in] list the options list that will create the data
+ */
+void ldns_pkt_set_edns_option_list(ldns_pkt *packet, ldns_edns_option_list *list);
+
 /**
  * allocates and initializes a ldns_pkt structure.
  * \return pointer to the new packet
@@ -849,7 +870,7 @@ void ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr);
 void ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr);
 
 /**
- * directly set the auhority section
+ * directly set the authority section
  * \param[in] p packet to operate on
  * \param[in] rr rrlist to set
  */
diff --git a/contrib/ldns/ldns/parse.h b/contrib/ldns/ldns/parse.h
index 0e9034c341..ba7edf5679 100644
--- a/contrib/ldns/ldns/parse.h
+++ b/contrib/ldns/ldns/parse.h
@@ -69,6 +69,32 @@ ssize_t ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit);
  */
 ssize_t ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr);
 
+/** 
+ * 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 this should be a reference to a string buffer in which
+ *                     the token is put. A new buffer will be allocated when
+ *                     *token is NULL and fixed is false. If the buffer is too
+ *                     small to hold the token, the buffer is reallocated with
+ *                     double the size (of limit).
+ *                     If fixed is true, the string buffer may not be NULL
+ *                     and limit must be set to the buffer size. In that case
+ *                     no reallocations will be done.
+ * \param[in,out] *limit reference to the size of the token buffer. Will be
+ *                       reset to the new limit of the token buffer if the
+ *                       buffer is reallocated.
+ * \param [in] fixed If fixed is false, the token buffer is allowed to grow
+ *                   when needed (by way of reallocation). If true, the token
+ *                   buffer will not be resized.
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return LDNS_STATUS_OK on success, LDNS_STATUS_SYNTAX_EMPTY when no token
+ *         was read and an error otherwise.
+ */
+ldns_status ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed, const char *delim, int *line_nr);
+
 /**
  * returns a token/char from the buffer b.
  * This function deals with ( and ) in the buffer,
@@ -86,9 +112,9 @@ ssize_t ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t l
  * 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[in] k_del keyword delimiter 
  * \param[out] data the data found 
- * \param[in] d_del the data delimeter
+ * \param[in] d_del the data delimiter
  * \param[in] data_limit maximum size the the data buffer
  * \return the number of character read
  */
@@ -99,9 +125,9 @@ ssize_t ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del,
  * 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[in] k_del keyword delimiter 
  * \param[out] data the data found 
- * \param[in] d_del the data delimeter
+ * \param[in] d_del the data delimiter
  * \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)
@@ -114,9 +140,9 @@ ssize_t ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del
  * 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[in] k_del keyword delimiter 
  * \param[out] data the data found 
- * \param[in] d_del the data delimeter
+ * \param[in] d_del the data delimiter
  * \param[in] data_limit maximum size the the data buffer
  * \return the number of character read
  */
diff --git a/contrib/ldns/ldns/radix.h b/contrib/ldns/ldns/radix.h
index ec70565a3c..4cb42b48ba 100644
--- a/contrib/ldns/ldns/radix.h
+++ b/contrib/ldns/ldns/radix.h
@@ -154,7 +154,7 @@ ldns_radix_node_t* ldns_radix_search(ldns_radix_t* tree, const uint8_t* key,
  * @param tree: tree to insert to.
  * @param key:  key.
  * @param len:  length of key.
- * @param result: the radix node with the exact or closest match. NULL if
+ * @param[out] result: the radix node with the exact or closest match. NULL if
  *                the key is smaller than the smallest key in the tree.
  * @return 1 if exact match, 0 otherwise.
  *
@@ -198,7 +198,7 @@ ldns_radix_node_t* ldns_radix_prev(ldns_radix_node_t* node);
  * Split radix tree intwo.
  * @param tree1: one tree.
  * @param num: number of elements to split off.
- * @param tree2: another tree.
+ * @param[out] tree2: another tree.
  * @return: status.
  *
  */
diff --git a/contrib/ldns/ldns/rbtree.h b/contrib/ldns/ldns/rbtree.h
index 0747a8e5b8..4cfaf38297 100644
--- a/contrib/ldns/ldns/rbtree.h
+++ b/contrib/ldns/ldns/rbtree.h
@@ -151,7 +151,7 @@ ldns_rbnode_t *ldns_rbtree_search(ldns_rbtree_t *rbtree, const void *key);
  * Find, but match does not have to be exact.
  * @param rbtree: tree to find in.
  * @param key: key to find position of.
- * @param result: set to the exact node if present, otherwise to element that
+ * @param[out] result: set to the exact node if present, otherwise to element that
  *   precedes the position of key in the tree. NULL if no smaller element.
  * @return: true if exact match in result. Else result points to <= element,
  * or NULL if key is smaller than the smallest key.
diff --git a/contrib/ldns/ldns/rdata.h b/contrib/ldns/ldns/rdata.h
index 2767e8b00b..c8a0396cfd 100644
--- a/contrib/ldns/ldns/rdata.h
+++ b/contrib/ldns/ldns/rdata.h
@@ -142,6 +142,9 @@ enum ldns_enum_rdf_type
 	/** draft-ietf-mboned-driad-amt-discovery **/
 	LDNS_RDF_TYPE_AMTRELAY,
 
+	/** draft-ietf-dnsop-svcb-https **/
+	LDNS_RDF_TYPE_SVCPARAMS,
+
 	/* Aliases */
 	LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC
 };
@@ -165,7 +168,23 @@ enum ldns_enum_cert_algorithm
 };
 typedef enum ldns_enum_cert_algorithm ldns_cert_algorithm;
 
-
+/**
+ * keys types in SVCPARAMS rdata fields
+ */
+enum ldns_enum_svcparam_key
+{
+	LDNS_SVCPARAM_KEY_MANDATORY		= 0,
+	LDNS_SVCPARAM_KEY_ALPN			= 1,
+	LDNS_SVCPARAM_KEY_NO_DEFAULT_ALPN	= 2,
+	LDNS_SVCPARAM_KEY_PORT			= 3,
+	LDNS_SVCPARAM_KEY_IPV4HINT		= 4,
+	LDNS_SVCPARAM_KEY_ECH			= 5,
+	LDNS_SVCPARAM_KEY_IPV6HINT		= 6,
+        LDNS_SVCPARAM_KEY_DOHPATH               = 7,
+	LDNS_SVCPARAM_KEY_LAST_KEY		= 7,
+	LDNS_SVCPARAM_KEY_RESERVED		= 65535
+};
+typedef	enum ldns_enum_svcparam_key ldns_svcparam_key;
 
 /**
  * Resource record data field.
@@ -243,7 +262,7 @@ uint8_t *ldns_rdf_data(const ldns_rdf *rd);
 /**
  * allocates a new rdf structure and fills it.
  * This function DOES NOT copy the contents from
- * the buffer, unlinke ldns_rdf_new_frm_data()
+ * the buffer, unlike ldns_rdf_new_frm_data()
  * \param[in] type type of the rdf
  * \param[in] size size of the buffer
  * \param[in] data pointer to the buffer to be copied
@@ -254,7 +273,7 @@ ldns_rdf *ldns_rdf_new(ldns_rdf_type type, size_t size, void *data);
 /**
  * allocates a new rdf structure and fills it.
  * This function _does_ copy the contents from
- * the buffer, unlinke ldns_rdf_new()
+ * the buffer, unlike ldns_rdf_new()
  * \param[in] type type of the rdf
  * \param[in] size size of the buffer
  * \param[in] data pointer to the buffer to be copied
diff --git a/contrib/ldns/ldns/resolver.h b/contrib/ldns/ldns/resolver.h
index 84128dfecf..e8459db7a3 100644
--- a/contrib/ldns/ldns/resolver.h
+++ b/contrib/ldns/ldns/resolver.h
@@ -250,7 +250,7 @@ bool ldns_resolver_dnssec_cd(const ldns_resolver *r);
 /**
  * Get the resolver's DNSSEC anchors
  * \param[in] r the resolver
- * \return an rr_list containg trusted DNSSEC anchors
+ * \return an rr_list containing trusted DNSSEC anchors
  */
 ldns_rr_list * ldns_resolver_dnssec_anchors(const ldns_resolver *r);
 /**
@@ -730,7 +730,7 @@ ldns_status ldns_resolver_new_frm_fp_l(ldns_resolver **r, FILE *fp, int *line_nr
 ldns_status ldns_resolver_new_frm_file(ldns_resolver **r, const char *filename);
 
 /**
- * Frees the allocated space for this resolver. Only frees the resolver pionter! You should probably be using _deep_free.
+ * Frees the allocated space for this resolver. Only frees the resolver pointer! You should probably be using _deep_free.
  * \param res resolver to free
  */
 void ldns_resolver_free(ldns_resolver *res);
@@ -766,7 +766,7 @@ bool ldns_axfr_complete(const ldns_resolver *resolver);
 
 /**
  * Returns a pointer to the last ldns_pkt that was sent by the server in the AXFR transfer
- * uasable for instance to get the error code on failure
+ * usable for instance to get the error code on failure
  * \param[in] res the resolver that was used in the axfr transfer
  * \return ldns_pkt the last packet sent
  */
diff --git a/contrib/ldns/ldns/rr.h b/contrib/ldns/ldns/rr.h
index 89cc0b6f00..44d54121f4 100644
--- a/contrib/ldns/ldns/rr.h
+++ b/contrib/ldns/ldns/rr.h
@@ -156,7 +156,7 @@ enum ldns_enum_rr_type
 	LDNS_RR_TYPE_DNAME = 39,
 	/**  dnsind-kitchen-sink-02.txt */
 	LDNS_RR_TYPE_SINK = 40,
-	/**  Pseudo OPT record... */
+	/**  OPT record RFC 6891 */
 	LDNS_RR_TYPE_OPT = 41,
 	/**  RFC3123 */
 	LDNS_RR_TYPE_APL = 42,
@@ -191,7 +191,9 @@ enum ldns_enum_rr_type
 	LDNS_RR_TYPE_CDNSKEY = 60, /* RFC 7344 */
 	LDNS_RR_TYPE_OPENPGPKEY = 61, /* RFC 7929 */
 	LDNS_RR_TYPE_CSYNC = 62, /* RFC 7477 */
-	LDNS_RR_TYPE_ZONEMD = 63, /* draft-wessels-dns-zone-digest */
+	LDNS_RR_TYPE_ZONEMD = 63, /* draft-ietf-dnsop-dns-zone-digest */
+	LDNS_RR_TYPE_SVCB = 64, /* draft-ietf-dnsop-svcb-https */
+	LDNS_RR_TYPE_HTTPS = 65, /* draft-ietf-dnsop-svcb-https */
 
 	LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */
 
@@ -525,7 +527,7 @@ void ldns_rr_set_class(ldns_rr *rr, ldns_rr_class rr_class);
  * \param[in] *rr the rr to operate on
  * \param[in] *f the rdf to set
  * \param[in] position the position the set the rdf
- * \return  the old value in the rr, NULL on failyre
+ * \return  the old value in the rr, NULL on failure
  */
 ldns_rdf* ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position);
 
@@ -815,7 +817,7 @@ int ldns_rr_compare_wire(const ldns_buffer *rr1_buf, const ldns_buffer *rr2_buf)
 bool ldns_rr_compare_ds(const ldns_rr *rr1, const ldns_rr *rr2);
 
 /**
- * compares two rr listss.
+ * compares two rr lists.
  * \param[in] rrl1 the first one
  * \param[in] rrl2 the second one
  * \return 0 if equal
diff --git a/contrib/ldns/ldns/rr_functions.h b/contrib/ldns/ldns/rr_functions.h
index 09a28dd7f8..5a84d40b13 100644
--- a/contrib/ldns/ldns/rr_functions.h
+++ b/contrib/ldns/ldns/rr_functions.h
@@ -121,9 +121,9 @@ bool ldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f);
  */
 ldns_rdf* ldns_rr_rrsig_expiration(const ldns_rr *r);
 /**
- * sets the expireation date of a LDNS_RR_TYPE_RRSIG rr
+ * sets the expiration date of a LDNS_RR_TYPE_RRSIG rr
  * \param[in] r the rr to use
- * \param[in] f the expireation date to set
+ * \param[in] f the expiration date to set
  * \return true on success, false otherwise
  */
 bool ldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f);
diff --git a/contrib/ldns/ldns/sha1.h b/contrib/ldns/ldns/sha1.h
index d5b1082e67..bc98411209 100644
--- a/contrib/ldns/ldns/sha1.h
+++ b/contrib/ldns/ldns/sha1.h
@@ -1,6 +1,13 @@
 #ifndef LDNS_SHA1_H
 #define LDNS_SHA1_H
 
+#include <stdint.h>  /* uint32_t and friends */
+#include <stddef.h>  /* size_t and NULL */
+
+#if LDNS_BUILD_CONFIG_HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -29,7 +36,7 @@ void ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ct
  *             available
  * \return the SHA1 digest of the given data
  */
-unsigned char *ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest);
+unsigned char *ldns_sha1(const unsigned char *data, unsigned int data_len, unsigned char *digest);
 
 #ifdef __cplusplus
 }
diff --git a/contrib/ldns/ldns/sha2.h b/contrib/ldns/ldns/sha2.h
index 238767af45..c3c1f1a096 100644
--- a/contrib/ldns/ldns/sha2.h
+++ b/contrib/ldns/ldns/sha2.h
@@ -46,23 +46,16 @@
 #ifndef __LDNS_SHA2_H__
 #define __LDNS_SHA2_H__
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * Import u_intXX_t size_t type definitions from system headers.  You
- * may need to change this, or define these things yourself in this
- * file.
- */
-#include <sys/types.h>
+#include <stdint.h>  /* uint32_t and friends */
+#include <stddef.h>  /* size_t and NULL */
 
 #if LDNS_BUILD_CONFIG_HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
 
-#include <inttypes.h>
-
-#endif /* LDNS_BUILD_CONFIG_HAVE_INTTYPES_H */
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 
 /*** SHA-256/384/512 Various Length Definitions ***********************/
@@ -116,7 +109,7 @@ void ldns_sha512_final(uint8_t[LDNS_SHA512_DIGEST_LENGTH], ldns_sha512_CTX*);
  *             available
  * \return the SHA1 digest of the given data
  */
-unsigned char *ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest);
+unsigned char *ldns_sha256(const unsigned char *data, unsigned int data_len, unsigned char *digest);
 
 /**
  * Convenience function to digest a fixed block of data at once.
@@ -128,7 +121,7 @@ unsigned char *ldns_sha256(unsigned char *data, unsigned int data_len, unsigned
  *             available
  * \return the SHA1 digest of the given data
  */
-unsigned char *ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest);
+unsigned char *ldns_sha384(const unsigned char *data, unsigned int data_len, unsigned char *digest);
 
 /**
  * Convenience function to digest a fixed block of data at once.
@@ -140,7 +133,7 @@ unsigned char *ldns_sha384(unsigned char *data, unsigned int data_len, unsigned
  *             available
  * \return the SHA1 digest of the given data
  */
-unsigned char *ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest);
+unsigned char *ldns_sha512(const unsigned char *data, unsigned int data_len, unsigned char *digest);
 
 #ifdef	__cplusplus
 }
diff --git a/contrib/ldns/ldns/str2host.h b/contrib/ldns/ldns/str2host.h
index e6f7004366..2892db0bfb 100644
--- a/contrib/ldns/ldns/str2host.h
+++ b/contrib/ldns/ldns/str2host.h
@@ -32,7 +32,7 @@ extern "C" {
 
 /**
  * convert a byte into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] bytestr the string to be converted
  * \return ldns_status
  */
@@ -40,7 +40,7 @@ ldns_status ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr);
 
 /**
  * convert a string to a int16 in wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] shortstr the string to be converted
  * \return ldns_status
  */
@@ -48,7 +48,7 @@ ldns_status ldns_str2rdf_int16(ldns_rdf **rd, const char *shortstr);
 
 /**
  * convert a strings into a 4 byte int in wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] longstr the string to be converted
  * \return ldns_status
  */
@@ -56,21 +56,21 @@ ldns_status ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr);
 
 /**
  * convert a time string to a time value in wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] time the string to be converted
  * \return ldns_status
  */
 ldns_status ldns_str2rdf_time(ldns_rdf **rd, const char *time);
 
 /* convert string with NSEC3 salt to wireformat) 
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * return ldns_status
  */
 ldns_status ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *nsec3_salt);
 
 /* convert a time period (think TTL's) to wireformat) 
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * return ldns_status
  */
@@ -78,7 +78,7 @@ ldns_status ldns_str2rdf_period(ldns_rdf **rd, const char *str);
 
 /**
  * convert str with an A record into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -86,7 +86,7 @@ ldns_status ldns_str2rdf_a(ldns_rdf **rd, const char *str);
 
 /**
  * convert the str with an AAAA record into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -94,7 +94,7 @@ ldns_status ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str);
 
 /**
  * convert a string into wireformat (think txt record)
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted (NULL terminated)
  * \return ldns_status
  */
@@ -102,7 +102,7 @@ ldns_status ldns_str2rdf_str(ldns_rdf **rd, const char *str);
 
 /**
  * convert str with the apl record into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -110,7 +110,7 @@ ldns_status ldns_str2rdf_apl(ldns_rdf **rd, const char *str);
 
 /**
  * convert the string with the b64 data into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -118,7 +118,7 @@ ldns_status ldns_str2rdf_b64(ldns_rdf **rd, const char *str);
 
 /**
  * convert the string with the b32 ext hex data into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -126,7 +126,7 @@ ldns_status ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str);
 
 /**
  * convert a hex value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -134,7 +134,7 @@ ldns_status ldns_str2rdf_hex(ldns_rdf **rd, const char *str);
 
 /**
  * convert string with nsec into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -142,7 +142,7 @@ ldns_status ldns_str2rdf_nsec(ldns_rdf **rd, const char *str);
 
 /**
  * convert a rrtype into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -150,7 +150,7 @@ ldns_status ldns_str2rdf_type(ldns_rdf **rd, const char *str);
 
 /**
  * convert string with a classname into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -158,7 +158,7 @@ ldns_status ldns_str2rdf_class(ldns_rdf **rd, const char *str);
 
 /**
  * convert an certificate algorithm value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -166,7 +166,7 @@ ldns_status ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str);
 
 /**
  * convert an algorithm value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -174,7 +174,7 @@ ldns_status ldns_str2rdf_alg(ldns_rdf **rd, const char *str);
 
 /**
  * convert a tlsa certificate usage value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -182,7 +182,7 @@ ldns_status ldns_str2rdf_certificate_usage(ldns_rdf **rd, const char *str);
 
 /**
  * convert a tlsa selector value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -190,7 +190,7 @@ ldns_status ldns_str2rdf_selector(ldns_rdf **rd, const char *str);
 
 /**
  * convert a tlsa matching type value into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -198,7 +198,7 @@ ldns_status ldns_str2rdf_matching_type(ldns_rdf **rd, const char *str);
 
 /**
  * convert a string with a unknown RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -206,7 +206,7 @@ ldns_status ldns_str2rdf_unknown(ldns_rdf **rd, const char *str);
 
 /**
  * convert string with a protocol service into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -214,7 +214,7 @@ ldns_status ldns_str2rdf_service(ldns_rdf **rd, const char *str);
 
 /**
  * convert a string with a LOC RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -222,7 +222,7 @@ ldns_status ldns_str2rdf_loc(ldns_rdf **rd, const char *str);
 
 /**
  * convert string with a WKS RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -230,7 +230,7 @@ ldns_status ldns_str2rdf_wks(ldns_rdf **rd, const char *str);
 
 /**
  * convert a str with a NSAP RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -238,7 +238,7 @@ ldns_status ldns_str2rdf_nsap(ldns_rdf **rd, const char *str);
 
 /**
  * convert a str with a ATMA RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -246,7 +246,7 @@ ldns_status ldns_str2rdf_atma(ldns_rdf **rd, const char *str);
 
 /**
  * convert a str with a IPSECKEY RR into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -254,7 +254,7 @@ ldns_status ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str);
 
 /**
  * convert a dname string into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -262,7 +262,7 @@ ldns_status ldns_str2rdf_dname(ldns_rdf **rd, const char *str);
 
 /**
  * convert 4 * 16bit hex separated by colons into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -270,7 +270,7 @@ ldns_status ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str);
 
 /**
  * convert 6 hex bytes separated by dashes into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -278,7 +278,7 @@ ldns_status ldns_str2rdf_eui48(ldns_rdf **rd, const char *str);
 
 /**
  * convert 8 hex bytes separated by dashes into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -286,7 +286,7 @@ ldns_status ldns_str2rdf_eui64(ldns_rdf **rd, const char *str);
 
 /**
  * Convert a non-zero sequence of US-ASCII letters and numbers into wireformat
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -295,7 +295,7 @@ ldns_status ldns_str2rdf_tag(ldns_rdf **rd, const char *str);
 /**
  * Convert a <character-string> encoding of the value field as specified 
  * [RFC1035], Section 5.1., encoded as one bug chunk of data.
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
@@ -305,23 +305,33 @@ ldns_status ldns_str2rdf_long_str(ldns_rdf **rd, const char *str);
  * Convert a "<algorithm> <hit> <pk>" encoding of the value field as specified 
  * in Section 6. of [RFC5205], encoded as wireformat as specified in Section 5.
  * of [RFC5205].
- * \param[in] rd the rdf where to put the data
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
 ldns_status ldns_str2rdf_hip(ldns_rdf **rd, const char *str);
 
 /**
- * Concert a"<precedence> <D-bit> <type> <relay>" encoding
+ * Convert a "<precedence> <D-bit> <type> <relay>" encoding
  * of the value field as specified in Section  4.3.1 of
  * [draft-ietf-mboned-driad-amt-discovery], encoded as wireformat as specified in
- * ection 4.2 of [draft-ietf-mboned-driad-amt-discovery]
- * \param[in] rd the rdf where to put the data
+ * Section 4.2 of [draft-ietf-mboned-driad-amt-discovery]
+ * \param[out] rd the rdf where to put the data
  * \param[in] str the string to be converted
  * \return ldns_status
  */
 ldns_status ldns_str2rdf_amtrelay(ldns_rdf **rd, const char *str);
 
+/**
+ * Convert a series of "key[=<value>]" encodings to wireformat as described in
+ * [draft-ietf-dnsop-svcb-https].
+ * \param[out] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_svcparams(ldns_rdf **rd, const char *str);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/contrib/ldns/ldns/util.h b/contrib/ldns/ldns/util.h
index 0e7ead89f1..1d8fa8836a 100644
--- a/contrib/ldns/ldns/util.h
+++ b/contrib/ldns/ldns/util.h
@@ -27,8 +27,8 @@ extern "C" {
 #define dprintf(X,Y) fprintf(stderr, (X), (Y))
 /* #define	dprintf(X, Y)  */
 
-#define LDNS_VERSION "1.7.1"
-#define LDNS_REVISION ((1<<16)|(7<<8)|(1))
+#define LDNS_VERSION "1.8.3"
+#define LDNS_REVISION ((1<<16)|(8<<8)|(3))
 
 /**
  * splint static inline workaround
@@ -274,19 +274,22 @@ time_t 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).
+ * with respect to now using serial arithmetics (rfc1982).
  * That number of seconds is then converted to broken-out time information.
  * This is especially useful 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.
+ *            to be interpreted as a serial arithmetics 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 * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+struct tm * ldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/* previously used wrong spelling */
+#define ldns_serial_arithmitics_gmtime_r ldns_serial_arithmetics_gmtime_r
  
 /**
  * Seed the random function.
diff --git a/contrib/ldns/ldns/wire2host.h b/contrib/ldns/ldns/wire2host.h
index 6a7999c31d..67b385c163 100644
--- a/contrib/ldns/ldns/wire2host.h
+++ b/contrib/ldns/ldns/wire2host.h
@@ -118,7 +118,7 @@ extern "C" {
  * This function will initialize and allocate memory space for the packet 
  * structure.
  * 
- * \param[in] packet pointer to the structure to hold the packet
+ * \param[out] packet pointer to the structure to hold the packet
  * \param[in] data pointer to the buffer with the data
  * \param[in] len the length of the data buffer (in bytes)
  * \return LDNS_STATUS_OK if everything succeeds, error otherwise
@@ -130,7 +130,7 @@ ldns_status ldns_wire2pkt(ldns_pkt **packet, const uint8_t *data, size_t len);
  * This function will initialize and allocate memory space for the packet 
  * structure.
  * 
- * \param[in] packet pointer to the structure to hold the packet
+ * \param[out] packet pointer to the structure to hold the packet
  * \param[in] buffer the buffer with the data
  * \return LDNS_STATUS_OK if everything succeeds, error otherwise
  */
@@ -142,7 +142,7 @@ ldns_status ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer);
  * space for the dname structure. The length of the wiredata of this rdf 
  * is added to the *pos value.
  *
- * \param[in] dname pointer to the structure to hold the rdata value
+ * \param[out] dname pointer to the structure to hold the rdata value
  * \param[in] wire pointer to the buffer with the data
  * \param[in] max the length of the data buffer (in bytes)
  * \param[in] pos the position of the rdf in the buffer (ie. the number of bytes 
@@ -177,7 +177,7 @@ ldns_status ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *
  * structure.
  * The length of the wiredata of this rr is added to the *pos value.
  * 
- * \param[in] rr pointer to the structure to hold the rdata value
+ * \param[out] rr pointer to the structure to hold the rdata value
  * \param[in] wire pointer to the buffer with the data
  * \param[in] max the length of the data buffer (in bytes)
  * \param[in] pos the position of the rr in the buffer (ie. the number of bytes 
diff --git a/contrib/ldns/ldns/zone.h b/contrib/ldns/ldns/zone.h
index f30d7c48cf..805661f878 100644
--- a/contrib/ldns/ldns/zone.h
+++ b/contrib/ldns/ldns/zone.h
@@ -97,7 +97,7 @@ void ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist);
  * copying, so the rr_list structure inside z is modified!
  * \param[in] z the zone to add to
  * \param[in] list the list to add
- * \return a true on succes otherwise falsed
+ * \return a true on success otherwise false
  */
 bool ldns_zone_push_rr_list(ldns_zone *z, const ldns_rr_list *list);
 
@@ -106,7 +106,7 @@ bool ldns_zone_push_rr_list(ldns_zone *z, const ldns_rr_list *list);
  * copying, so the rr_list structure inside z is modified!
  * \param[in] z the zone to add to
  * \param[in] rr the rr to add
- * \return a true on succes otherwise falsed
+ * \return a true on success otherwise false
  */
 bool ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr);
 
diff --git a/contrib/ldns/net.c b/contrib/ldns/net.c
index 38d00cffac..57d4dff24d 100644
--- a/contrib/ldns/net.c
+++ b/contrib/ldns/net.c
@@ -463,7 +463,7 @@ ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
 	}
 
         /* set to nonblocking, so if the checksum is bad, it becomes
-         * an EGAIN error and the ldns_udp_send function does not block,
+         * an EAGAIN error and the ldns_udp_send function does not block,
          * but returns a 'NETWORK_ERROR' much like a timeout. */
         ldns_sock_nonblock(sockfd);
 
diff --git a/contrib/ldns/packet.c b/contrib/ldns/packet.c
index a57e1901e0..afa59005c3 100644
--- a/contrib/ldns/packet.c
+++ b/contrib/ldns/packet.c
@@ -638,6 +638,15 @@ ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data)
 	packet->_edns_data = data;
 }
 
+void
+ldns_pkt_set_edns_option_list(ldns_pkt *packet, ldns_edns_option_list *list)
+{
+	if (packet->_edns_list)
+		ldns_edns_option_list_deep_free(packet->_edns_list);
+	packet->_edns_list = list;
+}
+
+
 void
 ldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count)
 {
@@ -738,15 +747,93 @@ ldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
 }
 
 bool
-ldns_pkt_edns(const ldns_pkt *pkt) {
+ldns_pkt_edns(const ldns_pkt *pkt)
+{
 	return (ldns_pkt_edns_udp_size(pkt) > 0 ||
 		ldns_pkt_edns_extended_rcode(pkt) > 0 ||
 		ldns_pkt_edns_data(pkt) ||
 		ldns_pkt_edns_do(pkt) ||
+		pkt->_edns_list ||
                 pkt->_edns_present
 	       );
 }
 
+ldns_edns_option_list*
+pkt_edns_data2edns_option_list(const ldns_rdf *edns_data)
+{
+	size_t pos = 0;
+	ldns_edns_option_list* edns_list;
+	size_t max;
+	const uint8_t* wire;
+
+	if (!edns_data)
+		return NULL;
+
+	max = ldns_rdf_size(edns_data);
+	wire = ldns_rdf_data(edns_data);
+	if (!max)
+		return NULL;
+
+	if (!(edns_list = ldns_edns_option_list_new()))
+		return NULL;
+
+	while (pos < max) {
+		ldns_edns_option* edns;
+		uint8_t *data;
+
+		if (pos + 4 > max) { /* make sure the header is  */
+			ldns_edns_option_list_deep_free(edns_list);
+			return NULL;
+		}
+		ldns_edns_option_code code = ldns_read_uint16(&wire[pos]);
+		size_t size = ldns_read_uint16(&wire[pos+2]);
+		pos += 4;
+
+		if (pos + size > max) { /* make sure the size fits the data */
+			ldns_edns_option_list_deep_free(edns_list);
+			return NULL;
+		}
+		data = LDNS_XMALLOC(uint8_t, size);
+
+		if (!data) {
+			ldns_edns_option_list_deep_free(edns_list);
+			return NULL;
+		}
+		memcpy(data, &wire[pos], size);
+		pos += size;
+
+		edns = ldns_edns_new(code, size, data);
+
+		if (!edns) {
+			ldns_edns_option_list_deep_free(edns_list);
+			return NULL;
+		}
+		if (!ldns_edns_option_list_push(edns_list, edns)) {
+			ldns_edns_option_list_deep_free(edns_list);
+			return NULL;
+		}
+	}
+	return edns_list;
+
+}
+
+ldns_edns_option_list*
+ldns_pkt_edns_get_option_list(ldns_pkt *packet)
+{
+	/* return the list if it already exists */
+	if (packet->_edns_list != NULL)
+		return packet->_edns_list;
+
+	/* if the list doesn't exists, we create it by parsing the
+	 * packet->_edns_data
+	 */
+	if (!ldns_pkt_edns_data(packet))
+		return NULL;
+
+	return ( packet->_edns_list
+	       = pkt_edns_data2edns_option_list(ldns_pkt_edns_data(packet)));
+}
+
 
 /* Create/destroy/convert functions
  */
@@ -796,8 +883,9 @@ ldns_pkt_new(void)
 	ldns_pkt_set_edns_version(packet, 0);
 	ldns_pkt_set_edns_z(packet, 0);
 	ldns_pkt_set_edns_data(packet, NULL);
+	packet->_edns_list = NULL;
 	packet->_edns_present = false;
-	
+
 	ldns_pkt_set_tsig(packet, NULL);
 	
 	return packet;
@@ -814,6 +902,7 @@ ldns_pkt_free(ldns_pkt *packet)
 		ldns_rr_list_deep_free(packet->_additional);
 		ldns_rr_free(packet->_tsig_rr);
 		ldns_rdf_deep_free(packet->_edns_data);
+		ldns_edns_option_list_deep_free(packet->_edns_list);
 		ldns_rdf_deep_free(packet->_answerfrom);
 		LDNS_FREE(packet);
 	}
@@ -1163,6 +1252,9 @@ ldns_pkt_clone(const ldns_pkt *pkt)
 		ldns_pkt_set_edns_data(new_pkt, 
 			ldns_rdf_clone(ldns_pkt_edns_data(pkt)));
 	ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt));
+	if (pkt->_edns_list)
+		ldns_pkt_set_edns_option_list(new_pkt,
+			ldns_edns_option_list_clone(pkt->_edns_list));
 
 	ldns_rr_list_deep_free(new_pkt->_question);
 	ldns_rr_list_deep_free(new_pkt->_answer);
diff --git a/contrib/ldns/parse.c b/contrib/ldns/parse.c
index 947dbb8984..9698ba71e8 100644
--- a/contrib/ldns/parse.c
+++ b/contrib/ldns/parse.c
@@ -27,31 +27,45 @@ ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
 	return ldns_fget_token_l(f, token, delim, limit, NULL);
 }
 
-ssize_t
-ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
+ldns_status
+ldns_fget_token_l_st(FILE *f, char **token, size_t *limit, bool fixed
+                    , const char *delim, int *line_nr)
 {
 	int c, prev_c;
-	int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+	int p; /* 0 -> no parentheses seen, >0 nr of ( seen */
 	int com, quoted;
-	char *t;
+	char *t, *old_token;
 	size_t i;
 	const char *d;
 	const char *del;
 
-	/* standard delimeters */
+	/* standard delimiters */
 	if (!delim) {
 		/* from isspace(3) */
 		del = LDNS_PARSE_NORMAL;
 	} else {
 		del = delim;
 	}
+	if (!token || !limit)
+		return LDNS_STATUS_NULL;
+
+	if (fixed) {
+		if (*token == NULL || *limit == 0)
+			return LDNS_STATUS_NULL;
 
+	} else if (*token == NULL) {
+		*limit = LDNS_MAX_LINELEN;
+		if (!(*token = LDNS_XMALLOC(char, *limit + 1)))
+			return LDNS_STATUS_MEM_ERR;
+
+	} else if (*limit == 0)
+		return LDNS_STATUS_ERR;
 	p = 0;
 	i = 0;
 	com = 0;
 	quoted = 0;
 	prev_c = 0;
-	t = token;
+	t = *token;
 	if (del[0] == '"') {
 		quoted = 1;
 	}
@@ -79,7 +93,8 @@ ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *li
 		if (p < 0) {
 			/* more ) then ( - close off the string */
 			*t = '\0';
-			return 0;
+			return i == 0 ? LDNS_STATUS_SYNTAX_EMPTY
+			              : LDNS_STATUS_OK;
 		}
 
 		/* do something with comments ; */
@@ -113,14 +128,27 @@ ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *li
 			continue;
 		}
 
-		if (c == '\n' && p != 0 && t > token) {
+		if (c == '\n' && p != 0 && t > *token) {
 			/* in parentheses */
 			if (line_nr) {
 				*line_nr = *line_nr + 1;
 			}
-			if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
-				*t = '\0';
-				return -1;
+			if (*limit > 0
+			&&  (i >= *limit || (size_t)(t - *token) >= *limit)) {
+				if (fixed) {
+					*t = '\0';
+					return LDNS_STATUS_SYNTAX_ERR;
+				}
+				old_token = *token;
+				*limit *= 2;
+				*token = LDNS_XREALLOC(*token, char, *limit + 1);
+				if (*token == NULL) {
+					*token = old_token;
+					*t = '\0';
+					return LDNS_STATUS_MEM_ERR;
+				}
+				if (*token != old_token)
+					t = *token + (t - old_token);
 			}
 			*t++ = ' ';
 			prev_c = c;
@@ -139,30 +167,42 @@ ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *li
 		if (c != '\0' && c != '\n') {
 			i++;
 		}
-		if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
-			*t = '\0';
-			return -1;
+		if (*limit > 0
+		&&  (i >= *limit || (size_t)(t - *token) >= *limit)) {
+			if (fixed) {
+				*t = '\0';
+				return LDNS_STATUS_SYNTAX_ERR;
+			}
+			old_token = *token;
+			*limit *= 2;
+			*token = LDNS_XREALLOC(*token, char, *limit + 1);
+			if (*token == NULL) {
+				*token = old_token;
+				*t = '\0';
+				return LDNS_STATUS_MEM_ERR;
+			}
+			if (*token != old_token)
+				t = *token + (t - old_token);
 		}
 		if (c != '\0' && c != '\n') {
 			*t++ = c;
 		}
+		if (c == '\n' && line_nr) {
+			*line_nr = *line_nr + 1;
+		}
 		if (c == '\\' && prev_c == '\\')
 			prev_c = 0;
 		else	prev_c = c;
 	}
 	*t = '\0';
 	if (c == EOF) {
-		return (ssize_t)i;
+		return i == 0 ? LDNS_STATUS_SYNTAX_EMPTY : LDNS_STATUS_OK;
 	}
 
-	if (i == 0) {
-		/* nothing read */
-		return -1;
-	}
 	if (p != 0) {
-		return -1;
+		return LDNS_STATUS_SYNTAX_ERR;
 	}
-	return (ssize_t)i;
+	return i == 0 ? LDNS_STATUS_SYNTAX_EMPTY : LDNS_STATUS_OK;
 
 tokenread:
 	if(*del == '"') /* do not skip over quotes, they are significant */
@@ -170,10 +210,21 @@ ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *li
 	else	ldns_fskipcs_l(f, del, line_nr);
 	*t = '\0';
 	if (p != 0) {
-		return -1;
+		return LDNS_STATUS_SYNTAX_ERR;
 	}
+	return i == 0 ? LDNS_STATUS_SYNTAX_EMPTY : LDNS_STATUS_OK;
+}
 
-	return (ssize_t)i;
+
+ssize_t
+ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
+{
+	if (limit == 0)
+		limit = LDNS_MAX_LINELEN;
+	if (ldns_fget_token_l_st(f, &token, &limit, true, delim, line_nr))
+		return -1;
+	else
+		return (ssize_t)strlen(token);
 }
 
 ssize_t
@@ -223,7 +274,7 @@ ssize_t
 ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit)
 {
 	int c, lc;
-	int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+	int p; /* 0 -> no parentheses seen, >0 nr of ( seen */
 	int com, quoted;
 	char *t;
 	size_t i;
diff --git a/contrib/ldns/rbtree.c b/contrib/ldns/rbtree.c
index 01ae9c7042..d43081a1b5 100644
--- a/contrib/ldns/rbtree.c
+++ b/contrib/ldns/rbtree.c
@@ -71,7 +71,7 @@ static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
 static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent);
 
 /*
- * Creates a new red black tree, intializes and returns a pointer to it.
+ * Creates a new red black tree, initializes and returns a pointer to it.
  *
  * Return NULL on failure.
  *
diff --git a/contrib/ldns/rdata.c b/contrib/ldns/rdata.c
index caf853d618..3f899a217e 100644
--- a/contrib/ldns/rdata.c
+++ b/contrib/ldns/rdata.c
@@ -363,6 +363,9 @@ ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
 	case LDNS_RDF_TYPE_AMTRELAY:
 		status = ldns_str2rdf_amtrelay(&rdf, str);
 		break;
+	case LDNS_RDF_TYPE_SVCPARAMS:
+		status = ldns_str2rdf_svcparams(&rdf, str);
+		break;
 	case LDNS_RDF_TYPE_NONE:
 	default:
 		/* default default ??? */
@@ -621,7 +624,7 @@ ldns_octet(char *word, size_t *length)
                         return LDNS_STATUS_DDD_OVERFLOW;
                     }
                 } else {
-                    /* an espaced character, like \<space> ? 
+                    /* an escaped character, like \<space> ? 
                     * remove the '\' keep the rest */
                     *p = *++s;
                     (*length)++;
diff --git a/contrib/ldns/resolver.c b/contrib/ldns/resolver.c
index 84dfe95ba0..f9ec65a559 100644
--- a/contrib/ldns/resolver.c
+++ b/contrib/ldns/resolver.c
@@ -780,7 +780,7 @@ ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
         if(!line_nr) line_nr = &lnr;
 
 	if(!fp) {
-		myfp = fopen("/etc/resolv.conf", "r");
+		myfp = fopen(LDNS_RESOLV_CONF, "r");
 		if(!myfp)
 			return LDNS_STATUS_FILE_ERR;
 	}
diff --git a/contrib/ldns/rr.c b/contrib/ldns/rr.c
index 6642aca775..95ab71d349 100644
--- a/contrib/ldns/rr.c
+++ b/contrib/ldns/rr.c
@@ -20,6 +20,12 @@
 #define LDNS_TTL_DATALEN    21
 #define LDNS_RRLIST_INIT    8
 
+#define _IS_WHITESPACE(chr) \
+    ( NULL != strchr( LDNS_PARSE_NO_NL, chr) )
+
+#define _BUFFER_IS_AT_WHITESPACE(rd_buf) \
+    _IS_WHITESPACE(*(ldns_buffer_current(rd_buf)))
+
 ldns_rr *
 ldns_rr_new(void)
 {
@@ -111,8 +117,9 @@ ldns_rdf_type_maybe_quoted(ldns_rdf_type rdf_type)
  */
 static ldns_status
 ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
-							 uint32_t default_ttl, const ldns_rdf *origin,
-							 ldns_rdf **prev, bool question)
+                             uint32_t default_ttl, const ldns_rdf *origin,
+                             ldns_rdf **prev, bool question,
+			     bool *explicit_ttl)
 {
 	ldns_rr *new;
 	const ldns_rr_descriptor *desc;
@@ -198,6 +205,9 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 		} else {
 			ttl_val = default_ttl;
 		}
+		if (explicit_ttl)
+			*explicit_ttl = false;
+
 		/* we not ASSUMING the TTL is missing and that
 		 * the rest of the RR is still there. That is
 		 * CLASS TYPE RDATA
@@ -217,6 +227,9 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 			strlcpy(type, ttl, type_sz);
 		}
 	} else {
+		if (explicit_ttl)
+			*explicit_ttl = true;
+
 		if (-1 == ldns_bget_token(
 				rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN)) {
 
@@ -259,7 +272,7 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 	}
 	ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata));
 
-	if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) {
+	if (strncmp(owner, "@", 1) == 0) {
 		if (origin) {
 			ldns_rr_set_owner(new, ldns_rdf_clone(origin));
 		} else if (prev && *prev) {
@@ -347,11 +360,12 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 		switch (ldns_rr_descriptor_field_type(desc, r_cnt)) {
 		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_NSEC       : /* tain whitespace, only if */
+		case LDNS_RDF_TYPE_LOC        : /* it is the last rd field. */
+		case LDNS_RDF_TYPE_WKS        :
 		case LDNS_RDF_TYPE_IPSECKEY   :
 		case LDNS_RDF_TYPE_AMTRELAY   :
-		case LDNS_RDF_TYPE_NSEC       :	if (r_cnt == r_max - 1) {
+		case LDNS_RDF_TYPE_SVCPARAMS  :	if (r_cnt == r_max - 1) {
 							delimiters = "\n";
 							break;
 						}
@@ -364,16 +378,19 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 				desc, r_cnt)) &&
 				ldns_buffer_remaining(rd_buf) > 0){
 
-			/* skip spaces */
-			while (*(ldns_buffer_current(rd_buf)) == ' ') {
+			/* skip whitespace */
+			while (ldns_buffer_remaining(rd_buf) > 0 &&
+				_BUFFER_IS_AT_WHITESPACE(rd_buf)) {
 				ldns_buffer_skip(rd_buf, 1);
 			}
 
-			if (*(ldns_buffer_current(rd_buf)) == '\"') {
+			if (ldns_buffer_remaining(rd_buf) > 0 &&
+				*(ldns_buffer_current(rd_buf)) == '\"') {
 				delimiters = "\"\0";
 				ldns_buffer_skip(rd_buf, 1);
 				quoted = true;
-			} else if (ldns_rr_descriptor_field_type(desc, r_cnt)
+			}
+			if (!quoted && ldns_rr_descriptor_field_type(desc, r_cnt)
 					== LDNS_RDF_TYPE_LONG_STR) {
 
 				status = LDNS_STATUS_SYNTAX_RDATA_ERR;
@@ -385,9 +402,9 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 		 * _maximum() only
 		 */
 
-		/* skip spaces */
+		/* skip whitespace */
 		while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf)
-				&& *(ldns_buffer_current(rd_buf)) == ' '
+				&& _BUFFER_IS_AT_WHITESPACE(rd_buf)
 				&& !quoted) {
 
 			ldns_buffer_skip(rd_buf, 1);
@@ -409,7 +426,7 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 
 		/* unknown RR data */
 		if (strncmp(rd, "\\#", 2) == 0 && !quoted &&
-				(rd_strlen == 2 || rd[2]==' ')) {
+				(rd_strlen == 2 || _IS_WHITESPACE(rd[2]))) {
 
 			was_unknown_rr_format = 1;
 			/* go back to before \#
@@ -579,10 +596,12 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 						    LDNS_RDF_TYPE_DNAME, ".")
 					    );
 
-				} else if (r && rd_strlen >= 1 && origin &&
-						!ldns_dname_str_absolute(rd)) {
+				} else if (r && rd_strlen >= 1
+				    && (origin || rr_type == LDNS_RR_TYPE_SOA)
+				    && !ldns_dname_str_absolute(rd)) {
 
-					status = ldns_dname_cat(r, origin);
+					status = ldns_dname_cat(r, origin
+					    ? origin : ldns_rr_owner(new));
 					if (status != LDNS_STATUS_OK) {
 						goto error;
 					}
@@ -600,14 +619,6 @@ ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
 			}
 			ldns_rr_push_rdf(new, r);
 		}
-		if (quoted) {
-			if (ldns_buffer_available(rd_buf, 1)) {
-				ldns_buffer_skip(rd_buf, 1);
-			} else {
-				done = true;
-			}
-		}
-
 	} /* for (done = false, r_cnt = 0; !done && r_cnt < r_max; r_cnt++) */
 	LDNS_FREE(rd);
 	LDNS_FREE(xtok);
@@ -671,7 +682,8 @@ ldns_rr_new_frm_str(ldns_rr **newrr, const char *str,
 	                                    default_ttl,
 	                                    origin,
 	                                    prev,
-	                                    false);
+	                                    false,
+					    NULL);
 }
 
 ldns_status
@@ -683,7 +695,8 @@ ldns_rr_new_question_frm_str(ldns_rr **newrr, const char *str,
 	                                    0,
 	                                    origin,
 	                                    prev,
-	                                    true);
+	                                    true,
+					    NULL);
 }
 
 /* Strip whitespace from the start and the end of <line>.  */
@@ -709,43 +722,28 @@ ldns_rr_new_frm_fp(ldns_rr **newrr, FILE *fp, uint32_t *ttl, ldns_rdf **origin,
 }
 
 ldns_status
-ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev, int *line_nr)
+_ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+		uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+		int *line_nr, bool *explicit_ttl)
 {
-	char *line;
+	char *line = NULL;
+	size_t limit = 0;
 	const char *endptr;  /* unused */
 	ldns_rr *rr;
 	uint32_t ttl;
 	ldns_rdf *tmp;
 	ldns_status s;
-	ssize_t size;
 
 	if (default_ttl) {
 		ttl = *default_ttl;
 	} else {
 		ttl = 0;
 	}
-
-	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
-	if (!line) {
-		return LDNS_STATUS_MEM_ERR;
-	}
-
 	/* read an entire line in from the file */
-	if ((size = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, LDNS_MAX_LINELEN, line_nr)) == -1) {
-		LDNS_FREE(line);
-		/* 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_STATUS_SYNTAX_ERR;
-	}
-
-	/* 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) {
+	if ((s = ldns_fget_token_l_st( fp, &line, &limit, false
+	                             , LDNS_PARSE_SKIP_SPACE, line_nr))) {
 		LDNS_FREE(line);
-		return LDNS_STATUS_SYNTAX_EMPTY;
+		return s;
 	}
 
 	if (strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) {
@@ -775,9 +773,11 @@ ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl, ldns_rdf
 		return LDNS_STATUS_SYNTAX_EMPTY;
 	} else {
 		if (origin && *origin) {
-			s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, *origin, prev);
+			s = ldns_rr_new_frm_str_internal(&rr, (const char*)line,
+				ttl, *origin, prev, false, explicit_ttl);
 		} else {
-			s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, NULL, prev);
+			s = ldns_rr_new_frm_str_internal(&rr, (const char*)line,
+				ttl, NULL, prev, false, explicit_ttl);
 		}
 	}
 	LDNS_FREE(line);
@@ -792,6 +792,14 @@ ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl, ldns_rdf
 	return s;
 }
 
+ldns_status
+ldns_rr_new_frm_fp_l(ldns_rr **newrr, FILE *fp, uint32_t *default_ttl,
+		ldns_rdf **origin, ldns_rdf **prev, int *line_nr)
+{
+	return _ldns_rr_new_frm_fp_l_internal(newrr, fp, default_ttl, origin,
+			prev, line_nr, NULL);
+}
+
 void
 ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner)
 {
@@ -836,7 +844,7 @@ ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position)
 
 	rd_count = ldns_rr_rd_count(rr);
 	if (position < rd_count) {
-		/* dicard the old one */
+		/* discard the old one */
 		pop = rr->_rdata_fields[position];
 		rr->_rdata_fields[position] = (ldns_rdf*)f;
 		return pop;
@@ -1190,6 +1198,7 @@ ldns_rr_list_pop_rr(ldns_rr_list *rr_list)
 		        rr_list->_rrs = a;
 		        rr_list->_rr_capacity = cap;
                 }
+                /* if the realloc fails, the capacity for the list remains unchanged */
 	}
 
 	ldns_rr_list_set_rr_count(rr_list, rr_count - 1);
@@ -1317,7 +1326,7 @@ ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr)
 			return false;
 		}
 		/* ok, still alive - check if the rr already
-		 * exists - if so, dont' add it */
+		 * exists - if so, don't add it */
 		for(i = 0; i < rr_count; i++) {
 			if(ldns_rr_compare(
 					ldns_rr_list_rr(rr_list, i), rr) == 0) {
@@ -1968,7 +1977,13 @@ static const ldns_rdf_type type_zonemd_wireformat[] = {
 	LDNS_RDF_TYPE_INT32,
 	LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
 };
-
+#ifdef RRTYPE_SVCB_HTTPS
+static const ldns_rdf_type type_svcb_wireformat[] = {
+	LDNS_RDF_TYPE_INT16,
+	LDNS_RDF_TYPE_DNAME, 
+	LDNS_RDF_TYPE_SVCPARAMS
+};
+#endif
 /* nsec3 is some vars, followed by same type of data of nsec */
 static const ldns_rdf_type type_nsec3_wireformat[] = {
 /*	LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/
@@ -2215,11 +2230,20 @@ static ldns_rr_descriptor rdata_field_descriptors[] = {
 #else
 {LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
 #endif
+	/* 62 */
+	{LDNS_RR_TYPE_CSYNC, "CSYNC", 3, 3, type_csync_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+	/* 63 */
+	{LDNS_RR_TYPE_ZONEMD, "ZONEMD", 4, 4, type_zonemd_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#ifdef RRTYPE_SVCB_HTTPS
+	/* 64 */
+	{LDNS_RR_TYPE_SVCB, "SVCB", 2, 3, type_svcb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+	/* 65 */
+	{LDNS_RR_TYPE_HTTPS, "HTTPS", 2, 3, type_svcb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
 
-{LDNS_RR_TYPE_CSYNC, "CSYNC", 3, 3, type_csync_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
-{LDNS_RR_TYPE_ZONEMD, "ZONEMD", 4, 4, type_zonemd_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+#else
 {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 },
+#endif
 {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 },
@@ -2489,7 +2513,7 @@ static ldns_rr_descriptor rdata_field_descriptors[] = {
 /*---------------------------------------------------------------------------*
  * The functions below return an bitmap RDF with the space required to set
  * or unset all known RR types. Arguably these functions are better situated
- * in rdata.c, however for the space calculation it is necesarry to walk
+ * in rdata.c, however for the space calculation it is necessary to walk
  * through rdata_field_descriptors which is not easily possible from anywhere
  * other than rr.c where it is declared static.
  *
diff --git a/contrib/ldns/rr_functions.c b/contrib/ldns/rr_functions.c
index 20a0bfaa1a..b9b9eae5be 100644
--- a/contrib/ldns/rr_functions.c
+++ b/contrib/ldns/rr_functions.c
@@ -24,7 +24,7 @@
  * return a specific rdf
  * \param[in] type type of RR
  * \param[in] rr   the rr itself
- * \param[in] pos  at which postion to get it
+ * \param[in] pos  at which position to get it
  * \return the rdf sought
  */
 static ldns_rdf *
@@ -41,7 +41,7 @@ ldns_rr_function(ldns_rr_type type, const ldns_rr *rr, size_t pos)
  * \param[in] type type of RR
  * \param[in] rr   the rr itself
  * \param[in] rdf  the rdf to set
- * \param[in] pos  at which postion to set it
+ * \param[in] pos  at which position to set it
  * \return true or false
  */
 static bool
@@ -269,14 +269,17 @@ ldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
                             const size_t len,
                             const ldns_algorithm alg)
 {
+#ifdef USE_DSA
 	/* for DSA keys */
 	uint8_t t;
+#endif /* USE_DSA */
 	
 	/* for RSA keys */
 	uint16_t exp;
 	uint16_t int16;
 	
 	switch ((ldns_signing_algorithm)alg) {
+#ifdef USE_DSA
 	case LDNS_SIGN_DSA:
 	case LDNS_SIGN_DSA_NSEC3:
 		if (len > 0) {
@@ -286,6 +289,7 @@ ldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
 			return 0;
 		}
 		break;
+#endif /* USE_DSA */
 	case LDNS_SIGN_RSAMD5:
 	case LDNS_SIGN_RSASHA1:
 	case LDNS_SIGN_RSASHA1_NSEC3:
diff --git a/contrib/ldns/sha1.c b/contrib/ldns/sha1.c
index 96e8f96830..9b7e60ece0 100644
--- a/contrib/ldns/sha1.c
+++ b/contrib/ldns/sha1.c
@@ -168,7 +168,7 @@ ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ctx *co
 }
 
 unsigned char *
-ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest)
+ldns_sha1(const unsigned char *data, unsigned int data_len, unsigned char *digest)
 {
     ldns_sha1_ctx ctx;
     ldns_sha1_init(&ctx);
diff --git a/contrib/ldns/sha2.c b/contrib/ldns/sha2.c
index e0b1f4b911..8988ee06d0 100644
--- a/contrib/ldns/sha2.c
+++ b/contrib/ldns/sha2.c
@@ -73,7 +73,7 @@
  * Please make sure that your system defines BYTE_ORDER.  If your
  * architecture is little-endian, make sure it also defines
  * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
- * equivilent.
+ * equivalent.
  *
  * If your system does not define the above, then you can do so by
  * hand like this:
@@ -554,7 +554,7 @@ typedef union _ldns_sha2_buffer_union {
         uint64_t* theLongs;
 } ldns_sha2_buffer_union;
 
-void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) {
+void ldns_sha256_final(sha2_byte digest[LDNS_SHA256_DIGEST_LENGTH], ldns_sha256_CTX* context) {
 	sha2_word32	*d = (sha2_word32*)digest;
 	size_t usedspace;
 	ldns_sha2_buffer_union cast_var;
@@ -621,7 +621,7 @@ void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) {
 }
 
 unsigned char *
-ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest)
+ldns_sha256(const unsigned char *data, unsigned int data_len, unsigned char *digest)
 {
     ldns_sha256_CTX ctx;
     ldns_sha256_init(&ctx);
@@ -905,7 +905,7 @@ static void ldns_sha512_Last(ldns_sha512_CTX* context) {
 	ldns_sha512_Transform(context, (sha2_word64*)context->buffer);
 }
 
-void ldns_sha512_final(sha2_byte digest[], ldns_sha512_CTX* context) {
+void ldns_sha512_final(sha2_byte digest[LDNS_SHA512_DIGEST_LENGTH], ldns_sha512_CTX* context) {
 	sha2_word64	*d = (sha2_word64*)digest;
 
 	/* Sanity check: */
@@ -935,7 +935,7 @@ void ldns_sha512_final(sha2_byte digest[], ldns_sha512_CTX* context) {
 }
 
 unsigned char *
-ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest)
+ldns_sha512(const unsigned char *data, unsigned int data_len, unsigned char *digest)
 {
     ldns_sha512_CTX ctx;
     ldns_sha512_init(&ctx);
@@ -958,7 +958,7 @@ void ldns_sha384_update(ldns_sha384_CTX* context, const sha2_byte* data, size_t
 	ldns_sha512_update((ldns_sha512_CTX*)context, data, len);
 }
 
-void ldns_sha384_final(sha2_byte digest[], ldns_sha384_CTX* context) {
+void ldns_sha384_final(sha2_byte digest[LDNS_SHA384_DIGEST_LENGTH], ldns_sha384_CTX* context) {
 	sha2_word64	*d = (sha2_word64*)digest;
 
 	/* Sanity check: */
@@ -988,7 +988,7 @@ void ldns_sha384_final(sha2_byte digest[], ldns_sha384_CTX* context) {
 }
 
 unsigned char *
-ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest)
+ldns_sha384(const unsigned char *data, unsigned int data_len, unsigned char *digest)
 {
     ldns_sha384_CTX ctx;
     ldns_sha384_init(&ctx);
diff --git a/contrib/ldns/str2host.c b/contrib/ldns/str2host.c
index 0bf62d106e..5b78e5bc59 100644
--- a/contrib/ldns/str2host.c
+++ b/contrib/ldns/str2host.c
@@ -304,7 +304,7 @@ parse_char(uint8_t *ch_p, const char** str_p)
 
 /*
  * No special care is taken, all dots are translated into
- * label seperators.
+ * label separators.
  * Could be made more efficient....we do 3 memcpy's in total...
  */
 ldns_status
@@ -344,7 +344,7 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str)
 	pq = buf;
 	label_len = 0;
 	for (s = str; *s; s++, q++) {
-		if (q > buf + LDNS_MAX_DOMAINLEN) {
+		if (q >= buf + LDNS_MAX_DOMAINLEN) {
 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
 		}
 		*q = 0;
@@ -378,7 +378,7 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str)
 
 	/* add root label if last char was not '.' */
 	if (!ldns_dname_str_absolute(str)) {
-		if (q > buf + LDNS_MAX_DOMAINLEN) {
+		if (q >= buf + LDNS_MAX_DOMAINLEN) {
 			return LDNS_STATUS_DOMAINNAME_OVERFLOW;
 		}
                 if (label_len > LDNS_MAX_LABELLEN) {
@@ -879,13 +879,16 @@ loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e)
 	/* read <digits>[.<digits>][mM] */
 	/* into mantissa exponent format for LOC type */
 	uint32_t meters = 0, cm = 0, val;
+	char* cm_endstr;
 	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);
+		cm = (uint32_t)strtol(my_str, &cm_endstr, 10);
+		if (cm_endstr - my_str == 1) cm *= 10;
+		my_str = cm_endstr;
 	}
 	if (meters >= 1) {
 		*e = 2;
@@ -926,8 +929,8 @@ ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
 	uint8_t vert_pre_b = 1, vert_pre_e = 3;
 
 	double s = 0.0;
-	bool northerness;
-	bool easterness;
+	bool northern_hemisphere;
+	bool eastern_hemisphere;
 
 	char *my_str = (char *) str;
 
@@ -963,9 +966,9 @@ ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
 	}
 
 	if (*my_str == 'N') {
-		northerness = true;
+		northern_hemisphere = true;
 	} else if (*my_str == 'S') {
-		northerness = false;
+		northern_hemisphere = false;
 	} else {
 		return LDNS_STATUS_INVALID_STR;
 	}
@@ -979,7 +982,7 @@ ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
 	latitude = (uint32_t) s;
 	latitude += 1000 * 60 * m;
 	latitude += 1000 * 60 * 60 * h;
-	if (northerness) {
+	if (northern_hemisphere) {
 		latitude = equator + latitude;
 	} else {
 		latitude = equator - latitude;
@@ -1020,9 +1023,9 @@ ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
 	}
 
 	if (*my_str == 'E') {
-		easterness = true;
+		eastern_hemisphere = true;
 	} else if (*my_str == 'W') {
-		easterness = false;
+		eastern_hemisphere = false;
 	} else {
 		return LDNS_STATUS_INVALID_STR;
 	}
@@ -1037,7 +1040,7 @@ ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
 	longitude += 1000 * 60 * m;
 	longitude += 1000 * 60 * 60 * h;
 
-	if (easterness) {
+	if (eastern_hemisphere) {
 		longitude += equator;
 	} else {
 		longitude = equator - longitude;
@@ -1415,8 +1418,8 @@ ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str)
 		LDNS_FREE(publickey);
 	LDNS_FREE(token);
 	ldns_buffer_free(str_buf);
-	ldns_rdf_free(gateway_rdf);
-	ldns_rdf_free(publickey_rdf);
+	ldns_rdf_deep_free(gateway_rdf);
+	ldns_rdf_deep_free(publickey_rdf);
 	LDNS_FREE(data);
 	if(!*rd) return LDNS_STATUS_MEM_ERR;
 	return LDNS_STATUS_OK;
@@ -1547,16 +1550,19 @@ ldns_str2rdf_long_str(ldns_rdf **rd, const char *str)
 		return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
 	}
 	if (!(length = (size_t)(dp - data))) {
+		/* An empty string is a data buffer of 0 bytes.  The rdf for 
+		 * this long string has to have length 0 and point to NULL.
+		 */
 		LDNS_FREE(data);
-		return LDNS_STATUS_SYNTAX_EMPTY;
-	}
-	/* Lose the overmeasure */
-	data = LDNS_XREALLOC(dp = data, uint8_t, length);
-	if (! data) {
-		LDNS_FREE(dp);
-		return LDNS_STATUS_MEM_ERR;
+		data = NULL;
+	} else {
+		/* Lose the overmeasure */
+		data = LDNS_XREALLOC(dp = data, uint8_t, length);
+		if (! data) {
+			LDNS_FREE(dp);
+			return LDNS_STATUS_MEM_ERR;
+		}
 	}
-
 	/* Create rdf */
 	*rd = ldns_rdf_new(LDNS_RDF_TYPE_LONG_STR, length, data);
 	if (! *rd) {
@@ -1800,3 +1806,632 @@ ldns_str2rdf_amtrelay(ldns_rdf **rd, const char *str)
 	if(!*rd) return LDNS_STATUS_MEM_ERR;
 	return LDNS_STATUS_OK;
 }
+
+#ifdef RRTYPE_SVCB_HTTPS
+static int
+network_uint16_cmp(const void *a, const void *b)
+{
+	return ((int)ldns_read_uint16(a)) - ((int)ldns_read_uint16(b));
+}
+
+static ldns_status parse_svcparam_key(const char **s, ldns_svcparam_key *key);
+static ldns_status
+parse_svcparam_mandatory(const char **s, uint8_t **dp, uint8_t *eod)
+{
+	bool quoted = false;
+	uint8_t *keys = *dp;
+	int prev_key;
+
+	if (**s == '"') {
+		*s += 1;
+		quoted = true;
+	}
+	for (;;) {
+		ldns_status st;
+		ldns_svcparam_key key;
+
+		if ((st = parse_svcparam_key(s, &key)))
+			return st;
+
+		if (*dp + 2 > eod)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+		
+		ldns_write_uint16(*dp, key);
+		*dp += 2;
+
+		if (**s == ',')
+			*s += 1;
+		else
+			break;
+	}
+	if (quoted) {
+		if (**s != '"')
+			return LDNS_STATUS_INVALID_STR;
+		*s += 1;
+	}
+	if (*dp - keys == 0)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	if (**s && !isspace((unsigned char)**s))
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	/* In draft-ietf-dnsop-svcb-https-02 Section 7:
+	 *
+	 *     In wire format, the keys are represented by their numeric
+	 *     values in network byte order, concatenated in ascending order.
+	 */
+	qsort(keys, (*dp - keys) / 2, 2, network_uint16_cmp);
+
+	/* In draft-ietf-dnsop-svcb-https-02 Section 7:
+	 *
+	 *     Keys ...<snip>... MUST NOT appear more than once.
+	 */
+	prev_key = -1;
+	while (keys < *dp) {
+		uint16_t key = ldns_read_uint16(keys);
+
+		if (key == prev_key) {
+			/* "Be conservative in what you send,
+			 *  be liberal in what you accept"
+			 *
+			 * Instead of
+			 *   `return LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE;`,
+			 *
+			 * we eliminate the double occurrence.
+			 */
+			memmove(keys - 2, keys, *dp - keys);
+			*dp -= 2;
+		} else {
+			prev_key = key;
+			keys += 2;
+		}
+	}
+	return LDNS_STATUS_OK;
+}
+
+INLINE bool parse_escape2(uint8_t *ch_p, const char** str_p)
+{ *str_p += 1; return parse_escape(ch_p, str_p); }
+
+static ldns_status
+parse_svcparam_alpn(const char **s, uint8_t **dp, uint8_t *eod)
+{
+	uint8_t *val;
+	size_t len;
+
+	if (*dp + 1 > eod)
+		return LDNS_STATUS_RDATA_OVERFLOW;
+	*dp += 1;
+	val = *dp;
+	if (**s == '"') {
+		*s += 1;
+		while (**s != '"') {
+			if (**s == 0)
+				return LDNS_STATUS_INVALID_STR;
+
+			else if (**s == ',') {
+				len = *dp - val;
+				if (len == 0 || len > 255)
+					return LDNS_STATUS_INVALID_STR;
+				val[-1] = len;
+				if (*dp + 1 > eod)
+					return LDNS_STATUS_RDATA_OVERFLOW;
+				*dp += 1;
+				val = *dp;
+				*s += 1;
+
+			} else if (*dp + 1 > eod)
+				return LDNS_STATUS_RDATA_OVERFLOW;
+
+			else if (**s != '\\')
+				*(*dp)++ = (uint8_t)*(*s)++;
+
+			else if (!parse_escape2(*dp, s))
+				return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+			else
+				*dp += 1;
+		}
+		*s += 1;
+
+	} else while (**s && !isspace((unsigned char)**s)) {
+		if (**s == ',') {
+			len = *dp - val;
+			if (len == 0 || len > 255)
+				return LDNS_STATUS_INVALID_STR;
+			val[-1] = len;
+			if (*dp + 1 > eod)
+				return LDNS_STATUS_RDATA_OVERFLOW;
+			*dp += 1;
+			val = *dp;
+			*s += 1;
+
+		} else if (*dp + 1 > eod)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+
+		else if (**s != '\\')
+			*(*dp)++ = (uint8_t)*(*s)++;
+
+		else if (!parse_escape2(*dp, s))
+			return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+		else
+			*dp += 1;
+	}
+	len = *dp - val;
+	if (len == 0 || len > 255)
+		return LDNS_STATUS_INVALID_STR;
+	val[-1] = len;
+	return **s && !isspace((unsigned char)**s)
+	     ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
+	     : LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam_value(const char **s, uint8_t **dp, uint8_t *eod)
+{
+	if (**s == '"') {
+		*s += 1;
+		while (**s != '"') {
+			if (**s == 0)
+				return LDNS_STATUS_INVALID_STR;
+
+			else if (*dp + 1 > eod)
+				return LDNS_STATUS_RDATA_OVERFLOW;
+
+			else if (**s != '\\')
+				*(*dp)++ = (uint8_t)*(*s)++;
+
+			else if (!parse_escape2(*dp, s))
+				return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+			else
+				*dp += 1;
+		}
+		*s += 1;
+
+	} else while (**s && !isspace((unsigned char)**s)) {
+		if (*dp + 1 > eod)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+
+		else if (**s != '\\')
+			*(*dp)++ = (uint8_t)*(*s)++;
+
+		else if (!parse_escape2(*dp, s))
+			return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+		else
+			*dp += 1;
+	}
+	return **s && !isspace((unsigned char)**s)
+	     ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
+	     : LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam_port(const char **s, uint8_t **dp, uint8_t *eod)
+{
+	uint8_t *val = *dp;
+	ldns_status st;
+	size_t len;
+	char num_str[6];
+	char *endptr;
+	unsigned long int num;
+
+	if ((st = parse_svcparam_value(s, dp, eod)))
+		return st;
+	len = *dp - val;
+	if (len == 0 || len > 5)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	memcpy(num_str, val, len);
+	num_str[len] = 0;
+	num = strtoul(num_str, &endptr, 10);
+	if (*endptr)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	ldns_write_uint16(val, num);
+	*dp = val + 2;
+	return LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam_ipv4hint(const char **s, uint8_t **dp, uint8_t *eod)                
+{                                                                               
+	bool quoted = false;
+
+	if (**s == '"') {
+		*s += 1;
+		quoted = true;
+	}
+	for (;;) {
+		const char *ipv4_start = *s;
+		char        ipv4_str[16];
+		size_t      len;
+
+		while (isdigit((unsigned char)**s) || **s == '.')
+			*s += 1;
+		
+		len = *s - ipv4_start;
+		if (len == 0 || len > 15)
+			return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+		if (*dp + 4 > eod)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+
+		memcpy(ipv4_str, ipv4_start, len);
+		ipv4_str[len] = 0;
+		if (inet_pton(AF_INET, ipv4_str, *dp) != 1)
+			return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+		*dp += 4;
+		if (**s == ',')
+			*s += 1;
+		else
+			break;
+	}
+	if (quoted) {
+		if (**s != '"')
+			return LDNS_STATUS_INVALID_STR;
+		*s += 1;
+	}
+	return **s && !isspace((unsigned char)**s)
+	     ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
+	     : LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam_ech(const char **s, uint8_t **dp, uint8_t *eod)
+{                                                                               
+	bool quoted = false;
+	const char *b64_str;
+	size_t len, pad, out_len;
+	char in_buf[4096];
+	char *in = in_buf;
+	int out;
+
+	if (**s == '"') {
+		*s += 1;
+		quoted = true;
+	}
+	b64_str = *s;
+	while (isalnum((unsigned char)**s) || **s == '+'
+	                                   || **s == '/'
+	                                   || **s == '=')
+		*s += 1;
+
+	len = *s - b64_str;
+	pad = len % 4;
+	pad = pad ? 4 - pad : 0;
+	if (len == 0 || pad == 3)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	if (quoted) {
+		if (**s != '"')
+			return LDNS_STATUS_INVALID_STR;
+		*s += 1;
+	}
+	if (**s && !isspace((unsigned char)**s))
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+	
+	out_len = ldns_b64_pton_calculate_size(len);
+	if (*dp + out_len > eod)
+		return LDNS_STATUS_RDATA_OVERFLOW;
+
+	if (len + pad > sizeof(in_buf) - 1
+	&& !(in = LDNS_XMALLOC(char, len + pad + 1)))
+		return LDNS_STATUS_MEM_ERR;
+
+	memcpy(in, b64_str, len);
+	while (pad--)
+		in[len++] = '=';
+	in[len] = 0;
+	out = ldns_b64_pton(in, *dp, out_len);
+	if (in != in_buf)
+		LDNS_FREE(in);
+
+	if (out <= 0)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+	*dp += out;
+	return LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam_ipv6hint(const char **s, uint8_t **dp, uint8_t *eod)                
+{                                                                               
+	bool quoted = false;
+
+	if (**s == '"') {
+		*s += 1;
+		quoted = true;
+	}
+	for (;;) {
+		const char *ipv6_start = *s;
+		char        ipv6_str[INET6_ADDRSTRLEN];
+		size_t      len;
+
+		while (isxdigit((unsigned char)**s) || **s == ':' || **s == '.')
+			*s += 1;
+		
+		len = *s - ipv6_start;
+		if (len == 0 || len > INET6_ADDRSTRLEN)
+			return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+		if (*dp + 16 > eod)
+			return LDNS_STATUS_RDATA_OVERFLOW;
+
+		memcpy(ipv6_str, ipv6_start, len);
+		ipv6_str[len] = 0;
+		if (inet_pton(AF_INET6, ipv6_str, *dp) != 1)
+			return LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR;
+
+		*dp += 16;
+		if (**s == ',')
+			*s += 1;
+		else
+			break;
+	}
+	if (quoted) {
+		if (**s != '"')
+			return LDNS_STATUS_INVALID_STR;
+		*s += 1;
+	}
+	return **s && !isspace((unsigned char)**s)
+	     ? LDNS_STATUS_SYNTAX_SVCPARAM_VALUE_ERR
+	     : LDNS_STATUS_OK;
+}
+
+struct struct_svcparam_key_def {
+	const char *str;
+	size_t      len;
+};
+typedef struct struct_svcparam_key_def svcparam_key_def;
+
+static svcparam_key_def svcparam_key_defs[] = { { "mandatory"      ,  9 }
+                                              , { "alpn"           ,  4 }
+                                              , { "no-default-alpn", 15 }
+                                              , { "port"           ,  4 }
+                                              , { "ipv4hint"       ,  8 }
+                                              , { "ech"            ,  3 }
+                                              , { "ipv6hint"       ,  8 }
+                                              , { "dohpath"        ,  7 } };
+
+static const size_t svcparam_key_defs_len = sizeof(svcparam_key_defs)
+                                          / sizeof(svcparam_key_def);
+
+/* svcparam_key2buffer_str() should actually be in host2str.c, but we need the
+ * svcparam_key_defs for it and it is not an exposed symbol anyway.
+ */
+ldns_status svcparam_key2buffer_str(ldns_buffer *output, uint16_t key)
+{
+	if (key <= LDNS_SVCPARAM_KEY_LAST_KEY)
+		ldns_buffer_write_string(output, svcparam_key_defs[key].str);
+	else
+		ldns_buffer_printf(output, "key%d", (int)key);
+	return	ldns_buffer_status(output);
+}
+
+static ldns_status
+parse_svcparam_key(const char **s, ldns_svcparam_key *key)
+{
+	size_t i, len;
+	const char *key_str = *s;
+	char num_str[6];
+	char *endptr;
+	unsigned long int num;
+
+	/* parse key */
+	while (islower((unsigned char)**s) || isdigit((unsigned char)**s)
+	                                   || **s == '-')
+		*s += 1;
+
+	len = *s - key_str;
+	for (i = 0; i < svcparam_key_defs_len; i++) {
+		if (len == svcparam_key_defs[i].len
+		&& !strncmp(key_str, svcparam_key_defs[i].str, len)) {
+			*key = i;
+			return LDNS_STATUS_OK;
+		}
+	}
+	/* Also allow "echconfig" from earlier draft versions. */
+	if (len == 9 && !strncmp(key_str, "echconfig", 9)) {
+		*key = LDNS_SVCPARAM_KEY_ECH;
+		return LDNS_STATUS_OK;
+	}
+	if (len < 4 || len > 8 || strncmp(key_str, "key", 3))
+		return LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR;
+
+	memcpy(num_str, key_str + 3, len - 3);
+	num_str[len - 3] = 0;
+	num = strtoul(num_str, &endptr, 10);
+	if (*endptr || num > 65535)
+		return LDNS_STATUS_SYNTAX_SVCPARAM_KEY_ERR;
+
+	/* key65535 is Reserved to be an ("Invalid key"), though there is no
+	 * physiological reason to deny usage. We restrict ourselves to the
+	 * anatomical limitations only to maximize serviceability.
+	 * ```
+	 * if (num == 65535)
+	 * 	return LDNS_STATUS_RESERVED_SVCPARAM_KEY;
+	 * ```
+	 */
+	*key = num;
+	return LDNS_STATUS_OK;
+}
+
+static ldns_status
+parse_svcparam(const char **s, uint8_t **dp, uint8_t *eod)
+{
+	ldns_svcparam_key key;
+	ldns_status st;
+	uint8_t *val;
+
+	if (*dp + 4 > eod)
+		return LDNS_STATUS_RDATA_OVERFLOW;
+	
+	if ((st = parse_svcparam_key(s, &key)))
+		return st;
+
+	ldns_write_uint16(*dp, key);
+	ldns_write_uint16(*dp + 2, 0);
+	*dp += 4;
+	if (isspace((unsigned char)**s) || !**s)
+		return LDNS_STATUS_OK;
+
+	else if (**s != '=')
+		return LDNS_STATUS_SYNTAX_ERR;
+	*s += 1;
+	val = *dp;
+	switch(key) {
+	case LDNS_SVCPARAM_KEY_MANDATORY:
+		st = parse_svcparam_mandatory(s, dp, eod);
+		break;
+	case LDNS_SVCPARAM_KEY_ALPN:
+		st = parse_svcparam_alpn(s, dp, eod);
+		break;
+	case LDNS_SVCPARAM_KEY_NO_DEFAULT_ALPN:
+		return LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED;
+	case LDNS_SVCPARAM_KEY_PORT:
+		st = parse_svcparam_port(s, dp, eod);
+		break;
+	case LDNS_SVCPARAM_KEY_IPV4HINT:
+		st = parse_svcparam_ipv4hint(s, dp, eod);
+		break;
+	case LDNS_SVCPARAM_KEY_ECH:
+		st = parse_svcparam_ech(s, dp, eod);
+		break;
+	case LDNS_SVCPARAM_KEY_IPV6HINT:
+		st = parse_svcparam_ipv6hint(s, dp, eod);
+		break;
+	default:
+		st = parse_svcparam_value(s, dp, eod);
+		break;
+	}
+	if (st)
+		return st;
+	ldns_write_uint16(val - 2, *dp - val);
+	return LDNS_STATUS_OK;
+}
+
+static int
+svcparam_ptr_cmp(const void *a, const void *b)
+{
+	uint8_t *x = *(uint8_t **)a          , *y = *(uint8_t **)b;
+	uint16_t x_type = ldns_read_uint16(x),  y_type = ldns_read_uint16(y);
+	uint16_t x_len                       ,  y_len;
+
+	if (x_type != y_type)
+		return x_type > y_type ? 1 : -1;
+
+	x_len = ldns_read_uint16(x + 2);
+	y_len = ldns_read_uint16(y + 2);
+
+	return  x_len != y_len
+	     ? (x_len >  y_len ? 1 : -1)
+	     : (x_len == 0     ? 0 : memcmp(x + 4, y + 4, x_len));
+}
+
+ldns_status
+ldns_str2rdf_svcparams(ldns_rdf **rd, const char *str)
+{
+	uint8_t *data, *dp, *eod, *p, *new_data;
+	ldns_status st = LDNS_STATUS_OK;
+	size_t length, i;
+	size_t nparams = 0;
+	uint8_t **svcparams;
+	int prev_key;
+
+	if (!rd || !str)
+		return LDNS_STATUS_NULL;
+
+	length = strlen(str);
+	/* Worst case space requirement. We'll realloc to actual size later. */
+	if (!(dp = data = LDNS_XMALLOC(uint8_t, length * 4)))
+		return LDNS_STATUS_MEM_ERR;
+	eod = data + length * 4;
+
+	/* Fill data with parsed bytes */
+	for (;;) {
+		while (isspace((unsigned char)*str))
+			str += 1;
+		if(!*str)
+			break;
+		if ((st = parse_svcparam(&str, &dp, eod))) {
+			LDNS_FREE(data);
+			return st;
+		}
+		nparams += 1;
+	}
+
+	/* draft-ietf-dnsop-svcb-https-02 in Section 2.2:
+	 *
+	 *     SvcParamKeys SHALL appear in increasing numeric order
+	 *
+	 * A svcparams array (with pointers to the individual key, value pairs)
+	 * is created to qsort the pairs in increasing numeric order.
+	 */
+	if (!(svcparams = LDNS_XMALLOC(uint8_t *, nparams))) {
+		LDNS_FREE(data);
+		return LDNS_STATUS_MEM_ERR;
+	}
+	for ( p = data, i = 0
+	    ; p < dp && i < nparams
+	    ; p += 4 + ldns_read_uint16(p + 2))
+		svcparams[i++] = p;
+
+	qsort(svcparams, i, sizeof(uint8_t *), svcparam_ptr_cmp);
+
+	/* Write out the (key, value) pairs to a newly allocated data in
+	 * sorted order.
+	 */
+	length = dp - data;
+	if (!(new_data = LDNS_XMALLOC(uint8_t, length))) {
+		LDNS_FREE(data);
+		LDNS_FREE(svcparams);
+		return LDNS_STATUS_MEM_ERR;
+	}
+	prev_key = -1;
+	for ( p = new_data, i = 0
+	    ; p < new_data + length && i < nparams
+	    ; p += 4 + ldns_read_uint16(p + 2), i += 1) {
+		uint16_t key = ldns_read_uint16(svcparams[i]);
+
+		/* In draft-ietf-dnsop-svcb-https-02 Section 2.1:
+		 *
+		 *     SvcParams ...<snip>... keys MUST NOT be repeated.
+		 *
+		 * ldns will not impose this limitation on the library user,
+		 * but we can merge completely equal repetitions into one.
+		 * So, not doing
+		 * ```
+		 * if (key == prev_key)
+		 * 	return LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE;
+		 * ```
+		 * but instead:
+		 */
+		if (key == prev_key && ldns_read_uint16(svcparams[i] + 2)
+		                    == ldns_read_uint16(svcparams[i - 1] + 2)
+		&&  0 == memcmp( svcparams[i    ] + 4
+		               , svcparams[i - 1] + 4
+		               , ldns_read_uint16(svcparams[i] + 2))) {
+			p -= 4 + ldns_read_uint16(svcparams[i] + 2);
+			continue;
+		}
+		memcpy(p, svcparams[i], 4 + ldns_read_uint16(svcparams[i] + 2));
+		prev_key = key;
+	}
+	LDNS_FREE(data);
+	LDNS_FREE(svcparams);
+
+	/* Create rdf */
+	*rd = ldns_rdf_new(LDNS_RDF_TYPE_SVCPARAMS, p - new_data, new_data);
+	if (! *rd) {
+		LDNS_FREE(new_data);
+		return LDNS_STATUS_MEM_ERR;
+	}
+	return LDNS_STATUS_OK;
+}
+#else	/* #ifdef RRTYPE_SVCB_HTTPS */
+ldns_status
+ldns_str2rdf_svcparams(ldns_rdf **rd, const char *str)
+{
+	(void)rd; (void)str;
+	return LDNS_STATUS_NOT_IMPL;
+}
+#endif	/* #ifdef RRTYPE_SVCB_HTTPS */
diff --git a/contrib/ldns/tsig.c b/contrib/ldns/tsig.c
index 458861a15b..26a1e73f1d 100644
--- a/contrib/ldns/tsig.c
+++ b/contrib/ldns/tsig.c
@@ -196,7 +196,7 @@ ldns_tsig_mac_new(ldns_rdf **tsig_mac, const uint8_t *pkt_wire, size_t pkt_wire_
 		return LDNS_STATUS_MEM_ERR;
 	}
 	/*
-	 * prepare the digestable information
+	 * prepare the digestible information
 	 */
 	data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
 	if (!data_buffer) {
@@ -354,7 +354,13 @@ ldns_pkt_tsig_verify_next(ldns_pkt *pkt, const uint8_t *wire, size_t wirelen, co
 		return false;
 	}
 	/* use time insensitive memory compare */
-	if(CRYPTO_memcmp(ldns_rdf_data(pkt_mac_rdf), ldns_rdf_data(my_mac_rdf),
+	if(
+#ifdef HAVE_CRYPTO_MEMCMP
+	    CRYPTO_memcmp
+#else
+	    memcmp
+#endif
+		(ldns_rdf_data(pkt_mac_rdf), ldns_rdf_data(my_mac_rdf),
 		ldns_rdf_size(my_mac_rdf)) == 0) {
 		ldns_rdf_deep_free(my_mac_rdf);
 		return true;
diff --git a/contrib/ldns/util.c b/contrib/ldns/util.c
index 1216134f96..807a99e230 100644
--- a/contrib/ldns/util.c
+++ b/contrib/ldns/util.c
@@ -293,25 +293,35 @@ ldns_gmtime64_r(int64_t clock, struct tm *result)
 #endif /* SIZEOF_TIME_T <= 4 */
 
 static int64_t
-ldns_serial_arithmitics_time(int32_t time, time_t now)
+ldns_serial_arithmetics_time(int32_t time, time_t now)
 {
-	int32_t offset = time - (int32_t) now;
+	/* Casting due to https://github.com/NLnetLabs/ldns/issues/71 */
+	int32_t offset = (int32_t) ((uint32_t) time - (uint32_t) now);
 	return (int64_t) now + offset;
 }
 
-
 struct tm *
-ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
+ldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result)
 {
 #if SIZEOF_TIME_T <= 4
-	int64_t secs_since_epoch = ldns_serial_arithmitics_time(time, now);
+	int64_t secs_since_epoch = ldns_serial_arithmetics_time(time, now);
 	return  ldns_gmtime64_r(secs_since_epoch, result);
 #else
-	time_t  secs_since_epoch = ldns_serial_arithmitics_time(time, now);
+	time_t  secs_since_epoch = ldns_serial_arithmetics_time(time, now);
 	return  gmtime_r(&secs_since_epoch, result);
 #endif
 }
 
+#ifdef ldns_serial_arithmitics_gmtime_r
+#undef ldns_serial_arithmitics_gmtime_r
+#endif
+/* alias function because of previously used wrong spelling */
+struct tm *
+ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
+{
+	return ldns_serial_arithmetics_gmtime_r(time, now, result);
+}
+
 /**
  * Init the random source
  * applications should call this if they need entropy data within ldns
@@ -377,7 +387,7 @@ ldns_init_random(FILE *fd, unsigned int size)
 		RAND_seed(seed, (int) size);
 #else
 		/* Seed the standard prng, only uses the first
-		 * unsigned sizeof(unsiged int) bytes found in the entropy pool
+		 * unsigned sizeof(unsigned int) bytes found in the entropy pool
 		 */
 		memcpy(&seed_i, seed, sizeof(seed_i));
 		srandom(seed_i);
diff --git a/contrib/ldns/wire2host.c b/contrib/ldns/wire2host.c
index 1473a9478d..63b67a0d17 100644
--- a/contrib/ldns/wire2host.c
+++ b/contrib/ldns/wire2host.c
@@ -273,6 +273,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
 		case LDNS_RDF_TYPE_IPSECKEY:
 		case LDNS_RDF_TYPE_LONG_STR:
 		case LDNS_RDF_TYPE_AMTRELAY:
+		case LDNS_RDF_TYPE_SVCPARAMS:
 		case LDNS_RDF_TYPE_NONE:
 			/*
 			 * Read to end of rr rdata
@@ -310,7 +311,6 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
 	return LDNS_STATUS_OK;
 }
 
-
 /* TODO:
          can *pos be incremented at READ_INT? or maybe use something like
          RR_CLASS(wire)?
diff --git a/contrib/ldns/zone.c b/contrib/ldns/zone.c
index e952074823..9a5d4c4e9e 100644
--- a/contrib/ldns/zone.c
+++ b/contrib/ldns/zone.c
@@ -180,7 +180,7 @@ ldns_zone_new(void)
 	return z;
 }
 
-/* we regocnize:
+/* we recognize:
  * $TTL, $ORIGIN
  */
 ldns_status
@@ -189,19 +189,28 @@ ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t t
 	return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
 }
 
+ldns_status _ldns_rr_new_frm_fp_l_internal(ldns_rr **newrr, FILE *fp,
+		uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev,
+		int *line_nr, bool *explicit_ttl);
+
 /* XXX: class is never used */
 ldns_status
-ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t ttl,
-        ldns_rr_class ATTR_UNUSED(c), int *line_nr)
+ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin,
+	uint32_t default_ttl, ldns_rr_class ATTR_UNUSED(c), int *line_nr)
 {
 	ldns_zone *newzone;
-	ldns_rr *rr;
+	ldns_rr *rr, *prev_rr = NULL;
 	uint32_t my_ttl;
 	ldns_rdf *my_origin;
 	ldns_rdf *my_prev;
 	bool soa_seen = false; 	/* 2 soa are an error */
 	ldns_status s;
 	ldns_status ret;
+	/* RFC 1035 Section 5.1, says 'Omitted class and TTL values are default
+	 * to the last explicitly stated values.'
+	 */
+	bool ttl_from_TTL = false;
+	bool explicit_ttl = false;
 
 	/* most cases of error are memory problems */
 	ret = LDNS_STATUS_MEM_ERR;
@@ -210,7 +219,7 @@ ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t
 	my_origin = NULL;
 	my_prev = NULL;
 
-	my_ttl    = ttl;
+	my_ttl    = default_ttl;
 	
 	if (origin) {
 		my_origin = ldns_rdf_clone(origin);
@@ -224,9 +233,58 @@ ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t
 	if (!newzone) goto error;
 
 	while(!feof(fp)) {
-		s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr);
+		/* If ttl came from $TTL line, then it should be the default.
+		 * (RFC 2308 Section 4)
+		 * Otherwise it "defaults to the last explicitly stated value"
+		 * (RFC 1035 Section 5.1)
+		 */
+		if (ttl_from_TTL)
+			my_ttl = default_ttl;
+		s = _ldns_rr_new_frm_fp_l_internal(&rr, fp, &my_ttl, &my_origin,
+				&my_prev, line_nr, &explicit_ttl);
 		switch (s) {
 		case LDNS_STATUS_OK:
+			if (explicit_ttl) {
+				if (!ttl_from_TTL) {
+					/* No $TTL, so ttl "defaults to the
+					 * last explicitly stated value"
+					 * (RFC 1035 Section 5.1)
+					 */
+					my_ttl = ldns_rr_ttl(rr);
+				}
+			/* When ttl is implicit, try to adhere to the rules as
+			 * much as possible. (also for compatibility with bind)
+			 * This was changed when fixing an issue with ZONEMD
+			 * which hashes the TTL too.
+			 */
+			} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SIG
+			       ||  ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
+				if (ldns_rr_rd_count(rr) >= 4
+				&&  ldns_rdf_get_type(ldns_rr_rdf(rr, 3)) == LDNS_RDF_TYPE_INT32)
+
+					/* SIG without explicit ttl get ttl
+					 * from the original_ttl field
+					 * (RFC 2535 Section 7.2)
+					 *
+					 * Similarly for RRSIG, but stated less
+					 * specifically in the spec.
+					 * (RFC 4034 Section 3)
+					 */
+					ldns_rr_set_ttl(rr,
+					    ldns_rdf2native_int32(
+					        ldns_rr_rdf(rr, 3)));
+
+			} else if (prev_rr
+			       &&  ldns_rr_get_type(prev_rr) == ldns_rr_get_type(rr)
+			       &&  ldns_dname_compare( ldns_rr_owner(prev_rr)
+			                             , ldns_rr_owner(rr)) == 0)
+
+				/* "TTLs of all RRs in an RRSet must be the same"
+				 * (RFC 2881 Section 5.2)
+				 */
+				ldns_rr_set_ttl(rr, ldns_rr_ttl(prev_rr));
+
+			prev_rr = rr;
 			if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
 				if (soa_seen) {
 					/* second SOA 
@@ -245,19 +303,25 @@ ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, const ldns_rdf *origin, uint32_t
 			}
 			
 			/* a normal RR - as sofar the DNS is normal */
-			if (!ldns_zone_push_rr(newzone, rr)) goto error;
+			if (!ldns_zone_push_rr(newzone, rr)) {
+				ldns_rr_free(rr);
+				goto error;
+			}
+			break;
 
 		case LDNS_STATUS_SYNTAX_EMPTY:
 			/* empty line was seen */
 		case LDNS_STATUS_SYNTAX_TTL:
 			/* the function set the ttl */
+			default_ttl = my_ttl;
+			ttl_from_TTL = true;
 			break;
 		case LDNS_STATUS_SYNTAX_ORIGIN:
 			/* the function set the origin */
 			break;
 		case LDNS_STATUS_SYNTAX_INCLUDE:
 			ret = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
-			break;
+			goto error;
 		default:
 			ret = s;
 			goto error;
diff --git a/lib/libldns/Makefile b/lib/libldns/Makefile
index 5668e210db..ee172f5020 100644
--- a/lib/libldns/Makefile
+++ b/lib/libldns/Makefile
@@ -3,14 +3,14 @@
 LDNS=		${.CURDIR}/../../contrib/ldns
 
 LIB=		private_ldns
-SHLIB_MAJOR=	2
+SHLIB_MAJOR=	3
 PRIVATELIB=	shpub
 
 NO_STRICT_ALIASING=
 
 SRCS+=		buffer.c dname.c dnssec.c dnssec_verify.c dnssec_zone.c \
 		error.c higher.c host2str.c host2wire.c keys.c net.c \
-		packet.c parse.c rbtree.c rdata.c resolver.c \
+		edns.c packet.c parse.c rbtree.c rdata.c resolver.c \
 		rr.c rr_functions.c sha1.c sha2.c \
 		str2host.c tsig.c util.c wire2host.c zone.c
 # not needed in base but included:
diff --git a/lib/libldns/ldns/common.h b/lib/libldns/ldns/common.h
index 9abd9b9396..dcc54db378 100644
--- a/lib/libldns/ldns/common.h
+++ b/lib/libldns/ldns/common.h
@@ -27,6 +27,9 @@
 #define LDNS_BUILD_CONFIG_USE_DANE         1
 #define LDNS_BUILD_CONFIG_HAVE_B32_PTON    0
 #define LDNS_BUILD_CONFIG_HAVE_B32_NTOP    0
+#define LDNS_BUILD_CONFIG_USE_DSA          1
+#define LDNS_BUILD_CONFIG_USE_ED25519      0
+#define LDNS_BUILD_CONFIG_USE_ED448        0
 
 /*
  * HAVE_STDBOOL_H is not available when distributed as a library, but no build 
diff --git a/lib/libldns/ldns/config.h b/lib/libldns/ldns/config.h
index 0993c32416..ccbdb30f7a 100644
--- a/lib/libldns/ldns/config.h
+++ b/lib/libldns/ldns/config.h
@@ -31,6 +31,15 @@
 /* Define to 1 if you have the `calloc' function. */
 #define HAVE_CALLOC 1
 
+/* Define to 1 if you have the `CONF_modules_unload' function. */
+#define HAVE_CONF_MODULES_UNLOAD 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define to 1 if you have the `CRYPTO_memcmp' function. */
+#define HAVE_CRYPTO_MEMCMP 1
+
 /* Define to 1 if you have the `ctime_r' function. */
 #define HAVE_CTIME_R 1
 
@@ -40,6 +49,10 @@
 /* Is a CAPATH given at configure time */
 #define HAVE_DANE_CA_PATH 0
 
+/* Define to 1 if you have the declaration of `EVP_PKEY_base_id', and to 0 if
+   you don't. */
+#define HAVE_DECL_EVP_PKEY_BASE_ID 1
+
 /* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
    don't. */
 #define HAVE_DECL_NID_ED25519 0
@@ -80,21 +93,33 @@
 /* Define to 1 if you have the `endservent' function. */
 #define HAVE_ENDSERVENT 1
 
-/* Define to 1 if you have the `ENGINE_load_cryptodev' function. */
-/* #undef HAVE_ENGINE_LOAD_CRYPTODEV */
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+/* #undef HAVE_ENGINE_CLEANUP */
+
+/* Define to 1 if you have the `ENGINE_free' function. */
+/* #undef HAVE_ENGINE_FREE */
+
+/* Define to 1 if you have the `ERR_free_strings' function. */
+#define HAVE_ERR_FREE_STRINGS 1
 
 /* Define to 1 if you have the `ERR_load_crypto_strings' function. */
 #define HAVE_ERR_LOAD_CRYPTO_STRINGS 1
 
+/* Define to 1 if you have the `EVP_cleanup' function. */
+#define HAVE_EVP_CLEANUP 1
+
 /* Define to 1 if you have the `EVP_dss1' function. */
 #define HAVE_EVP_DSS1 1
 
 /* Define to 1 if you have the `EVP_MD_CTX_new' function. */
 #define HAVE_EVP_MD_CTX_NEW 1
 
-/* Define to 1 if you have the `EVP_PKEY_base_id' function. */
+/* Define to 1 if you have the EVP_PKEY_base_id function or macro. */
 #define HAVE_EVP_PKEY_BASE_ID 1
 
+/* Define to 1 if you have the `EVP_PKEY_get_base_id' function. */
+/* #undef HAVE_EVP_PKEY_GET_BASE_ID */
+
 /* Define to 1 if you have the `EVP_PKEY_keygen' function. */
 #define HAVE_EVP_PKEY_KEYGEN 1
 
@@ -113,6 +138,9 @@
 /* Define to 1 if you have the `fork' function. */
 #define HAVE_FORK 1
 
+/* if fork is available for compile */
+#define HAVE_FORK_AVAILABLE 1
+
 /* Whether getaddrinfo is available */
 #define HAVE_GETADDRINFO 1
 
@@ -122,9 +150,6 @@
 /* Define to 1 if you have the `gmtime_r' function. */
 #define HAVE_GMTIME_R 1
 
-/* If you have HMAC_Update */
-#define HAVE_HMAC_UPDATE 1
-
 /* Define to 1 if you have the `inet_aton' function. */
 #define HAVE_INET_ATON 1
 
@@ -155,19 +180,15 @@
 /* Define to 1 if you have the `localtime_r' function. */
 #define HAVE_LOCALTIME_R 1
 
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
-   to 0 otherwise. */
-#define HAVE_MALLOC 1
-
 /* Define to 1 if you have the `memmove' function. */
 #define HAVE_MEMMOVE 1
 
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
 /* Define to 1 if you have the `memset' function. */
 #define HAVE_MEMSET 1
 
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
+
 /* Define to 1 if you have the <netdb.h> header file. */
 #define HAVE_NETDB_H 1
 
@@ -201,9 +222,18 @@
 /* Define to 1 if you have the <net/if.h> header file. */
 /* #undef HAVE_NET_IF_H */
 
+/* Define to 1 if you have the <openssl/conf.h> header file. */
+#define HAVE_OPENSSL_CONF_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
 /* Define to 1 if you have the <openssl/err.h> header file. */
 #define HAVE_OPENSSL_ERR_H 1
 
+/* Define to 1 if you have the <openssl/evp.h> header file. */
+#define HAVE_OPENSSL_EVP_H 1
+
 /* Define to 1 if you have the `OPENSSL_init_crypto' function. */
 #define HAVE_OPENSSL_INIT_CRYPTO 1
 
@@ -228,10 +258,6 @@
 /* Define to 1 if you have the `random' function. */
 #define HAVE_RANDOM 1
 
-/* Define to 1 if your system has a GNU libc compatible `realloc' function,
-   and to 0 otherwise. */
-#define HAVE_REALLOC 1
-
 /* Define to 1 if you have the `sleep' function. */
 #define HAVE_SLEEP 1
 
@@ -250,6 +276,9 @@
 /* Define to 1 if you have the <stdint.h> header file. */
 #define HAVE_STDINT_H 1
 
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
 /* Define to 1 if you have the <stdlib.h> header file. */
 #define HAVE_STDLIB_H 1
 
@@ -283,6 +312,9 @@
 /* define if you have sys/types.h */
 #define HAVE_SYS_TYPES_H 1
 
+/* Define to 1 if you have the <TargetConditionals.h> header file. */
+/* #undef HAVE_TARGETCONDITIONALS_H */
+
 /* Define to 1 if you have the `timegm' function. */
 #define HAVE_TIMEGM 1
 
@@ -298,6 +330,9 @@
 /* Define to 1 if you have the <vfork.h> header file. */
 /* #undef HAVE_VFORK_H */
 
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
 /* Define to 1 if you have the <winsock2.h> header file. */
 /* #undef HAVE_WINSOCK2_H */
 
@@ -329,7 +364,7 @@
 #define PACKAGE_NAME "ldns"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ldns 1.7.1"
+#define PACKAGE_STRING "ldns 1.8.3"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "libdns"
@@ -338,7 +373,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.7.1"
+#define PACKAGE_VERSION "1.8.3"
 
 /* Define this to enable RR type AMTRELAY. */
 /* #undef RRTYPE_AMTRELAY */
@@ -358,13 +393,18 @@
 /* Define this to enable RR type RKEY. */
 /* #undef RRTYPE_RKEY */
 
+/* Define this to enable RR types SVCB and HTTPS. */
+#define RRTYPE_SVCB_HTTPS /**/
+
 /* Define this to enable RR type TA. */
 /* #undef RRTYPE_TA */
 
 /* The size of `time_t', as computed by sizeof. */
 #define SIZEOF_TIME_T 8
 
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+   required in a freestanding environment). This macro is provided for
+   backward compatibility; new code need not use it. */
 #define STDC_HEADERS 1
 
 /* Define this to enable messages to stderr. */
@@ -404,21 +444,87 @@
 #ifndef _ALL_SOURCE
 # define _ALL_SOURCE 1
 #endif
+/* Enable general extensions on macOS.  */
+#ifndef _DARWIN_C_SOURCE
+# define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
 /* Enable GNU extensions on systems that have them.  */
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE 1
 #endif
-/* Enable threading extensions on Solaris.  */
+/* Enable X/Open compliant socket functions that do not require linking
+   with -lxnet on HP-UX 11.11.  */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+   This macro does not affect the system headers' behavior.
+   A future release of Autoconf may stop defining this macro.  */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+   Enable NetBSD compatibility extensions on Minix.  */
+#ifndef _NETBSD_SOURCE
+# define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+   Oddly enough, this does nothing on OpenBSD.  */
+#ifndef _OPENBSD_SOURCE
+# define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior.  */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris.  */
 #ifndef _POSIX_PTHREAD_SEMANTICS
 # define _POSIX_PTHREAD_SEMANTICS 1
 #endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015.  */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */
+#ifndef __STDC_WANT_LIB_EXT2__
+# define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009.  */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
 /* Enable extensions on HP NonStop.  */
 #ifndef _TANDEM_SOURCE
 # define _TANDEM_SOURCE 1
 #endif
-/* Enable general extensions on Solaris.  */
-#ifndef __EXTENSIONS__
-# define __EXTENSIONS__ 1
+/* Enable X/Open extensions.  Define to 500 only if necessary
+   to make mbstate_t available.  */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
 #endif
 
 
@@ -440,18 +546,8 @@
 # endif
 #endif
 
-/* Define to 1 if on MINIX. */
-/* #undef _MINIX */
-
 /* Enable for compile on Minix */
-/* #undef _NETBSD_SOURCE */
-
-/* Define to 2 if the system does not provide POSIX.1 features except with
-   this defined. */
-/* #undef _POSIX_1_SOURCE */
-
-/* Define to 1 if you need to in order for `stat' and other things to work. */
-/* #undef _POSIX_SOURCE */
+#define _NETBSD_SOURCE 1
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
@@ -483,15 +579,9 @@
 /* Define to `size_t' if <sys/types.h> does not define. */
 /* #undef intptr_t */
 
-/* Define to rpl_malloc if the replacement function should be used. */
-/* #undef malloc */
-
-/* Define to `int' if <sys/types.h> does not define. */
+/* Define as a signed integer type capable of holding a process identifier. */
 /* #undef pid_t */
 
-/* Define to rpl_realloc if the replacement function should be used. */
-/* #undef realloc */
-
 /* Define to `unsigned int' if <sys/types.h> does not define. */
 /* #undef size_t */
 
diff --git a/lib/libldns/ldns/net.h b/lib/libldns/ldns/net.h
index d074f20ace..0fbf1544d5 100644
--- a/lib/libldns/ldns/net.h
+++ b/lib/libldns/ldns/net.h
@@ -30,7 +30,7 @@ extern "C" {
  */
 
 /**
- * Sends a buffer to an ip using udp and return the respons as a ldns_pkt
+ * Sends a buffer to an ip using udp and return the response as a ldns_pkt
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] to the ip addr to send to
  * \param[in] tolen length of the ip addr
@@ -90,7 +90,7 @@ int ldns_tcp_bgsend2(ldns_buffer *qbin, const struct sockaddr_storage *to, sockl
 int ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
 
 /**
- * Sends a buffer to an ip using tcp and return the respons as a ldns_pkt
+ * Sends a buffer to an ip using tcp and return the response as a ldns_pkt
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] to the ip addr to send to
@@ -233,7 +233,7 @@ struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, u
  * returns an rdf with the sockaddr info. works for ip4 and ip6
  * \param[in] sock the struct sockaddr_storage to convert
  * \param[in] port what port was used. When NULL this is not set
- * \return ldns_rdf* wth the address
+ * \return ldns_rdf* with the address
  */
 ldns_rdf * ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port);
 
@@ -241,7 +241,7 @@ ldns_rdf * ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16
  * Prepares the resolver for an axfr query
  * The query is sent and the answers can be read with ldns_axfr_next
  * \param[in] resolver the resolver to use
- * \param[in] domain the domain to exfr
+ * \param[in] domain the domain to axfr
  * \param[in] c the class to use
  * \return ldns_status the status of the transfer
  */
diff --git a/lib/libldns/ldns/util.h b/lib/libldns/ldns/util.h
index 0e7ead89f1..1d8fa8836a 100644
--- a/lib/libldns/ldns/util.h
+++ b/lib/libldns/ldns/util.h
@@ -27,8 +27,8 @@ extern "C" {
 #define dprintf(X,Y) fprintf(stderr, (X), (Y))
 /* #define	dprintf(X, Y)  */
 
-#define LDNS_VERSION "1.7.1"
-#define LDNS_REVISION ((1<<16)|(7<<8)|(1))
+#define LDNS_VERSION "1.8.3"
+#define LDNS_REVISION ((1<<16)|(8<<8)|(3))
 
 /**
  * splint static inline workaround
@@ -274,19 +274,22 @@ time_t 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).
+ * with respect to now using serial arithmetics (rfc1982).
  * That number of seconds is then converted to broken-out time information.
  * This is especially useful 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.
+ *            to be interpreted as a serial arithmetics 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 * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+struct tm * ldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/* previously used wrong spelling */
+#define ldns_serial_arithmitics_gmtime_r ldns_serial_arithmetics_gmtime_r
  
 /**
  * Seed the random function.
diff --git a/usr.bin/drill/drill.1 b/usr.bin/drill/drill.1
index 85f75ce5a0..712dffb02a 100644
--- a/usr.bin/drill/drill.1
+++ b/usr.bin/drill/drill.1
@@ -1,5 +1,5 @@
 .\" @(#)drill.1 1.7.0 14-Jul-2004 OF; 
-.TH drill 1 "16 Jul 2020"
+.TH drill 1 "12 Nov 2022"
 .SH NAME
 drill \- get (debug) information out of DNS(SEC)
 .SH SYNOPSIS
