summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2012-03-12 17:32:02 (GMT)
committerTobias Markmann <tm@ayena.de>2012-03-21 20:41:16 (GMT)
commit2878d950c11526094dc2faeb2caeeb1004f1690d (patch)
tree891760e443f9c90135165bb4ec29c72647179bcf /3rdParty/Ldns
parent2fa37f2976b933ca0bcf5f85dd1615805776d67d (diff)
downloadswift-contrib-2878d950c11526094dc2faeb2caeeb1004f1690d.zip
swift-contrib-2878d950c11526094dc2faeb2caeeb1004f1690d.tar.bz2
Adding basic unbound support.
Diffstat (limited to '3rdParty/Ldns')
-rw-r--r--3rdParty/Ldns/SConscript68
-rw-r--r--3rdParty/Ldns/src/LICENSE26
-rw-r--r--3rdParty/Ldns/src/include/ldns/buffer.h644
-rw-r--r--3rdParty/Ldns/src/include/ldns/common.h69
-rw-r--r--3rdParty/Ldns/src/include/ldns/common.h.in69
-rw-r--r--3rdParty/Ldns/src/include/ldns/config.h556
-rw-r--r--3rdParty/Ldns/src/include/ldns/config.h.in555
-rw-r--r--3rdParty/Ldns/src/include/ldns/dname.h201
-rw-r--r--3rdParty/Ldns/src/include/ldns/dnssec.h522
-rw-r--r--3rdParty/Ldns/src/include/ldns/dnssec_sign.h383
-rw-r--r--3rdParty/Ldns/src/include/ldns/dnssec_verify.h873
-rw-r--r--3rdParty/Ldns/src/include/ldns/dnssec_zone.h440
-rw-r--r--3rdParty/Ldns/src/include/ldns/error.h121
-rw-r--r--3rdParty/Ldns/src/include/ldns/higher.h113
-rw-r--r--3rdParty/Ldns/src/include/ldns/host2str.h759
-rw-r--r--3rdParty/Ldns/src/include/ldns/host2wire.h164
-rw-r--r--3rdParty/Ldns/src/include/ldns/keys.h615
-rw-r--r--3rdParty/Ldns/src/include/ldns/ldns.h155
-rw-r--r--3rdParty/Ldns/src/include/ldns/net.h208
-rw-r--r--3rdParty/Ldns/src/include/ldns/net.h.in208
-rw-r--r--3rdParty/Ldns/src/include/ldns/packet.h855
-rw-r--r--3rdParty/Ldns/src/include/ldns/parse.h167
-rw-r--r--3rdParty/Ldns/src/include/ldns/rbtree.h230
-rw-r--r--3rdParty/Ldns/src/include/ldns/rdata.h385
-rw-r--r--3rdParty/Ldns/src/include/ldns/resolver.h721
-rw-r--r--3rdParty/Ldns/src/include/ldns/rr.h886
-rw-r--r--3rdParty/Ldns/src/include/ldns/rr_functions.h363
-rw-r--r--3rdParty/Ldns/src/include/ldns/sha1.h38
-rw-r--r--3rdParty/Ldns/src/include/ldns/sha2.h149
-rw-r--r--3rdParty/Ldns/src/include/ldns/str2host.h251
-rw-r--r--3rdParty/Ldns/src/include/ldns/tsig.h101
-rw-r--r--3rdParty/Ldns/src/include/ldns/update.h115
-rw-r--r--3rdParty/Ldns/src/include/ldns/util.h367
-rw-r--r--3rdParty/Ldns/src/include/ldns/util.h.in367
-rw-r--r--3rdParty/Ldns/src/include/ldns/wire2host.h197
-rw-r--r--3rdParty/Ldns/src/include/ldns/zone.h176
-rw-r--r--3rdParty/Ldns/src/src/buffer.c176
-rw-r--r--3rdParty/Ldns/src/src/compat/b32_ntop.c333
-rw-r--r--3rdParty/Ldns/src/src/compat/b32_pton.c387
-rw-r--r--3rdParty/Ldns/src/src/compat/b64_ntop.c202
-rw-r--r--3rdParty/Ldns/src/src/compat/b64_pton.c260
-rw-r--r--3rdParty/Ldns/src/src/dname.c567
-rw-r--r--3rdParty/Ldns/src/src/dnssec.c1766
-rw-r--r--3rdParty/Ldns/src/src/dnssec_sign.c1420
-rw-r--r--3rdParty/Ldns/src/src/dnssec_verify.c2642
-rw-r--r--3rdParty/Ldns/src/src/dnssec_zone.c921
-rw-r--r--3rdParty/Ldns/src/src/error.c107
-rw-r--r--3rdParty/Ldns/src/src/higher.c359
-rw-r--r--3rdParty/Ldns/src/src/host2str.c2311
-rw-r--r--3rdParty/Ldns/src/src/host2wire.c433
-rw-r--r--3rdParty/Ldns/src/src/keys.c1672
-rw-r--r--3rdParty/Ldns/src/src/linktest.c13
-rw-r--r--3rdParty/Ldns/src/src/net.c907
-rw-r--r--3rdParty/Ldns/src/src/packet.c1007
-rw-r--r--3rdParty/Ldns/src/src/parse.c450
-rw-r--r--3rdParty/Ldns/src/src/rbtree.c669
-rw-r--r--3rdParty/Ldns/src/src/rdata.c675
-rw-r--r--3rdParty/Ldns/src/src/resolver.c1350
-rw-r--r--3rdParty/Ldns/src/src/rr.c2421
-rw-r--r--3rdParty/Ldns/src/src/rr_functions.c419
-rw-r--r--3rdParty/Ldns/src/src/sha1.c177
-rw-r--r--3rdParty/Ldns/src/src/sha2.c982
-rw-r--r--3rdParty/Ldns/src/src/str2host.c1316
-rw-r--r--3rdParty/Ldns/src/src/tsig.c472
-rw-r--r--3rdParty/Ldns/src/src/update.c318
-rw-r--r--3rdParty/Ldns/src/src/util.c488
-rw-r--r--3rdParty/Ldns/src/src/wire2host.c456
-rw-r--r--3rdParty/Ldns/src/src/zone.c431
68 files changed, 38224 insertions, 0 deletions
diff --git a/3rdParty/Ldns/SConscript b/3rdParty/Ldns/SConscript
new file mode 100644
index 0000000..336656d
--- /dev/null
+++ b/3rdParty/Ldns/SConscript
@@ -0,0 +1,68 @@
+Import("env")
+
+if env.get("LDNS_BUNDLED", False) :
+
+ if env["PLATFORM"] == "win32" :
+ cppflags = ["/I" + Dir("#/3rdParty/Ldns/src/include").abspath]
+ else :
+ cppflags = [("-isystem", Dir("#/3rdParty/Ldns/src/include").abspath)]
+
+
+################################################################################
+# Flags
+################################################################################
+
+ if env["SCONS_STAGE"] == "flags" :
+ env["LDNS_FLAGS"] = {
+ "CPPPATH": [Dir("src/include")],
+ "CPPFLAGS": cppflags,
+ "LIBPATH": [env.Dir(".")],
+ "LIBS": ["Swiften_Ldns"],
+ }
+
+################################################################################
+# Build
+################################################################################
+
+ if env["SCONS_STAGE"] == "build" :
+ myenv = env.Clone()
+ myenv.Append(CPPDEFINES = [("LDNS_STATICLIB")])
+ myenv.Append(CPPPATH = ["src/include", "."])
+
+ myenv.Install("include", [
+
+ ])
+ myenv.StaticLibrary("Swiften_Ldns", [
+ "src/src/compat/b32_ntop.c",
+ "src/src/compat/b32_pton.c",
+ "src/src/compat/b64_ntop.c",
+ "src/src/compat/b64_pton.c",
+ "src/src/buffer.c",
+ "src/src/dname.c",
+ "src/src/dnssec_sign.c",
+ "src/src/dnssec_verify.c",
+ "src/src/dnssec_zone.c",
+ "src/src/dnssec.c",
+ "src/src/error.c",
+ "src/src/higher.c",
+ "src/src/host2str.c",
+ "src/src/host2wire.c",
+ "src/src/keys.c",
+ "src/src/linktest.c",
+ "src/src/net.c",
+ "src/src/packet.c",
+ "src/src/parse.c",
+ "src/src/rbtree.c",
+ "src/src/rdata.c",
+ "src/src/resolver.c",
+ "src/src/rr_functions.c",
+ "src/src/rr.c",
+ "src/src/sha1.c",
+ "src/src/sha2.c",
+ "src/src/str2host.c",
+ "src/src/tsig.c",
+ "src/src/update.c",
+ "src/src/util.c",
+ "src/src/wire2host.c",
+ "src/src/zone.c",
+ ])
diff --git a/3rdParty/Ldns/src/LICENSE b/3rdParty/Ldns/src/LICENSE
new file mode 100644
index 0000000..6d4c6be
--- /dev/null
+++ b/3rdParty/Ldns/src/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2005,2006, NLnetLabs
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of NLnetLabs nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdParty/Ldns/src/include/ldns/buffer.h b/3rdParty/Ldns/src/include/ldns/buffer.h
new file mode 100644
index 0000000..03df14c
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/buffer.h
@@ -0,0 +1,644 @@
+/*
+ * buffer.h -- generic memory buffer.
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ *
+ * The buffer module implements a generic buffer. The API is based on
+ * the java.nio.Buffer interface.
+ */
+
+#ifndef LDNS_BUFFER_H
+#define LDNS_BUFFER_H
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <ldns/error.h>
+#include <ldns/common.h>
+
+#include "ldns/util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * number of initial bytes in buffer of
+ * which we cannot tell the size before hand
+ */
+#define LDNS_MIN_BUFLEN 512
+
+/**
+ * \file buffer.h
+ *
+ * This file contains the definition of ldns_buffer, and functions to manipulate those.
+ */
+
+/**
+ * implementation of buffers to ease operations
+ *
+ * ldns_buffers can contain arbitrary information, per octet. You can write
+ * to the current end of a buffer, read from the current position, and
+ * access any data within it.
+ *
+ * Example use of buffers is in the source code of \ref host2str.c
+ */
+struct ldns_struct_buffer
+{
+ /** The current position used for reading/writing */
+ size_t _position;
+
+ /** The read/write limit */
+ size_t _limit;
+
+ /** The amount of data the buffer can contain */
+ size_t _capacity;
+
+ /** The data contained in the buffer */
+ uint8_t *_data;
+
+ /** If the buffer is fixed it cannot be resized */
+ unsigned _fixed : 1;
+
+ /** The current state of the buffer. If writing to the buffer fails
+ * for any reason, this value is changed. This way, you can perform
+ * multiple writes in sequence and check for success afterwards. */
+ ldns_status _status;
+};
+typedef struct ldns_struct_buffer ldns_buffer;
+
+
+#ifdef NDEBUG
+INLINE void
+ldns_buffer_invariant(ldns_buffer *ATTR_UNUSED(buffer))
+{
+}
+#else
+INLINE void
+ldns_buffer_invariant(ldns_buffer *buffer)
+{
+ assert(buffer != NULL);
+ assert(buffer->_position <= buffer->_limit);
+ assert(buffer->_limit <= buffer->_capacity);
+ assert(buffer->_data != NULL);
+}
+#endif
+
+/**
+ * creates a new buffer with the specified capacity.
+ *
+ * \param[in] capacity the size (in bytes) to allocate for the buffer
+ * \return the created buffer
+ */
+ldns_buffer *ldns_buffer_new(size_t capacity);
+
+/**
+ * creates a buffer with the specified data. The data IS copied
+ * and MEMORY allocations are done. The buffer is not fixed and can
+ * be resized using buffer_reserve().
+ *
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void ldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * clears the buffer and make it ready for writing. The buffer's limit
+ * is set to the capacity and the position is set to 0.
+ * \param[in] buffer the buffer to clear
+ */
+INLINE void ldns_buffer_clear(ldns_buffer *buffer)
+{
+ ldns_buffer_invariant(buffer);
+
+ /* reset status here? */
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity;
+}
+
+/**
+ * makes the buffer ready for reading the data that has been written to
+ * the buffer. The buffer's limit is set to the current position and
+ * the position is set to 0.
+ *
+ * \param[in] buffer the buffer to flip
+ * \return void
+ */
+INLINE void ldns_buffer_flip(ldns_buffer *buffer)
+{
+ ldns_buffer_invariant(buffer);
+
+ buffer->_limit = buffer->_position;
+ buffer->_position = 0;
+}
+
+/**
+ * make the buffer ready for re-reading the data. The buffer's
+ * position is reset to 0.
+ * \param[in] buffer the buffer to rewind
+ */
+INLINE void ldns_buffer_rewind(ldns_buffer *buffer)
+{
+ ldns_buffer_invariant(buffer);
+
+ buffer->_position = 0;
+}
+
+/**
+ * returns the current position in the buffer (as a number of bytes)
+ * \param[in] buffer the buffer
+ * \return the current position
+ */
+INLINE size_t
+ldns_buffer_position(ldns_buffer *buffer)
+{
+ return buffer->_position;
+}
+
+/**
+ * sets the buffer's position to MARK. The position must be less than
+ * or equal to the buffer's limit.
+ * \param[in] buffer the buffer
+ * \param[in] mark the mark to use
+ */
+INLINE void
+ldns_buffer_set_position(ldns_buffer *buffer, size_t mark)
+{
+ assert(mark <= buffer->_limit);
+ buffer->_position = mark;
+}
+
+/**
+ * changes the buffer's position by COUNT bytes. The position must not
+ * be moved behind the buffer's limit or before the beginning of the
+ * buffer.
+ * \param[in] buffer the buffer
+ * \param[in] count the count to use
+ */
+INLINE void
+ldns_buffer_skip(ldns_buffer *buffer, ssize_t count)
+{
+ assert(buffer->_position + count <= buffer->_limit);
+ buffer->_position += count;
+}
+
+/**
+ * returns the maximum size of the buffer
+ * \param[in] buffer
+ * \return the size
+ */
+INLINE size_t
+ldns_buffer_limit(ldns_buffer *buffer)
+{
+ return buffer->_limit;
+}
+
+/**
+ * changes the buffer's limit. If the buffer's position is greater
+ * than the new limit the position is set to the limit.
+ * \param[in] buffer the buffer
+ * \param[in] limit the new limit
+ */
+INLINE void
+ldns_buffer_set_limit(ldns_buffer *buffer, size_t limit)
+{
+ assert(limit <= buffer->_capacity);
+ buffer->_limit = limit;
+ if (buffer->_position > buffer->_limit)
+ buffer->_position = buffer->_limit;
+}
+
+/**
+ * returns the number of bytes the buffer can hold.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+ldns_buffer_capacity(ldns_buffer *buffer)
+{
+ return buffer->_capacity;
+}
+
+/**
+ * changes the buffer's capacity. The data is reallocated so any
+ * pointers to the data may become invalid. The buffer's limit is set
+ * to the buffer's new capacity.
+ * \param[in] buffer the buffer
+ * \param[in] capacity the capacity to use
+ * \return whether this failed or succeeded
+ */
+bool ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity);
+
+/**
+ * ensures BUFFER can contain at least AMOUNT more bytes. The buffer's
+ * capacity is increased if necessary using buffer_set_capacity().
+ *
+ * The buffer's limit is always set to the (possibly increased)
+ * capacity.
+ * \param[in] buffer the buffer
+ * \param[in] amount amount to use
+ * \return whether this failed or succeeded
+ */
+bool ldns_buffer_reserve(ldns_buffer *buffer, size_t amount);
+
+/**
+ * returns a pointer to the data at the indicated position.
+ * \param[in] buffer the buffer
+ * \param[in] at position
+ * \return the pointer to the data
+ */
+INLINE uint8_t *
+ldns_buffer_at(const ldns_buffer *buffer, size_t at)
+{
+ assert(at <= buffer->_limit);
+ return buffer->_data + at;
+}
+
+/**
+ * returns a pointer to the beginning of the buffer (the data at
+ * position 0).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+ldns_buffer_begin(const ldns_buffer *buffer)
+{
+ return ldns_buffer_at(buffer, 0);
+}
+
+/**
+ * returns a pointer to the end of the buffer (the data at the buffer's
+ * limit).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+ldns_buffer_end(ldns_buffer *buffer)
+{
+ return ldns_buffer_at(buffer, buffer->_limit);
+}
+
+/**
+ * returns a pointer to the data at the buffer's current position.
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+ldns_buffer_current(ldns_buffer *buffer)
+{
+ return ldns_buffer_at(buffer, buffer->_position);
+}
+
+/**
+ * returns the number of bytes remaining between the indicated position and
+ * the limit.
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \return number of bytes
+ */
+INLINE size_t
+ldns_buffer_remaining_at(ldns_buffer *buffer, size_t at)
+{
+ ldns_buffer_invariant(buffer);
+ assert(at <= buffer->_limit);
+ return buffer->_limit - at;
+}
+
+/**
+ * returns the number of bytes remaining between the buffer's position and
+ * limit.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+ldns_buffer_remaining(ldns_buffer *buffer)
+{
+ return ldns_buffer_remaining_at(buffer, buffer->_position);
+}
+
+/**
+ * checks if the buffer has at least COUNT more bytes available.
+ * Before reading or writing the caller needs to ensure enough space
+ * is available!
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+ldns_buffer_available_at(ldns_buffer *buffer, size_t at, size_t count)
+{
+ return count <= ldns_buffer_remaining_at(buffer, at);
+}
+
+/**
+ * checks if the buffer has count bytes available at the current position
+ * \param[in] buffer the buffer
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+ldns_buffer_available(ldns_buffer *buffer, size_t count)
+{
+ return ldns_buffer_available_at(buffer, buffer->_position, count);
+}
+
+/**
+ * writes the given data to the buffer at the specified position
+ * \param[in] buffer the buffer
+ * \param[in] at the position (in number of bytes) to write the data at
+ * \param[in] data pointer to the data to write to the buffer
+ * \param[in] count the number of bytes of data to write
+ */
+INLINE void
+ldns_buffer_write_at(ldns_buffer *buffer, size_t at, const void *data, size_t count)
+{
+ assert(ldns_buffer_available_at(buffer, at, count));
+ memcpy(buffer->_data + at, data, count);
+}
+
+/**
+ * writes count bytes of data to the current position of the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the data to write
+ * \param[in] count the lenght of the data to write
+ */
+INLINE void
+ldns_buffer_write(ldns_buffer *buffer, const void *data, size_t count)
+{
+ ldns_buffer_write_at(buffer, buffer->_position, data, count);
+ buffer->_position += count;
+}
+
+/**
+ * copies the given (null-delimited) string to the specified position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+ldns_buffer_write_string_at(ldns_buffer *buffer, size_t at, const char *str)
+{
+ ldns_buffer_write_at(buffer, at, str, strlen(str));
+}
+
+/**
+ * copies the given (null-delimited) string to the current position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+ldns_buffer_write_string(ldns_buffer *buffer, const char *str)
+{
+ ldns_buffer_write(buffer, str, strlen(str));
+}
+
+/**
+ * writes the given byte of data at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+ldns_buffer_write_u8_at(ldns_buffer *buffer, size_t at, uint8_t data)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(data)));
+ buffer->_data[at] = data;
+}
+
+/**
+ * writes the given byte of data at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+ldns_buffer_write_u8(ldns_buffer *buffer, uint8_t data)
+{
+ ldns_buffer_write_u8_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 2 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+ldns_buffer_write_u16_at(ldns_buffer *buffer, size_t at, uint16_t data)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(data)));
+ ldns_write_uint16(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 2 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+ldns_buffer_write_u16(ldns_buffer *buffer, uint16_t data)
+{
+ ldns_buffer_write_u16_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 4 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+ldns_buffer_write_u32_at(ldns_buffer *buffer, size_t at, uint32_t data)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(data)));
+ ldns_write_uint32(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 4 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+ldns_buffer_write_u32(ldns_buffer *buffer, uint32_t data)
+{
+ ldns_buffer_write_u32_at(buffer, buffer->_position, data);
+ buffer->_position += sizeof(data);
+}
+
+/**
+ * copies count bytes of data at the given position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer to start
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+ldns_buffer_read_at(ldns_buffer *buffer, size_t at, void *data, size_t count)
+{
+ assert(ldns_buffer_available_at(buffer, at, count));
+ memcpy(data, buffer->_data + at, count);
+}
+
+/**
+ * copies count bytes of data at the current position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+ldns_buffer_read(ldns_buffer *buffer, void *data, size_t count)
+{
+ ldns_buffer_read_at(buffer, buffer->_position, data, count);
+ buffer->_position += count;
+}
+
+/**
+ * returns the byte value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+ldns_buffer_read_u8_at(ldns_buffer *buffer, size_t at)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
+ return buffer->_data[at];
+}
+
+/**
+ * returns the byte value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+ldns_buffer_read_u8(ldns_buffer *buffer)
+{
+ uint8_t result = ldns_buffer_read_u8_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint8_t);
+ return result;
+}
+
+/**
+ * returns the 2-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+ldns_buffer_read_u16_at(ldns_buffer *buffer, size_t at)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
+ return ldns_read_uint16(buffer->_data + at);
+}
+
+/**
+ * returns the 2-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+ldns_buffer_read_u16(ldns_buffer *buffer)
+{
+ uint16_t result = ldns_buffer_read_u16_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint16_t);
+ return result;
+}
+
+/**
+ * returns the 4-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+ldns_buffer_read_u32_at(ldns_buffer *buffer, size_t at)
+{
+ assert(ldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
+ return ldns_read_uint32(buffer->_data + at);
+}
+
+/**
+ * returns the 4-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+ldns_buffer_read_u32(ldns_buffer *buffer)
+{
+ uint32_t result = ldns_buffer_read_u32_at(buffer, buffer->_position);
+ buffer->_position += sizeof(uint32_t);
+ return result;
+}
+
+/**
+ * returns the status of the buffer
+ * \param[in] buffer
+ * \return the status
+ */
+INLINE ldns_status
+ldns_buffer_status(ldns_buffer *buffer)
+{
+ return buffer->_status;
+}
+
+/**
+ * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise
+ * \param[in] buffer the buffer
+ * \return true or false
+ */
+INLINE bool
+ldns_buffer_status_ok(ldns_buffer *buffer)
+{
+ if (buffer) {
+ return ldns_buffer_status(buffer) == LDNS_STATUS_OK;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * prints to the buffer, increasing the capacity if required using
+ * buffer_reserve(). The buffer's position is set to the terminating '\\0'
+ * Returns the number of characters written (not including the
+ * terminating '\\0') or -1 on failure.
+ */
+int ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...);
+/* ATTR_FORMAT(printf, 2, 3);*/
+
+/**
+ * frees the buffer.
+ * \param[in] *buffer the buffer to be freed
+ * \return void
+ */
+void ldns_buffer_free(ldns_buffer *buffer);
+
+/**
+ * Makes the buffer fixed and returns a pointer to the data. The
+ * caller is responsible for free'ing the result.
+ * \param[in] *buffer the buffer to be exported
+ * \return void
+ */
+void *ldns_buffer_export(ldns_buffer *buffer);
+
+/**
+ * Copy contents of the other buffer to this buffer. Silently truncated
+ * if this buffer is too small.
+ * \param[out] *result resulting buffer which is copied to.
+ * \param[in] *from what to copy to result.
+ */
+void ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_BUFFER_H */
diff --git a/3rdParty/Ldns/src/include/ldns/common.h b/3rdParty/Ldns/src/include/ldns/common.h
new file mode 100644
index 0000000..ed3847f
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/common.h
@@ -0,0 +1,69 @@
+/**
+ * \file common.h
+ *
+ * Common definitions for LDNS
+ */
+
+/**
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_COMMON_H
+#define LDNS_COMMON_H
+
+/*
+ * The build configuration that is used in the distributed headers,
+ * as detected and determined by the auto configure script.
+ */
+#define LDNS_BUILD_CONFIG_HAVE_SSL 1
+#define LDNS_BUILD_CONFIG_USE_ECDSA 0
+#define LDNS_BUILD_CONFIG_HAVE_INTTYPES_H 1
+#define LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT 1
+#define LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED 1
+
+/*
+ * HAVE_STDBOOL_H is not available when distributed as a library, but no build
+ * configuration variables may be used (like those above) because the header
+ * is sometimes only available when using special compiler flags to enable the
+ * c99 environment. Because we cannot force the usage of this flag, we have to
+ * provide a default type. Below what is suggested by the autoconf manual.
+ */
+/*@ignore@*/
+/* splint barfs on this construct */
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# ifndef HAVE__BOOL
+# ifdef __cplusplus
+typedef bool _Bool;
+# else
+# define _Bool signed char
+# endif
+# endif
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
+/*@end@*/
+
+#if LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT
+#define ATTR_FORMAT(archetype, string_index, first_to_check) \
+ __attribute__ ((format (archetype, string_index, first_to_check)))
+#else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */
+#define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
+#endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */
+
+#if defined(__cplusplus)
+#define ATTR_UNUSED(x)
+#elif LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED
+#define ATTR_UNUSED(x) x __attribute__((unused))
+#else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */
+#define ATTR_UNUSED(x) x
+#endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */
+
+#endif /* LDNS_COMMON_H */
diff --git a/3rdParty/Ldns/src/include/ldns/common.h.in b/3rdParty/Ldns/src/include/ldns/common.h.in
new file mode 100644
index 0000000..98470ee
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/common.h.in
@@ -0,0 +1,69 @@
+/**
+ * \file common.h
+ *
+ * Common definitions for LDNS
+ */
+
+/**
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_COMMON_H
+#define LDNS_COMMON_H
+
+/*
+ * The build configuration that is used in the distributed headers,
+ * as detected and determined by the auto configure script.
+ */
+#define LDNS_BUILD_CONFIG_HAVE_SSL @ldns_build_config_have_ssl@
+#define LDNS_BUILD_CONFIG_USE_ECDSA @ldns_build_config_use_ecdsa@
+#define LDNS_BUILD_CONFIG_HAVE_INTTYPES_H @ldns_build_config_have_inttypes_h@
+#define LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT @ldns_build_config_have_attr_format@
+#define LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED @ldns_build_config_have_attr_unused@
+
+/*
+ * HAVE_STDBOOL_H is not available when distributed as a library, but no build
+ * configuration variables may be used (like those above) because the header
+ * is sometimes only available when using special compiler flags to enable the
+ * c99 environment. Because we cannot force the usage of this flag, we have to
+ * provide a default type. Below what is suggested by the autoconf manual.
+ */
+/*@ignore@*/
+/* splint barfs on this construct */
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# ifndef HAVE__BOOL
+# ifdef __cplusplus
+typedef bool _Bool;
+# else
+# define _Bool signed char
+# endif
+# endif
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
+/*@end@*/
+
+#if LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT
+#define ATTR_FORMAT(archetype, string_index, first_to_check) \
+ __attribute__ ((format (archetype, string_index, first_to_check)))
+#else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */
+#define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
+#endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_FORMAT */
+
+#if defined(__cplusplus)
+#define ATTR_UNUSED(x)
+#elif LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED
+#define ATTR_UNUSED(x) x __attribute__((unused))
+#else /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */
+#define ATTR_UNUSED(x) x
+#endif /* !LDNS_BUILD_CONFIG_HAVE_ATTR_UNUSED */
+
+#endif /* LDNS_COMMON_H */
diff --git a/3rdParty/Ldns/src/include/ldns/config.h b/3rdParty/Ldns/src/include/ldns/config.h
new file mode 100644
index 0000000..e271415
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/config.h
@@ -0,0 +1,556 @@
+/* ldns/config.h. Generated from config.h.in by configure. */
+/* ldns/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Whether the C compiler accepts the "format" attribute */
+#define HAVE_ATTR_FORMAT 1
+
+/* Whether the C compiler accepts the "unused" attribute */
+#define HAVE_ATTR_UNUSED 1
+
+/* Define to 1 if you have the `b32_ntop' function. */
+/* #undef HAVE_B32_NTOP */
+
+/* Define to 1 if you have the `b32_pton' function. */
+/* #undef HAVE_B32_PTON */
+
+/* Define to 1 if you have the `b64_ntop' function. */
+/* #undef HAVE_B64_NTOP */
+
+/* Define to 1 if you have the `b64_pton' function. */
+/* #undef HAVE_B64_PTON */
+
+/* Define to 1 if you have the `bzero' function. */
+#define HAVE_BZERO 1
+
+/* Define to 1 if you have the `calloc' function. */
+#define HAVE_CALLOC 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_NID_SECP384R1 */
+
+/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0
+ if you don't. */
+/* #undef HAVE_DECL_NID_X9_62_PRIME256V1 */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `endprotoent' function. */
+#define HAVE_ENDPROTOENT 1
+
+/* Define to 1 if you have the `endservent' function. */
+#define HAVE_ENDSERVENT 1
+
+/* Define to 1 if you have the `EVP_sha256' function. */
+#define HAVE_EVP_SHA256 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Whether getaddrinfo is available */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* If you have HMAC_CTX_init */
+#define HAVE_HMAC_CTX_INIT 1
+
+/* Define to 1 if you have the `inet_aton' function. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the `inet_pton' function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* define if you have inttypes.h */
+#define HAVE_INTTYPES_H 1
+
+/* if the function 'ioctlsocket' is available */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the `isascii' function. */
+#define HAVE_ISASCII 1
+
+/* Define to 1 if you have the `isblank' function. */
+#define HAVE_ISBLANK 1
+
+/* Define to 1 if you have the `pcap' library (-lpcap). */
+/* #undef HAVE_LIBPCAP */
+
+/* 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 <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/if_ether.h> header file. */
+/* #undef HAVE_NETINET_IF_ETHER_H */
+
+/* Define to 1 if you have the <netinet/igmp.h> header file. */
+/* #undef HAVE_NETINET_IGMP_H */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/in_systm.h> header file. */
+/* #undef HAVE_NETINET_IN_SYSTM_H */
+
+/* Define to 1 if you have the <netinet/ip6.h> header file. */
+/* #undef HAVE_NETINET_IP6_H */
+
+/* Define to 1 if you have the <netinet/ip_compat.h> header file. */
+/* #undef HAVE_NETINET_IP_COMPAT_H */
+
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+/* #undef HAVE_NETINET_IP_H */
+
+/* Define to 1 if you have the <netinet/udp.h> header file. */
+/* #undef HAVE_NETINET_UDP_H */
+
+/* Define to 1 if you have the <net/ethernet.h> header file. */
+/* #undef HAVE_NET_ETHERNET_H */
+
+/* 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/err.h> header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/rand.h> header file. */
+#define HAVE_OPENSSL_RAND_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <pcap.h> header file. */
+/* #undef HAVE_PCAP_H */
+
+/* If available, contains the Python version number currently in use. */
+/* #undef HAVE_PYTHON */
+
+/* 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
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define if you have the SSL libraries installed. */
+#define HAVE_SSL /**/
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define if you have SWIG libraries and header files. */
+/* #undef HAVE_SWIG */
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#define HAVE_SYS_MOUNT_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* define if you have sys/socket.h */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* define if you have sys/types.h */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `timegm' function. */
+#define HAVE_TIMEGM 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* define if you have unistd.h */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if the system has the type `_Bool'. */
+#define HAVE__BOOL 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libdns@nlnetlabs.nl"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "ldns"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "ldns 1.6.12"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libdns"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.6.12"
+
+/* 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 STDC_HEADERS 1
+
+/* System configuration dir */
+#define SYSCONFDIR sysconfdir
+
+/* Define this to enable ECDSA support. */
+/* #undef USE_ECDSA */
+
+/* Define this to enable GOST support. */
+/* #undef USE_GOST */
+
+/* Define this to enable SHA256 and SHA512 support. */
+#define USE_SHA2 1
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 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
+#endif
+
+
+/* Whether the windows socket API is used */
+/* #undef USE_WINSOCK */
+
+/* the version of the windows API enabled */
+#define WINVER 0x0502
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* 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 to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* in_addr_t */
+/* #undef in_addr_t */
+
+/* in_port_t */
+/* #undef in_port_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `short' if <sys/types.h> does not define. */
+/* #undef int16_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef int32_t */
+
+/* Define to `long long' if <sys/types.h> does not define. */
+/* #undef int64_t */
+
+/* Define to `char' if <sys/types.h> does not define. */
+/* #undef int8_t */
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+ if such a type exists, and if the system does not define it. */
+/* #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. */
+/* #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 */
+
+/* Define to 'int' if not defined */
+/* #undef socklen_t */
+
+/* Fallback member name for socket family in struct sockaddr_storage */
+/* #undef ss_family */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+/* #undef uint16_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef uint32_t */
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+/* #undef uint64_t */
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+/* #undef uint8_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#ifndef BYTE_ORDER
+#ifdef WORDS_BIGENDIAN
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif /* WORDS_BIGENDIAN */
+#endif /* BYTE_ORDER */
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+
+/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
+#ifdef HAVE_WINSOCK2_H
+#define FD_SET_T (u_int)
+#else
+#define FD_SET_T
+#endif
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef B64_PTON
+int ldns_b64_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b64_ntop
+ */
+/*@unused@*/
+static inline size_t ldns_b64_ntop_calculate_size(size_t srcsize)
+{
+ return ((((srcsize + 2) / 3) * 4) + 1);
+}
+#endif /* !B64_PTON */
+#ifndef B64_NTOP
+int ldns_b64_pton(char const *src, uint8_t *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of ldns_b64_pton
+ */
+/*@unused@*/
+static inline size_t ldns_b64_pton_calculate_size(size_t srcsize)
+{
+ return (((((srcsize + 3) / 4) * 3)) + 1);
+}
+#endif /* !B64_NTOP */
+
+#ifndef HAVE_SLEEP
+/* use windows sleep, in millisecs, instead */
+#define sleep(x) Sleep((x)*1000)
+#endif
+
+#ifndef HAVE_RANDOM
+#define srandom(x) srand(x)
+#define random(x) rand(x)
+#endif
+
+#ifndef HAVE_TIMEGM
+#include <time.h>
+time_t timegm (struct tm *tm);
+#endif /* !TIMEGM */
+#ifndef HAVE_GMTIME_R
+struct tm *gmtime_r(const time_t *timep, struct tm *result);
+#endif
+#ifndef HAVE_LOCALTIME_R
+struct tm *localtime_r(const time_t *timep, struct tm *result);
+#endif
+#ifndef HAVE_ISBLANK
+int isblank(int c);
+#endif /* !HAVE_ISBLANK */
+#ifndef HAVE_ISASCII
+int isascii(int c);
+#endif /* !HAVE_ISASCII */
+#ifndef HAVE_SNPRINTF
+#include <stdarg.h>
+int snprintf (char *str, size_t count, const char *fmt, ...);
+int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
+#endif /* HAVE_SNPRINTF */
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, const char* src, void* dst);
+#endif /* HAVE_INET_PTON */
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *cp, struct in_addr *addr);
+#endif
+#ifndef HAVE_MEMMOVE
+void *memmove(void *dest, const void *src, size_t n);
+#endif
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#ifndef HAVE_GETADDRINFO
+#include "compat/fake-rfc2553.h"
+#endif
+#ifndef HAVE_STRTOUL
+#define strtoul (unsigned long)strtol
+#endif
+
diff --git a/3rdParty/Ldns/src/include/ldns/config.h.in b/3rdParty/Ldns/src/include/ldns/config.h.in
new file mode 100644
index 0000000..3393e99
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/config.h.in
@@ -0,0 +1,555 @@
+/* ldns/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Whether the C compiler accepts the "format" attribute */
+#undef HAVE_ATTR_FORMAT
+
+/* Whether the C compiler accepts the "unused" attribute */
+#undef HAVE_ATTR_UNUSED
+
+/* Define to 1 if you have the `b32_ntop' function. */
+#undef HAVE_B32_NTOP
+
+/* Define to 1 if you have the `b32_pton' function. */
+#undef HAVE_B32_PTON
+
+/* Define to 1 if you have the `b64_ntop' function. */
+#undef HAVE_B64_NTOP
+
+/* Define to 1 if you have the `b64_pton' function. */
+#undef HAVE_B64_PTON
+
+/* Define to 1 if you have the `bzero' function. */
+#undef HAVE_BZERO
+
+/* Define to 1 if you have the `calloc' function. */
+#undef HAVE_CALLOC
+
+/* Define to 1 if you have the `ctime_r' function. */
+#undef HAVE_CTIME_R
+
+/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you
+ don't. */
+#undef HAVE_DECL_NID_SECP384R1
+
+/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0
+ if you don't. */
+#undef HAVE_DECL_NID_X9_62_PRIME256V1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `endprotoent' function. */
+#undef HAVE_ENDPROTOENT
+
+/* Define to 1 if you have the `endservent' function. */
+#undef HAVE_ENDSERVENT
+
+/* Define to 1 if you have the `EVP_sha256' function. */
+#undef HAVE_EVP_SHA256
+
+/* Define to 1 if you have the `fcntl' function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Whether getaddrinfo is available */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#undef HAVE_GMTIME_R
+
+/* If you have HMAC_CTX_init */
+#undef HAVE_HMAC_CTX_INIT
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#undef HAVE_INTPTR_T
+
+/* define if you have inttypes.h */
+#undef HAVE_INTTYPES_H
+
+/* if the function 'ioctlsocket' is available */
+#undef HAVE_IOCTLSOCKET
+
+/* Define to 1 if you have the `isascii' function. */
+#undef HAVE_ISASCII
+
+/* Define to 1 if you have the `isblank' function. */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the `pcap' library (-lpcap). */
+#undef HAVE_LIBPCAP
+
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define to 1 if you have the <netinet/igmp.h> header file. */
+#undef HAVE_NETINET_IGMP_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define to 1 if you have the <netinet/ip6.h> header file. */
+#undef HAVE_NETINET_IP6_H
+
+/* Define to 1 if you have the <netinet/ip_compat.h> header file. */
+#undef HAVE_NETINET_IP_COMPAT_H
+
+/* Define to 1 if you have the <netinet/ip.h> header file. */
+#undef HAVE_NETINET_IP_H
+
+/* Define to 1 if you have the <netinet/udp.h> header file. */
+#undef HAVE_NETINET_UDP_H
+
+/* Define to 1 if you have the <net/ethernet.h> header file. */
+#undef HAVE_NET_ETHERNET_H
+
+/* 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/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H
+
+/* Define to 1 if you have the <openssl/rand.h> header file. */
+#undef HAVE_OPENSSL_RAND_H
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define to 1 if you have the <pcap.h> header file. */
+#undef HAVE_PCAP_H
+
+/* If available, contains the Python version number currently in use. */
+#undef HAVE_PYTHON
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#undef HAVE_REALLOC
+
+/* Define to 1 if you have the `sleep' function. */
+#undef HAVE_SLEEP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the SSL libraries installed. */
+#undef HAVE_SSL
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define if you have SWIG libraries and header files. */
+#undef HAVE_SWIG
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* define if you have sys/socket.h */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* define if you have sys/types.h */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the `timegm' function. */
+#undef HAVE_TIMEGM
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* define if you have unistd.h */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+#undef HAVE_WS2TCPIP_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `time_t', as computed by sizeof. */
+#undef SIZEOF_TIME_T
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* System configuration dir */
+#undef SYSCONFDIR
+
+/* Define this to enable ECDSA support. */
+#undef USE_ECDSA
+
+/* Define this to enable GOST support. */
+#undef USE_GOST
+
+/* Define this to enable SHA256 and SHA512 support. */
+#undef USE_SHA2
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Whether the windows socket API is used */
+#undef USE_WINSOCK
+
+/* the version of the windows API enabled */
+#undef WINVER
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* 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 to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* in_addr_t */
+#undef in_addr_t
+
+/* in_port_t */
+#undef in_port_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `char' if <sys/types.h> does not define. */
+#undef int8_t
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+ if such a type exists, and if the system does not define it. */
+#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. */
+#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
+
+/* Define to 'int' if not defined */
+#undef socklen_t
+
+/* Fallback member name for socket family in struct sockaddr_storage */
+#undef ss_family
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+#undef uint8_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#ifndef BYTE_ORDER
+#ifdef WORDS_BIGENDIAN
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif /* WORDS_BIGENDIAN */
+#endif /* BYTE_ORDER */
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+
+/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
+#ifdef HAVE_WINSOCK2_H
+#define FD_SET_T (u_int)
+#else
+#define FD_SET_T
+#endif
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef B64_PTON
+int ldns_b64_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b64_ntop
+ */
+/*@unused@*/
+static inline size_t ldns_b64_ntop_calculate_size(size_t srcsize)
+{
+ return ((((srcsize + 2) / 3) * 4) + 1);
+}
+#endif /* !B64_PTON */
+#ifndef B64_NTOP
+int ldns_b64_pton(char const *src, uint8_t *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of ldns_b64_pton
+ */
+/*@unused@*/
+static inline size_t ldns_b64_pton_calculate_size(size_t srcsize)
+{
+ return (((((srcsize + 3) / 4) * 3)) + 1);
+}
+#endif /* !B64_NTOP */
+
+#ifndef HAVE_SLEEP
+/* use windows sleep, in millisecs, instead */
+#define sleep(x) Sleep((x)*1000)
+#endif
+
+#ifndef HAVE_RANDOM
+#define srandom(x) srand(x)
+#define random(x) rand(x)
+#endif
+
+#ifndef HAVE_TIMEGM
+#include <time.h>
+time_t timegm (struct tm *tm);
+#endif /* !TIMEGM */
+#ifndef HAVE_GMTIME_R
+struct tm *gmtime_r(const time_t *timep, struct tm *result);
+#endif
+#ifndef HAVE_LOCALTIME_R
+struct tm *localtime_r(const time_t *timep, struct tm *result);
+#endif
+#ifndef HAVE_ISBLANK
+int isblank(int c);
+#endif /* !HAVE_ISBLANK */
+#ifndef HAVE_ISASCII
+int isascii(int c);
+#endif /* !HAVE_ISASCII */
+#ifndef HAVE_SNPRINTF
+#include <stdarg.h>
+int snprintf (char *str, size_t count, const char *fmt, ...);
+int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
+#endif /* HAVE_SNPRINTF */
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, const char* src, void* dst);
+#endif /* HAVE_INET_PTON */
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *cp, struct in_addr *addr);
+#endif
+#ifndef HAVE_MEMMOVE
+void *memmove(void *dest, const void *src, size_t n);
+#endif
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#ifndef HAVE_GETADDRINFO
+#include "compat/fake-rfc2553.h"
+#endif
+#ifndef HAVE_STRTOUL
+#define strtoul (unsigned long)strtol
+#endif
+
diff --git a/3rdParty/Ldns/src/include/ldns/dname.h b/3rdParty/Ldns/src/include/ldns/dname.h
new file mode 100644
index 0000000..a91f075
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/dname.h
@@ -0,0 +1,201 @@
+/*
+ * dname.h
+ *
+ * dname definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file dname.h
+ *
+ * dname contains function to read and manipulate domain names.
+ *
+ * Example domain names are "www.nlnetlabs.nl." and "." (the root)
+ *
+ * If a domain name ends with a dot ("."), it is called a Fully Qualified
+ * Domain Name (FQDN). In certain places (for instance when reading a zone
+ * file), an origin (which is just another domain name) non-FQDNs will be
+ * placed after the current. For instance, if i have a zone file where the
+ * origin has been set to "nl.", and my file contains the name
+ * "www.nlnetlabs", it will result in "www.nlnetlabs.nl.". Internally, dnames are
+ * always absolute (the dot is added when it is missing and there is no origin).
+ *
+ * An FQDN is also
+ * known as an absolute domain name, therefore the function to check this is
+ * called \ref ldns_dname_str_absolute
+ *
+ * Domain names are stored in \ref ldns_rdf structures, with the type
+ * \ref LDNS_RDF_TYPE_DNAME
+ *
+ * This module is *NOT* about the RR type called DNAME.
+ */
+
+
+#ifndef LDNS_DNAME_H
+#define LDNS_DNAME_H
+
+#include <ldns/common.h>
+#include <ldns/rdata.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_DNAME_NORMALIZE tolower
+
+/**
+ * concatenates two dnames together
+ * \param[in] rd1 the leftside
+ * \param[in] rd2 the rightside
+ * \return a new rdf with leftside/rightside
+ */
+ldns_rdf *ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2);
+
+/**
+ * concatenates rd2 after rd1 (rd2 is copied, rd1 is modified)
+ * \param[in] rd1 the leftside
+ * \param[in] rd2 the rightside
+ * \return LDNS_STATUS_OK on success
+ */
+ldns_status ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2);
+
+/**
+ * Returns a clone of the given dname with the labels
+ * reversed
+ * \param[in] d the dname to reverse
+ * \return clone of the dname with the labels reversed.
+ */
+ldns_rdf *ldns_dname_reverse(const ldns_rdf *d);
+
+/**
+ * Clones the given dname from the nth label on
+ * \param[in] d The dname to clone
+ * \param[in] n the label nr to clone from, if this is 0, the complete
+ * dname is cloned
+ * \return A newly allocated *rdf structure, containing the cloned dname,
+ * or NULL if either d was NULL, not a dname, or if n >=
+ * label_count
+ */
+ldns_rdf *
+ldns_dname_clone_from(const ldns_rdf *d, uint16_t n);
+
+/**
+ * chop one label off the left side of a dname. so
+ * wwww.nlnetlabs.nl, becomes nlnetlabs.nl
+ * This new name is a clone and must be freed with ldns_deep_free()
+ * \param[in] d the dname to chop
+ * \return the remaining dname
+ */
+ldns_rdf *ldns_dname_left_chop(const ldns_rdf *d);
+
+/**
+ * count the number of labels inside a LDNS_RDF_DNAME type rdf.
+ * \param[in] *r the rdf
+ * \return the number of labels
+ */
+uint8_t ldns_dname_label_count(const ldns_rdf *r);
+
+/**
+ * creates a new dname rdf from a string.
+ * \param[in] str string to use
+ * \return ldns_rdf* or NULL in case of an error
+ */
+ldns_rdf *ldns_dname_new_frm_str(const char *str);
+
+/**
+ * Create a new dname rdf from a string
+ * \param[in] s the size of the new dname
+ * \param[in] *data pointer to the actual data
+ * \return ldns_rdf*
+ */
+ldns_rdf *ldns_dname_new(uint16_t s, void *data);
+
+/**
+ * Create a new dname rdf from data (the data is copied)
+ * \param[in] size the size of the data
+ * \param[in] *data pointer to the actual data
+ * \return ldns_rdf*
+ */
+ldns_rdf *ldns_dname_new_frm_data(uint16_t size, const void *data);
+
+/**
+ * Put a dname into canonical fmt - ie. lowercase it
+ * \param[in] rdf the dname to lowercase
+ * \return void
+ */
+void ldns_dname2canonical(const ldns_rdf *rdf);
+
+/**
+ * test wether the name sub falls under parent (i.e. is a subdomain
+ * of parent). This function will return false if the given dnames are
+ * equal.
+ * \param[in] sub the name to test
+ * \param[in] parent the parent's name
+ * \return true if sub falls under parent, otherwise false
+ */
+bool ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent);
+
+/**
+ * Compares the two dname rdf's according to the algorithm for ordering
+ * in RFC4034 Section 6.
+ * \param[in] dname1 First dname rdf to compare
+ * \param[in] dname2 Second dname rdf to compare
+ * \return -1 if dname1 comes before dname2, 1 if dname1 comes after dname2, and 0 if they are equal.
+ */
+int ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2);
+
+/**
+ * Checks whether the dname matches the given wildcard
+ * \param[in] dname The dname to check
+ * \param[in] wildcard The wildcard to check with
+ * \return 1 If the wildcard matches, OR if 'wildcard' is not a wildcard and
+ * the names are *exactly* the same
+ * 0 If the wildcard does not match, or if it is not a wildcard and
+ * the names are not the same
+ */
+int ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard);
+
+/**
+ * check if middle lays in the interval defined by prev and next
+ * prev <= middle < next. This is usefull for nsec checking
+ * \param[in] prev the previous dname
+ * \param[in] middle the dname to check
+ * \param[in] next the next dname
+ * return 0 on error or unknown, -1 when middle is in the interval, +1 when not
+ */
+int ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, const ldns_rdf *next);
+
+/**
+ * Checks whether the given dname string is absolute (i.e. ends with a '.')
+ * \param[in] *dname_str a string representing the dname
+ * \return true or false
+ */
+bool ldns_dname_str_absolute(const char *dname_str);
+
+/**
+ * look inside the rdf and if it is an LDNS_RDF_TYPE_DNAME
+ * try and retrieve a specific label. The labels are numbered
+ * starting from 0 (left most).
+ * \param[in] rdf the rdf to look in
+ * \param[in] labelpos return the label with this number
+ * \return a ldns_rdf* with the label as name or NULL on error
+ */
+ldns_rdf * ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos);
+
+/**
+ * Check if dname is a wildcard, starts with *.
+ * \param[in] dname: the rdf to look in
+ * \return true if a wildcard, false if not.
+ */
+int ldns_dname_is_wildcard(const ldns_rdf* dname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_DNAME_H */
diff --git a/3rdParty/Ldns/src/include/ldns/dnssec.h b/3rdParty/Ldns/src/include/ldns/dnssec.h
new file mode 100644
index 0000000..9e602b5
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/dnssec.h
@@ -0,0 +1,522 @@
+/*
+ * dnssec.h -- defines for the Domain Name System (SEC) (DNSSEC)
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ * A bunch of defines that are used in the DNS
+ */
+
+/**
+ * \file dnssec.h
+ *
+ * This module contains base functions for DNSSEC operations
+ * (RFC4033 t/m RFC4035).
+ *
+ * Since those functions heavily rely op cryptographic operations,
+ * this module is dependent on openssl.
+ *
+ */
+
+
+#ifndef LDNS_DNSSEC_H
+#define LDNS_DNSSEC_H
+
+#include <ldns/common.h>
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+#include <ldns/packet.h>
+#include <ldns/keys.h>
+#include <ldns/zone.h>
+#include <ldns/resolver.h>
+#include <ldns/dnssec_zone.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_MAX_KEYLEN 2048
+#define LDNS_DNSSEC_KEYPROTO 3
+/* default time before sigs expire */
+#define LDNS_DEFAULT_EXP_TIME 2419200 /* 4 weeks */
+
+/** return values for the old-signature callback */
+#define LDNS_SIGNATURE_LEAVE_ADD_NEW 0
+#define LDNS_SIGNATURE_LEAVE_NO_ADD 1
+#define LDNS_SIGNATURE_REMOVE_ADD_NEW 2
+#define LDNS_SIGNATURE_REMOVE_NO_ADD 3
+
+/**
+ * Returns the first RRSIG rr that corresponds to the rrset
+ * with the given name and type
+ *
+ * \param[in] name The dname of the RRset covered by the RRSIG to find
+ * \param[in] type The type of the RRset covered by the RRSIG to find
+ * \param[in] rrs List of rrs to search in
+ * \returns Pointer to the first RRsig ldns_rr found, or NULL if it is
+ * not present
+ */
+ldns_rr *ldns_dnssec_get_rrsig_for_name_and_type(const ldns_rdf *name,
+ const ldns_rr_type type,
+ const ldns_rr_list *rrs);
+
+/**
+ * Returns the DNSKEY that corresponds to the given RRSIG rr from the list, if
+ * any
+ *
+ * \param[in] rrsig The rrsig to find the DNSKEY for
+ * \param[in] rrs The rr list to find the key in
+ * \return The DNSKEY that corresponds to the given RRSIG, or NULL if it was
+ * not found.
+ */
+ldns_rr *ldns_dnssec_get_dnskey_for_rrsig(const ldns_rr *rrsig, const ldns_rr_list *rrs);
+
+/**
+ * Returns the rdata field that contains the bitmap of the covered types of
+ * the given NSEC record
+ *
+ * \param[in] nsec The nsec to get the covered type bitmap of
+ * \return An ldns_rdf containing the bitmap, or NULL on error
+ */
+ldns_rdf *ldns_nsec_get_bitmap(ldns_rr *nsec);
+
+
+#define LDNS_NSEC3_MAX_ITERATIONS 65535
+
+/**
+ * Returns the dname of the closest (provable) encloser
+ */
+ldns_rdf *
+ldns_dnssec_nsec3_closest_encloser(ldns_rdf *qname,
+ ldns_rr_type qtype,
+ ldns_rr_list *nsec3s);
+
+/**
+ * Checks whether the packet contains rrsigs
+ */
+bool
+ldns_dnssec_pkt_has_rrsigs(const ldns_pkt *pkt);
+
+/**
+ * Returns a ldns_rr_list containing the signatures covering the given name
+ * and type
+ */
+ldns_rr_list *ldns_dnssec_pkt_get_rrsigs_for_name_and_type(const ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type);
+
+/**
+ * Returns a ldns_rr_list containing the signatures covering the given type
+ */
+ldns_rr_list *ldns_dnssec_pkt_get_rrsigs_for_type(const ldns_pkt *pkt, ldns_rr_type type);
+
+/**
+ * calculates a keytag of a key for use in DNSSEC.
+ *
+ * \param[in] key the key as an RR to use for the calc.
+ * \return the keytag
+ */
+uint16_t ldns_calc_keytag(const ldns_rr *key);
+
+/**
+ * Calculates keytag of DNSSEC key, operates on wireformat rdata.
+ * \param[in] key the key as uncompressed wireformat rdata.
+ * \param[in] keysize length of key data.
+ * \return the keytag
+ */
+uint16_t ldns_calc_keytag_raw(uint8_t* key, size_t keysize);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * converts a buffer holding key material to a DSA key in openssl.
+ *
+ * \param[in] key the key to convert
+ * \return a DSA * structure with the key material
+ */
+DSA *ldns_key_buf2dsa(ldns_buffer *key);
+/**
+ * Like ldns_key_buf2dsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a DSA * structure with the key material
+ */
+DSA *ldns_key_buf2dsa_raw(unsigned char* key, size_t len);
+
+/**
+ * Utility function to calculate hash using generic EVP_MD pointer.
+ * \param[in] data the data to hash.
+ * \param[in] len length of data.
+ * \param[out] dest the destination of the hash, must be large enough.
+ * \param[in] md the message digest to use.
+ * \return true if worked, false on failure.
+ */
+int ldns_digest_evp(unsigned char* data, unsigned int len,
+ unsigned char* dest, const EVP_MD* md);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with GOST.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* ldns_gost2pkey_raw(unsigned char* key, size_t keylen);
+
+/**
+ * Converts a holding buffer with key material to EVP PKEY in openssl.
+ * Only available if ldns was compiled with ECDSA.
+ * \param[in] key data to convert
+ * \param[in] keylen length of the key data
+ * \param[in] algo precise algorithm to initialize ECC group values.
+ * \return the key or NULL on error.
+ */
+EVP_PKEY* ldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo);
+
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * converts a buffer holding key material to a RSA key in openssl.
+ *
+ * \param[in] key the key to convert
+ * \return a RSA * structure with the key material
+ */
+RSA *ldns_key_buf2rsa(ldns_buffer *key);
+
+/**
+ * Like ldns_key_buf2rsa, but uses raw buffer.
+ * \param[in] key the uncompressed wireformat of the key.
+ * \param[in] len length of key data
+ * \return a RSA * structure with the key material
+ */
+RSA *ldns_key_buf2rsa_raw(unsigned char* key, size_t len);
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * returns a new DS rr that represents the given key rr.
+ *
+ * \param[in] *key the key to convert
+ * \param[in] h the hash to use LDNS_SHA1/LDNS_SHA256
+ * \return ldns_rr* a new rr pointer to a DS
+ */
+ldns_rr *ldns_key_rr2ds(const ldns_rr *key, ldns_hash h);
+
+/**
+ * Create the type bitmap for an NSEC(3) record
+ */
+ldns_rdf *
+ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[],
+ size_t size,
+ ldns_rr_type nsec_type);
+
+/**
+ * returns whether a rrset of the given type is found in the rrsets.
+ *
+ * \param[in] rrsets the rrsets to be tested
+ * \param[in] type the type to test for
+ * \return int 1 if the type was found, 0 otherwise.
+ */
+int
+ldns_dnssec_rrsets_contains_type (ldns_dnssec_rrsets *rrsets, ldns_rr_type type);
+
+/**
+ * Creates NSEC
+ */
+ldns_rr *
+ldns_dnssec_create_nsec(ldns_dnssec_name *from,
+ ldns_dnssec_name *to,
+ ldns_rr_type nsec_type);
+
+
+/**
+ * Creates NSEC3
+ */
+ldns_rr *
+ldns_dnssec_create_nsec3(ldns_dnssec_name *from,
+ ldns_dnssec_name *to,
+ ldns_rdf *zone_name,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt);
+
+/**
+ * Create a NSEC record
+ * \param[in] cur_owner the current owner which should be taken as the starting point
+ * \param[in] next_owner the rrlist which the nsec rr should point to
+ * \param[in] rrs all rrs from the zone, to find all RR types of cur_owner in
+ * \return a ldns_rr with the nsec record in it
+ */
+ldns_rr * ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs);
+
+/**
+ * Calculates the hashed name using the given parameters
+ * \param[in] *name The owner name to calculate the hash for
+ * \param[in] algorithm The hash algorithm to use
+ * \param[in] iterations The number of hash iterations to use
+ * \param[in] salt_length The length of the salt in bytes
+ * \param[in] salt The salt to use
+ * \return The hashed owner name rdf, without the domain name
+ */
+ldns_rdf *ldns_nsec3_hash_name(ldns_rdf *name, uint8_t algorithm, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
+
+/**
+ * Sets all the NSEC3 options. The rr to set them in must be initialized with _new() and
+ * type LDNS_RR_TYPE_NSEC3
+ * \param[in] *rr The RR to set the values in
+ * \param[in] algorithm The NSEC3 hash algorithm
+ * \param[in] flags The flags field
+ * \param[in] iterations The number of hash iterations
+ * \param[in] salt_length The length of the salt in bytes
+ * \param[in] salt The salt bytes
+ */
+void ldns_nsec3_add_param_rdfs(ldns_rr *rr,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt);
+
+/* this will NOT return the NSEC3 completed, you will have to run the
+ finalize function on the rrlist later! */
+ldns_rr *
+ldns_create_nsec3(ldns_rdf *cur_owner,
+ ldns_rdf *cur_zone,
+ ldns_rr_list *rrs,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ bool emptynonterminal);
+
+/**
+ * Returns the hash algorithm used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The algorithm identifier, or 0 on error
+ */
+uint8_t ldns_nsec3_algorithm(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns flags field
+ */
+uint8_t
+ldns_nsec3_flags(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns true if the opt-out flag has been set in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return true if the RR has type NSEC3 and the opt-out bit has been set, false otherwise
+ */
+bool ldns_nsec3_optout(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the number of hash iterations used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The number of iterations
+ */
+uint16_t ldns_nsec3_iterations(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the salt used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The salt rdf, or NULL on error
+ */
+ldns_rdf *ldns_nsec3_salt(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the length of the salt used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The length of the salt in bytes
+ */
+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
+ */
+uint8_t *ldns_nsec3_salt_data(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the first label of the next ownername in the NSEC3 chain (ie. without the domain)
+ * \param[in] nsec3_rr The RR to read from
+ * \return The first label of the next owner name in the NSEC3 chain, or NULL on error
+ */
+ldns_rdf *ldns_nsec3_next_owner(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the bitmap specifying the covered types of the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The covered type bitmap rdf
+ */
+ldns_rdf *ldns_nsec3_bitmap(const ldns_rr *nsec3_rr);
+
+/**
+ * Calculates the hashed name using the parameters of the given NSEC3 RR
+ * \param[in] *nsec The RR to use the parameters from
+ * \param[in] *name The owner name to calculate the hash for
+ * \return The hashed owner name rdf, without the domain name
+ */
+ldns_rdf *ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name);
+
+/**
+ * Checks coverage of NSEC RR type bitmap
+ * \param[in] nsec_bitmap The NSEC bitmap rdata field to check
+ * \param[in] type The type to check
+ * \return true if the NSEC RR covers the type
+ */
+bool ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type);
+
+/**
+ * Checks coverage of NSEC(3) RR name span
+ * Remember that nsec and name must both be in canonical form (ie use
+ * \ref ldns_rr2canonical and \ref ldns_dname2canonical prior to calling this
+ * function)
+ *
+ * \param[in] nsec The NSEC RR to check
+ * \param[in] name The owner dname to check, if the nsec record is a NSEC3 record, this should be the hashed name
+ * \return true if the NSEC RR covers the owner name
+ */
+bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * verify a packet
+ * \param[in] p the packet
+ * \param[in] t the rr set type to check
+ * \param[in] o the rr set name to check
+ * \param[in] k list of keys
+ * \param[in] s list of sigs (may be null)
+ * \param[out] good_keys keys which validated the packet
+ * \return status
+ *
+ */
+ldns_status ldns_pkt_verify(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, ldns_rr_list *good_keys);
+
+/**
+ * verify a packet
+ * \param[in] p the packet
+ * \param[in] t the rr set type to check
+ * \param[in] o the rr set name to check
+ * \param[in] k list of keys
+ * \param[in] s list of sigs (may be null)
+ * \param[in] check_time the time for which the validation is performed
+ * \param[out] good_keys keys which validated the packet
+ * \return status
+ *
+ */
+ldns_status ldns_pkt_verify_time(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_list *k, ldns_rr_list *s, time_t check_time, ldns_rr_list *good_keys);
+
+#endif
+
+/**
+ * chains nsec3 list
+ */
+ldns_status
+ldns_dnssec_chain_nsec3_list(ldns_rr_list *nsec3_rrs);
+
+/**
+ * compare for nsec3 sort
+ */
+int
+qsort_rr_compare_nsec3(const void *a, const void *b);
+
+/**
+ * sort nsec3 list
+ */
+void
+ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted);
+
+/**
+ * Default callback function to always leave present signatures, and
+ * add new ones
+ * \param[in] sig The signature to check for removal (unused)
+ * \param[in] n Optional argument (unused)
+ * \return LDNS_SIGNATURE_LEAVE_ADD_NEW
+ */
+int ldns_dnssec_default_add_to_signatures(ldns_rr *sig, void *n);
+/**
+ * Default callback function to always leave present signatures, and
+ * add no new ones for the keys of these signatures
+ * \param[in] sig The signature to check for removal (unused)
+ * \param[in] n Optional argument (unused)
+ * \return LDNS_SIGNATURE_LEAVE_NO_ADD
+ */
+int ldns_dnssec_default_leave_signatures(ldns_rr *sig, void *n);
+/**
+ * Default callback function to always remove present signatures, but
+ * add no new ones
+ * \param[in] sig The signature to check for removal (unused)
+ * \param[in] n Optional argument (unused)
+ * \return LDNS_SIGNATURE_REMOVE_NO_ADD
+ */
+int ldns_dnssec_default_delete_signatures(ldns_rr *sig, void *n);
+/**
+ * Default callback function to always leave present signatures, and
+ * add new ones
+ * \param[in] sig The signature to check for removal (unused)
+ * \param[in] n Optional argument (unused)
+ * \return LDNS_SIGNATURE_REMOVE_ADD_NEW
+ */
+int ldns_dnssec_default_replace_signatures(ldns_rr *sig, void *n);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * Converts the DSA signature from ASN1 representation (RFC2459, as
+ * used by OpenSSL) to raw signature data as used in DNS (rfc2536)
+ *
+ * \param[in] sig The signature in RFC2459 format
+ * \param[in] sig_len The length of the signature
+ * \return a new rdf with the signature
+ */
+ldns_rdf *
+ldns_convert_dsa_rrsig_asn12rdf(const ldns_buffer *sig,
+ const long sig_len);
+
+/**
+ * Converts the RRSIG signature RDF (in rfc2536 format) to a buffer
+ * with the signature in rfc2459 format
+ *
+ * \param[out] target_buffer buffer to place the signature data
+ * \param[in] sig_rdf The signature rdf to convert
+ * \return LDNS_STATUS_OK on success, error code otherwise
+ */
+ldns_status
+ldns_convert_dsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+ const ldns_rdf *sig_rdf);
+
+/**
+ * Converts the ECDSA signature from ASN1 representation (as
+ * used by OpenSSL) to raw signature data as used in DNS
+ * This routine is only present if ldns is compiled with ecdsa support.
+ *
+ * \param[in] sig The signature in ASN1 format
+ * \param[in] sig_len The length of the signature
+ * \return a new rdf with the signature
+ */
+ldns_rdf *
+ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len);
+
+/**
+ * Converts the RRSIG signature RDF (from DNS) to a buffer with the
+ * signature in ASN1 format as openssl uses it.
+ * This routine is only present if ldns is compiled with ecdsa support.
+ *
+ * \param[out] target_buffer buffer to place the signature data in ASN1.
+ * \param[in] sig_rdf The signature rdf to convert
+ * \return LDNS_STATUS_OK on success, error code otherwise
+ */
+ldns_status
+ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+ const ldns_rdf *sig_rdf);
+
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_DNSSEC_H */
diff --git a/3rdParty/Ldns/src/include/ldns/dnssec_sign.h b/3rdParty/Ldns/src/include/ldns/dnssec_sign.h
new file mode 100644
index 0000000..e77cb69
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/dnssec_sign.h
@@ -0,0 +1,383 @@
+/** dnssec_verify */
+
+#ifndef LDNS_DNSSEC_SIGN_H
+#define LDNS_DNSSEC_SIGN_H
+
+#include <ldns/dnssec.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* sign functions */
+
+/** Sign flag that makes DNSKEY type signed by all keys, not only by SEP keys*/
+#define LDNS_SIGN_DNSKEY_WITH_ZSK 1
+
+/**
+ * Create an empty RRSIG RR (i.e. without the actual signature data)
+ * \param[in] rrset The RRset to create the signature for
+ * \param[in] key The key that will create the signature
+ * \return signature rr
+ */
+ldns_rr *
+ldns_create_empty_rrsig(ldns_rr_list *rrset,
+ ldns_key *key);
+
+/**
+ * Sign the buffer which contains the wiredata of an rrset, and the
+ * corresponding empty rrsig rr with the given key
+ * \param[in] sign_buf the buffer with data to sign
+ * \param[in] key the key to sign with
+ * \return an rdata field with the signature data
+ */
+ldns_rdf *
+ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *key);
+
+/**
+ * Sign an rrset
+ * \param[in] rrset the rrset
+ * \param[in] keys the keys to use
+ * \return a rr_list with the signatures
+ */
+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
+ */
+ldns_rdf *ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key);
+
+/**
+ * Sign data with EVP (general method for different algorithms)
+ *
+ * \param[in] to_sign The ldns_buffer containing raw data that is
+ * to be signed
+ * \param[in] key The EVP_PKEY key structure to sign with
+ * \param[in] digest_type The digest algorithm to use in the creation of
+ * the signature
+ * \return ldns_rdf for the RRSIG ldns_rr
+ */
+ldns_rdf *ldns_sign_public_evp(ldns_buffer *to_sign,
+ EVP_PKEY *key,
+ const EVP_MD *digest_type);
+
+/**
+ * Sign a buffer with the RSA 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
+ */
+ldns_rdf *ldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key);
+
+/**
+ * Sign a buffer with the RSA key (hash with MD5)
+ * \param[in] to_sign buffer with the data
+ * \param[in] key the key to use
+ * \return a ldns_rdf with the signed data
+ */
+ldns_rdf *ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key);
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * 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 seperately.
+ *
+ * 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 the delegation name.
+ *
+ * \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);
+
+/**
+ * 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 seperately.
+ *
+ * \param[in] zone the zone in which to mark the names
+ * \return LDNS_STATUS_OK on succesful completion
+ */
+ldns_status
+ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone);
+
+/**
+ * Finds the first dnssec_name node in the rbtree that is not occluded.
+ * It *does* return names that are partially occluded.
+ *
+ * \param[in] node the first node to check
+ * \return the first node that has not been marked as glue, or NULL
+ * if not found (TODO: make that LDNS_RBTREE_NULL?)
+ */
+ldns_rbnode_t *ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node);
+
+/**
+ * Adds NSEC records to the given dnssec_zone
+ *
+ * \param[in] zone the zone to add the records to
+ * \param[in] new_rrs ldns_rr's created by this function are
+ * added to this rr list, so the caller can free them later
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs);
+
+/**
+ * Adds NSEC3 records to the zone
+ */
+ldns_status
+ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt);
+
+/**
+ * remove signatures if callback function tells to
+ *
+ * \param[in] signatures list of signatures to check, and
+ * possibly remove, depending on the value of the
+ * callback
+ * \param[in] key_list these are marked to be used or not,
+ * on the return value of the callback
+ * \param[in] func this function is called to specify what to
+ * do with each signature (and corresponding key)
+ * \param[in] arg Optional argument for the callback function
+ * \returns pointer to the new signatures rrs (the original
+ * passed to this function may have been removed)
+ */
+ldns_dnssec_rrs *ldns_dnssec_remove_signatures(ldns_dnssec_rrs *signatures,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg);
+
+/**
+ * Adds signatures to the zone
+ *
+ * \param[in] zone the zone to add RRSIG Resource Records to
+ * \param[in] new_rrs the RRSIG RRs that are created are also
+ * added to this list, so the caller can free them
+ * later
+ * \param[in] key_list list of keys to sign with.
+ * \param[in] func Callback function to decide what keys to
+ * use and what to do with old signatures
+ * \param[in] arg Optional argument for the callback function
+ * \param[in] flags option flags for signing process. 0 makes DNSKEY
+ * RRset signed with the minimal key set, that is only SEP keys are used
+ * for signing. If there are no SEP keys available, non-SEP keys will
+ * be used. LDNS_SIGN_DNSKEY_WITH_ZSK makes DNSKEY type signed with all
+ * keys. 0 is the default.
+ * \return LDNS_STATUS_OK on success, error otherwise
+ */
+ldns_status ldns_dnssec_zone_create_rrsigs_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void*),
+ void *arg,
+ int flags);
+
+/**
+ * Adds signatures to the zone
+ *
+ * \param[in] zone the zone to add RRSIG Resource Records to
+ * \param[in] new_rrs the RRSIG RRs that are created are also
+ * added to this list, so the caller can free them
+ * later
+ * \param[in] key_list list of keys to sign with.
+ * \param[in] func Callback function to decide what keys to
+ * use and what to do with old signatures
+ * \param[in] arg Optional argument for the callback function
+ * \return LDNS_STATUS_OK on success, error otherwise
+ */
+ldns_status ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void*),
+ void *arg);
+
+/**
+ * signs the given zone with the given keys
+ *
+ * \param[in] zone the zone to sign
+ * \param[in] key_list the list of keys to sign the zone with
+ * \param[in] new_rrs newly created resource records are added to this list, to free them later
+ * \param[in] func callback function that decides what to do with old signatures
+ * This function takes an ldns_rr* and an optional void *arg argument, and returns one of four values:
+ * LDNS_SIGNATURE_LEAVE_ADD_NEW:
+ * leave the signature and add a new one for the corresponding key
+ * LDNS_SIGNATURE_REMOVE_ADD_NEW:
+ * remove the signature and replace is with a new one from the same key
+ * LDNS_SIGNATURE_LEAVE_NO_ADD:
+ * leave the signature and do not add a new one with the corresponding key
+ * LDNS_SIGNATURE_REMOVE_NO_ADD:
+ * remove the signature and do not replace
+ *
+ * \param[in] arg optional argument for the callback function
+ * \param[in] flags option flags for signing process. 0 makes DNSKEY
+ * RRset signed with the minimal key set, that is only SEP keys are used
+ * for signing. If there are no SEP keys available, non-SEP keys will
+ * be used. LDNS_SIGN_DNSKEY_WITH_ZSK makes DNSKEY type signed with all
+ * keys. 0 is the default.
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ int flags);
+
+/**
+ * signs the given zone with the given new zone, with NSEC3
+ *
+ * \param[in] zone the zone to sign
+ * \param[in] key_list the list of keys to sign the zone with
+ * \param[in] new_rrs newly created resource records are added to this list, to free them later
+ * \param[in] func callback function that decides what to do with old signatures
+ * \param[in] arg optional argument for the callback function
+ * \param[in] algorithm the NSEC3 hashing algorithm to use
+ * \param[in] flags NSEC3 flags
+ * \param[in] iterations the number of NSEC3 hash iterations to use
+ * \param[in] salt_length the length (in octets) of the NSEC3 salt
+ * \param[in] salt the NSEC3 salt data
+ * \param[in] signflags option flags for signing process. 0 is the default.
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ int signflags);
+
+/**
+ * signs the given zone with the given new zone, with NSEC3
+ *
+ * \param[in] zone the zone to sign
+ * \param[in] key_list the list of keys to sign the zone with
+ * \param[in] new_rrs newly created resource records are added to this list, to free them later
+ * \param[in] func callback function that decides what to do with old signatures
+ * \param[in] arg optional argument for the callback function
+ * \param[in] algorithm the NSEC3 hashing algorithm to use
+ * \param[in] flags NSEC3 flags
+ * \param[in] iterations the number of NSEC3 hash iterations to use
+ * \param[in] salt_length the length (in octets) of the NSEC3 salt
+ * \param[in] salt the NSEC3 salt data
+ * \param[in] signflags option flags for signing process. 0 is the default.
+ * \param[out] map a referenced rbtree pointer variable. The newly created
+ * rbtree will contain mappings from hashed owner names to the
+ * unhashed name.
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ int signflags,
+ ldns_rbtree_t **map
+ );
+
+
+/**
+ * signs the given zone with the given keys
+ *
+ * \param[in] zone the zone to sign
+ * \param[in] key_list the list of keys to sign the zone with
+ * \param[in] new_rrs newly created resource records are added to this list, to free them later
+ * \param[in] func callback function that decides what to do with old signatures
+ * This function takes an ldns_rr* and an optional void *arg argument, and returns one of four values:
+ * LDNS_SIGNATURE_LEAVE_ADD_NEW:
+ * leave the signature and add a new one for the corresponding key
+ * LDNS_SIGNATURE_REMOVE_ADD_NEW:
+ * remove the signature and replace is with a new one from the same key
+ * LDNS_SIGNATURE_LEAVE_NO_ADD:
+ * leave the signature and do not add a new one with the corresponding key
+ * LDNS_SIGNATURE_REMOVE_NO_ADD:
+ * remove the signature and do not replace
+ *
+ * \param[in] arg optional argument for the callback function
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_sign(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg);
+
+/**
+ * signs the given zone with the given new zone, with NSEC3
+ *
+ * \param[in] zone the zone to sign
+ * \param[in] key_list the list of keys to sign the zone with
+ * \param[in] new_rrs newly created resource records are added to this list, to free them later
+ * \param[in] func callback function that decides what to do with old signatures
+ * \param[in] arg optional argument for the callback function
+ * \param[in] algorithm the NSEC3 hashing algorithm to use
+ * \param[in] flags NSEC3 flags
+ * \param[in] iterations the number of NSEC3 hash iterations to use
+ * \param[in] salt_length the length (in octets) of the NSEC3 salt
+ * \param[in] salt the NSEC3 salt data
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt);
+
+/**
+ * Signs the zone, and returns a newly allocated signed zone
+ * \param[in] zone the zone to sign
+ * \param[in] key_list list of keys to sign with
+ * \return signed zone
+ */
+ldns_zone *ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list);
+
+/**
+ * Signs the zone with NSEC3, and returns a newly allocated signed zone
+ * \param[in] zone the zone to sign
+ * \param[in] key_list list of keys to sign with
+ * \param[in] algorithm the NSEC3 hashing algorithm to use
+ * \param[in] flags NSEC3 flags
+ * \param[in] iterations the number of NSEC3 hash iterations to use
+ * \param[in] salt_length the length (in octets) of the NSEC3 salt
+ * \param[in] salt the NSEC3 salt data
+ * \return signed zone
+ */
+ldns_zone *ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/3rdParty/Ldns/src/include/ldns/dnssec_verify.h b/3rdParty/Ldns/src/include/ldns/dnssec_verify.h
new file mode 100644
index 0000000..1350f48
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/dnssec_verify.h
@@ -0,0 +1,873 @@
+/** dnssec_verify */
+
+#ifndef LDNS_DNSSEC_VERIFY_H
+#define LDNS_DNSSEC_VERIFY_H
+
+#define LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS 10
+
+#include <ldns/dnssec.h>
+#include <ldns/host2str.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Chain structure that contains all DNSSEC data needed to
+ * verify an rrset
+ */
+typedef struct ldns_dnssec_data_chain_struct ldns_dnssec_data_chain;
+struct ldns_dnssec_data_chain_struct
+{
+ ldns_rr_list *rrset;
+ ldns_rr_list *signatures;
+ ldns_rr_type parent_type;
+ ldns_dnssec_data_chain *parent;
+ ldns_pkt_rcode packet_rcode;
+ ldns_rr_type packet_qtype;
+ bool packet_nodata;
+};
+
+/**
+ * Creates a new dnssec_chain structure
+ * \return ldns_dnssec_data_chain *
+ */
+ldns_dnssec_data_chain *ldns_dnssec_data_chain_new();
+
+/**
+ * Frees a dnssec_data_chain structure
+ *
+ * \param[in] *chain The chain to free
+ */
+void ldns_dnssec_data_chain_free(ldns_dnssec_data_chain *chain);
+
+/**
+ * Frees a dnssec_data_chain structure, and all data
+ * contained therein
+ *
+ * \param[in] *chain The dnssec_data_chain to free
+ */
+void ldns_dnssec_data_chain_deep_free(ldns_dnssec_data_chain *chain);
+
+/**
+ * Prints the dnssec_data_chain to the given file stream
+ *
+ * \param[in] *out The file stream to print to
+ * \param[in] *chain The dnssec_data_chain to print
+ */
+void ldns_dnssec_data_chain_print(FILE *out, const ldns_dnssec_data_chain *chain);
+
+/**
+ * Prints the dnssec_data_chain to the given file stream
+ *
+ * \param[in] *out The file stream to print to
+ * \param[in] *fmt The format of the textual representation
+ * \param[in] *chain The dnssec_data_chain to print
+ */
+void ldns_dnssec_data_chain_print_fmt(FILE *out,
+ const ldns_output_format *fmt,
+ const ldns_dnssec_data_chain *chain);
+
+/**
+ * Build an ldns_dnssec_data_chain, which contains all
+ * DNSSEC data that is needed to derive the trust tree later
+ *
+ * The data_set will be cloned
+ *
+ * \param[in] *res resolver structure for further needed queries
+ * \param[in] qflags resolution flags
+ * \param[in] *data_set The original rrset where the chain ends
+ * \param[in] *pkt optional, can contain the original packet
+ * (and hence the sigs and maybe the key)
+ * \param[in] *orig_rr The original Resource Record
+ *
+ * \return the DNSSEC data chain
+ */
+ldns_dnssec_data_chain *ldns_dnssec_build_data_chain(ldns_resolver *res,
+ const uint16_t qflags,
+ const ldns_rr_list *data_set,
+ const ldns_pkt *pkt,
+ ldns_rr *orig_rr);
+
+/**
+ * Tree structure that contains the relation of DNSSEC data,
+ * and their cryptographic status.
+ *
+ * This tree is derived from a data_chain, and can be used
+ * to look whether there is a connection between an RRSET
+ * and a trusted key. The tree only contains pointers to the
+ * data_chain, and therefore one should *never* free() the
+ * data_chain when there is still a trust tree derived from
+ * that chain.
+ *
+ * Example tree:
+ * key key key
+ * \ | /
+ * \ | /
+ * \ | /
+ * ds
+ * |
+ * key
+ * |
+ * key
+ * |
+ * rr
+ *
+ * For each signature there is a parent; if the parent
+ * pointer is null, it couldn't be found and there was no
+ * denial; otherwise is a tree which contains either a
+ * DNSKEY, a DS, or a NSEC rr
+ */
+typedef struct ldns_dnssec_trust_tree_struct ldns_dnssec_trust_tree;
+struct ldns_dnssec_trust_tree_struct
+{
+ ldns_rr *rr;
+ /* the complete rrset this rr was in */
+ ldns_rr_list *rrset;
+ ldns_dnssec_trust_tree *parents[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS];
+ ldns_status parent_status[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS];
+ /** for debugging, add signatures too (you might want
+ those if they contain errors) */
+ ldns_rr *parent_signature[LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS];
+ size_t parent_count;
+};
+
+/**
+ * Creates a new (empty) dnssec_trust_tree structure
+ *
+ * \return ldns_dnssec_trust_tree *
+ */
+ldns_dnssec_trust_tree *ldns_dnssec_trust_tree_new();
+
+/**
+ * Frees the dnssec_trust_tree recursively
+ *
+ * There is no deep free; all data in the trust tree
+ * consists of pointers to a data_chain
+ *
+ * \param[in] tree The tree to free
+ */
+void ldns_dnssec_trust_tree_free(ldns_dnssec_trust_tree *tree);
+
+/**
+ * returns the depth of the trust tree
+ *
+ * \param[in] tree tree to calculate the depth of
+ * \return The depth of the tree
+ */
+size_t ldns_dnssec_trust_tree_depth(ldns_dnssec_trust_tree *tree);
+
+/**
+ * Prints the dnssec_trust_tree structure to the given file
+ * stream.
+ *
+ * If a link status is not LDNS_STATUS_OK; the status and
+ * relevant signatures are printed too
+ *
+ * \param[in] *out The file stream to print to
+ * \param[in] tree The trust tree to print
+ * \param[in] tabs Prepend each line with tabs*2 spaces
+ * \param[in] extended If true, add little explanation lines to the output
+ */
+void ldns_dnssec_trust_tree_print(FILE *out,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended);
+
+/**
+ * Prints the dnssec_trust_tree structure to the given file
+ * stream.
+ *
+ * If a link status is not LDNS_STATUS_OK; the status and
+ * relevant signatures are printed too
+ *
+ * \param[in] *out The file stream to print to
+ * \param[in] *fmt The format of the textual representation
+ * \param[in] tree The trust tree to print
+ * \param[in] tabs Prepend each line with tabs*2 spaces
+ * \param[in] extended If true, add little explanation lines to the output
+ */
+void ldns_dnssec_trust_tree_print_fmt(FILE *out,
+ const ldns_output_format *fmt,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended);
+
+/**
+ * Adds a trust tree as a parent for the given trust tree
+ *
+ * \param[in] *tree The tree to add the parent to
+ * \param[in] *parent The parent tree to add
+ * \param[in] *parent_signature The RRSIG relevant to this parent/child
+ * connection
+ * \param[in] parent_status The DNSSEC status for this parent, child and RRSIG
+ * \return LDNS_STATUS_OK if the addition succeeds, error otherwise
+ */
+ldns_status ldns_dnssec_trust_tree_add_parent(ldns_dnssec_trust_tree *tree,
+ const ldns_dnssec_trust_tree *parent,
+ const ldns_rr *parent_signature,
+ const ldns_status parent_status);
+
+/**
+ * Generates a dnssec_trust_ttree for the given rr from the
+ * given data_chain
+ *
+ * This does not clone the actual data; Don't free the
+ * data_chain before you are done with this tree
+ *
+ * \param[in] *data_chain The chain to derive the trust tree from
+ * \param[in] *rr The RR this tree will be about
+ * \return ldns_dnssec_trust_tree *
+ */
+ldns_dnssec_trust_tree *ldns_dnssec_derive_trust_tree(
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *rr);
+
+/**
+ * Generates a dnssec_trust_ttree for the given rr from the
+ * given data_chain
+ *
+ * This does not clone the actual data; Don't free the
+ * data_chain before you are done with this tree
+ *
+ * \param[in] *data_chain The chain to derive the trust tree from
+ * \param[in] *rr The RR this tree will be about
+ * \param[in] check_time the time for which the validation is performed
+ * \return ldns_dnssec_trust_tree *
+ */
+ldns_dnssec_trust_tree *ldns_dnssec_derive_trust_tree_time(
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *rr, time_t check_time);
+
+/**
+ * Sub function for derive_trust_tree that is used for a 'normal' rrset
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_sig_rr The currently relevant signature
+ */
+void ldns_dnssec_derive_trust_tree_normal_rrset(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_sig_rr);
+
+/**
+ * Sub function for derive_trust_tree that is used for a 'normal' rrset
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_sig_rr The currently relevant signature
+ * \param[in] check_time the time for which the validation is performed
+ */
+void ldns_dnssec_derive_trust_tree_normal_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_sig_rr, time_t check_time);
+
+
+/**
+ * Sub function for derive_trust_tree that is used for DNSKEY rrsets
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_rr The currently relevant DNSKEY RR
+ * \param[in] cur_sig_rr The currently relevant signature
+ */
+void ldns_dnssec_derive_trust_tree_dnskey_rrset(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr,
+ ldns_rr *cur_sig_rr);
+
+/**
+ * Sub function for derive_trust_tree that is used for DNSKEY rrsets
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_rr The currently relevant DNSKEY RR
+ * \param[in] cur_sig_rr The currently relevant signature
+ * \param[in] check_time the time for which the validation is performed
+ */
+void ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr, ldns_rr *cur_sig_rr,
+ time_t check_time);
+
+
+/**
+ * Sub function for derive_trust_tree that is used for DNSKEY rrsets
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_rr The currently relevant DNSKEY RR
+ * \param[in] cur_sig_rr The currently relevant signature
+ * \param[in] check_time the time for which the validation is performed
+ */
+void ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr, ldns_rr *cur_sig_rr,
+ time_t check_time);
+
+
+/**
+ * Sub function for derive_trust_tree that is used for DS rrsets
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_rr The currently relevant DS RR
+ */
+void ldns_dnssec_derive_trust_tree_ds_rrset(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr);
+
+/**
+ * Sub function for derive_trust_tree that is used for DS rrsets
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] cur_rr The currently relevant DS RR
+ * \param[in] check_time the time for which the validation is performed
+ */
+void ldns_dnssec_derive_trust_tree_ds_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr, time_t check_time);
+
+/**
+ * Sub function for derive_trust_tree that is used when there are no
+ * signatures
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ */
+void ldns_dnssec_derive_trust_tree_no_sig(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain);
+
+/**
+ * Sub function for derive_trust_tree that is used when there are no
+ * signatures
+ *
+ * \param[in] new_tree The trust tree that we are building
+ * \param[in] data_chain The data chain containing the data for the trust tree
+ * \param[in] check_time the time for which the validation is performed
+ */
+void ldns_dnssec_derive_trust_tree_no_sig_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ time_t check_time);
+
+
+/**
+ * Returns OK if there is a trusted path in the tree to one of
+ * the DNSKEY or DS RRs in the given list
+ *
+ * \param *tree The trust tree so search
+ * \param *keys A ldns_rr_list of DNSKEY and DS rrs to look for
+ * \return LDNS_STATUS_OK if there is a trusted path to one of
+ * the keys, or the *first* error encountered
+ * if there were no paths
+ */
+ldns_status ldns_dnssec_trust_tree_contains_keys(
+ ldns_dnssec_trust_tree *tree,
+ ldns_rr_list *keys);
+
+/**
+ * Verifies a list of signatures for one rrset.
+ *
+ * \param[in] rrset the rrset to verify
+ * \param[in] rrsig a list of signatures to check
+ * \param[in] keys a list of keys to check with
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return status LDNS_STATUS_OK if there is at least one correct key
+ */
+ldns_status ldns_verify(ldns_rr_list *rrset,
+ ldns_rr_list *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys);
+
+/**
+ * Verifies a list of signatures for one rrset.
+ *
+ * \param[in] rrset the rrset to verify
+ * \param[in] rrsig a list of signatures to check
+ * \param[in] keys a list of keys to check with
+ * \param[in] check_time the time for which the validation is performed
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return status LDNS_STATUS_OK if there is at least one correct key
+ */
+ldns_status ldns_verify_time(ldns_rr_list *rrset,
+ ldns_rr_list *rrsig,
+ const ldns_rr_list *keys,
+ time_t check_time,
+ ldns_rr_list *good_keys);
+
+
+/**
+ * Verifies a list of signatures for one rrset, but disregard the time.
+ * Inception and Expiration are not checked.
+ *
+ * \param[in] rrset the rrset to verify
+ * \param[in] rrsig a list of signatures to check
+ * \param[in] keys a list of keys to check with
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return status LDNS_STATUS_OK if there is at least one correct key
+ */
+ldns_status ldns_verify_notime(ldns_rr_list *rrset,
+ ldns_rr_list *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys);
+
+/**
+ * Tries to build an authentication chain from the given
+ * keys down to the queried domain.
+ *
+ * If we find a valid trust path, return the valid keys for the domain.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \param[out] status pointer to the status variable where the result
+ * code will be stored
+ * \return the set of trusted keys for the domain, or NULL if no
+ * trust path could be built.
+ */
+ldns_rr_list *ldns_fetch_valid_domain_keys(const ldns_resolver * res,
+ const ldns_rdf * domain,
+ const ldns_rr_list * keys,
+ ldns_status *status);
+
+/**
+ * Tries to build an authentication chain from the given
+ * keys down to the queried domain.
+ *
+ * If we find a valid trust path, return the valid keys for the domain.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \param[in] check_time the time for which the validation is performed
+ * \param[out] status pointer to the status variable where the result
+ * code will be stored
+ * \return the set of trusted keys for the domain, or NULL if no
+ * trust path could be built.
+ */
+ldns_rr_list *ldns_fetch_valid_domain_keys_time(const ldns_resolver * res,
+ const ldns_rdf * domain, const ldns_rr_list * keys,
+ time_t check_time, ldns_status *status);
+
+
+/**
+ * Validates the DNSKEY RRset for the given domain using the provided
+ * trusted keys.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \return the set of trusted keys for the domain, or NULL if the RRSET
+ * could not be validated
+ */
+ldns_rr_list *ldns_validate_domain_dnskey (const ldns_resolver *res,
+ const ldns_rdf *domain,
+ const ldns_rr_list *keys);
+
+/**
+ * Validates the DNSKEY RRset for the given domain using the provided
+ * trusted keys.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \param[in] check_time the time for which the validation is performed
+ * \return the set of trusted keys for the domain, or NULL if the RRSET
+ * could not be validated
+ */
+ldns_rr_list *ldns_validate_domain_dnskey_time(
+ const ldns_resolver *res, const ldns_rdf *domain,
+ const ldns_rr_list *keys, time_t check_time);
+
+
+/**
+ * Validates the DS RRset for the given domain using the provided trusted keys.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \return the set of trusted keys for the domain, or NULL if the RRSET could not be validated
+ */
+ldns_rr_list *ldns_validate_domain_ds(const ldns_resolver *res,
+ const ldns_rdf *
+ domain,
+ const ldns_rr_list * keys);
+
+/**
+ * Validates the DS RRset for the given domain using the provided trusted keys.
+ *
+ * \param[in] res the current resolver
+ * \param[in] domain the domain we want valid keys for
+ * \param[in] keys the current set of trusted keys
+ * \param[in] check_time the time for which the validation is performed
+ * \return the set of trusted keys for the domain, or NULL if the RRSET could not be validated
+ */
+ldns_rr_list *ldns_validate_domain_ds_time(
+ const ldns_resolver *res, const ldns_rdf *domain,
+ const ldns_rr_list * keys, time_t check_time);
+
+
+/**
+ * Verifies a list of signatures for one RRset using a valid trust path.
+ *
+ * \param[in] res the current resolver
+ * \param[in] rrset the rrset to verify
+ * \param[in] rrsigs a list of signatures to check
+ * \param[out] validating_keys if this is a (initialized) list, the
+ * keys from keys that validate one of
+ * the signatures are added to it
+ * \return status LDNS_STATUS_OK if there is at least one correct key
+ */
+ldns_status ldns_verify_trusted(ldns_resolver *res,
+ ldns_rr_list *rrset,
+ ldns_rr_list *rrsigs,
+ ldns_rr_list *validating_keys);
+
+/**
+ * Verifies a list of signatures for one RRset using a valid trust path.
+ *
+ * \param[in] res the current resolver
+ * \param[in] rrset the rrset to verify
+ * \param[in] rrsigs a list of signatures to check
+ * \param[in] check_time the time for which the validation is performed
+ * \param[out] validating_keys if this is a (initialized) list, the
+ * keys from keys that validate one of
+ * the signatures are added to it
+ * \return status LDNS_STATUS_OK if there is at least one correct key
+ */
+ldns_status ldns_verify_trusted_time(
+ ldns_resolver *res, ldns_rr_list *rrset,
+ ldns_rr_list *rrsigs, time_t check_time,
+ ldns_rr_list *validating_keys);
+
+
+/**
+ * denial is not just a river in egypt
+ *
+ * \param[in] rr The (query) RR to check the denial of existence for
+ * \param[in] nsecs The list of NSEC RRs that are supposed to deny the
+ * existence of the RR
+ * \param[in] rrsigs The RRSIG RR covering the NSEC RRs
+ * \return LDNS_STATUS_OK if the NSEC RRs deny the existence, error code
+ * containing the reason they do not otherwise
+ */
+ldns_status ldns_dnssec_verify_denial(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs);
+
+/**
+ * Denial of existence using NSEC3 records
+ * Since NSEC3 is a bit more complicated than normal denial, some
+ * context arguments are needed
+ *
+ * \param[in] rr The (query) RR to check the denial of existence for
+ * \param[in] nsecs The list of NSEC3 RRs that are supposed to deny the
+ * existence of the RR
+ * \param[in] rrsigs The RRSIG rr covering the NSEC RRs
+ * \param[in] packet_rcode The RCODE value of the packet that provided the
+ * NSEC3 RRs
+ * \param[in] packet_qtype The original query RR type
+ * \param[in] packet_nodata True if the providing packet had an empty ANSWER
+ * section
+ * \return LDNS_STATUS_OK if the NSEC3 RRs deny the existence, error code
+ * containing the reason they do not otherwise
+ */
+ldns_status ldns_dnssec_verify_denial_nsec3(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs,
+ ldns_pkt_rcode packet_rcode,
+ ldns_rr_type packet_qtype,
+ bool packet_nodata);
+
+/**
+ * Same as ldns_status ldns_dnssec_verify_denial_nsec3 but also returns
+ * the nsec rr that matched.
+ *
+ * \param[in] rr The (query) RR to check the denial of existence for
+ * \param[in] nsecs The list of NSEC3 RRs that are supposed to deny the
+ * existence of the RR
+ * \param[in] rrsigs The RRSIG rr covering the NSEC RRs
+ * \param[in] packet_rcode The RCODE value of the packet that provided the
+ * NSEC3 RRs
+ * \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
+ * 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
+ */
+ldns_status ldns_dnssec_verify_denial_nsec3_match(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs,
+ ldns_pkt_rcode packet_rcode,
+ ldns_rr_type packet_qtype,
+ bool packet_nodata,
+ ldns_rr **match);
+/**
+ * Verifies the already processed data in the buffers
+ * This function should probably not be used directly.
+ *
+ * \param[in] rawsig_buf Buffer containing signature data to use
+ * \param[in] verify_buf Buffer containing data to verify
+ * \param[in] key_buf Buffer containing key data to use
+ * \param[in] algo Signing algorithm
+ * \return status LDNS_STATUS_OK if the data verifies. Error if not.
+ */
+ldns_status ldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf,
+ ldns_buffer *verify_buf,
+ ldns_buffer *key_buf,
+ uint8_t algo);
+
+/**
+ * Like ldns_verify_rrsig_buffers, but uses raw data.
+ *
+ * \param[in] sig signature data to use
+ * \param[in] siglen length of signature data to use
+ * \param[in] verify_buf Buffer containing data to verify
+ * \param[in] key key data to use
+ * \param[in] keylen length of key data to use
+ * \param[in] algo Signing algorithm
+ * \return status LDNS_STATUS_OK if the data verifies. Error if not.
+ */
+ldns_status ldns_verify_rrsig_buffers_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer *verify_buf,
+ unsigned char* key,
+ size_t keylen,
+ uint8_t algo);
+
+/**
+ * Verifies an rrsig. All keys in the keyset are tried.
+ * \param[in] rrset the rrset to check
+ * \param[in] rrsig the signature of the rrset
+ * \param[in] keys the keys to try
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return a list of keys which validate the rrsig + rrset. Returns
+ * status LDNS_STATUS_OK if at least one key matched. Else an error.
+ */
+ldns_status ldns_verify_rrsig_keylist(ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys);
+
+/**
+ * Verifies an rrsig. All keys in the keyset are tried.
+ * \param[in] rrset the rrset to check
+ * \param[in] rrsig the signature of the rrset
+ * \param[in] keys the keys to try
+ * \param[in] check_time the time for which the validation is performed
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return a list of keys which validate the rrsig + rrset. Returns
+ * status LDNS_STATUS_OK if at least one key matched. Else an error.
+ */
+ldns_status ldns_verify_rrsig_keylist_time(
+ ldns_rr_list *rrset, ldns_rr *rrsig,
+ const ldns_rr_list *keys, time_t check_time,
+ ldns_rr_list *good_keys);
+
+
+/**
+ * Verifies an rrsig. All keys in the keyset are tried. Time is not checked.
+ * \param[in] rrset the rrset to check
+ * \param[in] rrsig the signature of the rrset
+ * \param[in] keys the keys to try
+ * \param[out] good_keys if this is a (initialized) list, the pointer to keys
+ * from keys that validate one of the signatures
+ * are added to it
+ * \return a list of keys which validate the rrsig + rrset. Returns
+ * status LDNS_STATUS_OK if at least one key matched. Else an error.
+ */
+ldns_status ldns_verify_rrsig_keylist_notime(ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys);
+
+/**
+ * verify an rrsig with 1 key
+ * \param[in] rrset the rrset
+ * \param[in] rrsig the rrsig to verify
+ * \param[in] key the key to use
+ * \return status message wether verification succeeded.
+ */
+ldns_status ldns_verify_rrsig(ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ ldns_rr *key);
+
+
+/**
+ * verify an rrsig with 1 key
+ * \param[in] rrset the rrset
+ * \param[in] rrsig the rrsig to verify
+ * \param[in] key the key to use
+ * \param[in] check_time the time for which the validation is performed
+ * \return status message wether verification succeeded.
+ */
+ldns_status ldns_verify_rrsig_time(
+ ldns_rr_list *rrset, ldns_rr *rrsig,
+ ldns_rr *key, time_t check_time);
+
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * verifies a buffer with signature data for a buffer with rrset data
+ * with an EVP_PKEY
+ *
+ * \param[in] sig the signature data
+ * \param[in] rrset the rrset data, sorted and processed for verification
+ * \param[in] key the EVP key structure
+ * \param[in] digest_type The digest type of the signature
+ */
+ldns_status ldns_verify_rrsig_evp(ldns_buffer *sig,
+ ldns_buffer *rrset,
+ EVP_PKEY *key,
+ const EVP_MD *digest_type);
+
+/**
+ * Like ldns_verify_rrsig_evp, but uses raw signature data.
+ * \param[in] sig the signature data, wireformat uncompressed
+ * \param[in] siglen length of the signature data
+ * \param[in] rrset the rrset data, sorted and processed for verification
+ * \param[in] key the EVP key structure
+ * \param[in] digest_type The digest type of the signature
+ */
+ldns_status ldns_verify_rrsig_evp_raw(unsigned char *sig,
+ size_t siglen,
+ ldns_buffer *rrset,
+ EVP_PKEY *key,
+ const EVP_MD *digest_type);
+#endif
+
+/**
+ * verifies a buffer with signature data (DSA) for a buffer with rrset data
+ * with a buffer with key data.
+ *
+ * \param[in] sig the signature data
+ * \param[in] rrset the rrset data, sorted and processed for verification
+ * \param[in] key the key data
+ */
+ldns_status ldns_verify_rrsig_dsa(ldns_buffer *sig,
+ ldns_buffer *rrset,
+ ldns_buffer *key);
+
+/**
+ * verifies a buffer with signature data (RSASHA1) for a buffer with rrset data
+ * with a buffer with key data.
+ *
+ * \param[in] sig the signature data
+ * \param[in] rrset the rrset data, sorted and processed for verification
+ * \param[in] key the key data
+ */
+ldns_status ldns_verify_rrsig_rsasha1(ldns_buffer *sig,
+ ldns_buffer *rrset,
+ ldns_buffer *key);
+
+/**
+ * verifies a buffer with signature data (RSAMD5) for a buffer with rrset data
+ * with a buffer with key data.
+ *
+ * \param[in] sig the signature data
+ * \param[in] rrset the rrset data, sorted and processed for verification
+ * \param[in] key the key data
+ */
+ldns_status ldns_verify_rrsig_rsamd5(ldns_buffer *sig,
+ ldns_buffer *rrset,
+ ldns_buffer *key);
+
+/**
+ * Like ldns_verify_rrsig_dsa, but uses raw signature and key data.
+ * \param[in] sig raw uncompressed wireformat signature data
+ * \param[in] siglen length of signature data
+ * \param[in] rrset ldns buffer with prepared rrset data.
+ * \param[in] key raw uncompressed wireformat key data
+ * \param[in] keylen length of key data
+ */
+ldns_status ldns_verify_rrsig_dsa_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen);
+
+/**
+ * Like ldns_verify_rrsig_rsasha1, but uses raw signature and key data.
+ * \param[in] sig raw uncompressed wireformat signature data
+ * \param[in] siglen length of signature data
+ * \param[in] rrset ldns buffer with prepared rrset data.
+ * \param[in] key raw uncompressed wireformat key data
+ * \param[in] keylen length of key data
+ */
+ldns_status ldns_verify_rrsig_rsasha1_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen);
+
+/**
+ * Like ldns_verify_rrsig_rsasha256, but uses raw signature and key data.
+ * \param[in] sig raw uncompressed wireformat signature data
+ * \param[in] siglen length of signature data
+ * \param[in] rrset ldns buffer with prepared rrset data.
+ * \param[in] key raw uncompressed wireformat key data
+ * \param[in] keylen length of key data
+ */
+
+ldns_status ldns_verify_rrsig_rsasha256_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen);
+
+/**
+ * Like ldns_verify_rrsig_rsasha512, but uses raw signature and key data.
+ * \param[in] sig raw uncompressed wireformat signature data
+ * \param[in] siglen length of signature data
+ * \param[in] rrset ldns buffer with prepared rrset data.
+ * \param[in] key raw uncompressed wireformat key data
+ * \param[in] keylen length of key data
+ */
+ldns_status ldns_verify_rrsig_rsasha512_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen);
+
+/**
+ * Like ldns_verify_rrsig_rsamd5, but uses raw signature and key data.
+ * \param[in] sig raw uncompressed wireformat signature data
+ * \param[in] siglen length of signature data
+ * \param[in] rrset ldns buffer with prepared rrset data.
+ * \param[in] key raw uncompressed wireformat key data
+ * \param[in] keylen length of key data
+ */
+ldns_status ldns_verify_rrsig_rsamd5_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/3rdParty/Ldns/src/include/ldns/dnssec_zone.h b/3rdParty/Ldns/src/include/ldns/dnssec_zone.h
new file mode 100644
index 0000000..e2dd402
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/dnssec_zone.h
@@ -0,0 +1,440 @@
+/*
+ * special zone file structures and functions for better dnssec handling
+ *
+ * A zone contains a SOA dnssec_zone_rrset, and an AVL tree of 'normal'
+ * dnssec_zone_rrsets, indexed by name and type
+ */
+
+#ifndef LDNS_DNSSEC_ZONE_H
+#define LDNS_DNSSEC_ZONE_H
+
+#include <ldns/ldns.h>
+#include <ldns/rbtree.h>
+#include <ldns/host2str.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Singly linked list of rrs
+ */
+typedef struct ldns_struct_dnssec_rrs ldns_dnssec_rrs;
+struct ldns_struct_dnssec_rrs
+{
+ ldns_rr *rr;
+ ldns_dnssec_rrs *next;
+};
+
+/**
+ * Singly linked list of RRsets
+ */
+typedef struct ldns_struct_dnssec_rrsets ldns_dnssec_rrsets;
+struct ldns_struct_dnssec_rrsets
+{
+ ldns_dnssec_rrs *rrs;
+ ldns_rr_type type;
+ ldns_dnssec_rrs *signatures;
+ ldns_dnssec_rrsets *next;
+};
+
+/**
+ * Structure containing all resource records for a domain name
+ * Including the derived NSEC3, if present
+ */
+typedef struct ldns_struct_dnssec_name ldns_dnssec_name;
+struct ldns_struct_dnssec_name
+{
+ /**
+ * pointer to a dname containing the name.
+ * Usually points to the owner name of the first RR of the first RRset
+ */
+ ldns_rdf *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
+ * indicate that this data must also be freed when the name is freed
+ */
+ bool name_alloced;
+ /**
+ * The rrsets for this name
+ */
+ ldns_dnssec_rrsets *rrsets;
+ /**
+ * NSEC pointing to the next name (or NSEC3 pointing to the next NSEC3)
+ */
+ ldns_rr *nsec;
+ /**
+ * signatures for the NSEC record
+ */
+ ldns_dnssec_rrs *nsec_signatures;
+ /**
+ * Unlike what the name is_glue suggests, this field is set to true by
+ * ldns_dnssec_zone_mark_glue() or ldns_dnssec_zone_mark_and_get_glue()
+ * when the name, this dnssec_name struct represents, is occluded.
+ * Names that contain other occluded rrsets and records with glue on
+ * the delegation point will NOT have this bool set to true.
+ * This field should NOT be read directly, but only via the
+ * ldns_dnssec_name_is_glue() function!
+ */
+ bool is_glue;
+ /**
+ * pointer to store the hashed name (only used when in an NSEC3 zone
+ */
+ ldns_rdf *hashed_name;
+};
+
+/**
+ * Structure containing a dnssec zone
+ */
+struct ldns_struct_dnssec_zone {
+ /** points to the name containing the SOA RR */
+ ldns_dnssec_name *soa;
+ /** tree of ldns_dnssec_names */
+ ldns_rbtree_t *names;
+};
+typedef struct ldns_struct_dnssec_zone ldns_dnssec_zone;
+
+/**
+ * Creates a new entry for 1 pointer to an rr and 1 pointer to the next rrs
+ * \return the allocated data
+ */
+ldns_dnssec_rrs *ldns_dnssec_rrs_new();
+
+/**
+ * Frees the list of rrs, but *not* the individual ldns_rr records
+ * contained in the list
+ *
+ * \param[in] rrs the data structure to free
+ */
+void ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs);
+
+/**
+ * Frees the list of rrs, and the individual ldns_rr records
+ * contained in the list
+ *
+ * \param[in] rrs the data structure to free
+ */
+void ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs);
+
+/**
+ * Adds an RR to the list of RRs. The list will remain ordered
+ *
+ * \param[in] rrs the list to add to
+ * \param[in] rr the RR to add
+ * \return LDNS_STATUS_OK on success
+ */
+ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr);
+
+/**
+ * Prints the given rrs to the file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] rrs the list of RRs to print
+ */
+void ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs);
+
+/**
+ * Prints the given rrs to the file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] fmt the format of the textual representation
+ * \param[in] rrs the list of RRs to print
+ */
+void ldns_dnssec_rrs_print_fmt(FILE *out,
+ const ldns_output_format *fmt, ldns_dnssec_rrs *rrs);
+
+/**
+ * Creates a new list (entry) of RRsets
+ * \return the newly allocated structure
+ */
+ldns_dnssec_rrsets *ldns_dnssec_rrsets_new();
+
+/**
+ * Frees the list of rrsets and their rrs, but *not* the ldns_rr
+ * records in the sets
+ *
+ * \param[in] rrsets the data structure to free
+ */
+void ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets);
+
+/**
+ * Frees the list of rrsets and their rrs, and the ldns_rr
+ * records in the sets
+ *
+ * \param[in] rrsets the data structure to free
+ */
+void ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets);
+
+/**
+ * Returns the rr type of the rrset (that is head of the given list)
+ *
+ * \param[in] rrsets the rrset to get the type of
+ * \return the rr type
+ */
+ldns_rr_type ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets);
+
+/**
+ * Sets the RR type of the rrset (that is head of the given list)
+ *
+ * \param[in] rrsets the rrset to set the type of
+ * \param[in] type the type to set
+ * \return LDNS_STATUS_OK on success
+ */
+ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
+ ldns_rr_type type);
+
+/**
+ * Add an ldns_rr to the corresponding RRset in the given list of RRsets.
+ * If it is not present, add it as a new RRset with 1 record.
+ *
+ * \param[in] rrsets the list of rrsets to add the RR to
+ * \param[in] rr the rr to add to the list of rrsets
+ * \return LDNS_STATUS_OK on success
+ */
+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
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] rrsets the list of RRsets to print
+ * \param[in] follow if set to false, only print the first RRset
+ */
+void ldns_dnssec_rrsets_print(FILE *out,
+ ldns_dnssec_rrsets *rrsets,
+ bool follow);
+
+/**
+ * Print the given list of rrsets to the fiven file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] fmt the format of the textual representation
+ * \param[in] rrsets the list of RRsets to print
+ * \param[in] follow if set to false, only print the first RRset
+ */
+void ldns_dnssec_rrsets_print_fmt(FILE *out,
+ const ldns_output_format *fmt,
+ ldns_dnssec_rrsets *rrsets,
+ bool follow);
+
+
+/**
+ * Create a new data structure for a dnssec name
+ * \return the allocated structure
+ */
+ldns_dnssec_name *ldns_dnssec_name_new();
+
+/**
+ * Create a new data structure for a dnssec name for the given RR
+ *
+ * \param[in] rr the RR to derive properties from, and to add to the name
+ */
+ldns_dnssec_name *ldns_dnssec_name_new_frm_rr(ldns_rr *rr);
+
+/**
+ * Frees the name structure and its rrs and rrsets.
+ * Individual ldns_rr records therein are not freed
+ *
+ * \param[in] name the structure to free
+ */
+void ldns_dnssec_name_free(ldns_dnssec_name *name);
+
+/**
+ * Frees the name structure and its rrs and rrsets.
+ * Individual ldns_rr records contained in the name are also freed
+ *
+ * \param[in] name the structure to free
+ */
+void ldns_dnssec_name_deep_free(ldns_dnssec_name *name);
+
+/**
+ * Returns the domain name of the given dnssec_name structure
+ *
+ * \param[in] name the dnssec name to get the domain name from
+ * \return the domain name
+ */
+ldns_rdf *ldns_dnssec_name_name(ldns_dnssec_name *name);
+
+
+/**
+ * Sets the domain name of the given dnssec_name structure
+ *
+ * \param[in] name the dnssec name to set the domain name of
+ * \param[in] dname the domain name to set it to. This data is *not* copied.
+ */
+void ldns_dnssec_name_set_name(ldns_dnssec_name *name,
+ ldns_rdf *dname);
+/**
+ * Returns if dnssec_name structure is marked as glue.
+ * The ldns_dnssec_zone_mark_glue() function has to be called on a zone before
+ * using this function.
+ * Only names that have only glue rrsets will be marked.
+ * Names that have other occluded rrsets and names containing glue on the
+ * delegation point will NOT be marked!
+ *
+ * \param[in] name the dnssec name to get the domain name from
+ * \return true if the structure is marked as glue, false otherwise.
+ */
+bool ldns_dnssec_name_is_glue(ldns_dnssec_name *name);
+
+/**
+ * Sets the NSEC(3) RR of the given dnssec_name structure
+ *
+ * \param[in] name the dnssec name to set the domain name of
+ * \param[in] nsec the nsec rr to set it to. This data is *not* copied.
+ */
+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.
+ *
+ * \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
+ * equal
+ */
+int ldns_dnssec_name_cmp(const void *a, const void *b);
+
+/**
+ * Inserts the given rr at the right place in the current dnssec_name
+ * No checking is done whether the name matches
+ *
+ * \param[in] name The ldns_dnssec_name to add the RR to
+ * \param[in] rr The RR to add
+ * \return LDNS_STATUS_OK on success, error code otherwise
+ */
+ldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
+ ldns_rr *rr);
+
+/**
+ * Find the RRset with the given type in within this name structure
+ *
+ * \param[in] name the name to find the RRset in
+ * \param[in] type the type of the RRset to find
+ * \return the RRset, or NULL if not present
+ */
+ldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
+ ldns_rr_type type);
+
+/**
+ * Find the RRset with the given name and type in the zone
+ *
+ * \param[in] zone the zone structure to find the RRset in
+ * \param[in] dname the domain name of the RRset to find
+ * \param[in] type the type of the RRset to find
+ * \return the RRset, or NULL if not present
+ */
+ldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
+ ldns_rdf *dname,
+ ldns_rr_type type);
+
+/**
+ * Prints the RRs in the dnssec name structure to the given
+ * file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] name the name structure to print the contents of
+ */
+void ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name);
+
+/**
+ * Prints the RRs in the dnssec name structure to the given
+ * file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] fmt the format of the textual representation
+ * \param[in] name the name structure to print the contents of
+ */
+void ldns_dnssec_name_print_fmt(FILE *out,
+ const ldns_output_format *fmt, ldns_dnssec_name *name);
+
+/**
+ * Creates a new dnssec_zone structure
+ * \return the allocated structure
+ */
+ldns_dnssec_zone *ldns_dnssec_zone_new();
+
+/**
+ * Frees the given zone structure, and its rbtree of dnssec_names
+ * Individual ldns_rr RRs within those names are *not* freed
+ * \param[in] *zone the zone to free
+ */
+void ldns_dnssec_zone_free(ldns_dnssec_zone *zone);
+
+/**
+ * Frees the given zone structure, and its rbtree of dnssec_names
+ * Individual ldns_rr RRs within those names are also freed
+ * \param[in] *zone the zone to free
+ */
+void ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone);
+
+/**
+ * Adds the given RR to the zone.
+ * It find whether there is a dnssec_name with that name present.
+ * If so, add it to that, if not create a new one.
+ * Special handling of NSEC and RRSIG provided
+ *
+ * \param[in] zone the zone to add the RR to
+ * \param[in] rr The RR to add
+ * \return LDNS_STATUS_OK on success, an error code otherwise
+ */
+ldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone,
+ ldns_rr *rr);
+
+/**
+ * Prints the rbtree of ldns_dnssec_name structures to the file descriptor
+ *
+ * \param[in] out the file descriptor to print the names to
+ * \param[in] tree the tree of ldns_dnssec_name structures to print
+ * \param[in] print_soa if true, print SOA records, if false, skip them
+ */
+void ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa);
+
+/**
+ * Prints the rbtree of ldns_dnssec_name structures to the file descriptor
+ *
+ * \param[in] out the file descriptor to print the names to
+ * \param[in] fmt the format of the textual representation
+ * \param[in] tree the tree of ldns_dnssec_name structures to print
+ * \param[in] print_soa if true, print SOA records, if false, skip them
+ */
+void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_rbtree_t *tree, bool print_soa);
+
+/**
+ * Prints the complete zone to the given file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] zone the dnssec_zone to print
+ */
+void ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone);
+
+/**
+ * Prints the complete zone to the given file descriptor
+ *
+ * \param[in] out the file descriptor to print to
+ * \param[in] fmt the format of the textual representation
+ * \param[in] zone the dnssec_zone to print
+ */
+void ldns_dnssec_zone_print_fmt(FILE *out,
+ const ldns_output_format *fmt, ldns_dnssec_zone *zone);
+
+/**
+ * Adds explicit dnssec_name structures for the empty nonterminals
+ * in this zone. (this is needed for NSEC3 generation)
+ *
+ * \param[in] zone the zone to check for empty nonterminals
+ * return LDNS_STATUS_OK on success.
+ */
+ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/3rdParty/Ldns/src/include/ldns/error.h b/3rdParty/Ldns/src/include/ldns/error.h
new file mode 100644
index 0000000..99d4f0b
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/error.h
@@ -0,0 +1,121 @@
+/**
+ * \file error.h
+ *
+ * Defines error numbers and functions to translate those to a readable string.
+ *
+ */
+
+/**
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_ERROR_H
+#define LDNS_ERROR_H
+
+#include <ldns/util.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum ldns_enum_status {
+ LDNS_STATUS_OK,
+ LDNS_STATUS_EMPTY_LABEL,
+ LDNS_STATUS_LABEL_OVERFLOW,
+ LDNS_STATUS_DOMAINNAME_OVERFLOW,
+ LDNS_STATUS_DOMAINNAME_UNDERFLOW,
+ LDNS_STATUS_DDD_OVERFLOW,
+ LDNS_STATUS_PACKET_OVERFLOW,
+ LDNS_STATUS_INVALID_POINTER,
+ LDNS_STATUS_MEM_ERR,
+ LDNS_STATUS_INTERNAL_ERR,
+ LDNS_STATUS_SSL_ERR,
+ LDNS_STATUS_ERR,
+ LDNS_STATUS_INVALID_INT,
+ LDNS_STATUS_INVALID_IP4,
+ LDNS_STATUS_INVALID_IP6,
+ LDNS_STATUS_INVALID_STR,
+ LDNS_STATUS_INVALID_B32_EXT,
+ LDNS_STATUS_INVALID_B64,
+ LDNS_STATUS_INVALID_HEX,
+ LDNS_STATUS_INVALID_TIME,
+ LDNS_STATUS_NETWORK_ERR,
+ LDNS_STATUS_ADDRESS_ERR,
+ LDNS_STATUS_FILE_ERR,
+ LDNS_STATUS_UNKNOWN_INET,
+ LDNS_STATUS_NOT_IMPL,
+ LDNS_STATUS_NULL,
+ LDNS_STATUS_CRYPTO_UNKNOWN_ALGO,
+ LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL,
+ LDNS_STATUS_CRYPTO_NO_RRSIG,
+ LDNS_STATUS_CRYPTO_NO_DNSKEY,
+ LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY,
+ LDNS_STATUS_CRYPTO_NO_DS,
+ LDNS_STATUS_CRYPTO_NO_TRUSTED_DS,
+ LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY,
+ LDNS_STATUS_CRYPTO_VALIDATED,
+ LDNS_STATUS_CRYPTO_BOGUS,
+ LDNS_STATUS_CRYPTO_SIG_EXPIRED,
+ LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED,
+ LDNS_STATUS_CRYPTO_TSIG_BOGUS,
+ LDNS_STATUS_CRYPTO_TSIG_ERR,
+ LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION,
+ LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR,
+ LDNS_STATUS_ENGINE_KEY_NOT_LOADED,
+ LDNS_STATUS_NSEC3_ERR,
+ LDNS_STATUS_RES_NO_NS,
+ LDNS_STATUS_RES_QUERY,
+ LDNS_STATUS_WIRE_INCOMPLETE_HEADER,
+ LDNS_STATUS_WIRE_INCOMPLETE_QUESTION,
+ LDNS_STATUS_WIRE_INCOMPLETE_ANSWER,
+ LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY,
+ LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL,
+ LDNS_STATUS_NO_DATA,
+ LDNS_STATUS_CERT_BAD_ALGORITHM,
+ LDNS_STATUS_SYNTAX_TYPE_ERR,
+ LDNS_STATUS_SYNTAX_CLASS_ERR,
+ LDNS_STATUS_SYNTAX_TTL_ERR,
+ LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL,
+ LDNS_STATUS_SYNTAX_RDATA_ERR,
+ LDNS_STATUS_SYNTAX_DNAME_ERR,
+ LDNS_STATUS_SYNTAX_VERSION_ERR,
+ LDNS_STATUS_SYNTAX_ALG_ERR,
+ LDNS_STATUS_SYNTAX_KEYWORD_ERR,
+ LDNS_STATUS_SYNTAX_TTL,
+ LDNS_STATUS_SYNTAX_ORIGIN,
+ LDNS_STATUS_SYNTAX_INCLUDE,
+ LDNS_STATUS_SYNTAX_EMPTY,
+ LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW,
+ LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR,
+ LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW,
+ LDNS_STATUS_SYNTAX_BAD_ESCAPE,
+ LDNS_STATUS_SOCKET_ERROR,
+ LDNS_STATUS_SYNTAX_ERR,
+ LDNS_STATUS_DNSSEC_EXISTENCE_DENIED,
+ LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED,
+ LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED,
+ LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND,
+ LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG,
+ LDNS_STATUS_MISSING_RDATA_FIELDS_KEY
+};
+typedef enum ldns_enum_status ldns_status;
+
+extern ldns_lookup_table ldns_error_str[];
+
+/**
+ * look up a descriptive text by each error. This function
+ * could use a better name
+ * \param[in] err ldns_status number
+ * \return the string for that error
+ */
+const char *ldns_get_errorstr_by_id(ldns_status err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_ERROR_H */
diff --git a/3rdParty/Ldns/src/include/ldns/higher.h b/3rdParty/Ldns/src/include/ldns/higher.h
new file mode 100644
index 0000000..597e134
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/higher.h
@@ -0,0 +1,113 @@
+/**
+ * \file higher.h
+ *
+ * Specifies some higher level functions that could
+ * be useful for certain applications
+ */
+
+/*
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_HIGHER_H
+#define LDNS_HIGHER_H
+
+#include <ldns/resolver.h>
+#include <ldns/rdata.h>
+#include <ldns/rr.h>
+#include <ldns/host2str.h>
+#include <ldns/tsig.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Ask the resolver about name
+ * and return all address records
+ * \param[in] r the resolver to use
+ * \param[in] name the name to look for
+ * \param[in] c the class to use
+ * \param[in] flags give some optional flags to the query
+ */
+ldns_rr_list *ldns_get_rr_list_addr_by_name(ldns_resolver *r, ldns_rdf *name, ldns_rr_class c, uint16_t flags);
+
+/**
+ * ask the resolver about the address
+ * and return the name
+ * \param[in] r the resolver to use
+ * \param[in] addr the addr to look for
+ * \param[in] c the class to use
+ * \param[in] flags give some optional flags to the query
+ */
+ldns_rr_list *ldns_get_rr_list_name_by_addr(ldns_resolver *r, ldns_rdf *addr, ldns_rr_class c, uint16_t flags);
+
+/**
+ * wade through fp (a /etc/hosts like file)
+ * and return a rr_list containing all the
+ * defined hosts in there
+ * \param[in] fp the file pointer to use
+ * \return ldns_rr_list * with the names
+ */
+ldns_rr_list *ldns_get_rr_list_hosts_frm_fp(FILE *fp);
+
+/**
+ * wade through fp (a /etc/hosts like file)
+ * and return a rr_list containing all the
+ * defined hosts in there
+ * \param[in] fp the file pointer to use
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return ldns_rr_list * with the names
+ */
+ldns_rr_list *ldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr);
+
+/**
+ * wade through fp (a /etc/hosts like file)
+ * and return a rr_list containing all the
+ * defined hosts in there
+ * \param[in] filename the filename to use (NULL for /etc/hosts)
+ * \return ldns_rr_list * with the names
+ */
+ldns_rr_list *ldns_get_rr_list_hosts_frm_file(char *filename);
+
+/**
+ * This function is a wrapper function for ldns_get_rr_list_name_by_addr
+ * and ldns_get_rr_list_addr_by_name. It's name is from the getaddrinfo()
+ * library call. It tries to mimic that call, but without the lowlevel
+ * stuff.
+ * \param[in] res The resolver. If this value is NULL then a resolver will
+ * be created by ldns_getaddrinfo.
+ * \param[in] node the name or ip address to look up
+ * \param[in] c the class to look in
+ * \param[out] list put the found RR's in this list
+ * \return the number of RR found.
+ */
+uint16_t ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c, ldns_rr_list **list);
+
+/**
+ * Check if t is enumerated in the nsec type rdata
+ * \param[in] nsec the NSEC Record to look in
+ * \param[in] t the type to check for
+ * \return true when t is found, otherwise return false
+ */
+bool ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t);
+
+/**
+ * Print a number of rdf's of the RR. The rdfnum-list must
+ * be ended by -1, otherwise unpredictable things might happen.
+ * rdfs may be printed multiple times
+ * \param[in] fp FILE * to write to
+ * \param[in] r RR to write
+ * \param[in] rdfnum a list of rdf to print.
+ */
+void ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_HIGHER_H */
diff --git a/3rdParty/Ldns/src/include/ldns/host2str.h b/3rdParty/Ldns/src/include/ldns/host2str.h
new file mode 100644
index 0000000..f0a14a4
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/host2str.h
@@ -0,0 +1,759 @@
+/**
+ * host2str.h - txt presentation of RRs
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions to translate the main structures to their text
+ * representation, as well as functions to print them.
+ */
+
+#ifndef LDNS_HOST2STR_H
+#define LDNS_HOST2STR_H
+
+#include <ldns/common.h>
+#include <ldns/error.h>
+#include <ldns/rr.h>
+#include <ldns/rdata.h>
+#include <ldns/packet.h>
+#include <ldns/buffer.h>
+#include <ldns/resolver.h>
+#include <ldns/zone.h>
+#include <ctype.h>
+
+#include "ldns/util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_APL_IP4 1
+#define LDNS_APL_IP6 2
+#define LDNS_APL_MASK 0x7f
+#define LDNS_APL_NEGATION 0x80
+
+/**
+ * Represent a NULL pointer (in stead of a pointer to a ldns_rr as "; (null)"
+ * as opposed to outputting nothing at all in such a case.
+ */
+#define LDNS_COMMENT_NULLS 0x0001
+/** Show key id with DNSKEY RR's as comment */
+#define LDNS_COMMENT_KEY_ID 0x0002
+/** Show if a DNSKEY is a ZSK or KSK as comment */
+#define LDNS_COMMENT_KEY_TYPE 0x0004
+/** Show DNSKEY key size as comment */
+#define LDNS_COMMENT_KEY_SIZE 0x0008
+/** Show key id, type and size as comment for DNSKEY RR's */
+#define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \
+ |LDNS_COMMENT_KEY_TYPE\
+ |LDNS_COMMENT_KEY_SIZE)
+/** Provide bubblebabble representation for DS RR's as comment */
+#define LDNS_COMMENT_BUBBLEBABBLE 0x0010
+/** Show when a NSEC3 RR has the optout flag set as comment */
+#define LDNS_COMMENT_FLAGS 0x0020
+/** Show the unhashed owner and next owner names for NSEC3 RR's as comment */
+#define LDNS_COMMENT_NSEC3_CHAIN 0x0040
+/** Print mark up */
+#define LDNS_COMMENT_LAYOUT 0x0080
+/** Also comment KEY_ID with RRSIGS **/
+#define LDNS_COMMENT_RRSIGS 0x0100
+
+/**
+ * Output format specifier
+ *
+ * Determines how Packets, Resource Records and Resource record data fiels 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
+ * a lookup map of hashes to real names for annotation NSEC3 records).
+ */
+struct ldns_struct_output_format
+{
+ /** Specification of how RR's should be formatted in text */
+ int flags;
+ /** Potential extra data to be used with formatting RR's in text */
+ void *data;
+};
+typedef struct ldns_struct_output_format ldns_output_format;
+
+/**
+ * Standard output format record that disables commenting in the textual
+ * representation of Resource Records completely.
+ */
+extern const ldns_output_format *ldns_output_format_nocomments;
+/**
+ * Standard output format record that annotated only DNSKEY RR's with commenti
+ * text.
+ */
+extern const ldns_output_format *ldns_output_format_onlykeyids;
+/**
+ * The default output format record. Same as ldns_output_format_onlykeyids.
+ */
+extern const ldns_output_format *ldns_output_format_default;
+/**
+ * Standard output format record that shows all DNSKEY related information in
+ * the comment text, plus the optout flag when set with NSEC3's, plus the
+ * bubblebabble representation of DS RR's.
+ */
+extern const ldns_output_format *ldns_output_format_bubblebabble;
+
+/**
+ * Converts an ldns packet opcode value to its mnemonic, and adds that
+ * to the output buffer
+ * \param[in] *output the buffer to add the data to
+ * \param[in] opcode to find the string representation of
+ * \return LDNS_STATUS_OK on success, or a buffer failure mode on error
+ */
+ldns_status
+ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode);
+
+/**
+ * Converts an ldns packet rcode value to its mnemonic, and adds that
+ * to the output buffer
+ * \param[in] *output the buffer to add the data to
+ * \param[in] rcode to find the string representation of
+ * \return LDNS_STATUS_OK on success, or a buffer failure mode on error
+ */
+ldns_status
+ldns_pkt_rcode2buffer_str(ldns_buffer *output, ldns_pkt_rcode rcode);
+
+/**
+ * Converts an ldns algorithm type to its mnemonic, and adds that
+ * to the output buffer
+ * \param[in] *output the buffer to add the data to
+ * \param[in] algorithm to find the string representation of
+ * \return LDNS_STATUS_OK on success, or a buffer failure mode on error
+ */
+ldns_status
+ldns_algorithm2buffer_str(ldns_buffer *output,
+ ldns_algorithm algorithm);
+
+/**
+ * Converts an ldns certificate algorithm type to its mnemonic,
+ * and adds that to the output buffer
+ * \param[in] *output the buffer to add the data to
+ * \param[in] cert_algorithm to find the string representation of
+ * \return LDNS_STATUS_OK on success, or a buffer failure mode on error
+ */
+ldns_status
+ldns_cert_algorithm2buffer_str(ldns_buffer *output,
+ ldns_cert_algorithm cert_algorithm);
+
+
+/**
+ * Converts a packet opcode to its mnemonic and returns that as
+ * an allocated null-terminated string.
+ * Remember to free it.
+ *
+ * \param[in] opcode the opcode to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt_opcode2str(ldns_pkt_opcode opcode);
+
+/**
+ * Converts a packet rcode to its mnemonic and returns that as
+ * an allocated null-terminated string.
+ * Remember to free it.
+ *
+ * \param[in] rcode the rcode to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt_rcode2str(ldns_pkt_rcode rcode);
+
+/**
+ * Converts a signing algorithms to its mnemonic and returns that as
+ * an allocated null-terminated string.
+ * Remember to free it.
+ *
+ * \param[in] algorithm the algorithm to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt_algorithm2str(ldns_algorithm algorithm);
+
+/**
+ * Converts a cert algorithm to its mnemonic and returns that as
+ * an allocated null-terminated string.
+ * Remember to free it.
+ *
+ * \param[in] cert_algorithm to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt_cert_algorithm2str(ldns_cert_algorithm cert_algorithm);
+
+/**
+ * Converts an LDNS_RDF_TYPE_A rdata element to string format and adds it to the output buffer
+ * \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_a(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_AAAA rdata element to string format and adds it to the output buffer
+ * \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_aaaa(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_STR rdata element to string format and adds it to the output buffer
+ * \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_str(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_B64 rdata element to string format and adds it to the output buffer
+ * \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_b64(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_B32_EXT rdata element to string format and adds it to the output buffer
+ * \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_b32_ext(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_HEX rdata element to string format and adds it to the output buffer
+ * \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_hex(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_TYPE rdata element to string format and adds it to the output buffer
+ * \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_type(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_CLASS rdata element to string format and adds it to the output buffer
+ * \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_class(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_ALG rdata element to string format and adds it to the output buffer
+ * \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_alg(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an ldns_rr_type value to its string representation,
+ * and places it in the given buffer
+ * \param[in] *output The buffer to add the data to
+ * \param[in] type the ldns_rr_type to convert
+ * \return LDNS_STATUS_OK on success, and error status on failure
+ */
+ldns_status ldns_rr_type2buffer_str(ldns_buffer *output,
+ const ldns_rr_type type);
+
+/**
+ * Converts an ldns_rr_type value to its string representation,
+ * and returns that string. For unknown types, the string
+ * "TYPE<id>" is returned. This function allocates data that must be
+ * freed by the caller
+ * \param[in] type the ldns_rr_type to convert
+ * \return a newly allocated string
+ */
+char *ldns_rr_type2str(const ldns_rr_type type);
+
+/**
+ * Converts an ldns_rr_class value to its string representation,
+ * and places it in the given buffer
+ * \param[in] *output The buffer to add the data to
+ * \param[in] klass the ldns_rr_class to convert
+ * \return LDNS_STATUS_OK on success, and error status on failure
+ */
+ldns_status ldns_rr_class2buffer_str(ldns_buffer *output,
+ const ldns_rr_class klass);
+
+/**
+ * Converts an ldns_rr_class value to its string representation,
+ * and returns that string. For unknown types, the string
+ * "CLASS<id>" is returned. This function allocates data that must be
+ * freed by the caller
+ * \param[in] klass the ldns_rr_class to convert
+ * \return a newly allocated string
+ */
+char *ldns_rr_class2str(const ldns_rr_class klass);
+
+
+/**
+ * Converts an LDNS_RDF_TYPE_CERT rdata element to string format and adds it to the output buffer
+ * \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_cert_alg(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_LOC rdata element to string format and adds it to the output buffer
+ * \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_loc(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_UNKNOWN rdata element to string format and adds it to the output buffer
+ * \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_unknown(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_NSAP rdata element to string format and adds it to the output buffer
+ * \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_nsap(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_ATMA rdata element to string format and adds it to the output buffer
+ * \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_atma(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_WKS rdata element to string format and adds it to the output buffer
+ * \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_wks(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_NSEC rdata element to string format and adds it to the output buffer
+ * \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_nsec(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_PERIOD rdata element to string format and adds it to the output buffer
+ * \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_period(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_TSIGTIME rdata element to string format and adds it to the output buffer
+ * \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_tsigtime(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_APL rdata element to string format and adds it to the output buffer
+ * \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_apl(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_INT16_DATA rdata element to string format and adds it to the output buffer
+ * \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_int16_data(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_IPSECKEY rdata element to string format and adds it to the output buffer
+ * \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_ipseckey(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_TSIG rdata element to string format and adds it to the output buffer
+ * \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_tsig(ldns_buffer *output, const ldns_rdf *rdf);
+
+
+/**
+ * Converts the data in the rdata field 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] rdf the pointer to the rdafa field containing the data
+ * \return status
+ */
+ldns_status ldns_rdf2buffer_str(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts the data in the resource record to presentation
+ * format (as char *) and appends it to the given buffer.
+ * The presentation format of DNSKEY record is annotated with comments giving
+ * the id, type and size of the key.
+ *
+ * \param[in] output pointer to the buffer to append the data to
+ * \param[in] rr the pointer to the rr field to convert
+ * \return status
+ */
+ldns_status ldns_rr2buffer_str(ldns_buffer *output, const ldns_rr *rr);
+
+/**
+ * Converts the data in the resource record to presentation
+ * format (as char *) and appends it to the given buffer.
+ * The presentation format is annotated with comments giving
+ * additional information on the record.
+ *
+ * \param[in] output pointer to the buffer to append the data to
+ * \param[in] fmt how to format the textual representation of the
+ * resource record.
+ * \param[in] rr the pointer to the rr field to convert
+ * \return status
+ */
+ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_rr *rr);
+
+/**
+ * Converts the data in the DNS packet 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] pkt the pointer to the packet to convert
+ * \return status
+ */
+ldns_status ldns_pkt2buffer_str(ldns_buffer *output, const ldns_pkt *pkt);
+
+/**
+ * Converts the data in the DNS packet 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] fmt how to format the textual representation of the packet
+ * \param[in] pkt the pointer to the packet to convert
+ * \return status
+ */
+ldns_status ldns_pkt2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_pkt *pkt);
+
+/**
+ * Converts an LDNS_RDF_TYPE_NSEC3_SALT rdata element to string format and adds it to the output buffer
+ * \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_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf);
+
+
+/**
+ * Converts the data in the DNS packet 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] k the pointer to the private key to convert
+ * \return status
+ */
+ldns_status ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k);
+
+/**
+ * Converts an LDNS_RDF_TYPE_INT8 rdata element to string format and adds it to the output buffer
+ * \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_int8(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_INT16 rdata element to string format and adds it to the output buffer
+ * \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_int16(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_INT32 rdata element to string format and adds it to the output buffer
+ * \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_int32(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts an LDNS_RDF_TYPE_TIME rdata element to string format and adds it to the output buffer
+ * \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_time(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Converts the data in the rdata field to presentation format and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] rdf The rdata field to convert
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_rdf2str(const ldns_rdf *rdf);
+
+/**
+ * Converts the data in the resource record to presentation format and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] rr The rdata field to convert
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_rr2str(const ldns_rr *rr);
+
+/**
+ * Converts the data in the resource record to presentation format and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] fmt how to format the resource record
+ * \param[in] rr The rdata field to convert
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_rr2str_fmt(const ldns_output_format *fmt, const ldns_rr *rr);
+
+/**
+ * Converts the data in the DNS packet to presentation format and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] pkt The rdata field to convert
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt2str(const ldns_pkt *pkt);
+
+/**
+ * Converts the data in the DNS packet to presentation format and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] fmt how to format the packet
+ * \param[in] pkt The rdata field to convert
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_pkt2str_fmt(const ldns_output_format *fmt, const ldns_pkt *pkt);
+
+/**
+ * Converts a private key to the test presentation fmt and
+ * returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] k the key to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_key2str(const ldns_key *k);
+
+/**
+ * Converts a list of resource records to presentation format
+ * and returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] rr_list the rr_list to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_rr_list2str(const ldns_rr_list *rr_list);
+
+/**
+ * Converts a list of resource records to presentation format
+ * and returns that as a char *.
+ * Remember to free it.
+ *
+ * \param[in] fmt how to format the list of resource records
+ * \param[in] rr_list the rr_list to convert to text
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_rr_list2str_fmt(
+ const ldns_output_format *fmt, const ldns_rr_list *rr_list);
+
+/**
+ * Returns the data in the buffer as a null terminated char * string
+ * Buffer data must be char * type, and must be freed by the caller
+ *
+ * \param[in] buffer buffer containing char * data
+ * \return null terminated char * data, or NULL on error
+ */
+char *ldns_buffer2str(ldns_buffer *buffer);
+
+/**
+ * Prints the data in the rdata field to the given file stream
+ * (in presentation format)
+ *
+ * \param[in] output the file stream to print to
+ * \param[in] rdf the rdata field to print
+ * \return void
+ */
+void ldns_rdf_print(FILE *output, const ldns_rdf *rdf);
+
+/**
+ * Prints the data in the resource record to the given file stream
+ * (in presentation format)
+ *
+ * \param[in] output the file stream to print to
+ * \param[in] rr the resource record to print
+ * \return void
+ */
+void ldns_rr_print(FILE *output, const ldns_rr *rr);
+
+/**
+ * Prints the data in the resource record to the given file stream
+ * (in presentation format)
+ *
+ * \param[in] output the file stream to print to
+ * \param[in] fmt format of the textual representation
+ * \param[in] rr the resource record to print
+ * \return void
+ */
+void ldns_rr_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_rr *rr);
+
+/**
+ * Prints the data in the DNS packet to the given file stream
+ * (in presentation format)
+ *
+ * \param[in] output the file stream to print to
+ * \param[in] pkt the packet to print
+ * \return void
+ */
+void ldns_pkt_print(FILE *output, const ldns_pkt *pkt);
+
+/**
+ * Prints the data in the DNS packet to the given file stream
+ * (in presentation format)
+ *
+ * \param[in] output the file stream to print to
+ * \param[in] fmt format of the textual representation
+ * \param[in] pkt the packet to print
+ * \return void
+ */
+void ldns_pkt_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_pkt *pkt);
+
+/**
+ * Converts a rr_list to presentation format and appends it to
+ * the output buffer
+ * \param[in] output the buffer to append output to
+ * \param[in] list the ldns_rr_list to print
+ * \return ldns_status
+ */
+ldns_status ldns_rr_list2buffer_str(ldns_buffer *output, const ldns_rr_list *list);
+
+/**
+ * Converts a rr_list to presentation format and appends it to
+ * the output buffer
+ * \param[in] output the buffer to append output to
+ * \param[in] fmt format of the textual representation
+ * \param[in] list the ldns_rr_list to print
+ * \return ldns_status
+ */
+ldns_status ldns_rr_list2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_rr_list *list);
+
+/**
+ * Converts the header of a packet to presentation format and appends it to
+ * the output buffer
+ * \param[in] output the buffer to append output to
+ * \param[in] pkt the packet to convert the header of
+ * \return ldns_status
+ */
+ldns_status ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt);
+
+/**
+ * print a rr_list to output
+ * \param[in] output the fd to print to
+ * \param[in] list the rr_list to print
+ */
+void ldns_rr_list_print(FILE *output, const ldns_rr_list *list);
+
+/**
+ * print a rr_list to output
+ * \param[in] output the fd to print to
+ * \param[in] fmt format of the textual representation
+ * \param[in] list the rr_list to print
+ */
+void ldns_rr_list_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_rr_list *list);
+
+/**
+ * Print a resolver (in sofar that is possible) state
+ * to output.
+ * \param[in] output the fd to print to
+ * \param[in] r the resolver to print
+ */
+void ldns_resolver_print(FILE *output, const ldns_resolver *r);
+
+/**
+ * Print a resolver (in sofar that is possible) state
+ * to output.
+ * \param[in] output the fd to print to
+ * \param[in] fmt format of the textual representation
+ * \param[in] r the resolver to print
+ */
+void ldns_resolver_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_resolver *r);
+
+/**
+ * Print a zone structure * to output. Note the SOA record
+ * is included in this output
+ * \param[in] output the fd to print to
+ * \param[in] z the zone to print
+ */
+void ldns_zone_print(FILE *output, const ldns_zone *z);
+
+/**
+ * Print a zone structure * to output. Note the SOA record
+ * is included in this output
+ * \param[in] output the fd to print to
+ * \param[in] fmt format of the textual representation
+ * \param[in] z the zone to print
+ */
+void ldns_zone_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_zone *z);
+
+/**
+ * Print the ldns_rdf containing a dname to the buffer
+ * \param[in] output the buffer to print to
+ * \param[in] dname the dname to print
+ * \return ldns_status message if the printing succeeded
+ */
+ldns_status ldns_rdf2buffer_str_dname(ldns_buffer *output, const ldns_rdf *dname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_HOST2STR_H */
diff --git a/3rdParty/Ldns/src/include/ldns/host2wire.h b/3rdParty/Ldns/src/include/ldns/host2wire.h
new file mode 100644
index 0000000..5eafe9d
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/host2wire.h
@@ -0,0 +1,164 @@
+/*
+ * host2wire.h - 2wire conversion routines
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains all functions to translate the main structures to wire format
+ */
+
+#ifndef LDNS_HOST2WIRE_H
+#define LDNS_HOST2WIRE_H
+
+#include <ldns/common.h>
+#include <ldns/error.h>
+#include <ldns/rr.h>
+#include <ldns/rdata.h>
+#include <ldns/packet.h>
+#include <ldns/buffer.h>
+#include <ctype.h>
+
+#include "ldns/util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Copies the dname data to the buffer in wire format
+ * \param[out] *buffer buffer to append the result to
+ * \param[in] *name rdata dname to convert
+ * \return ldns_status
+ */
+ldns_status ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name);
+
+/**
+ * Copies the rdata data to the buffer in wire format
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rdf rdata to convert
+ * \return ldns_status
+ */
+ldns_status ldns_rdf2buffer_wire(ldns_buffer *output, const ldns_rdf *rdf);
+
+/**
+ * Copies the rdata data to the buffer in wire format
+ * If the rdata is a dname, the letters will be lowercased
+ * during the conversion
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rdf rdata to convert
+ * \return ldns_status
+ */
+ldns_status ldns_rdf2buffer_wire_canonical(ldns_buffer *output,
+ const ldns_rdf *rdf);
+
+/**
+ * Copies the rr data to the buffer in wire format
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rr resource record to convert
+ * \param[in] section the section in the packet this rr is supposed to be in
+ * (to determine whether to add rdata or not)
+ * \return ldns_status
+ */
+ldns_status ldns_rr2buffer_wire(ldns_buffer *output,
+ const ldns_rr *rr,
+ int section);
+
+/**
+ * Copies the rr data to the buffer in wire format, in canonical format
+ * according to RFC3597 (every dname in rdata fields of RR's mentioned in
+ * that RFC will be lowercased)
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rr resource record to convert
+ * \param[in] section the section in the packet this rr is supposed to be in
+ * (to determine whether to add rdata or not)
+ * \return ldns_status
+ */
+ldns_status ldns_rr2buffer_wire_canonical(ldns_buffer *output,
+ const ldns_rr *rr,
+ int section);
+
+
+/**
+ * Converts a rrsig to wireformat BUT EXCLUDE the rrsig rdata
+ * This is needed in DNSSEC verification
+ * \param[out] output buffer to append the result to
+ * \param[in] sigrr signature rr to operate on
+ * \return ldns_status
+ */
+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.
+ *
+ * \param[out] *output buffer where to put the result
+ * \param[in] *rr rr to operate on
+ * \return ldns_status
+ */
+ldns_status ldns_rr_rdata2buffer_wire(ldns_buffer *output, const ldns_rr *rr);
+
+/**
+ * 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
+ * \return ldns_status
+ */
+ldns_status ldns_pkt2buffer_wire(ldns_buffer *output, const ldns_pkt *pkt);
+
+/**
+ * Copies the rr_list data to the buffer in wire format
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rrlist rr_list to to convert
+ * \return ldns_status
+ */
+ldns_status ldns_rr_list2buffer_wire(ldns_buffer *output, const ldns_rr_list *rrlist);
+
+/**
+ * Allocates an array of uint8_t at dest, and puts the wireformat of the
+ * given rdf 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] rdf the rdata field to convert
+ * \param[out] size the size of the converted result
+ */
+ldns_status ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *size);
+
+/**
+ * Allocates an array of uint8_t at dest, and puts the wireformat of the
+ * given rr 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)
+ *
+ * If the section argument is LDNS_SECTION_QUESTION, data like ttl and rdata
+ * are not put into the result
+ *
+ * \param[out] dest pointer to the array of bytes to be created
+ * \param[in] rr the rr to convert
+ * \param[out] size the size of the converted result
+ */
+ldns_status ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int, size_t *size);
+
+/**
+ * Allocates an array of uint8_t at dest, and puts the wireformat of the
+ * 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)
+ */
+ldns_status ldns_pkt2wire(uint8_t **dest, const ldns_pkt *p, size_t *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_HOST2WIRE_H */
diff --git a/3rdParty/Ldns/src/include/ldns/keys.h b/3rdParty/Ldns/src/include/ldns/keys.h
new file mode 100644
index 0000000..ad3ff25
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/keys.h
@@ -0,0 +1,615 @@
+/*
+ *
+ * keys.h
+ *
+ * priv key definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Addendum to \ref dnssec.h, this module contains key and algorithm definitions and functions.
+ */
+
+
+#ifndef LDNS_KEYS_H
+#define LDNS_KEYS_H
+
+#include <ldns/common.h>
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+#include <openssl/ssl.h>
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+#include <ldns/dnssec.h>
+#include <ldns/util.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern ldns_lookup_table ldns_signing_algorithms[];
+
+#define LDNS_KEY_ZONE_KEY 0x0100 /* rfc 4034 */
+#define LDNS_KEY_SEP_KEY 0x0001 /* rfc 4034 */
+#define LDNS_KEY_REVOKE_KEY 0x0080 /* rfc 5011 */
+
+/**
+ * Algorithms used in dns
+ */
+enum ldns_enum_algorithm
+{
+ LDNS_RSAMD5 = 1, /* RFC 4034,4035 */
+ LDNS_DH = 2,
+ LDNS_DSA = 3,
+ LDNS_ECC = 4,
+ LDNS_RSASHA1 = 5,
+ LDNS_DSA_NSEC3 = 6,
+ LDNS_RSASHA1_NSEC3 = 7,
+ LDNS_RSASHA256 = 8, /* RFC 5702 */
+ LDNS_RSASHA512 = 10, /* RFC 5702 */
+ LDNS_ECC_GOST = 12, /* RFC 5933 */
+#if LDNS_BUILD_CONFIG_USE_ECDSA
+ /* this ifdef has to be removed once it is no longer experimental,
+ * to be able to use these values outside of the ldns library itself */
+ LDNS_ECDSAP256SHA256 = 13, /* draft-hoffman-dnssec-ecdsa */
+ LDNS_ECDSAP384SHA384 = 14, /* EXPERIMENTAL */
+#endif
+ LDNS_INDIRECT = 252,
+ LDNS_PRIVATEDNS = 253,
+ LDNS_PRIVATEOID = 254
+};
+typedef enum ldns_enum_algorithm ldns_algorithm;
+
+/**
+ * Hashing algorithms used in the DS record
+ */
+enum ldns_enum_hash
+{
+ LDNS_SHA1 = 1, /* RFC 4034 */
+ LDNS_SHA256 = 2, /* RFC 4509 */
+ LDNS_HASH_GOST = 3 /* RFC 5933 */
+#if LDNS_BUILD_CONFIG_USE_ECDSA
+ /* this ifdef has to be removed once it is no longer experimental,
+ * to be able to use these values outside of the ldns library itself */
+ ,LDNS_SHA384 = 4 /* draft-hoffman-dnssec-ecdsa EXPERIMENTAL */
+#endif
+};
+typedef enum ldns_enum_hash ldns_hash;
+
+/**
+ * Algorithms used in dns for signing
+ */
+enum ldns_enum_signing_algorithm
+{
+ LDNS_SIGN_RSAMD5 = LDNS_RSAMD5,
+ LDNS_SIGN_RSASHA1 = LDNS_RSASHA1,
+ LDNS_SIGN_DSA = LDNS_DSA,
+ LDNS_SIGN_RSASHA1_NSEC3 = LDNS_RSASHA1_NSEC3,
+ LDNS_SIGN_RSASHA256 = LDNS_RSASHA256,
+ LDNS_SIGN_RSASHA512 = LDNS_RSASHA512,
+ LDNS_SIGN_DSA_NSEC3 = LDNS_DSA_NSEC3,
+ LDNS_SIGN_ECC_GOST = LDNS_ECC_GOST,
+#if LDNS_BUILD_CONFIG_USE_ECDSA
+ /* this ifdef has to be removed once it is no longer experimental,
+ * to be able to use these values outside of the ldns library itself */
+ LDNS_SIGN_ECDSAP256SHA256 = LDNS_ECDSAP256SHA256,
+ LDNS_SIGN_ECDSAP384SHA384 = LDNS_ECDSAP384SHA384,
+#endif
+ 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 */
+};
+typedef enum ldns_enum_signing_algorithm ldns_signing_algorithm;
+
+/**
+ * General key structure, can contain all types of keys that
+ * are used in DNSSEC. Mostly used to store private keys, since
+ * public keys can also be stored in a \ref ldns_rr with type
+ * \ref LDNS_RR_TYPE_DNSKEY.
+ *
+ * This structure can also store some variables that influence the
+ * signatures generated by signing with this key, for instance the
+ * inception date.
+ */
+struct ldns_struct_key {
+ ldns_signing_algorithm _alg;
+ /** Whether to use this key when signing */
+ bool _use;
+ /** Storage pointers for the types of keys supported */
+ /* TODO remove unions? */
+ struct {
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+#ifndef S_SPLINT_S
+ /* The key can be an OpenSSL EVP Key
+ */
+ EVP_PKEY *key;
+#endif
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+ /**
+ * The key can be an HMAC key
+ */
+ struct {
+ unsigned char *key;
+ size_t size;
+ } hmac;
+ /** the key structure can also just point to some external
+ * key data
+ */
+ void *external_key;
+ } _key;
+ /** Depending on the key we can have extra data */
+ union {
+ /** Some values that influence generated signatures */
+ struct {
+ /** The TTL of the rrset that is currently signed */
+ uint32_t orig_ttl;
+ /** The inception date of signatures made with this key. */
+ uint32_t inception;
+ /** The expiration date of signatures made with this key. */
+ uint32_t expiration;
+ /** The keytag of this key. */
+ uint16_t keytag;
+ /** The dnssec key flags as specified in RFC4035, like ZSK and KSK */
+ uint16_t flags;
+ } dnssec;
+ } _extra;
+ /** Owner name of the key */
+ ldns_rdf *_pubkey_owner;
+};
+typedef struct ldns_struct_key ldns_key;
+
+/**
+ * Same as rr_list, but now for keys
+ */
+struct ldns_struct_key_list
+{
+ size_t _key_count;
+ ldns_key **_keys;
+};
+typedef struct ldns_struct_key_list ldns_key_list;
+
+
+/**
+ * Creates a new empty key list
+ * \return a new ldns_key_list structure pointer
+ */
+ldns_key_list *ldns_key_list_new();
+
+/**
+ * Creates a new empty key structure
+ * \return a new ldns_key * structure
+ */
+ldns_key *ldns_key_new();
+
+/**
+ * Creates a new key based on the algorithm
+ *
+ * \param[in] a The algorithm to use
+ * \param[in] size the number of bytes for the keysize
+ * \return a new ldns_key structure with the key
+ */
+ldns_key *ldns_key_new_frm_algorithm(ldns_signing_algorithm a, uint16_t size);
+
+/**
+ * Creates a new priv key based on the
+ * contents of the file pointed by fp.
+ *
+ * The file should be in Private-key-format v1.x.
+ *
+ * \param[out] k the new ldns_key structure
+ * \param[in] fp the file pointer to use
+ * \return an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_key_new_frm_fp(ldns_key **k, FILE *fp);
+
+/**
+ * Creates a new private key based on the
+ * contents of the file pointed by fp
+ *
+ * The file should be in Private-key-format v1.x.
+ *
+ * \param[out] k the new ldns_key structure
+ * \param[in] fp the file pointer to use
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_key_new_frm_fp_l(ldns_key **k, FILE *fp, int *line_nr);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * 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
+ */
+ldns_status ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm);
+
+
+/**
+ * frm_fp helper function. This function parses the
+ * remainder of the (RSA) priv. key file generated from bind9
+ * \param[in] fp the file to parse
+ * \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
+ * \param[in] fp the file to parse
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \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
+/**
+ * frm_fp helper function. This function parses the
+ * remainder of the (DSA) priv. key file
+ * \param[in] fp the file to parse
+ * \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
+ * \param[in] fp the file to parse
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \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 */
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * frm_fp helper function. This function parses the
+ * remainder of the (HMAC-MD5) key file
+ * This function allocated a buffer that needs to be freed
+ * \param[in] fp the file to parse
+ * \param[out] hmac_size the number of bits in the resulting buffer
+ * \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
+ * This function allocated a buffer that needs to be freed
+ * \param[in] fp the file to parse
+ * \param[in] line_nr pointer to an integer containing the current line number (for error reporting purposes)
+ * \param[out] hmac_size the number of bits in the resulting buffer
+ * \return NULL on failure otherwise a newly allocated char buffer
+ */
+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 */
+/**
+ * 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
+ * \param[in] k the key
+ * \param[in] e the evp key
+ */
+void ldns_key_set_evp_key(ldns_key *k, EVP_PKEY *e);
+
+/**
+ * Set the key's rsa data
+ * \param[in] k the key
+ * \param[in] r the rsa data
+ */
+void ldns_key_set_rsa_key(ldns_key *k, RSA *r);
+/**
+ * Set the key's dsa data
+ * \param[in] k the key
+ * \param[in] d the dsa data
+ */
+void ldns_key_set_dsa_key(ldns_key *k, DSA *d);
+
+/**
+ * Get the PKEY id for GOST, loads GOST into openssl as a side effect.
+ * Only available if GOST is compiled into the library and openssl.
+ * \return the gost id for EVP_CTX creation.
+ */
+int ldns_key_EVP_load_gost_id(void);
+
+/** Release the engine reference held for the GOST engine. */
+void ldns_key_EVP_unload_gost(void);
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * Set the key's hmac data
+ * \param[in] k the key
+ * \param[in] hmac the raw key data
+ */
+void ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac);
+
+/**
+ * Set the key id data. This is used if the key points to
+ * some externally stored key data
+ *
+ * Only the pointer is set, the data there is not copied,
+ * and must be freed manually; ldns_key_deep_free() does
+ * *not* free this data
+ * \param[in] key the key
+ * \param[in] external_key key id data
+ */
+void ldns_key_set_external_key(ldns_key *key, void *external_key);
+
+/**
+ * Set the key's hmac size
+ * \param[in] k the key
+ * \param[in] hmac_size the size of the hmac data
+ */
+void ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size);
+/**
+ * Set the key's original ttl
+ * \param[in] k the key
+ * \param[in] t the ttl
+ */
+void ldns_key_set_origttl(ldns_key *k, uint32_t t);
+/**
+ * Set the key's inception date (seconds after epoch)
+ * \param[in] k the key
+ * \param[in] i the inception
+ */
+void ldns_key_set_inception(ldns_key *k, uint32_t i);
+/**
+ * Set the key's expiration date (seconds after epoch)
+ * \param[in] k the key
+ * \param[in] e the expiration
+ */
+void ldns_key_set_expiration(ldns_key *k, uint32_t e);
+/**
+ * Set the key's pubkey owner
+ * \param[in] k the key
+ * \param[in] r the owner
+ */
+void ldns_key_set_pubkey_owner(ldns_key *k, ldns_rdf *r);
+/**
+ * Set the key's key tag
+ * \param[in] k the key
+ * \param[in] tag the keytag
+ */
+void ldns_key_set_keytag(ldns_key *k, uint16_t tag);
+/**
+ * Set the key's flags
+ * \param[in] k the key
+ * \param[in] flags the flags
+ */
+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
+ */
+void ldns_key_list_set_key_count(ldns_key_list *key, size_t count);
+
+/**
+ * pushes a key to a keylist
+ * \param[in] key_list the key_list to push to
+ * \param[in] key the key to push
+ * \return false on error, otherwise true
+ */
+bool ldns_key_list_push_key(ldns_key_list *key_list, ldns_key *key);
+
+/**
+ * returns the number of keys in the key list
+ * \param[in] key_list the key_list
+ * \return the numbers of keys in the list
+ */
+size_t ldns_key_list_key_count(const ldns_key_list *key_list);
+
+/**
+ * returns a pointer to the key in the list at the given position
+ * \param[in] key the key
+ * \param[in] nr the position in the list
+ * \return the key
+ */
+ldns_key *ldns_key_list_key(const ldns_key_list *key, size_t nr);
+
+#if LDNS_BUILD_CONFIG_HAVE_SSL
+/**
+ * returns the (openssl) RSA struct contained in the key
+ * \param[in] k the key to look in
+ * \return the RSA * structure in the key
+ */
+RSA *ldns_key_rsa_key(const ldns_key *k);
+/**
+ * returns the (openssl) EVP struct contained in the key
+ * \param[in] k the key to look in
+ * \return the RSA * structure in the key
+ */
+EVP_PKEY *ldns_key_evp_key(const ldns_key *k);
+#endif /* LDNS_BUILD_CONFIG_HAVE_SSL */
+
+/**
+ * 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_HAVE_SSL */
+
+/**
+ * return the signing alg of the key
+ * \param[in] k the key
+ * \return the algorithm
+ */
+ldns_signing_algorithm ldns_key_algorithm(const ldns_key *k);
+/**
+ * set the use flag
+ * \param[in] k the key
+ * \param[in] v the boolean value to set the _use field to
+ */
+void ldns_key_set_use(ldns_key *k, bool v);
+/**
+ * return the use flag
+ * \param[in] k the key
+ * \return the boolean value of the _use field
+ */
+bool ldns_key_use(const ldns_key *k);
+/**
+ * return the hmac key data
+ * \param[in] k the key
+ * \return the hmac key data
+ */
+unsigned char *ldns_key_hmac_key(const ldns_key *k);
+/**
+ * return the key id key data
+ * \param[in] k the key
+ * \return the key id data
+ */
+void *ldns_key_external_key(const ldns_key *k);
+/**
+ * return the hmac key size
+ * \param[in] k the key
+ * \return the hmac key size
+ */
+size_t ldns_key_hmac_size(const ldns_key *k);
+/**
+ * return the original ttl of the key
+ * \param[in] k the key
+ * \return the original ttl
+ */
+uint32_t ldns_key_origttl(const ldns_key *k);
+/**
+ * return the key's inception date
+ * \param[in] k the key
+ * \return the inception date
+ */
+uint32_t ldns_key_inception(const ldns_key *k);
+/**
+ * return the key's expiration date
+ * \param[in] k the key
+ * \return the experiration date
+ */
+uint32_t ldns_key_expiration(const ldns_key *k);
+/**
+ * return the keytag
+ * \param[in] k the key
+ * \return the keytag
+ */
+uint16_t ldns_key_keytag(const ldns_key *k);
+/**
+ * return the public key's owner
+ * \param[in] k the key
+ * \return the owner
+ */
+ldns_rdf *ldns_key_pubkey_owner(const ldns_key *k);
+/**
+ * Set the 'use' flag for all keys in the list
+ * \param[in] keys The key_list
+ * \param[in] v The value to set the use flags to
+ */
+void
+ldns_key_list_set_use(ldns_key_list *keys, bool v);
+
+/**
+ * return the flag of the key
+ * \param[in] k the key
+ * \return the flag
+ */
+uint16_t ldns_key_flags(const ldns_key *k);
+
+/**
+ * pops the last rr from a keylist
+ * \param[in] key_list the rr_list to pop from
+ * \return NULL if nothing to pop. Otherwise the popped RR
+ */
+ldns_key *ldns_key_list_pop_key(ldns_key_list *key_list);
+
+/**
+ * converts a ldns_key to a public key rr
+ * If the key data exists at an external point, the corresponding
+ * rdata field must still be added with ldns_rr_rdf_push() to the
+ * result rr of this function
+ *
+ * \param[in] k the ldns_key to convert
+ * \return ldns_rr representation of the key
+ */
+ldns_rr *ldns_key2rr(const ldns_key *k);
+
+/**
+ * print a private key to the file ouput
+ *
+ * \param[in] output the FILE descriptor where to print to
+ * \param[in] k the ldns_key to print
+ */
+void ldns_key_print(FILE *output, const ldns_key *k);
+
+/**
+ * frees a key structure, but not its internal data structures
+ *
+ * \param[in] key the key object to free
+ */
+void ldns_key_free(ldns_key *key);
+
+/**
+ * frees a key structure and all its internal data structures, except
+ * the data set by ldns_key_set_external_key()
+ *
+ * \param[in] key the key object to free
+ */
+void ldns_key_deep_free(ldns_key *key);
+
+/**
+ * Frees a key list structure
+ * \param[in] key_list the key list object to free
+ */
+void ldns_key_list_free(ldns_key_list *key_list);
+
+/**
+ * Instantiates a DNSKEY or DS RR from file.
+ * \param[in] filename the file to read the record from
+ * \return the corresponding RR, or NULL if the parsing failed
+ */
+ldns_rr * ldns_read_anchor_file(const char *filename);
+
+/**
+ * Returns the 'default base name' for key files;
+ * IE. K\<zone\>+\<alg\>+\<keytag\>
+ * (without the .key or .private)
+ * The memory for this is allocated by this function,
+ * and should be freed by the caller
+ *
+ * \param[in] key the key to get the file name from
+ * \returns A string containing the file base name
+ */
+char *ldns_key_get_file_base_name(ldns_key *key);
+
+/**
+ * See if a key algorithm is supported
+ * \param[in] algo the signing algorithm number.
+ * \returns true if supported.
+ */
+int ldns_key_algo_supported(int algo);
+
+/**
+ * Get signing algorithm by name. Comparison is case insensitive.
+ * \param[in] name string with the name.
+ * \returns 0 on parse failure or the algorithm number.
+ */
+ldns_signing_algorithm ldns_get_signing_algorithm_by_name(const char* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_KEYS_H */
diff --git a/3rdParty/Ldns/src/include/ldns/ldns.h b/3rdParty/Ldns/src/include/ldns/ldns.h
new file mode 100644
index 0000000..6f57733
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/ldns.h
@@ -0,0 +1,155 @@
+/*
+ * dns.h -- defines for the Domain Name System
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ * This library was created by:
+ * Jelte Jansen, Erik Rozendaal and Miek Gieben
+ *
+ * A bunch of defines that are used in the DNS.
+ */
+
+
+/**
+\mainpage LDNS Documentation
+
+\section introduction Introduction
+
+The goal of ldns is to simplify DNS programming, it supports recent RFCs
+like the DNSSEC documents, and allow developers to easily create software
+conforming to current RFCs, and experimental software for current Internet
+drafts. A secondary benefit of using ldns is speed, because ldns is written
+in C, and although it is not optimized for performance, it should be a lot
+faster than Perl.
+
+The first main tool to use ldns is Drill, from which part of the library was
+derived. From version 1.0.0 on, drill is included in the ldns release
+and will not be distributed seperately anymore. The library also includes some
+other examples and tools to show how it can be used. These can be found in the
+examples/ directory in the tarball.
+
+ldns depends on OpenSSL for it's cryptographic functions.
+Feature list
+
+ - Transparent IPv4 and IPv6 support (overridable if necessary),
+ - TSIG support,
+ - DNSSEC support; signing and verification,
+ - small size,
+ - online documentation as well as manual pages.
+
+If you want to send us patches please use the code from subversion (trunk).
+
+\section using_ldns Using ldns
+
+Almost all interaction between an application and ldns goes through the ldns
+data structures (\ref ldns_rr, \ref ldns_pkt, etc.). These are input or
+output to the functions of ldns. For example, \ref ldns_zone_new_frm_fp
+reads a zone from a \c FILE pointer, and returns an \ref ldns_zone
+structure.
+
+
+Let's use Drill as an example. Drill is a tool much like dig, whose most
+basic function is to send 1 query to a nameserver and print the response.
+
+To be able to do this, drill uses the resolver module of ldns, which acts as
+a stub resolver. The resolver module uses the net module to actually send
+the query that drill requested. It then uses the wire2host module to
+translate the response and place it in ldns' internal structures. These are
+passed back to drill, which then uses the host2str module to print the
+response in presentation format.
+
+\section gettingstarted Getting Started
+
+See the \ref design page for a very high level description of the design
+choices made for ldns.
+
+For an overview of the functions and types ldns provides, you can check out
+the \ref ldns ldns header file descriptions.
+
+If you want to see some libdns action, you can read our tutorials:
+ - \ref tutorial1_mx
+ - \ref tutorial2_zone
+ - \ref tutorial3_signzone
+
+Or you can just use the menu above to browse through the API docs.
+
+<div style="visibility:hidden;">
+\image html LogoInGradientBar2-y100.png
+</div>
+*/
+
+/**
+ * \file ldns.h
+ *
+ * Including this file will include all ldns files, and define some lookup tables.
+ */
+
+#ifndef LDNS_DNS_H
+#define LDNS_DNS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <ldns/util.h>
+#include <ldns/buffer.h>
+#include <ldns/common.h>
+#include <ldns/dname.h>
+#include <ldns/dnssec.h>
+#include <ldns/dnssec_verify.h>
+#include <ldns/dnssec_sign.h>
+#include <ldns/error.h>
+#include <ldns/higher.h>
+#include <ldns/host2str.h>
+#include <ldns/host2wire.h>
+#include <ldns/net.h>
+#include <ldns/packet.h>
+#include <ldns/rdata.h>
+#include <ldns/resolver.h>
+#include <ldns/rr.h>
+#include <ldns/str2host.h>
+#include <ldns/tsig.h>
+#include <ldns/update.h>
+#include <ldns/wire2host.h>
+#include <ldns/rr_functions.h>
+#include <ldns/keys.h>
+#include <ldns/parse.h>
+#include <ldns/zone.h>
+#include <ldns/dnssec_zone.h>
+#include <ldns/rbtree.h>
+#include <ldns/sha1.h>
+#include <ldns/sha2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_IP4ADDRLEN (32/8)
+#define LDNS_IP6ADDRLEN (128/8)
+#define LDNS_PORT 53
+#define LDNS_ROOT_LABEL_STR "."
+#define LDNS_DEFAULT_TTL 3600
+
+/* lookup tables for standard DNS stuff */
+
+/** Taken from RFC 2538, section 2.1. */
+extern ldns_lookup_table ldns_certificate_types[];
+/** Taken from RFC 2535, section 7. */
+extern ldns_lookup_table ldns_algorithms[];
+/** Taken from RFC 2538. */
+extern ldns_lookup_table ldns_cert_algorithms[];
+/** rr types */
+extern ldns_lookup_table ldns_rr_classes[];
+/** Response codes */
+extern ldns_lookup_table ldns_rcodes[];
+/** Operation codes */
+extern ldns_lookup_table ldns_opcodes[];
+/** EDNS flags */
+extern ldns_lookup_table ldns_edns_flags[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_DNS_H */
diff --git a/3rdParty/Ldns/src/include/ldns/net.h b/3rdParty/Ldns/src/include/ldns/net.h
new file mode 100644
index 0000000..cd7bc4b
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/net.h
@@ -0,0 +1,208 @@
+/*
+ * net.h
+ *
+ * DNS Resolver definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_NET_H
+#define LDNS_NET_H
+
+#include <ldns/ldns.h>
+#include <sys/socket.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_DEFAULT_TIMEOUT_SEC 5
+#define LDNS_DEFAULT_TIMEOUT_USEC 0
+
+/**
+ * \file
+ *
+ * Contains functions to send and receive packets over a network.
+ */
+
+/**
+ * Sends a buffer to an ip using udp and return the respons 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
+ * \param[in] timeout the timeout value for the network
+ * \param[out] answersize size of the packet
+ * \param[out] result packet with the answer
+ * \return status
+ */
+ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize);
+
+/**
+ * Send an udp query and don't wait for an answer but return
+ * the socket
+ * \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
+ * \param[in] timeout *unused*, was the timeout value for the network
+ * \return the socket used
+ */
+
+int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
+
+/**
+ * Send an tcp query and don't wait for an answer but return
+ * the socket
+ * \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
+ * \param[in] timeout the timeout value for the connect attempt
+ * \return the socket used
+ */
+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
+ * \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
+ * \param[in] tolen length of the ip addr
+ * \param[in] timeout the timeout value for the network
+ * \param[out] answersize size of the packet
+ * \param[out] result packet with the answer
+ * \return status
+ */
+ldns_status ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize);
+
+/**
+ * Sends ptk to the nameserver at the resolver object. Returns the data
+ * as a ldns_pkt
+ *
+ * \param[out] pkt packet received from the nameserver
+ * \param[in] r the resolver to use
+ * \param[in] query_pkt the query to send
+ * \return status
+ */
+ldns_status ldns_send(ldns_pkt **pkt, ldns_resolver *r, const ldns_pkt *query_pkt);
+
+/**
+ * Sends and ldns_buffer (presumably containing a packet to the nameserver at the resolver object. Returns the data
+ * as a ldns_pkt
+ *
+ * \param[out] pkt packet received from the nameserver
+ * \param[in] r the resolver to use
+ * \param[in] qb the buffer to send
+ * \param[in] tsig_mac the tsig MAC to authenticate the response with (NULL to do no TSIG authentication)
+ * \return status
+ */
+ldns_status ldns_send_buffer(ldns_pkt **pkt, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac);
+
+/**
+ * Create a tcp socket to the specified address
+ * \param[in] to ip and family
+ * \param[in] tolen length of to
+ * \param[in] timeout timeout for the connect attempt
+ * \return a socket descriptor
+ */
+int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
+
+/**
+ * Create a udp socket to the specified address
+ * \param[in] to ip and family
+ * \param[in] timeout *unused*, was timeout for the socket
+ * \return a socket descriptor
+ */
+int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval timeout);
+
+/**
+ * send a query via tcp to a server. Don't want for the answer
+ *
+ * \param[in] qbin the buffer to send
+ * \param[in] sockfd the socket to use
+ * \param[in] to which ip to send it
+ * \param[in] tolen socketlen
+ * \return number of bytes sent
+ */
+ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen);
+
+/**
+ * send a query via udp to a server. Don;t want for the answer
+ *
+ * \param[in] qbin the buffer to send
+ * \param[in] sockfd the socket to use
+ * \param[in] to which ip to send it
+ * \param[in] tolen socketlen
+ * \return number of bytes sent
+ */
+ssize_t ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen);
+
+/**
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[out] size the number of bytes that are read
+ * \param[in] timeout the time allowed between packets.
+ * \return the data read
+ */
+uint8_t *ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout);
+
+/**
+ * This routine may block. Use ldns_tcp_read_wire_timeout, it checks timeouts.
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[out] size the number of bytes that are read
+ * \return the data read
+ */
+uint8_t *ldns_tcp_read_wire(int sockfd, size_t *size);
+
+/**
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[in] fr the address of the client (if applicable)
+ * \param[in] *frlen the lenght of the client's addr (if applicable)
+ * \param[out] size the number of bytes that are read
+ * \return the data read
+ */
+uint8_t *ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *fr, socklen_t *frlen);
+
+/**
+ * returns the native sockaddr representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \param[in] port what port to use. 0 means; use default (53)
+ * \param[out] size what is the size of the sockaddr_storage
+ * \return struct sockaddr* the address in the format so other
+ * functions can use it (sendto)
+ */
+struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size);
+
+/**
+ * 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
+ */
+ldns_rdf * ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port);
+
+/**
+ * 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] c the class to use
+ * \return ldns_status the status of the transfer
+ */
+ldns_status ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_NET_H */
diff --git a/3rdParty/Ldns/src/include/ldns/net.h.in b/3rdParty/Ldns/src/include/ldns/net.h.in
new file mode 100644
index 0000000..cd4cfde
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/net.h.in
@@ -0,0 +1,208 @@
+/*
+ * net.h
+ *
+ * DNS Resolver definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_NET_H
+#define LDNS_NET_H
+
+#include <ldns/ldns.h>
+@include_sys_socket_h@
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_DEFAULT_TIMEOUT_SEC 5
+#define LDNS_DEFAULT_TIMEOUT_USEC 0
+
+/**
+ * \file
+ *
+ * Contains functions to send and receive packets over a network.
+ */
+
+/**
+ * Sends a buffer to an ip using udp and return the respons 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
+ * \param[in] timeout the timeout value for the network
+ * \param[out] answersize size of the packet
+ * \param[out] result packet with the answer
+ * \return status
+ */
+ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize);
+
+/**
+ * Send an udp query and don't wait for an answer but return
+ * the socket
+ * \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
+ * \param[in] timeout *unused*, was the timeout value for the network
+ * \return the socket used
+ */
+
+int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
+
+/**
+ * Send an tcp query and don't wait for an answer but return
+ * the socket
+ * \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
+ * \param[in] timeout the timeout value for the connect attempt
+ * \return the socket used
+ */
+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
+ * \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
+ * \param[in] tolen length of the ip addr
+ * \param[in] timeout the timeout value for the network
+ * \param[out] answersize size of the packet
+ * \param[out] result packet with the answer
+ * \return status
+ */
+ldns_status ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize);
+
+/**
+ * Sends ptk to the nameserver at the resolver object. Returns the data
+ * as a ldns_pkt
+ *
+ * \param[out] pkt packet received from the nameserver
+ * \param[in] r the resolver to use
+ * \param[in] query_pkt the query to send
+ * \return status
+ */
+ldns_status ldns_send(ldns_pkt **pkt, ldns_resolver *r, const ldns_pkt *query_pkt);
+
+/**
+ * Sends and ldns_buffer (presumably containing a packet to the nameserver at the resolver object. Returns the data
+ * as a ldns_pkt
+ *
+ * \param[out] pkt packet received from the nameserver
+ * \param[in] r the resolver to use
+ * \param[in] qb the buffer to send
+ * \param[in] tsig_mac the tsig MAC to authenticate the response with (NULL to do no TSIG authentication)
+ * \return status
+ */
+ldns_status ldns_send_buffer(ldns_pkt **pkt, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac);
+
+/**
+ * Create a tcp socket to the specified address
+ * \param[in] to ip and family
+ * \param[in] tolen length of to
+ * \param[in] timeout timeout for the connect attempt
+ * \return a socket descriptor
+ */
+int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
+
+/**
+ * Create a udp socket to the specified address
+ * \param[in] to ip and family
+ * \param[in] timeout *unused*, was timeout for the socket
+ * \return a socket descriptor
+ */
+int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval timeout);
+
+/**
+ * send a query via tcp to a server. Don't want for the answer
+ *
+ * \param[in] qbin the buffer to send
+ * \param[in] sockfd the socket to use
+ * \param[in] to which ip to send it
+ * \param[in] tolen socketlen
+ * \return number of bytes sent
+ */
+ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen);
+
+/**
+ * send a query via udp to a server. Don;t want for the answer
+ *
+ * \param[in] qbin the buffer to send
+ * \param[in] sockfd the socket to use
+ * \param[in] to which ip to send it
+ * \param[in] tolen socketlen
+ * \return number of bytes sent
+ */
+ssize_t ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen);
+
+/**
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[out] size the number of bytes that are read
+ * \param[in] timeout the time allowed between packets.
+ * \return the data read
+ */
+uint8_t *ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout);
+
+/**
+ * This routine may block. Use ldns_tcp_read_wire_timeout, it checks timeouts.
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[out] size the number of bytes that are read
+ * \return the data read
+ */
+uint8_t *ldns_tcp_read_wire(int sockfd, size_t *size);
+
+/**
+ * Gives back a raw packet from the wire and reads the header data from the given
+ * socket. Allocates the data (of size size) itself, so don't forget to free
+ *
+ * \param[in] sockfd the socket to read from
+ * \param[in] fr the address of the client (if applicable)
+ * \param[in] *frlen the lenght of the client's addr (if applicable)
+ * \param[out] size the number of bytes that are read
+ * \return the data read
+ */
+uint8_t *ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *fr, socklen_t *frlen);
+
+/**
+ * returns the native sockaddr representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \param[in] port what port to use. 0 means; use default (53)
+ * \param[out] size what is the size of the sockaddr_storage
+ * \return struct sockaddr* the address in the format so other
+ * functions can use it (sendto)
+ */
+struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size);
+
+/**
+ * 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
+ */
+ldns_rdf * ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port);
+
+/**
+ * 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] c the class to use
+ * \return ldns_status the status of the transfer
+ */
+ldns_status ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_NET_H */
diff --git a/3rdParty/Ldns/src/include/ldns/packet.h b/3rdParty/Ldns/src/include/ldns/packet.h
new file mode 100644
index 0000000..687a6a2
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/packet.h
@@ -0,0 +1,855 @@
+/*
+ * packet.h
+ *
+ * DNS packet definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains the definition of ldns_pkt and its parts, as well
+ * as functions to manipulate those.
+ */
+
+
+#ifndef LDNS_PACKET_H
+#define LDNS_PACKET_H
+
+#define LDNS_MAX_PACKETLEN 65535
+
+/* allow flags to be given to mk_query */
+#define LDNS_QR 1 /* QueRy - query flag */
+#define LDNS_AA 2 /* Authoritative Answer - server flag */
+#define LDNS_TC 4 /* TrunCated - server flag */
+#define LDNS_RD 8 /* Recursion Desired - query flag */
+#define LDNS_CD 16 /* Checking Disabled - query flag */
+#define LDNS_RA 32 /* Recursion Available - server flag */
+#define LDNS_AD 64 /* Authenticated Data - server flag */
+
+#include <ldns/error.h>
+#include <ldns/common.h>
+#include <ldns/rr.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* opcodes for pkt's */
+enum ldns_enum_pkt_opcode {
+ LDNS_PACKET_QUERY = 0,
+ LDNS_PACKET_IQUERY = 1,
+ LDNS_PACKET_STATUS = 2, /* there is no 3?? DNS is weird */
+ LDNS_PACKET_NOTIFY = 4,
+ LDNS_PACKET_UPDATE = 5
+};
+typedef enum ldns_enum_pkt_opcode ldns_pkt_opcode;
+
+/* rcodes for pkts */
+enum ldns_enum_pkt_rcode {
+ LDNS_RCODE_NOERROR = 0,
+ LDNS_RCODE_FORMERR = 1,
+ LDNS_RCODE_SERVFAIL = 2,
+ LDNS_RCODE_NXDOMAIN = 3,
+ LDNS_RCODE_NOTIMPL = 4,
+ LDNS_RCODE_REFUSED = 5,
+ LDNS_RCODE_YXDOMAIN = 6,
+ LDNS_RCODE_YXRRSET = 7,
+ LDNS_RCODE_NXRRSET = 8,
+ LDNS_RCODE_NOTAUTH = 9,
+ LDNS_RCODE_NOTZONE = 10
+};
+typedef enum ldns_enum_pkt_rcode ldns_pkt_rcode;
+
+/**
+ * Header of a dns packet
+ *
+ * Contains the information about the packet itself, as specified in RFC1035
+<pre>
+4.1.1. Header section format
+
+The header contains the following fields:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID A 16 bit identifier assigned by the program that
+ generates any kind of query. This identifier is copied
+ the corresponding reply and can be used by the requester
+ to match up replies to outstanding queries.
+
+QR A one bit field that specifies whether this message is a
+ query (0), or a response (1).
+
+OPCODE A four bit field that specifies kind of query in this
+ message. This value is set by the originator of a query
+ and copied into the response. The values are:
+
+ 0 a standard query (QUERY)
+
+ 1 an inverse query (IQUERY)
+
+ 2 a server status request (STATUS)
+
+ 3-15 reserved for future use
+
+AA Authoritative Answer - this bit is valid in responses,
+ and specifies that the responding name server is an
+ authority for the domain name in question section.
+
+ Note that the contents of the answer section may have
+ multiple owner names because of aliases. The AA bit
+
+ corresponds to the name which matches the query name, or
+ the first owner name in the answer section.
+
+TC TrunCation - specifies that this message was truncated
+ due to length greater than that permitted on the
+ transmission channel.
+
+RD Recursion Desired - this bit may be set in a query and
+ is copied into the response. If RD is set, it directs
+ the name server to pursue the query recursively.
+ Recursive query support is optional.
+
+RA Recursion Available - this be is set or cleared in a
+ response, and denotes whether recursive query support is
+ available in the name server.
+
+Z Reserved for future use. Must be zero in all queries
+ and responses.
+
+RCODE Response code - this 4 bit field is set as part of
+ responses. The values have the following
+ interpretation:
+
+ 0 No error condition
+
+ 1 Format error - The name server was
+ unable to interpret the query.
+
+ 2 Server failure - The name server was
+ unable to process this query due to a
+ problem with the name server.
+
+ 3 Name Error - Meaningful only for
+ responses from an authoritative name
+ server, this code signifies that the
+ domain name referenced in the query does
+ not exist.
+
+ 4 Not Implemented - The name server does
+ not support the requested kind of query.
+
+ 5 Refused - The name server refuses to
+ perform the specified operation for
+ policy reasons. For example, a name
+ server may not wish to provide the
+ information to the particular requester,
+ or a name server may not wish to perform
+ a particular operation (e.g., zone
+
+ transfer) for particular data.
+
+ 6-15 Reserved for future use.
+
+QDCOUNT an unsigned 16 bit integer specifying the number of
+ entries in the question section.
+
+ANCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the answer section.
+
+NSCOUNT an unsigned 16 bit integer specifying the number of name
+ server resource records in the authority records
+ section.
+
+ARCOUNT an unsigned 16 bit integer specifying the number of
+ resource records in the additional records section.
+
+</pre>
+ */
+struct ldns_struct_hdr
+{
+ /** Id of a packet */
+ uint16_t _id;
+ /** Query bit (0=query, 1=answer) */
+ bool _qr;
+ /** Authoritative answer */
+ bool _aa;
+ /** Packet truncated */
+ bool _tc;
+ /** Recursion desired */
+ bool _rd;
+ /** Checking disabled */
+ bool _cd;
+ /** Recursion available */
+ bool _ra;
+ /** Authentic data */
+ bool _ad;
+ /** Query type */
+ ldns_pkt_opcode _opcode; /* XXX 8 bits? */
+ /** Response code */
+ uint8_t _rcode;
+ /** question sec */
+ uint16_t _qdcount;
+ /** answer sec */
+ uint16_t _ancount;
+ /** auth sec */
+ uint16_t _nscount;
+ /** add sec */
+ uint16_t _arcount;
+};
+typedef struct ldns_struct_hdr ldns_hdr;
+
+/**
+ * DNS packet
+ *
+ * This structure contains a complete DNS packet (either a query or an answer)
+ *
+ * It is the complete representation of what you actually send to a
+ * nameserver, and what it sends back (assuming you are the client here).
+ */
+struct ldns_struct_pkt
+{
+ /** Header section */
+ ldns_hdr *_header;
+ /* extra items needed in a packet */
+ /** The size of the wire format of the packet in octets */
+ ldns_rdf *_answerfrom;
+ /** Timestamp of the time the packet was sent or created */
+ struct timeval timestamp;
+ /** The duration of the query this packet is an answer to */
+ uint32_t _querytime;
+ /** The size of the wire format of the packet in octets */
+ size_t _size;
+ /** Optional tsig rr */
+ ldns_rr *_tsig_rr;
+ /** EDNS0 available buffer size, see RFC2671 */
+ uint16_t _edns_udp_size;
+ /** EDNS0 Extended rcode */
+ uint8_t _edns_extended_rcode;
+ /** EDNS Version */
+ uint8_t _edns_version;
+ /** Reserved EDNS data bits */
+ uint16_t _edns_z;
+ /** Arbitrary EDNS rdata */
+ ldns_rdf *_edns_data;
+ /** Question section */
+ ldns_rr_list *_question;
+ /** Answer section */
+ ldns_rr_list *_answer;
+ /** Authority section */
+ ldns_rr_list *_authority;
+ /** Additional section */
+ ldns_rr_list *_additional;
+};
+typedef struct ldns_struct_pkt ldns_pkt;
+
+/**
+ * The sections of a packet
+ */
+enum ldns_enum_pkt_section {
+ LDNS_SECTION_QUESTION = 0,
+ LDNS_SECTION_ANSWER = 1,
+ LDNS_SECTION_AUTHORITY = 2,
+ LDNS_SECTION_ADDITIONAL = 3,
+ /** bogus section, if not interested */
+ LDNS_SECTION_ANY = 4,
+ /** used to get all non-question rrs from a packet */
+ LDNS_SECTION_ANY_NOQUESTION = 5
+};
+typedef enum ldns_enum_pkt_section ldns_pkt_section;
+
+/**
+ * The different types of packets
+ */
+enum ldns_enum_pkt_type {
+ LDNS_PACKET_QUESTION,
+ LDNS_PACKET_REFERRAL,
+ LDNS_PACKET_ANSWER,
+ LDNS_PACKET_NXDOMAIN,
+ LDNS_PACKET_NODATA,
+ LDNS_PACKET_UNKNOWN
+};
+typedef enum ldns_enum_pkt_type ldns_pkt_type;
+
+/* prototypes */
+
+/* read */
+
+/**
+ * Read the packet id
+ * \param[in] p the packet
+ * \return the packet id
+ */
+uint16_t ldns_pkt_id(const ldns_pkt *p);
+/**
+ * Read the packet's qr bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_qr(const ldns_pkt *p);
+/**
+ * Read the packet's aa bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_aa(const ldns_pkt *p);
+/**
+ * Read the packet's tc bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_tc(const ldns_pkt *p);
+/**
+ * Read the packet's rd bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_rd(const ldns_pkt *p);
+/**
+ * Read the packet's cd bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_cd(const ldns_pkt *p);
+/**
+ * Read the packet's ra bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_ra(const ldns_pkt *p);
+/**
+ * Read the packet's ad bit
+ * \param[in] p the packet
+ * \return value of the bit
+ */
+bool ldns_pkt_ad(const ldns_pkt *p);
+/**
+ * Read the packet's code
+ * \param[in] p the packet
+ * \return the opcode
+ */
+ldns_pkt_opcode ldns_pkt_get_opcode(const ldns_pkt *p);
+/**
+ * Return the packet's respons code
+ * \param[in] p the packet
+ * \return the respons code
+ */
+ldns_pkt_rcode ldns_pkt_get_rcode(const ldns_pkt *p);
+/**
+ * Return the packet's qd count
+ * \param[in] p the packet
+ * \return the qd count
+ */
+uint16_t ldns_pkt_qdcount(const ldns_pkt *p);
+/**
+ * Return the packet's an count
+ * \param[in] p the packet
+ * \return the an count
+ */
+uint16_t ldns_pkt_ancount(const ldns_pkt *p);
+/**
+ * Return the packet's ns count
+ * \param[in] p the packet
+ * \return the ns count
+ */
+uint16_t ldns_pkt_nscount(const ldns_pkt *p);
+/**
+ * Return the packet's ar count
+ * \param[in] p the packet
+ * \return the ar count
+ */
+uint16_t ldns_pkt_arcount(const ldns_pkt *p);
+
+/**
+ * Return the packet's answerfrom
+ * \param[in] p packet
+ * \return the name of the server
+ */
+ldns_rdf *ldns_pkt_answerfrom(const ldns_pkt *p);
+
+/**
+ * Return the packet's timestamp
+ * \param[in] p the packet
+ * \return the timestamp
+ */
+struct timeval ldns_pkt_timestamp(const ldns_pkt *p);
+/**
+ * Return the packet's querytime
+ * \param[in] p the packet
+ * \return the querytime
+ */
+uint32_t ldns_pkt_querytime(const ldns_pkt *p);
+
+/**
+ * Return the packet's size in bytes
+ * \param[in] p the packet
+ * \return the size
+ */
+size_t ldns_pkt_size(const ldns_pkt *p);
+
+/**
+ * Return the packet's tsig pseudo rr's
+ * \param[in] p the packet
+ * \return the tsig rr
+ */
+ldns_rr *ldns_pkt_tsig(const ldns_pkt *p);
+
+/**
+ * Return the packet's question section
+ * \param[in] p the packet
+ * \return the section
+ */
+ldns_rr_list *ldns_pkt_question(const ldns_pkt *p);
+/**
+ * Return the packet's answer section
+ * \param[in] p the packet
+ * \return the section
+ */
+ldns_rr_list *ldns_pkt_answer(const ldns_pkt *p);
+/**
+ * Return the packet's authority section
+ * \param[in] p the packet
+ * \return the section
+ */
+ldns_rr_list *ldns_pkt_authority(const ldns_pkt *p);
+/**
+ * Return the packet's additional section
+ * \param[in] p the packet
+ * \return the section
+ */
+ldns_rr_list *ldns_pkt_additional(const ldns_pkt *p);
+/**
+ * Return the packet's question, answer, authority and additional sections
+ * concatenated, in a new rr_list clone.
+ * \param[in] p the packet
+ * \return the rrs
+ */
+ldns_rr_list *ldns_pkt_all(const ldns_pkt *p);
+/**
+ * Return the packet's answer, authority and additional sections concatenated,
+ * in a new rr_list clone. Like ldns_pkt_all but without the questions.
+ * \param[in] p the packet
+ * \return the rrs except the question rrs
+ */
+ldns_rr_list *ldns_pkt_all_noquestion(const ldns_pkt *p);
+
+/**
+ * return all the rr_list's in the packet. Clone the lists, instead
+ * of returning pointers.
+ * \param[in] p the packet to look in
+ * \param[in] s what section(s) to return
+ * \return ldns_rr_list with the rr's or NULL if none were found
+ */
+ldns_rr_list *ldns_pkt_get_section_clone(const ldns_pkt *p, ldns_pkt_section s);
+
+/**
+ * return all the rr with a specific name from a packet. Optionally
+ * specify from which section in the packet
+ * \param[in] p the packet
+ * \param[in] r the name
+ * \param[in] s the packet's section
+ * \return a list with the rr's or NULL if none were found
+ */
+ldns_rr_list *ldns_pkt_rr_list_by_name(ldns_pkt *p, ldns_rdf *r, ldns_pkt_section s);
+/**
+ * return all the rr with a specific type from a packet. Optionally
+ * specify from which section in the packet
+ * \param[in] p the packet
+ * \param[in] t the type
+ * \param[in] s the packet's section
+ * \return a list with the rr's or NULL if none were found
+ */
+ldns_rr_list *ldns_pkt_rr_list_by_type(const ldns_pkt *p, ldns_rr_type t, ldns_pkt_section s);
+/**
+ * return all the rr with a specific type and type from a packet. Optionally
+ * specify from which section in the packet
+ * \param[in] packet the packet
+ * \param[in] ownername the name
+ * \param[in] type the type
+ * \param[in] sec the packet's section
+ * \return a list with the rr's or NULL if none were found
+ */
+ldns_rr_list *ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, const ldns_rdf *ownername, ldns_rr_type type, ldns_pkt_section sec);
+
+
+/**
+ * check to see if an rr exist in the packet
+ * \param[in] pkt the packet to examine
+ * \param[in] sec in which section to look
+ * \param[in] rr the rr to look for
+ */
+bool ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr);
+
+
+/**
+ * sets the flags in a packet.
+ * \param[in] pkt the packet to operate on
+ * \param[in] flags ORed values: LDNS_QR| LDNS_AR for instance
+ * \return true on success otherwise false
+ */
+bool ldns_pkt_set_flags(ldns_pkt *pkt, uint16_t flags);
+
+/**
+ * Set the packet's id
+ * \param[in] p the packet
+ * \param[in] id the id to set
+ */
+void ldns_pkt_set_id(ldns_pkt *p, uint16_t id);
+/**
+ * Set the packet's id to a random value
+ * \param[in] p the packet
+ */
+void ldns_pkt_set_random_id(ldns_pkt *p);
+/**
+ * Set the packet's qr bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_qr(ldns_pkt *p, bool b);
+/**
+ * Set the packet's aa bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_aa(ldns_pkt *p, bool b);
+/**
+ * Set the packet's tc bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_tc(ldns_pkt *p, bool b);
+/**
+ * Set the packet's rd bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_rd(ldns_pkt *p, bool b);
+/**
+ * Set the packet's cd bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_cd(ldns_pkt *p, bool b);
+/**
+ * Set the packet's ra bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_ra(ldns_pkt *p, bool b);
+/**
+ * Set the packet's ad bit
+ * \param[in] p the packet
+ * \param[in] b the value to set (boolean)
+ */
+void ldns_pkt_set_ad(ldns_pkt *p, bool b);
+
+/**
+ * Set the packet's opcode
+ * \param[in] p the packet
+ * \param[in] c the opcode
+ */
+void ldns_pkt_set_opcode(ldns_pkt *p, ldns_pkt_opcode c);
+/**
+ * Set the packet's respons code
+ * \param[in] p the packet
+ * \param[in] c the rcode
+ */
+void ldns_pkt_set_rcode(ldns_pkt *p, uint8_t c);
+/**
+ * Set the packet's qd count
+ * \param[in] p the packet
+ * \param[in] c the count
+ */
+void ldns_pkt_set_qdcount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the packet's an count
+ * \param[in] p the packet
+ * \param[in] c the count
+ */
+void ldns_pkt_set_ancount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the packet's ns count
+ * \param[in] p the packet
+ * \param[in] c the count
+ */
+void ldns_pkt_set_nscount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the packet's arcount
+ * \param[in] p the packet
+ * \param[in] c the count
+ */
+void ldns_pkt_set_arcount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the packet's answering server
+ * \param[in] p the packet
+ * \param[in] r the address
+ */
+void ldns_pkt_set_answerfrom(ldns_pkt *p, ldns_rdf *r);
+/**
+ * Set the packet's query time
+ * \param[in] p the packet
+ * \param[in] t the querytime in msec
+ */
+void ldns_pkt_set_querytime(ldns_pkt *p, uint32_t t);
+/**
+ * Set the packet's size
+ * \param[in] p the packet
+ * \param[in] s the size
+ */
+void ldns_pkt_set_size(ldns_pkt *p, size_t s);
+
+/**
+ * Set the packet's timestamp
+ * \param[in] p the packet
+ * \param[in] timeval the timestamp
+ */
+void ldns_pkt_set_timestamp(ldns_pkt *p, struct timeval timeval);
+/**
+ * Set a packet's section count to x
+ * \param[in] p the packet
+ * \param[in] s the section
+ * \param[in] x the section count
+ */
+void ldns_pkt_set_section_count(ldns_pkt *p, ldns_pkt_section s, uint16_t x);
+/**
+ * Set the packet's tsig rr
+ * \param[in] p the packet
+ * \param[in] t the tsig rr
+ */
+void ldns_pkt_set_tsig(ldns_pkt *p, ldns_rr *t);
+
+/**
+ * looks inside the packet to determine
+ * what kind of packet it is, AUTH, NXDOMAIN, REFERRAL, etc.
+ * \param[in] p the packet to examine
+ * \return the type of packet
+ */
+ldns_pkt_type ldns_pkt_reply_type(ldns_pkt *p);
+
+/**
+ * return the packet's edns udp size
+ * \param[in] packet the packet
+ * \return the size
+ */
+uint16_t ldns_pkt_edns_udp_size(const ldns_pkt *packet);
+/**
+ * return the packet's edns extended rcode
+ * \param[in] packet the packet
+ * \return the rcode
+ */
+uint8_t ldns_pkt_edns_extended_rcode(const ldns_pkt *packet);
+/**
+ * return the packet's edns version
+ * \param[in] packet the packet
+ * \return the version
+ */
+uint8_t ldns_pkt_edns_version(const ldns_pkt *packet);
+/**
+ * return the packet's edns z value
+ * \param[in] packet the packet
+ * \return the z value
+ */
+uint16_t ldns_pkt_edns_z(const ldns_pkt *packet);
+/**
+ * return the packet's edns data
+ * \param[in] packet the packet
+ * \return the data
+ */
+ldns_rdf *ldns_pkt_edns_data(const ldns_pkt *packet);
+
+/**
+ * return the packet's edns do bit
+ * \param[in] packet the packet
+ * \return the bit's value
+ */
+bool ldns_pkt_edns_do(const ldns_pkt *packet);
+/**
+ * Set the packet's edns do bit
+ * \param[in] packet the packet
+ * \param[in] value the bit's new value
+ */
+void ldns_pkt_set_edns_do(ldns_pkt *packet, bool value);
+
+/**
+ * returns true if this packet needs and EDNS rr to be sent.
+ * At the moment the only reason is an expected packet
+ * size larger than 512 bytes, but for instance dnssec would
+ * be a good reason too.
+ *
+ * \param[in] packet the packet to check
+ * \return true if packet needs edns rr
+ */
+bool ldns_pkt_edns(const ldns_pkt *packet);
+
+/**
+ * Set the packet's edns udp size
+ * \param[in] packet the packet
+ * \param[in] s the size
+ */
+void ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s);
+/**
+ * Set the packet's edns extended rcode
+ * \param[in] packet the packet
+ * \param[in] c the code
+ */
+void ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c);
+/**
+ * Set the packet's edns version
+ * \param[in] packet the packet
+ * \param[in] v the version
+ */
+void ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v);
+/**
+ * Set the packet's edns z value
+ * \param[in] packet the packet
+ * \param[in] z the value
+ */
+void ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z);
+/**
+ * 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);
+
+/**
+ * allocates and initializes a ldns_pkt structure.
+ * \return pointer to the new packet
+ */
+ldns_pkt *ldns_pkt_new();
+
+/**
+ * frees the packet structure and all data that it contains.
+ * \param[in] packet The packet structure to free
+ * \return void
+ */
+void ldns_pkt_free(ldns_pkt *packet);
+
+/**
+ * creates a query packet for the given name, type, class.
+ * \param[out] p the packet to be returned
+ * \param[in] rr_name the name to query for (as string)
+ * \param[in] rr_type the type to query for
+ * \param[in] rr_class the class to query for
+ * \param[in] flags packet flags
+ * \return LDNS_STATUS_OK or a ldns_status mesg with the error
+ */
+ldns_status ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class , uint16_t flags);
+
+/**
+ * creates a packet with a query in it for the given name, type and class.
+ * \param[in] rr_name the name to query for
+ * \param[in] rr_type the type to query for
+ * \param[in] rr_class the class to query for
+ * \param[in] flags packet flags
+ * \return ldns_pkt* a pointer to the new pkt
+ */
+ldns_pkt *ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags);
+
+/**
+ * clones the given packet, creating a fully allocated copy
+ *
+ * \param[in] pkt the packet to clone
+ * \return ldns_pkt* pointer to the new packet
+ */
+ldns_pkt *ldns_pkt_clone(ldns_pkt *pkt);
+
+/**
+ * directly set the additional section
+ * \param[in] p packet to operate on
+ * \param[in] rr rrlist to set
+ */
+void ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr);
+
+/**
+ * directly set the answer section
+ * \param[in] p packet to operate on
+ * \param[in] rr rrlist to set
+ */
+void ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr);
+
+/**
+ * directly set the question section
+ * \param[in] p packet to operate on
+ * \param[in] rr rrlist to set
+ */
+void ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr);
+
+/**
+ * directly set the auhority section
+ * \param[in] p packet to operate on
+ * \param[in] rr rrlist to set
+ */
+void ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr);
+
+/**
+ * push an rr on a packet
+ * \param[in] packet packet to operate on
+ * \param[in] section where to put it
+ * \param[in] rr rr to push
+ * \return a boolean which is true when the rr was added
+ */
+bool ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr);
+
+/**
+ * push an rr on a packet, provided the RR is not there.
+ * \param[in] pkt packet to operate on
+ * \param[in] sec where to put it
+ * \param[in] rr rr to push
+ * \return a boolean which is true when the rr was added
+ */
+bool ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr);
+
+/**
+ * push a rr_list on a packet
+ * \param[in] packet packet to operate on
+ * \param[in] section where to put it
+ * \param[in] list the rr_list to push
+ * \return a boolean which is true when the rr was added
+ */
+bool ldns_pkt_push_rr_list(ldns_pkt *packet, ldns_pkt_section section, ldns_rr_list *list);
+
+/**
+ * push an rr_list to a packet, provided the RRs are not already there.
+ * \param[in] pkt packet to operate on
+ * \param[in] sec where to put it
+ * \param[in] list the rr_list to push
+ * \return a boolean which is true when the rr was added
+ */
+bool ldns_pkt_safe_push_rr_list(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr_list *list);
+
+/**
+ * check if a packet is empty
+ * \param[in] p packet
+ * \return true: empty, false: not empty
+ */
+bool ldns_pkt_empty(ldns_pkt *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PACKET_H */
diff --git a/3rdParty/Ldns/src/include/ldns/parse.h b/3rdParty/Ldns/src/include/ldns/parse.h
new file mode 100644
index 0000000..0e9034c
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/parse.h
@@ -0,0 +1,167 @@
+/*
+ * parse.h
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_PARSE_H
+#define LDNS_PARSE_H
+
+#include <ldns/common.h>
+#include <ldns/buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_PARSE_SKIP_SPACE "\f\n\r\v"
+#define LDNS_PARSE_NORMAL " \f\n\r\t\v"
+#define LDNS_PARSE_NO_NL " \t"
+#define LDNS_MAX_LINELEN 10230
+#define LDNS_MAX_KEYWORDLEN 32
+
+
+/**
+ * \file
+ *
+ * Contains some low-level parsing functions, mostly used in the _frm_str
+ * family of functions.
+ */
+
+/**
+ * different type of directives in zone files
+ * We now deal with $TTL, $ORIGIN and $INCLUDE.
+ * The latter is not implemented in ldns (yet)
+ */
+enum ldns_enum_directive
+{
+ LDNS_DIR_TTL,
+ LDNS_DIR_ORIGIN,
+ LDNS_DIR_INCLUDE
+};
+typedef enum ldns_enum_directive ldns_directive;
+
+/**
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores them when encountered
+ * \param[in] *f the file to read from
+ * \param[out] *token the read token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \return 0 on error of EOF of the stream F. Otherwise return the length of what is read
+ */
+ssize_t ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit);
+
+/**
+ * returns a token/char from the stream F.
+ * This function deals with ( and ) in the stream,
+ * and ignores when it finds them.
+ * \param[in] *f the file to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 use builtin maximum
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return 0 on error of EOF of F otherwise return the length of what is read
+ */
+ssize_t ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr);
+
+/**
+ * returns a token/char from the buffer b.
+ * This function deals with ( and ) in the buffer,
+ * and ignores when it finds them.
+ * \param[in] *b the buffer to read from
+ * \param[out] *token the token is put here
+ * \param[in] *delim chars at which the parsing should stop
+ * \param[in] *limit how much to read. If 0 the builtin maximum is used
+ * \returns 0 on error of EOF of b. Otherwise return the length of what is read
+ */
+ssize_t ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit);
+
+/*
+ * searches for keyword and delim in a file. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/*
+ * searches for keyword and delim. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] f file pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \param[in] line_nr pointer to an integer containing the current line number (for
+debugging purposes)
+ * \return the number of character read
+ */
+ssize_t ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit, int *line_nr);
+
+/*
+ * searches for keyword and delim in a buffer. Gives everything back
+ * after the keyword + k_del until we hit d_del
+ * \param[in] b buffer pointer to read from
+ * \param[in] keyword keyword to look for
+ * \param[in] k_del keyword delimeter
+ * \param[out] data the data found
+ * \param[in] d_del the data delimeter
+ * \param[in] data_limit maximum size the the data buffer
+ * \return the number of character read
+ */
+ssize_t ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
+
+/**
+ * returns the next character from a buffer. Advances the position pointer with 1.
+ * When end of buffer is reached returns EOF. This is the buffer's equivalent
+ * for getc().
+ * \param[in] *buffer buffer to read from
+ * \return EOF on failure otherwise return the character
+ */
+int ldns_bgetc(ldns_buffer *buffer);
+
+/**
+ * skips all of the characters in the given string in the buffer, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *buffer buffer to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void ldns_bskipcs(ldns_buffer *buffer, const char *s);
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \return void
+ */
+void ldns_fskipcs(FILE *fp, const char *s);
+
+
+/**
+ * skips all of the characters in the given string in the fp, moving
+ * the position to the first character that is not in *s.
+ * \param[in] *fp file to use
+ * \param[in] *s characters to skip
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return void
+ */
+void ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_PARSE_H */
diff --git a/3rdParty/Ldns/src/include/ldns/rbtree.h b/3rdParty/Ldns/src/include/ldns/rbtree.h
new file mode 100644
index 0000000..98bd880
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/rbtree.h
@@ -0,0 +1,230 @@
+/*
+ * rbtree.h -- generic red-black tree
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * \file
+ * Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
+ * in unbound (memory allocation, logging and so on).
+ */
+
+#ifndef LDNS_RBTREE_H_
+#define LDNS_RBTREE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This structure must be the first member of the data structure in
+ * the rbtree. This allows easy casting between an rbnode_t and the
+ * user data (poor man's inheritance).
+ * Or you can use the data pointer member to get to your data item.
+ */
+typedef struct ldns_rbnode_t ldns_rbnode_t;
+/**
+ * The rbnode_t struct definition.
+ */
+struct ldns_rbnode_t {
+ /** parent in rbtree, RBTREE_NULL for root */
+ ldns_rbnode_t *parent;
+ /** left node (smaller items) */
+ ldns_rbnode_t *left;
+ /** right node (larger items) */
+ ldns_rbnode_t *right;
+ /** pointer to sorting key */
+ const void *key;
+ /** pointer to data */
+ const void *data;
+ /** colour of this node */
+ uint8_t color;
+};
+
+/** The nullpointer, points to empty node */
+#define LDNS_RBTREE_NULL &ldns_rbtree_null_node
+/** the global empty node */
+extern ldns_rbnode_t ldns_rbtree_null_node;
+
+/** An entire red black tree */
+typedef struct ldns_rbtree_t ldns_rbtree_t;
+/** definition for tree struct */
+struct ldns_rbtree_t {
+ /** The root of the red-black tree */
+ ldns_rbnode_t *root;
+
+ /** The number of the nodes in the tree */
+ size_t count;
+
+ /**
+ * Key compare function. <0,0,>0 like strcmp.
+ * Return 0 on two NULL ptrs.
+ */
+ int (*cmp) (const void *, const void *);
+};
+
+/**
+ * Create new tree (malloced) with given key compare function.
+ * @param cmpf: compare function (like strcmp) takes pointers to two keys.
+ * @return: new tree, empty.
+ */
+ldns_rbtree_t *ldns_rbtree_create(int (*cmpf)(const void *, const void *));
+
+/**
+ * Free the complete tree (but not its keys)
+ * @param rbtree The tree to free
+ */
+void ldns_rbtree_free(ldns_rbtree_t *rbtree);
+
+/**
+ * Init a new tree (malloced by caller) with given key compare function.
+ * @param rbtree: uninitialised memory for new tree, returned empty.
+ * @param cmpf: compare function (like strcmp) takes pointers to two keys.
+ */
+void ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *));
+
+/**
+ * Insert data into the tree.
+ * @param rbtree: tree to insert to.
+ * @param data: element to insert.
+ * @return: data ptr or NULL if key already present.
+ */
+ldns_rbnode_t *ldns_rbtree_insert(ldns_rbtree_t *rbtree, ldns_rbnode_t *data);
+
+/**
+ * Insert data into the tree (reversed arguments, for use as callback)
+ * \param[in] data element to insert
+ * \param[out] rbtree tree to insert in to
+ * \return data ptr or NULL if key is already present
+ */
+void ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree);
+
+/**
+ * Delete element from tree.
+ * @param rbtree: tree to delete from.
+ * @param key: key of item to delete.
+ * @return: node that is now unlinked from the tree. User to delete it.
+ * returns 0 if node not present
+ */
+ldns_rbnode_t *ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key);
+
+/**
+ * Find key in tree. Returns NULL if not found.
+ * @param rbtree: tree to find in.
+ * @param key: key that must match.
+ * @return: node that fits or NULL.
+ */
+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
+ * 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.
+ */
+int ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key,
+ ldns_rbnode_t **result);
+
+/**
+ * Returns first (smallest) node in the tree
+ * @param rbtree: tree
+ * @return: smallest element or NULL if tree empty.
+ */
+ldns_rbnode_t *ldns_rbtree_first(ldns_rbtree_t *rbtree);
+
+/**
+ * Returns last (largest) node in the tree
+ * @param rbtree: tree
+ * @return: largest element or NULL if tree empty.
+ */
+ldns_rbnode_t *ldns_rbtree_last(ldns_rbtree_t *rbtree);
+
+/**
+ * Returns next larger node in the tree
+ * @param rbtree: tree
+ * @return: next larger element or NULL if no larger in tree.
+ */
+ldns_rbnode_t *ldns_rbtree_next(ldns_rbnode_t *rbtree);
+
+/**
+ * Returns previous smaller node in the tree
+ * @param rbtree: tree
+ * @return: previous smaller element or NULL if no previous in tree.
+ */
+ldns_rbnode_t *ldns_rbtree_previous(ldns_rbnode_t *rbtree);
+
+/**
+ * split off 'elements' number of elements from the start
+ * of the name tree and return a new tree containing those
+ * elements
+ */
+ldns_rbtree_t *ldns_rbtree_split(ldns_rbtree_t *tree, size_t elements);
+
+/**
+ * add all node from the second tree to the first (removing them from the
+ * second), and fix up nsec(3)s if present
+ */
+void ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2);
+
+/**
+ * Call with node=variable of struct* with rbnode_t as first element.
+ * with type is the type of a pointer to that struct.
+ */
+#define LDNS_RBTREE_FOR(node, type, rbtree) \
+ for(node=(type)ldns_rbtree_first(rbtree); \
+ (ldns_rbnode_t*)node != LDNS_RBTREE_NULL; \
+ node = (type)ldns_rbtree_next((ldns_rbnode_t*)node))
+
+/**
+ * Call function for all elements in the redblack tree, such that
+ * leaf elements are called before parent elements. So that all
+ * elements can be safely free()d.
+ * Note that your function must not remove the nodes from the tree.
+ * Since that may trigger rebalances of the rbtree.
+ * @param tree: the tree
+ * @param func: function called with element and user arg.
+ * The function must not alter the rbtree.
+ * @param arg: user argument.
+ */
+void ldns_traverse_postorder(ldns_rbtree_t* tree,
+ void (*func)(ldns_rbnode_t*, void*), void* arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTIL_RBTREE_H_ */
diff --git a/3rdParty/Ldns/src/include/ldns/rdata.h b/3rdParty/Ldns/src/include/ldns/rdata.h
new file mode 100644
index 0000000..90dcbf1
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/rdata.h
@@ -0,0 +1,385 @@
+/*
+ * rdata.h
+ *
+ * rdata definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+
+/**
+ * \file
+ *
+ * Defines ldns_rdf and functions to manipulate those.
+ */
+
+
+#ifndef LDNS_RDATA_H
+#define LDNS_RDATA_H
+
+#include <ldns/common.h>
+#include <ldns/error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_MAX_RDFLEN 8192
+
+#define LDNS_RDF_SIZE_BYTE 1
+#define LDNS_RDF_SIZE_WORD 2
+#define LDNS_RDF_SIZE_DOUBLEWORD 4
+#define LDNS_RDF_SIZE_6BYTES 6
+#define LDNS_RDF_SIZE_16BYTES 16
+
+#define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01
+
+/**
+ * The different types of RDATA fields.
+ */
+enum ldns_enum_rdf_type
+{
+ /** none */
+ LDNS_RDF_TYPE_NONE,
+ /** domain name */
+ LDNS_RDF_TYPE_DNAME,
+ /** 8 bits */
+ LDNS_RDF_TYPE_INT8,
+ /** 16 bits */
+ LDNS_RDF_TYPE_INT16,
+ /** 32 bits */
+ LDNS_RDF_TYPE_INT32,
+ /** A record */
+ LDNS_RDF_TYPE_A,
+ /** AAAA record */
+ LDNS_RDF_TYPE_AAAA,
+ /** txt string */
+ LDNS_RDF_TYPE_STR,
+ /** apl data */
+ LDNS_RDF_TYPE_APL,
+ /** b32 string */
+ LDNS_RDF_TYPE_B32_EXT,
+ /** b64 string */
+ LDNS_RDF_TYPE_B64,
+ /** hex string */
+ LDNS_RDF_TYPE_HEX,
+ /** nsec type codes */
+ LDNS_RDF_TYPE_NSEC,
+ /** a RR type */
+ LDNS_RDF_TYPE_TYPE,
+ /** a class */
+ LDNS_RDF_TYPE_CLASS,
+ /** certificate algorithm */
+ LDNS_RDF_TYPE_CERT_ALG,
+ /** a key algorithm */
+ LDNS_RDF_TYPE_ALG,
+ /** unknown types */
+ LDNS_RDF_TYPE_UNKNOWN,
+ /** time (32 bits) */
+ LDNS_RDF_TYPE_TIME,
+ /** period */
+ LDNS_RDF_TYPE_PERIOD,
+ /** tsig time 48 bits */
+ LDNS_RDF_TYPE_TSIGTIME,
+ LDNS_RDF_TYPE_TSIG,
+ /** variable length any type rdata where the length
+ is specified by the first 2 bytes */
+ LDNS_RDF_TYPE_INT16_DATA,
+ /** protocol and port bitmaps */
+ LDNS_RDF_TYPE_SERVICE,
+ /** location data */
+ LDNS_RDF_TYPE_LOC,
+ /** well known services */
+ LDNS_RDF_TYPE_WKS,
+ /** NSAP */
+ LDNS_RDF_TYPE_NSAP,
+ /** ATMA */
+ LDNS_RDF_TYPE_ATMA,
+ /** IPSECKEY */
+ LDNS_RDF_TYPE_IPSECKEY,
+ /** nsec3 hash salt */
+ LDNS_RDF_TYPE_NSEC3_SALT,
+ /** nsec3 base32 string (with length byte on wire */
+ LDNS_RDF_TYPE_NSEC3_NEXT_OWNER
+};
+typedef enum ldns_enum_rdf_type ldns_rdf_type;
+
+/**
+ * algorithms used in CERT rrs
+ */
+enum ldns_enum_cert_algorithm
+{
+ LDNS_CERT_PKIX = 1,
+ LDNS_CERT_SPKI = 2,
+ LDNS_CERT_PGP = 3,
+ LDNS_CERT_IPKIX = 4,
+ LDNS_CERT_ISPKI = 5,
+ LDNS_CERT_IPGP = 6,
+ LDNS_CERT_ACPKIX = 7,
+ LDNS_CERT_IACPKIX = 8,
+ LDNS_CERT_URI = 253,
+ LDNS_CERT_OID = 254
+};
+typedef enum ldns_enum_cert_algorithm ldns_cert_algorithm;
+
+
+
+/**
+ * Resource record data field.
+ *
+ * The data is a network ordered array of bytes, which size is specified by
+ * the (16-bit) size field. To correctly parse it, use the type
+ * specified in the (16-bit) type field with a value from \ref ldns_rdf_type.
+ */
+struct ldns_struct_rdf
+{
+ /** The size of the data (in octets) */
+ size_t _size;
+ /** The type of the data */
+ ldns_rdf_type _type;
+ /** Pointer to the data (raw octets) */
+ void *_data;
+};
+typedef struct ldns_struct_rdf ldns_rdf;
+
+/* prototypes */
+
+/* write access functions */
+
+/**
+ * sets the size of the rdf.
+ * \param[in] *rd the rdf to operate on
+ * \param[in] size the new size
+ * \return void
+ */
+void ldns_rdf_set_size(ldns_rdf *rd, size_t size);
+
+/**
+ * sets the size of the rdf.
+ * \param[in] *rd the rdf to operate on
+ * \param[in] type the new type
+ * \return void
+ */
+void ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type);
+
+/**
+ * sets the size of the rdf.
+ * \param[in] *rd the rdf to operate on
+ * \param[in] *data pointer to the new data
+ * \return void
+ */
+void ldns_rdf_set_data(ldns_rdf *rd, void *data);
+
+/* read access */
+
+/**
+ * returns the size of the rdf.
+ * \param[in] *rd the rdf to read from
+ * \return uint16_t with the size
+ */
+size_t ldns_rdf_size(const ldns_rdf *rd);
+
+/**
+ * returns the type of the rdf. We need to insert _get_
+ * here to prevent conflict the the rdf_type TYPE.
+ * \param[in] *rd the rdf to read from
+ * \return ldns_rdf_type with the type
+ */
+ldns_rdf_type ldns_rdf_get_type(const ldns_rdf *rd);
+
+/**
+ * returns the data of the rdf.
+ * \param[in] *rd the rdf to read from
+ * \return uint8_t* pointer to the rdf's data
+ */
+uint8_t *ldns_rdf_data(const ldns_rdf *rd);
+
+/* creator functions */
+
+/**
+ * allocates a new rdf structure and fills it.
+ * This function DOES NOT copy the contents from
+ * the buffer, unlinke 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
+ * \return the new rdf structure or NULL on failure
+ */
+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()
+ * \param[in] type type of the rdf
+ * \param[in] size size of the buffer
+ * \param[in] data pointer to the buffer to be copied
+ * \return the new rdf structure or NULL on failure
+ */
+ldns_rdf *ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data);
+
+/**
+ * creates a new rdf from a string.
+ * \param[in] type type to use
+ * \param[in] str string to use
+ * \return ldns_rdf* or NULL in case of an error
+ */
+ldns_rdf *ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str);
+
+/**
+ * creates a new rdf from a file containing a string.
+ * \param[out] r the new rdf
+ * \param[in] type type to use
+ * \param[in] fp the file pointer to use
+ * \return LDNS_STATUS_OK or the error
+ */
+ldns_status ldns_rdf_new_frm_fp(ldns_rdf **r, ldns_rdf_type type, FILE *fp);
+
+/**
+ * creates a new rdf from a file containing a string.
+ * \param[out] r the new rdf
+ * \param[in] type type to use
+ * \param[in] fp the file pointer to use
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return LDNS_STATUS_OK or the error
+ */
+ldns_status ldns_rdf_new_frm_fp_l(ldns_rdf **r, ldns_rdf_type type, FILE *fp, int *line_nr);
+
+/* destroy functions */
+
+/**
+ * frees a rdf structure, leaving the
+ * data pointer intact.
+ * \param[in] rd the pointer to be freed
+ * \return void
+ */
+void ldns_rdf_free(ldns_rdf *rd);
+
+/**
+ * frees a rdf structure _and_ frees the
+ * data. rdf should be created with _new_frm_data
+ * \param[in] rd the rdf structure to be freed
+ * \return void
+ */
+void ldns_rdf_deep_free(ldns_rdf *rd);
+
+/* conversion functions */
+
+/**
+ * returns the rdf containing the native uint8_t repr.
+ * \param[in] type the ldns_rdf type to use
+ * \param[in] value the uint8_t to use
+ * \return ldns_rdf* with the converted value
+ */
+ldns_rdf *ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value);
+
+/**
+ * returns the rdf containing the native uint16_t representation.
+ * \param[in] type the ldns_rdf type to use
+ * \param[in] value the uint16_t to use
+ * \return ldns_rdf* with the converted value
+ */
+ldns_rdf *ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value);
+
+/**
+ * returns an rdf that contains the given int32 value.
+ *
+ * Because multiple rdf types can contain an int32, the
+ * type must be specified
+ * \param[in] type the ldns_rdf type to use
+ * \param[in] value the uint32_t to use
+ * \return ldns_rdf* with the converted value
+ */
+ldns_rdf *ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value);
+
+/**
+ * returns an int16_data rdf that contains the data in the
+ * given array, preceded by an int16 specifying the length.
+ *
+ * The memory is copied, and an LDNS_RDF_TYPE_INT16DATA is returned
+ * \param[in] size the size of the data
+ * \param[in] *data pointer to the actual data
+ * \return ldns_rd* the rdf with the data
+ */
+ldns_rdf *ldns_native2rdf_int16_data(size_t size, uint8_t *data);
+
+/**
+ * reverses an rdf, only actually useful for AAAA and A records.
+ * The returned rdf has the type LDNS_RDF_TYPE_DNAME!
+ * \param[in] *rd rdf to be reversed
+ * \return the reversed rdf (a newly created rdf)
+ */
+ldns_rdf *ldns_rdf_address_reverse(ldns_rdf *rd);
+
+/**
+ * returns the native uint8_t representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \return uint8_t the value extracted
+ */
+uint8_t ldns_rdf2native_int8(const ldns_rdf *rd);
+
+/**
+ * returns the native uint16_t representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \return uint16_t the value extracted
+ */
+uint16_t ldns_rdf2native_int16(const ldns_rdf *rd);
+
+/**
+ * returns the native uint32_t representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \return uint32_t the value extracted
+ */
+uint32_t ldns_rdf2native_int32(const ldns_rdf *rd);
+
+/**
+ * returns the native time_t representation from the rdf.
+ * \param[in] rd the ldns_rdf to operate on
+ * \return time_t the value extracted (32 bits currently)
+ */
+time_t ldns_rdf2native_time_t(const ldns_rdf *rd);
+
+/**
+ * converts a ttl value (like 5d2h) to a long.
+ * \param[in] nptr the start of the string
+ * \param[out] endptr points to the last char in case of error
+ * \return the convert duration value
+ */
+uint32_t ldns_str2period(const char *nptr, const char **endptr);
+
+/**
+ * removes \\DDD, \\[space] and other escapes from the input.
+ * See RFC 1035, section 5.1.
+ * \param[in] word what to check
+ * \param[in] length the string
+ * \return ldns_status mesg
+ */
+ldns_status ldns_octet(char *word, size_t *length);
+
+/**
+ * clones a rdf structure. The data is copied.
+ * \param[in] rd rdf to be copied
+ * \return a new rdf structure
+ */
+ldns_rdf *ldns_rdf_clone(const ldns_rdf *rd);
+
+/**
+ * compares two rdf's on their wire formats.
+ * (To order dnames according to rfc4034, use ldns_dname_compare)
+ * \param[in] rd1 the first one
+ * \param[in] rd2 the second one
+ * \return 0 if equal
+ * \return -1 if rd1 comes before rd2
+ * \return +1 if rd2 comes before rd1
+ */
+int ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RDATA_H */
diff --git a/3rdParty/Ldns/src/include/ldns/resolver.h b/3rdParty/Ldns/src/include/ldns/resolver.h
new file mode 100644
index 0000000..f887aaf
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/resolver.h
@@ -0,0 +1,721 @@
+/*
+ * resolver.h
+ *
+ * DNS Resolver definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Defines the ldns_resolver structure, a stub resolver that can send queries and parse answers.
+ *
+ */
+
+#ifndef LDNS_RESOLVER_H
+#define LDNS_RESOLVER_H
+
+#include <ldns/error.h>
+#include <ldns/common.h>
+#include <ldns/rr.h>
+#include <ldns/tsig.h>
+#include <ldns/rdata.h>
+#include <ldns/packet.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Default location of the resolv.conf file */
+#define LDNS_RESOLV_CONF "/etc/resolv.conf"
+/** Default location of the hosts file */
+#define LDNS_RESOLV_HOSTS "/etc/hosts"
+
+#define LDNS_RESOLV_KEYWORD -1
+#define LDNS_RESOLV_DEFDOMAIN 0
+#define LDNS_RESOLV_NAMESERVER 1
+#define LDNS_RESOLV_SEARCH 2
+#define LDNS_RESOLV_SORTLIST 3
+#define LDNS_RESOLV_OPTIONS 4
+#define LDNS_RESOLV_ANCHOR 5
+#define LDNS_RESOLV_KEYWORDS 6
+
+#define LDNS_RESOLV_INETANY 0
+#define LDNS_RESOLV_INET 1
+#define LDNS_RESOLV_INET6 2
+
+#define LDNS_RESOLV_RTT_INF 0 /* infinity */
+#define LDNS_RESOLV_RTT_MIN 1 /* reachable */
+
+/**
+ * DNS stub resolver structure
+ */
+struct ldns_struct_resolver
+{
+ /** Port to send queries to */
+ uint16_t _port;
+
+ /** Array of nameservers to query (IP addresses or dnames) */
+ ldns_rdf **_nameservers;
+ /** Number of nameservers in \c _nameservers */
+ size_t _nameserver_count; /* how many do we have */
+
+ /** Round trip time; 0 -> infinity. Unit: ms? */
+ size_t *_rtt;
+
+ /** Wether or not to be recursive */
+ bool _recursive;
+
+ /** Print debug information */
+ bool _debug;
+
+ /** Default domain to add to non fully qualified domain names */
+ ldns_rdf *_domain;
+
+ /** Searchlist array, add the names in this array if a query cannot be found */
+ ldns_rdf **_searchlist;
+
+ /** Number of entries in the searchlist array */
+ size_t _searchlist_count;
+
+ /** Number of times to retry before giving up */
+ uint8_t _retry;
+ /** Time to wait before retrying */
+ uint8_t _retrans;
+ /** Use new fallback mechanism (try EDNS, then do TCP) */
+ bool _fallback;
+
+ /** Whether to do DNSSEC */
+ bool _dnssec;
+ /** Whether to set the CD bit on DNSSEC requests */
+ bool _dnssec_cd;
+ /** Optional trust anchors for complete DNSSEC validation */
+ ldns_rr_list * _dnssec_anchors;
+ /** Whether to use tcp or udp (tcp if the value is true)*/
+ bool _usevc;
+ /** Whether to ignore the tc bit */
+ bool _igntc;
+ /** Whether to use ip6, 0->does not matter, 1 is IPv4, 2 is IPv6 */
+ uint8_t _ip6;
+ /** If true append the default domain */
+ bool _defnames;
+ /** If true apply the search list */
+ bool _dnsrch;
+ /** Timeout for socket connections */
+ struct timeval _timeout;
+ /** Only try the first nameserver, and return with an error directly if it fails */
+ bool _fail;
+ /** Randomly choose a nameserver */
+ bool _random;
+ /** Keep some things to make AXFR possible */
+ int _socket;
+ /** Count the number of LDNS_RR_TYPE_SOA RRs we have seen so far
+ * (the second one signifies the end of the AXFR)
+ */
+ int _axfr_soa_count;
+ /* when axfring we get complete packets from the server
+ but we want to give the caller 1 rr at a time, so
+ keep the current pkt */
+ /** Packet currently handled when doing part of an AXFR */
+ ldns_pkt *_cur_axfr_pkt;
+ /** Counter for within the AXFR packets */
+ uint16_t _axfr_i;
+ /* EDNS0 available buffer size */
+ uint16_t _edns_udp_size;
+
+ /* Optional tsig key for signing queries,
+ outgoing messages are signed if and only if both are set
+ */
+ /** Name of the key to use with TSIG, if _tsig_keyname and _tsig_keydata both contain values, outgoing messages are automatically signed with TSIG. */
+ char *_tsig_keyname;
+ /** Secret key data to use with TSIG, if _tsig_keyname and _tsig_keydata both contain values, outgoing messages are automatically signed with TSIG. */
+ char *_tsig_keydata;
+ /** TSIG signing algorithm */
+ char *_tsig_algorithm;
+};
+typedef struct ldns_struct_resolver ldns_resolver;
+
+/* prototypes */
+/* read access functions */
+
+/**
+ * Get the port the resolver should use
+ * \param[in] r the resolver
+ * \return the port number
+ */
+uint16_t ldns_resolver_port(const ldns_resolver *r);
+
+/**
+ * Is the resolver set to recurse
+ * \param[in] r the resolver
+ * \return true if so, otherwise false
+ */
+bool ldns_resolver_recursive(const ldns_resolver *r);
+
+/**
+ * Get the debug status of the resolver
+ * \param[in] r the resolver
+ * \return true if so, otherwise false
+ */
+bool ldns_resolver_debug(const ldns_resolver *r);
+
+/**
+ * Get the number of retries
+ * \param[in] r the resolver
+ * \return the number of retries
+ */
+uint8_t ldns_resolver_retry(const ldns_resolver *r);
+
+/**
+ * Get the retransmit interval
+ * \param[in] r the resolver
+ * \return the retransmit interval
+ */
+uint8_t ldns_resolver_retrans(const ldns_resolver *r);
+
+/**
+ * Get the truncation fallback status
+ * \param[in] r the resolver
+ * \return whether the truncation fallback mechanism is used
+ */
+bool ldns_resolver_fallback(const ldns_resolver *r);
+
+/**
+ * Does the resolver use ip6 or ip4
+ * \param[in] r the resolver
+ * \return 0: both, 1: ip4, 2:ip6
+ */
+uint8_t ldns_resolver_ip6(const ldns_resolver *r);
+
+/**
+ * Get the resolver's udp size
+ * \param[in] r the resolver
+ * \return the udp mesg size
+ */
+uint16_t ldns_resolver_edns_udp_size(const ldns_resolver *r);
+/**
+ * Does the resolver use tcp or udp
+ * \param[in] r the resolver
+ * \return true: tcp, false: udp
+ */
+bool ldns_resolver_usevc(const ldns_resolver *r);
+/**
+ * Does the resolver only try the first nameserver
+ * \param[in] r the resolver
+ * \return true: yes, fail, false: no, try the others
+ */
+bool ldns_resolver_fail(const ldns_resolver *r);
+/**
+ * Does the resolver apply default domain name
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+bool ldns_resolver_defnames(const ldns_resolver *r);
+/**
+ * Does the resolver apply search list
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+bool ldns_resolver_dnsrch(const ldns_resolver *r);
+/**
+ * Does the resolver do DNSSEC
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+bool ldns_resolver_dnssec(const ldns_resolver *r);
+/**
+ * Does the resolver set the CD bit
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+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
+ */
+ldns_rr_list * ldns_resolver_dnssec_anchors(const ldns_resolver *r);
+/**
+ * Does the resolver ignore the TC bit (truncated)
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+bool ldns_resolver_igntc(const ldns_resolver *r);
+/**
+ * Does the resolver randomize the nameserver before usage
+ * \param[in] r the resolver
+ * \return true: yes, false: no
+ */
+bool ldns_resolver_random(const ldns_resolver *r);
+/**
+ * How many nameserver are configured in the resolver
+ * \param[in] r the resolver
+ * \return number of nameservers
+ */
+size_t ldns_resolver_nameserver_count(const ldns_resolver *r);
+/**
+ * What is the default dname to add to relative queries
+ * \param[in] r the resolver
+ * \return the dname which is added
+ */
+ldns_rdf *ldns_resolver_domain(const ldns_resolver *r);
+/**
+ * What is the timeout on socket connections
+ * \param[in] r the resolver
+ * \return the timeout as struct timeval
+ */
+struct timeval ldns_resolver_timeout(const ldns_resolver *r);
+/**
+ * What is the searchlist as used by the resolver
+ * \param[in] r the resolver
+ * \return a ldns_rdf pointer to a list of the addresses
+ */
+ldns_rdf** ldns_resolver_searchlist(const ldns_resolver *r);
+/**
+ * Return the configured nameserver ip address
+ * \param[in] r the resolver
+ * \return a ldns_rdf pointer to a list of the addresses
+ */
+ldns_rdf** ldns_resolver_nameservers(const ldns_resolver *r);
+/**
+ * Return the used round trip times for the nameservers
+ * \param[in] r the resolver
+ * \return a size_t* pointer to the list.
+ * yet)
+ */
+size_t * ldns_resolver_rtt(const ldns_resolver *r);
+/**
+ * Return the used round trip time for a specific nameserver
+ * \param[in] r the resolver
+ * \param[in] pos the index to the nameserver
+ * \return the rrt, 0: infinite, >0: undefined (as of * yet)
+ */
+size_t ldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos);
+/**
+ * Return the tsig keyname as used by the nameserver
+ * \param[in] r the resolver
+ * \return the name used.
+ */
+char *ldns_resolver_tsig_keyname(const ldns_resolver *r);
+/**
+ * Return the tsig algorithm as used by the nameserver
+ * \param[in] r the resolver
+ * \return the algorithm used.
+ */
+char *ldns_resolver_tsig_algorithm(const ldns_resolver *r);
+/**
+ * Return the tsig keydata as used by the nameserver
+ * \param[in] r the resolver
+ * \return the keydata used.
+ */
+char *ldns_resolver_tsig_keydata(const ldns_resolver *r);
+/**
+ * pop the last nameserver from the resolver.
+ * \param[in] r the resolver
+ * \return the popped address or NULL if empty
+ */
+ldns_rdf* ldns_resolver_pop_nameserver(ldns_resolver *r);
+
+/**
+ * Return the resolver's searchlist count
+ * \param[in] r the resolver
+ * \return the searchlist count
+ */
+size_t ldns_resolver_searchlist_count(const ldns_resolver *r);
+
+/* write access function */
+/**
+ * Set the port the resolver should use
+ * \param[in] r the resolver
+ * \param[in] p the port number
+ */
+void ldns_resolver_set_port(ldns_resolver *r, uint16_t p);
+
+/**
+ * Set the resolver recursion
+ * \param[in] r the resolver
+ * \param[in] b true: set to recurse, false: unset
+ */
+void ldns_resolver_set_recursive(ldns_resolver *r, bool b);
+
+/**
+ * Set the resolver debugging
+ * \param[in] r the resolver
+ * \param[in] b true: debug on: false debug off
+ */
+void ldns_resolver_set_debug(ldns_resolver *r, bool b);
+
+/**
+ * Incremental the resolver's nameserver count.
+ * \param[in] r the resolver
+ */
+void ldns_resolver_incr_nameserver_count(ldns_resolver *r);
+
+/**
+ * Decrement the resolver's nameserver count.
+ * \param[in] r the resolver
+ */
+void ldns_resolver_dec_nameserver_count(ldns_resolver *r);
+
+/**
+ * Set the resolver's nameserver count directly.
+ * \param[in] r the resolver
+ * \param[in] c the nameserver count
+ */
+void ldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c);
+
+/**
+ * Set the resolver's nameserver count directly by using an rdf list
+ * \param[in] r the resolver
+ * \param[in] rd the resolver addresses
+ */
+void ldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **rd);
+
+/**
+ * Set the resolver's default domain. This gets appended when no
+ * absolute name is given
+ * \param[in] r the resolver
+ * \param[in] rd the name to append
+ */
+void ldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *rd);
+
+/**
+ * Set the resolver's socket time out when talking to remote hosts
+ * \param[in] r the resolver
+ * \param[in] timeout the timeout to use
+ */
+void ldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout);
+
+/**
+ * Push a new rd to the resolver's searchlist
+ * \param[in] r the resolver
+ * \param[in] rd to push
+ */
+void ldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *rd);
+
+/**
+ * Whether the resolver uses the name set with _set_domain
+ * \param[in] r the resolver
+ * \param[in] b true: use the defaults, false: don't use them
+ */
+void ldns_resolver_set_defnames(ldns_resolver *r, bool b);
+
+/**
+ * Whether the resolver uses a virtual circuit (TCP)
+ * \param[in] r the resolver
+ * \param[in] b true: use TCP, false: don't use TCP
+ */
+void ldns_resolver_set_usevc(ldns_resolver *r, bool b);
+
+/**
+ * Whether the resolver uses the searchlist
+ * \param[in] r the resolver
+ * \param[in] b true: use the list, false: don't use the list
+ */
+void ldns_resolver_set_dnsrch(ldns_resolver *r, bool b);
+
+/**
+ * Whether the resolver uses DNSSEC
+ * \param[in] r the resolver
+ * \param[in] b true: use DNSSEC, false: don't use DNSSEC
+ */
+void ldns_resolver_set_dnssec(ldns_resolver *r, bool b);
+
+/**
+ * Whether the resolver uses the checking disable bit
+ * \param[in] r the resolver
+ * \param[in] b true: enable , false: don't use TCP
+ */
+void ldns_resolver_set_dnssec_cd(ldns_resolver *r, bool b);
+/**
+ * Set the resolver's DNSSEC anchor list directly. RRs should be of type DS or DNSKEY.
+ * \param[in] r the resolver
+ * \param[in] l the list of RRs to use as trust anchors
+ */
+void ldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l);
+
+/**
+ * Push a new trust anchor to the resolver. It must be a DS or DNSKEY rr
+ * \param[in] r the resolver.
+ * \param[in] rr the RR to add as a trust anchor.
+ * \return a status
+ */
+ldns_status ldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr);
+
+/**
+ * Set the resolver retrans timeout (in seconds)
+ * \param[in] r the resolver
+ * \param[in] re the retransmission interval in seconds
+ */
+void ldns_resolver_set_retrans(ldns_resolver *r, uint8_t re);
+
+/**
+ * Set whether the resolvers truncation fallback mechanism is used
+ * when ldns_resolver_query() is called.
+ * \param[in] r the resolver
+ * \param[in] fallback whether to use the fallback mechanism
+ */
+void ldns_resolver_set_fallback(ldns_resolver *r, bool fallback);
+
+/**
+ * Set the resolver retry interval (in seconds)
+ * \param[in] r the resolver
+ * \param[in] re the retry interval
+ */
+void ldns_resolver_set_retry(ldns_resolver *r, uint8_t re);
+
+/**
+ * Whether the resolver uses ip6
+ * \param[in] r the resolver
+ * \param[in] i 0: no pref, 1: ip4, 2: ip6
+ */
+void ldns_resolver_set_ip6(ldns_resolver *r, uint8_t i);
+
+/**
+ * Whether or not to fail after one failed query
+ * \param[in] r the resolver
+ * \param[in] b true: yes fail, false: continue with next nameserver
+ */
+void ldns_resolver_set_fail(ldns_resolver *r, bool b);
+
+/**
+ * Whether or not to ignore the TC bit
+ * \param[in] r the resolver
+ * \param[in] b true: yes ignore, false: don't ignore
+ */
+void ldns_resolver_set_igntc(ldns_resolver *r, bool b);
+
+/**
+ * Set maximum udp size
+ * \param[in] r the resolver
+ * \param[in] s the udp max size
+ */
+void ldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s);
+
+/**
+ * Set the tsig key name
+ * \param[in] r the resolver
+ * \param[in] tsig_keyname the tsig key name
+ */
+void ldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname);
+
+/**
+ * Set the tsig algorithm
+ * \param[in] r the resolver
+ * \param[in] tsig_algorithm the tsig algorithm
+ */
+void ldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm);
+
+/**
+ * Set the tsig key data
+ * \param[in] r the resolver
+ * \param[in] tsig_keydata the key data
+ */
+void ldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata);
+
+/**
+ * Set round trip time for all nameservers. Note this currently
+ * differentiates between: unreachable and reachable.
+ * \param[in] r the resolver
+ * \param[in] rtt a list with the times
+ */
+void ldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt);
+
+/**
+ * Set round trip time for a specific nameserver. Note this
+ * currently differentiates between: unreachable and reachable.
+ * \param[in] r the resolver
+ * \param[in] pos the nameserver position
+ * \param[in] value the rtt
+ */
+void ldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value);
+
+/**
+ * Should the nameserver list be randomized before each use
+ * \param[in] r the resolver
+ * \param[in] b: true: randomize, false: don't
+ */
+void ldns_resolver_set_random(ldns_resolver *r, bool b);
+
+/**
+ * Push a new nameserver to the resolver. It must be an IP
+ * address v4 or v6.
+ * \param[in] r the resolver
+ * \param[in] n the ip address
+ * \return ldns_status a status
+ */
+ldns_status ldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n);
+
+/**
+ * Push a new nameserver to the resolver. It must be an
+ * A or AAAA RR record type
+ * \param[in] r the resolver
+ * \param[in] rr the resource record
+ * \return ldns_status a status
+ */
+ldns_status ldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr);
+
+/**
+ * Push a new nameserver rr_list to the resolver.
+ * \param[in] r the resolver
+ * \param[in] rrlist the rr_list to push
+ * \return ldns_status a status
+ */
+ldns_status ldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist);
+
+/**
+ * Send the query for using the resolver and take the search list into account
+ * The search algorithm is as follows:
+ * If the name is absolute, try it as-is, otherwise apply the search list
+ * \param[in] *r operate using this resolver
+ * \param[in] *rdf query for this name
+ * \param[in] t query for this type (may be 0, defaults to A)
+ * \param[in] c query for this class (may be 0, default to IN)
+ * \param[in] flags the query flags
+ * \return ldns_pkt* a packet with the reply from the nameserver
+ */
+ldns_pkt* ldns_resolver_search(const ldns_resolver *r, const ldns_rdf *rdf, ldns_rr_type t, ldns_rr_class c, uint16_t flags);
+
+/**
+ * Form a query packet from a resolver and name/type/class combo
+ * \param[out] **q a pointer to a ldns_pkt pointer (initialized by this function)
+ * \param[in] *r operate using this resolver
+ * \param[in] *name query for this name
+ * \param[in] t query for this type (may be 0, defaults to A)
+ * \param[in] c query for this class (may be 0, default to IN)
+ * \param[in] f the query flags
+ * \return ldns_pkt* a packet with the reply from the nameserver
+ */
+ldns_status ldns_resolver_prepare_query_pkt(ldns_pkt **q, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t f);
+
+/**
+ * Send the query for name as-is
+ * \param[out] **answer a pointer to a ldns_pkt pointer (initialized by this function)
+ * \param[in] *r operate using this resolver
+ * \param[in] *name query for this name
+ * \param[in] t query for this type (may be 0, defaults to A)
+ * \param[in] c query for this class (may be 0, default to IN)
+ * \param[in] flags the query flags
+ * \return ldns_pkt* a packet with the reply from the nameserver
+ */
+ldns_status ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags);
+
+/**
+ * Send the given packet to a nameserver
+ * \param[out] **answer a pointer to a ldns_pkt pointer (initialized by this function)
+ * \param[in] *r operate using this resolver
+ * \param[in] *query_pkt query
+ */
+ldns_status ldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r, ldns_pkt *query_pkt);
+
+/**
+ * Send a query to a nameserver
+ * \param[in] *r operate using this resolver
+ * \param[in] *name query for this name
+ * \param[in] *t query for this type (may be 0, defaults to A)
+ * \param[in] *c query for this class (may be 0, default to IN)
+ * \param[in] flags the query flags
+ * \return ldns_pkt* a packet with the reply from the nameserver
+ * if _defnames is true the default domain will be added
+ */
+ldns_pkt* ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, uint16_t flags);
+
+
+/**
+ * Create a new resolver structure
+ * \return ldns_resolver* pointer to new strcture
+ */
+ldns_resolver* ldns_resolver_new(void);
+
+/**
+ * Create a resolver structure from a file like /etc/resolv.conf
+ * \param[out] r the new resolver
+ * \param[in] fp file pointer to create new resolver from
+ * if NULL use /etc/resolv.conf
+ * \return LDNS_STATUS_OK or the error
+ */
+ldns_status ldns_resolver_new_frm_fp(ldns_resolver **r, FILE *fp);
+
+/**
+ * Create a resolver structure from a file like /etc/resolv.conf
+ * \param[out] r the new resolver
+ * \param[in] fp file pointer to create new resolver from
+ * if NULL use /etc/resolv.conf
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \return LDNS_STATUS_OK or the error
+ */
+ldns_status ldns_resolver_new_frm_fp_l(ldns_resolver **r, FILE *fp, int *line_nr);
+
+/**
+ * Configure a resolver by means of a resolv.conf file
+ * The file may be NULL in which case there will be
+ * looked the RESOLV_CONF (defaults to /etc/resolv.conf
+ * \param[out] r the new resolver
+ * \param[in] filename the filename to use
+ * \return LDNS_STATUS_OK or the error
+ */
+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.
+ * \param res resolver to free
+ */
+void ldns_resolver_free(ldns_resolver *res);
+
+/**
+ * Frees the allocated space for this resolver and all it's data
+ * \param res resolver to free
+ */
+void ldns_resolver_deep_free(ldns_resolver *res);
+
+/**
+ * Get the next stream of RRs in a AXFR
+ * \param[in] resolver the resolver to use. First ldns_axfr_start() must be
+ * called
+ * \return ldns_rr the next RR from the AXFR stream
+ * After you get this returned RR (not NULL: on error), then check if
+ * ldns_axfr_complete() is true to see if the zone transfer has completed.
+ */
+ldns_rr* ldns_axfr_next(ldns_resolver *resolver);
+
+/**
+ * Returns true if the axfr transfer has completed (i.e. 2 SOA RRs and no errors were encountered
+ * \param[in] resolver the resolver that is used
+ * \return bool true if axfr transfer was completed without error
+ */
+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
+ * \param[in] res the resolver that was used in the axfr transfer
+ * \return ldns_pkt the last packet sent
+ */
+ldns_pkt *ldns_axfr_last_pkt(const ldns_resolver *res);
+
+/**
+ * Randomize the nameserver list in the resolver
+ * \param[in] r the resolver
+ */
+void ldns_resolver_nameservers_randomize(ldns_resolver *r);
+
+/**
+ * Returns true if at least one of the provided keys is a trust anchor
+ * \param[in] r the current resolver
+ * \param[in] keys the keyset to check
+ * \param[out] trusted_keys the subset of trusted keys in the 'keys' rrset
+ * \return true if at least one of the provided keys is a configured trust anchor
+ */
+bool ldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RESOLVER_H */
diff --git a/3rdParty/Ldns/src/include/ldns/rr.h b/3rdParty/Ldns/src/include/ldns/rr.h
new file mode 100644
index 0000000..2e1dd76
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/rr.h
@@ -0,0 +1,886 @@
+/*
+ * rr.h - resource record definitions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains the definition of ldns_rr and functions to manipulate those.
+ */
+
+
+#ifndef LDNS_RR_H
+#define LDNS_RR_H
+
+#include <ldns/common.h>
+#include <ldns/rdata.h>
+#include <ldns/buffer.h>
+#include <ldns/error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum length of a dname label */
+#define LDNS_MAX_LABELLEN 63
+/** Maximum length of a complete dname */
+#define LDNS_MAX_DOMAINLEN 255
+/** Maximum number of pointers in 1 dname */
+#define LDNS_MAX_POINTERS 65535
+/** The bytes TTL, CLASS and length use up in an rr */
+#define LDNS_RR_OVERHEAD 10
+
+/* The first fields are 'common' and can be referenced instantly */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 52
+
+
+
+/**
+ * The different RR classes.
+ */
+enum ldns_enum_rr_class
+{
+ /** the Internet */
+ LDNS_RR_CLASS_IN = 1,
+ /** Chaos class */
+ LDNS_RR_CLASS_CH = 3,
+ /** Hesiod (Dyer 87) */
+ LDNS_RR_CLASS_HS = 4,
+ /** None class, dynamic update */
+ LDNS_RR_CLASS_NONE = 254,
+ /** Any class */
+ LDNS_RR_CLASS_ANY = 255,
+
+ LDNS_RR_CLASS_FIRST = 0,
+ LDNS_RR_CLASS_LAST = 65535,
+ LDNS_RR_CLASS_COUNT = LDNS_RR_CLASS_LAST - LDNS_RR_CLASS_FIRST + 1
+};
+typedef enum ldns_enum_rr_class ldns_rr_class;
+
+/**
+ * Used to specify whether compression is allowed.
+ */
+enum ldns_enum_rr_compress
+{
+ /** compression is allowed */
+ LDNS_RR_COMPRESS,
+ LDNS_RR_NO_COMPRESS
+};
+typedef enum ldns_enum_rr_compress ldns_rr_compress;
+
+/**
+ * The different RR types.
+ */
+enum ldns_enum_rr_type
+{
+ /** a host address */
+ LDNS_RR_TYPE_A = 1,
+ /** an authoritative name server */
+ LDNS_RR_TYPE_NS = 2,
+ /** a mail destination (Obsolete - use MX) */
+ LDNS_RR_TYPE_MD = 3,
+ /** a mail forwarder (Obsolete - use MX) */
+ LDNS_RR_TYPE_MF = 4,
+ /** the canonical name for an alias */
+ LDNS_RR_TYPE_CNAME = 5,
+ /** marks the start of a zone of authority */
+ LDNS_RR_TYPE_SOA = 6,
+ /** a mailbox domain name (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MB = 7,
+ /** a mail group member (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MG = 8,
+ /** a mail rename domain name (EXPERIMENTAL) */
+ LDNS_RR_TYPE_MR = 9,
+ /** a null RR (EXPERIMENTAL) */
+ LDNS_RR_TYPE_NULL = 10,
+ /** a well known service description */
+ LDNS_RR_TYPE_WKS = 11,
+ /** a domain name pointer */
+ LDNS_RR_TYPE_PTR = 12,
+ /** host information */
+ LDNS_RR_TYPE_HINFO = 13,
+ /** mailbox or mail list information */
+ LDNS_RR_TYPE_MINFO = 14,
+ /** mail exchange */
+ LDNS_RR_TYPE_MX = 15,
+ /** text strings */
+ LDNS_RR_TYPE_TXT = 16,
+ /** RFC1183 */
+ LDNS_RR_TYPE_RP = 17,
+ /** RFC1183 */
+ LDNS_RR_TYPE_AFSDB = 18,
+ /** RFC1183 */
+ LDNS_RR_TYPE_X25 = 19,
+ /** RFC1183 */
+ LDNS_RR_TYPE_ISDN = 20,
+ /** RFC1183 */
+ LDNS_RR_TYPE_RT = 21,
+ /** RFC1706 */
+ LDNS_RR_TYPE_NSAP = 22,
+ /** RFC1348 */
+ LDNS_RR_TYPE_NSAP_PTR = 23,
+ /** 2535typecode */
+ LDNS_RR_TYPE_SIG = 24,
+ /** 2535typecode */
+ LDNS_RR_TYPE_KEY = 25,
+ /** RFC2163 */
+ LDNS_RR_TYPE_PX = 26,
+ /** RFC1712 */
+ LDNS_RR_TYPE_GPOS = 27,
+ /** ipv6 address */
+ LDNS_RR_TYPE_AAAA = 28,
+ /** LOC record RFC1876 */
+ LDNS_RR_TYPE_LOC = 29,
+ /** 2535typecode */
+ LDNS_RR_TYPE_NXT = 30,
+ /** draft-ietf-nimrod-dns-01.txt */
+ LDNS_RR_TYPE_EID = 31,
+ /** draft-ietf-nimrod-dns-01.txt */
+ LDNS_RR_TYPE_NIMLOC = 32,
+ /** SRV record RFC2782 */
+ LDNS_RR_TYPE_SRV = 33,
+ /** http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
+ LDNS_RR_TYPE_ATMA = 34,
+ /** RFC2915 */
+ LDNS_RR_TYPE_NAPTR = 35,
+ /** RFC2230 */
+ LDNS_RR_TYPE_KX = 36,
+ /** RFC2538 */
+ LDNS_RR_TYPE_CERT = 37,
+ /** RFC2874 */
+ LDNS_RR_TYPE_A6 = 38,
+ /** RFC2672 */
+ LDNS_RR_TYPE_DNAME = 39,
+ /** dnsind-kitchen-sink-02.txt */
+ LDNS_RR_TYPE_SINK = 40,
+ /** Pseudo OPT record... */
+ LDNS_RR_TYPE_OPT = 41,
+ /** RFC3123 */
+ LDNS_RR_TYPE_APL = 42,
+ /** draft-ietf-dnsext-delegation */
+ LDNS_RR_TYPE_DS = 43,
+ /** SSH Key Fingerprint */
+ LDNS_RR_TYPE_SSHFP = 44,
+ /** draft-richardson-ipseckey-rr-11.txt */
+ LDNS_RR_TYPE_IPSECKEY = 45,
+ /** draft-ietf-dnsext-dnssec-25 */
+ LDNS_RR_TYPE_RRSIG = 46,
+ LDNS_RR_TYPE_NSEC = 47,
+ LDNS_RR_TYPE_DNSKEY = 48,
+ LDNS_RR_TYPE_DHCID = 49,
+
+ LDNS_RR_TYPE_NSEC3 = 50,
+ LDNS_RR_TYPE_NSEC3PARAM = 51,
+ LDNS_RR_TYPE_NSEC3PARAMS = 51,
+
+ /** draft-ietf-dnsop-trust-history */
+ LDNS_RR_TYPE_TALINK = 58,
+
+ LDNS_RR_TYPE_SPF = 99,
+
+ LDNS_RR_TYPE_UINFO = 100,
+ LDNS_RR_TYPE_UID = 101,
+ LDNS_RR_TYPE_GID = 102,
+ LDNS_RR_TYPE_UNSPEC = 103,
+
+ LDNS_RR_TYPE_TSIG = 250,
+ LDNS_RR_TYPE_IXFR = 251,
+ LDNS_RR_TYPE_AXFR = 252,
+ /** A request for mailbox-related records (MB, MG or MR) */
+ LDNS_RR_TYPE_MAILB = 253,
+ /** A request for mail agent RRs (Obsolete - see MX) */
+ LDNS_RR_TYPE_MAILA = 254,
+ /** any type (wildcard) */
+ LDNS_RR_TYPE_ANY = 255,
+
+ /* RFC 4431, 5074, DNSSEC Lookaside Validation */
+ LDNS_RR_TYPE_DLV = 32769,
+
+ /* type codes from nsec3 experimental phase
+ LDNS_RR_TYPE_NSEC3 = 65324,
+ LDNS_RR_TYPE_NSEC3PARAMS = 65325, */
+ LDNS_RR_TYPE_FIRST = 0,
+ LDNS_RR_TYPE_LAST = 65535,
+ LDNS_RR_TYPE_COUNT = LDNS_RR_TYPE_LAST - LDNS_RR_TYPE_FIRST + 1
+};
+typedef enum ldns_enum_rr_type ldns_rr_type;
+
+/**
+ * Resource Record
+ *
+ * This is the basic DNS element that contains actual data
+ *
+ * From RFC1035:
+ * <pre>
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME an owner name, i.e., the name of the node to which this
+ resource record pertains.
+
+TYPE two octets containing one of the RR TYPE codes.
+
+CLASS two octets containing one of the RR CLASS codes.
+
+TTL a 32 bit signed integer that specifies the time interval
+ that the resource record may be cached before the source
+ of the information should again be consulted. Zero
+ values are interpreted to mean that the RR can only be
+ used for the transaction in progress, and should not be
+ cached. For example, SOA records are always distributed
+ with a zero TTL to prohibit caching. Zero values can
+ also be used for extremely volatile data.
+
+RDLENGTH an unsigned 16 bit integer that specifies the length in
+ octets of the RDATA field.
+
+RDATA a variable length string of octets that describes the
+ resource. The format of this information varies
+ according to the TYPE and CLASS of the resource record.
+ * </pre>
+ *
+ * The actual amount and type of rdata fields depend on the RR type of the
+ * RR, and can be found by using \ref ldns_rr_descriptor functions.
+ */
+struct ldns_struct_rr
+{
+ /** Owner name, uncompressed */
+ ldns_rdf *_owner;
+ /** Time to live */
+ uint32_t _ttl;
+ /** Number of data fields */
+ size_t _rd_count;
+ /** the type of the RR. A, MX etc. */
+ ldns_rr_type _rr_type;
+ /** Class of the resource record. */
+ ldns_rr_class _rr_class;
+ /* everything in the rdata is in network order */
+ /** The array of rdata's */
+ ldns_rdf **_rdata_fields;
+ /** question rr [it would be nicer if thous is after _rd_count]
+ ABI change: Fix this in next major release
+ */
+ bool _rr_question;
+};
+typedef struct ldns_struct_rr ldns_rr;
+
+/**
+ * List or Set of Resource Records
+ *
+ * Contains a list of rr's <br>
+ * No official RFC-like checks are made
+ */
+struct ldns_struct_rr_list
+{
+ size_t _rr_count;
+ size_t _rr_capacity;
+ ldns_rr **_rrs;
+};
+typedef struct ldns_struct_rr_list ldns_rr_list;
+
+/**
+ * Contains all information about resource record types.
+ *
+ * This structure contains, for all rr types, the rdata fields that are defined.
+ */
+struct ldns_struct_rr_descriptor
+{
+ /** Type of the RR that is described here */
+ ldns_rr_type _type;
+ /** Textual name of the RR type. */
+ const char *_name;
+ /** Minimum number of rdata fields in the RRs of this type. */
+ uint8_t _minimum;
+ /** Maximum number of rdata fields in the RRs of this type. */
+ uint8_t _maximum;
+ /** Wireformat specification for the rr, i.e. the types of rdata fields in their respective order. */
+ const ldns_rdf_type *_wireformat;
+ /** Special rdf types */
+ ldns_rdf_type _variable;
+ /** Specifies whether compression can be used for dnames in this RR type. */
+ ldns_rr_compress _compress;
+ /** The number of DNAMEs in the _wireformat string, for parsing. */
+ uint8_t _dname_count;
+};
+typedef struct ldns_struct_rr_descriptor ldns_rr_descriptor;
+
+/**
+ * creates a new rr structure.
+ * \return ldns_rr *
+ */
+ldns_rr* ldns_rr_new(void);
+
+/**
+ * creates a new rr structure, based on the given type.
+ * alloc enough space to hold all the rdf's
+ */
+ldns_rr* ldns_rr_new_frm_type(ldns_rr_type t);
+
+/**
+ * frees an RR structure
+ * \param[in] *rr the RR to be freed
+ * \return void
+ */
+void ldns_rr_free(ldns_rr *rr);
+
+/**
+ * creates an rr from a string.
+ * The string should be a fully filled-in rr, like
+ * ownername &lt;space&gt; TTL &lt;space&gt; CLASS &lt;space&gt;
+ * TYPE &lt;space&gt; RDATA.
+ * \param[out] n the rr to return
+ * \param[in] str the string to convert
+ * \param[in] default_ttl default ttl value for the rr.
+ * If 0 DEF_TTL will be used
+ * \param[in] origin when the owner is relative add this.
+ * The caller must ldns_rdf_deep_free it.
+ * \param[out] prev the previous ownername. if this value is not NULL,
+ * the function overwrites this with the ownername found in this
+ * string. The caller must then ldns_rdf_deep_free it.
+ * \return a status msg describing an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_rr_new_frm_str(ldns_rr **n, const char *str,
+ uint32_t default_ttl, ldns_rdf *origin,
+ ldns_rdf **prev);
+
+/**
+ * creates an rr for the question section from a string, i.e.
+ * without RDATA fields
+ * Origin and previous RR functionality are the same as in
+ * ldns_rr_new_frm_str()
+ * \param[out] n the rr to return
+ * \param[in] str the string to convert
+ * \param[in] origin when the owner is relative add this.
+ * The caller must ldns_rdf_deep_free it.
+ * \param prev the previous ownername. the function overwrite this with
+ * the current found ownername. The caller must ldns_rdf_deep_free it.
+ * \return a status msg describing an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_rr_new_question_frm_str(ldns_rr **n, const char *str,
+ ldns_rdf *origin, ldns_rdf **prev);
+
+/**
+ * creates a new rr from a file containing a string.
+ * \param[out] rr the new rr
+ * \param[in] fp the file pointer to use
+ * \param[in] default_ttl pointer to a default ttl for the rr. If NULL DEF_TTL will be used
+ * the pointer will be updated if the file contains a $TTL directive
+ * \param[in] origin when the owner is relative add this
+ * the pointer will be updated if the file contains a $ORIGIN directive
+ * The caller must ldns_rdf_deep_free it.
+ * \param[in] prev when the owner is whitespaces use this as the * ownername
+ * the pointer will be updated after the call
+ * The caller must ldns_rdf_deep_free it.
+ * \return a ldns_status with an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_rr_new_frm_fp(ldns_rr **rr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev);
+
+/**
+ * creates a new rr from a file containing a string.
+ * \param[out] rr the new rr
+ * \param[in] fp the file pointer to use
+ * \param[in] default_ttl a default ttl for the rr. If NULL DEF_TTL will be used
+ * the pointer will be updated if the file contains a $TTL directive
+ * \param[in] origin when the owner is relative add this
+ * the pointer will be updated if the file contains a $ORIGIN directive
+ * The caller must ldns_rdf_deep_free it.
+ * \param[in] line_nr pointer to an integer containing the current line number (for debugging purposes)
+ * \param[in] prev when the owner is whitespaces use this as the * ownername
+ * the pointer will be updated after the call
+ * The caller must ldns_rdf_deep_free it.
+ * \return a ldns_status with an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_rr_new_frm_fp_l(ldns_rr **rr, FILE *fp, uint32_t *default_ttl, ldns_rdf **origin, ldns_rdf **prev, int *line_nr);
+
+/**
+ * sets the owner in the rr structure.
+ * \param[in] *rr rr to operate on
+ * \param[in] *owner set to this owner
+ * \return void
+ */
+void ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner);
+
+/**
+ * sets the question flag in the rr structure.
+ * \param[in] *rr rr to operate on
+ * \param[in] question question flag
+ * \return void
+ */
+void ldns_rr_set_question(ldns_rr *rr, bool question);
+
+/**
+ * sets the ttl in the rr structure.
+ * \param[in] *rr rr to operate on
+ * \param[in] ttl set to this ttl
+ * \return void
+ */
+void ldns_rr_set_ttl(ldns_rr *rr, uint32_t ttl);
+
+/**
+ * sets the rd_count in the rr.
+ * \param[in] *rr rr to operate on
+ * \param[in] count set to this count
+ * \return void
+ */
+void ldns_rr_set_rd_count(ldns_rr *rr, size_t count);
+
+/**
+ * sets the type in the rr.
+ * \param[in] *rr rr to operate on
+ * \param[in] rr_type set to this type
+ * \return void
+ */
+void ldns_rr_set_type(ldns_rr *rr, ldns_rr_type rr_type);
+
+/**
+ * sets the class in the rr.
+ * \param[in] *rr rr to operate on
+ * \param[in] rr_class set to this class
+ * \return void
+ */
+void ldns_rr_set_class(ldns_rr *rr, ldns_rr_class rr_class);
+
+/**
+ * sets a rdf member, it will be set on the
+ * position given. The old value is returned, like pop.
+ * \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
+ */
+ldns_rdf* ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position);
+
+/**
+ * sets rd_field member, it will be
+ * placed in the next available spot.
+ * \param[in] *rr rr to operate on
+ * \param[in] *f the data field member to set
+ * \return bool
+ */
+bool ldns_rr_push_rdf(ldns_rr *rr, const ldns_rdf *f);
+
+/**
+ * removes a rd_field member, it will be
+ * popped from the last position.
+ * \param[in] *rr rr to operate on
+ * \return rdf which was popped (null if nothing)
+ */
+ldns_rdf* ldns_rr_pop_rdf(ldns_rr *rr);
+
+/**
+ * returns the rdata field member counter.
+ * \param[in] *rr rr to operate on
+ * \param[in] nr the number of the rdf to return
+ * \return ldns_rdf *
+ */
+ldns_rdf* ldns_rr_rdf(const ldns_rr *rr, size_t nr);
+
+/**
+ * returns the owner name of an rr structure.
+ * \param[in] *rr rr to operate on
+ * \return ldns_rdf *
+ */
+ldns_rdf* ldns_rr_owner(const ldns_rr *rr);
+
+/**
+ * returns the question flag of an rr structure.
+ * \param[in] *rr rr to operate on
+ * \return bool true if question
+ */
+bool ldns_rr_is_question(const ldns_rr *rr);
+
+/**
+ * returns the ttl of an rr structure.
+ * \param[in] *rr the rr to read from
+ * \return the ttl of the rr
+ */
+uint32_t ldns_rr_ttl(const ldns_rr *rr);
+
+/**
+ * returns the rd_count of an rr structure.
+ * \param[in] *rr the rr to read from
+ * \return the rd count of the rr
+ */
+size_t ldns_rr_rd_count(const ldns_rr *rr);
+
+/**
+ * returns the type of the rr.
+ * \param[in] *rr the rr to read from
+ * \return the type of the rr
+ */
+ldns_rr_type ldns_rr_get_type(const ldns_rr *rr);
+
+/**
+ * returns the class of the rr.
+ * \param[in] *rr the rr to read from
+ * \return the class of the rr
+ */
+ldns_rr_class ldns_rr_get_class(const ldns_rr *rr);
+
+/* rr_lists */
+
+/**
+ * returns the number of rr's in an rr_list.
+ * \param[in] rr_list the rr_list to read from
+ * \return the number of rr's
+ */
+size_t ldns_rr_list_rr_count(const ldns_rr_list *rr_list);
+
+/**
+ * sets the number of rr's in an rr_list.
+ * \param[in] rr_list the rr_list to set the count on
+ * \param[in] count the number of rr in this list
+ * \return void
+ */
+void ldns_rr_list_set_rr_count(ldns_rr_list *rr_list, size_t count);
+
+/**
+ * set a rr on a specific index in a ldns_rr_list
+ * \param[in] rr_list the rr_list to use
+ * \param[in] r the rr to set
+ * \param[in] count index into the rr_list
+ * \return the old rr which was stored in the rr_list, or
+ * NULL is the index was too large
+ * set a specific rr */
+ldns_rr * ldns_rr_list_set_rr(ldns_rr_list *rr_list, const ldns_rr *r, size_t count);
+
+/**
+ * returns a specific rr of an rrlist.
+ * \param[in] rr_list the rr_list to read from
+ * \param[in] nr return this rr
+ * \return the rr at position nr
+ */
+ldns_rr* ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr);
+
+/**
+ * creates a new rr_list structure.
+ * \return a new rr_list structure
+ */
+ldns_rr_list* ldns_rr_list_new();
+
+/**
+ * frees an rr_list structure.
+ * \param[in] rr_list the list to free
+ */
+void ldns_rr_list_free(ldns_rr_list *rr_list);
+
+/**
+ * frees an rr_list structure and all rrs contained therein.
+ * \param[in] rr_list the list to free
+ */
+void ldns_rr_list_deep_free(ldns_rr_list *rr_list);
+
+/**
+ * concatenates two ldns_rr_lists together. This modifies
+ * *left (to extend it and add the pointers from *right).
+ * \param[in] left the leftside
+ * \param[in] right the rightside
+ * \return a left with right concatenated to it
+ */
+bool ldns_rr_list_cat(ldns_rr_list *left, ldns_rr_list *right);
+
+/**
+ * concatenates two ldns_rr_lists together, but makes clones of the rr's
+ * (instead of pointer copying).
+ * \param[in] left the leftside
+ * \param[in] right the rightside
+ * \return a new rr_list with leftside/rightside concatenated
+ */
+ldns_rr_list* ldns_rr_list_cat_clone(ldns_rr_list *left, ldns_rr_list *right);
+
+/**
+ * pushes an rr to an rrlist.
+ * \param[in] rr_list the rr_list to push to
+ * \param[in] rr the rr to push
+ * \return false on error, otherwise true
+ */
+bool ldns_rr_list_push_rr(ldns_rr_list *rr_list, const ldns_rr *rr);
+
+/**
+ * pushes an rr_list to an rrlist.
+ * \param[in] rr_list the rr_list to push to
+ * \param[in] push_list the rr_list to push
+ * \return false on error, otherwise true
+ */
+bool ldns_rr_list_push_rr_list(ldns_rr_list *rr_list, const ldns_rr_list *push_list);
+
+/**
+ * pops the last rr from an rrlist.
+ * \param[in] rr_list the rr_list to pop from
+ * \return NULL if nothing to pop. Otherwise the popped RR
+ */
+ldns_rr* ldns_rr_list_pop_rr(ldns_rr_list *rr_list);
+
+/**
+ * pops an rr_list of size s from an rrlist.
+ * \param[in] rr_list the rr_list to pop from
+ * \param[in] size the number of rr's to pop
+ * \return NULL if nothing to pop. Otherwise the popped rr_list
+ */
+ldns_rr_list* ldns_rr_list_pop_rr_list(ldns_rr_list *rr_list, size_t size);
+
+/**
+ * returns true if the given rr is one of the rrs in the
+ * list, or if it is equal to one
+ * \param[in] rr_list the rr_list to check
+ * \param[in] rr the rr to check
+ * \return true if rr_list contains rr, false otherwise
+ */
+bool ldns_rr_list_contains_rr(const ldns_rr_list *rr_list, ldns_rr *rr);
+
+/**
+ * checks if an rr_list is a rrset.
+ * \param[in] rr_list the rr_list to check
+ * \return true if it is an rrset otherwise false
+ */
+bool ldns_is_rrset(ldns_rr_list *rr_list);
+
+/**
+ * pushes an rr to an rrset (which really are rr_list's).
+ * \param[in] *rr_list the rrset to push the rr to
+ * \param[in] *rr the rr to push
+ * \return true if the push succeeded otherwise false
+ */
+bool ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr);
+
+/**
+ * pops the last rr from an rrset. This function is there only
+ * for the symmetry.
+ * \param[in] rr_list the rr_list to pop from
+ * \return NULL if nothing to pop. Otherwise the popped RR
+ *
+ */
+ldns_rr* ldns_rr_set_pop_rr(ldns_rr_list *rr_list);
+
+/**
+ * pops the first rrset from the list,
+ * the list must be sorted, so that all rr's from each rrset
+ * are next to each other
+ */
+ldns_rr_list *ldns_rr_list_pop_rrset(ldns_rr_list *rr_list);
+
+
+/**
+ * retrieves a rrtype by looking up its name.
+ * \param[in] name a string with the name
+ * \return the type which corresponds with the name
+ */
+ldns_rr_type ldns_get_rr_type_by_name(const char *name);
+
+/**
+ * retrieves a class by looking up its name.
+ * \param[in] name string with the name
+ * \return the cass which corresponds with the name
+ */
+ldns_rr_class ldns_get_rr_class_by_name(const char *name);
+
+/**
+ * clones a rr and all its data
+ * \param[in] rr the rr to clone
+ * \return the new rr or NULL on failure
+ */
+ldns_rr* ldns_rr_clone(const ldns_rr *rr);
+
+/**
+ * clones an rrlist.
+ * \param[in] rrlist the rrlist to clone
+ * \return the cloned rr list
+ */
+ldns_rr_list* ldns_rr_list_clone(const ldns_rr_list *rrlist);
+
+/**
+ * sorts an rr_list (canonical wire format). the sorting is done inband.
+ * \param[in] unsorted the rr_list to be sorted
+ * \return void
+ */
+void ldns_rr_list_sort(ldns_rr_list *unsorted);
+
+/**
+ * compares two rrs. The TTL is not looked at.
+ * \param[in] rr1 the first one
+ * \param[in] rr2 the second one
+ * \return 0 if equal
+ * -1 if rr1 comes before rr2
+ * +1 if rr2 comes before rr1
+ */
+int ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2);
+
+/**
+ * compares two rrs, up to the rdata.
+ * \param[in] rr1 the first one
+ * \param[in] rr2 the second one
+ * \return 0 if equal
+ * -1 if rr1 comes before rr2
+ * +1 if rr2 comes before rr1
+ */
+int ldns_rr_compare_no_rdata(const ldns_rr *rr1, const ldns_rr *rr2);
+
+/**
+ * compares the wireformat of two rrs, contained in the given buffers.
+ * \param[in] rr1_buf the first one
+ * \param[in] rr2_buf the second one
+ * \return 0 if equal
+ * -1 if rr1_buf comes before rr2_buf
+ * +1 if rr2_buf comes before rr1_buf
+ */
+int ldns_rr_compare_wire(ldns_buffer *rr1_buf, ldns_buffer *rr2_buf);
+
+/**
+ * returns true of the given rr's are equal.
+ * Also returns true if one record is a DS that represents the
+ * same DNSKEY record as the other record
+ * \param[in] rr1 the first rr
+ * \param[in] rr2 the second rr
+ * \return true if equal otherwise false
+ */
+bool ldns_rr_compare_ds(const ldns_rr *rr1, const ldns_rr *rr2);
+
+/**
+ * compares two rr listss.
+ * \param[in] rrl1 the first one
+ * \param[in] rrl2 the second one
+ * \return 0 if equal
+ * -1 if rrl1 comes before rrl2
+ * +1 if rrl2 comes before rrl1
+ */
+int ldns_rr_list_compare(const ldns_rr_list *rrl1, const ldns_rr_list *rrl2);
+
+/**
+ * calculates the uncompressed size of an RR.
+ * \param[in] r the rr to operate on
+ * \return size of the rr
+ */
+size_t ldns_rr_uncompressed_size(const ldns_rr *r);
+
+/**
+ * converts each dname in a rr to its canonical form.
+ * \param[in] rr the rr to work on
+ * \return void
+ */
+void ldns_rr2canonical(ldns_rr *rr);
+
+/**
+ * converts each dname in each rr in a rr_list to its canonical form.
+ * \param[in] rr_list the rr_list to work on
+ * \return void
+ */
+void ldns_rr_list2canonical(ldns_rr_list *rr_list);
+
+/**
+ * counts the number of labels of the ownername.
+ * \param[in] rr count the labels of this rr
+ * \return the number of labels
+ */
+uint8_t ldns_rr_label_count(ldns_rr *rr);
+
+/**
+ * returns the resource record descriptor for the given rr type.
+ *
+ * \param[in] type the type value of the rr type
+ *\return the ldns_rr_descriptor for this type
+ */
+const ldns_rr_descriptor *ldns_rr_descript(uint16_t type);
+
+/**
+ * returns the minimum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in] descriptor for an rr type
+ * \return the minimum number of rdata fields
+ */
+size_t ldns_rr_descriptor_minimum(const ldns_rr_descriptor *descriptor);
+
+/**
+ * returns the maximum number of rdata fields of the rr type this descriptor describes.
+ *
+ * \param[in] descriptor for an rr type
+ * \return the maximum number of rdata fields
+ */
+size_t ldns_rr_descriptor_maximum(const ldns_rr_descriptor *descriptor);
+
+/**
+ * returns the rdf type for the given rdata field number of the rr type for the given descriptor.
+ *
+ * \param[in] descriptor for an rr type
+ * \param[in] field the field number
+ * \return the rdf type for the field
+ */
+ldns_rdf_type ldns_rr_descriptor_field_type(const ldns_rr_descriptor *descriptor, size_t field);
+
+/**
+ * Return the rr_list which matches the rdf at position field. Think
+ * type-covered stuff for RRSIG
+ *
+ * \param[in] l the rr_list to look in
+ * \param[in] r the rdf to use for the comparison
+ * \param[in] pos at which position can we find the rdf
+ *
+ * \return a new rr list with only the RRs that match
+ *
+ */
+ldns_rr_list *ldns_rr_list_subtype_by_rdf(ldns_rr_list *l, ldns_rdf *r, size_t pos);
+
+/**
+ * convert an rdf of type LDNS_RDF_TYPE_TYPE to an actual
+ * LDNS_RR_TYPE. This is usefull in the case when inspecting
+ * the rrtype covered field of an RRSIG.
+ * \param[in] rd the rdf to look at
+ * \return a ldns_rr_type with equivalent LDNS_RR_TYPE
+ *
+ */
+ldns_rr_type ldns_rdf2rr_type(const ldns_rdf *rd);
+
+/**
+ * Returns the type of the first element of the RR
+ * If there are no elements present, 0 is returned
+ *
+ * \param[in] rr_list The rr list
+ * \return rr_type of the first element, or 0 if the list is empty
+ */
+ldns_rr_type
+ldns_rr_list_type(const ldns_rr_list *rr_list);
+
+/**
+ * Returns the owner domain name rdf of the first element of the RR
+ * If there are no elements present, NULL is returned
+ *
+ * \param[in] rr_list The rr list
+ * \return dname of the first element, or NULL if the list is empty
+ */
+ldns_rdf *
+ldns_rr_list_owner(const ldns_rr_list *rr_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RR_H */
diff --git a/3rdParty/Ldns/src/include/ldns/rr_functions.h b/3rdParty/Ldns/src/include/ldns/rr_functions.h
new file mode 100644
index 0000000..3db3b3d
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/rr_functions.h
@@ -0,0 +1,363 @@
+/*
+ * rr_functions.h
+ *
+ * the .h file with defs for the per rr
+ * functions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+#ifndef LDNS_RR_FUNCTIONS_H
+#define LDNS_RR_FUNCTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file
+ *
+ * Defines some extra convenience functions for ldns_rr structures
+ */
+
+/* A / AAAA */
+/**
+ * returns the address of a LDNS_RR_TYPE_A rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the address or NULL on failure
+ */
+ldns_rdf* ldns_rr_a_address(const ldns_rr *r);
+
+/**
+ * sets the address of a LDNS_RR_TYPE_A rr
+ * \param[in] r the rr to use
+ * \param[in] f the address to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_a_set_address(ldns_rr *r, ldns_rdf *f);
+
+/* NS */
+/**
+ * returns the name of a LDNS_RR_TYPE_NS rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the name or NULL on failure
+ */
+ldns_rdf* ldns_rr_ns_nsdname(const ldns_rr *r);
+
+/* MX */
+/**
+ * returns the mx pref. of a LDNS_RR_TYPE_MX rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the preference or NULL on failure
+ */
+ldns_rdf* ldns_rr_mx_preference(const ldns_rr *r);
+/**
+ * returns the mx host of a LDNS_RR_TYPE_MX rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the name of the MX host or NULL on failure
+ */
+ldns_rdf* ldns_rr_mx_exchange(const ldns_rr *r);
+
+/* RRSIG */
+/**
+ * returns the type covered of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the type covered or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_typecovered(const ldns_rr *r);
+/**
+ * sets the typecovered of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the typecovered to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_typecovered(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the algorithm of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the algorithm or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_algorithm(const ldns_rr *r);
+/**
+ * sets the algorithm of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the algorithm to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_algorithm(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the number of labels of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the number of labels or NULL on failure
+ */
+ldns_rdf *ldns_rr_rrsig_labels(const ldns_rr *r);
+/**
+ * sets the number of labels of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the number of labels to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_labels(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the original TTL of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the original TTL or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_origttl(const ldns_rr *r);
+/**
+ * sets the original TTL of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the original TTL to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the expiration time of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the expiration time or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_expiration(const ldns_rr *r);
+/**
+ * sets the expireation date of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the expireation date to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the inception time of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the inception time or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_inception(const ldns_rr *r);
+/**
+ * sets the inception date of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the inception date to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_inception(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the keytag of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the keytag or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_keytag(const ldns_rr *r);
+/**
+ * sets the keytag of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the keytag to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_keytag(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the signers name of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the signers name or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_signame(const ldns_rr *r);
+/**
+ * sets the signers name of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the signers name to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_signame(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the signature data of a LDNS_RR_TYPE_RRSIG RR
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the signature data or NULL on failure
+ */
+ldns_rdf* ldns_rr_rrsig_sig(const ldns_rr *r);
+/**
+ * sets the signature data of a LDNS_RR_TYPE_RRSIG rr
+ * \param[in] r the rr to use
+ * \param[in] f the signature data to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_rrsig_set_sig(ldns_rr *r, ldns_rdf *f);
+
+/* DNSKEY */
+/**
+ * returns the flags of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the flags or NULL on failure
+ */
+ldns_rdf* ldns_rr_dnskey_flags(const ldns_rr *r);
+/**
+ * sets the flags of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the rr to use
+ * \param[in] f the flags to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_dnskey_set_flags(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the protocol of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the protocol or NULL on failure
+ */
+ldns_rdf* ldns_rr_dnskey_protocol(const ldns_rr *r);
+/**
+ * sets the protocol of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the rr to use
+ * \param[in] f the protocol to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_dnskey_set_protocol(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the algorithm of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the algorithm or NULL on failure
+ */
+ldns_rdf* ldns_rr_dnskey_algorithm(const ldns_rr *r);
+/**
+ * sets the algorithm of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the rr to use
+ * \param[in] f the algorithm to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_dnskey_set_algorithm(ldns_rr *r, ldns_rdf *f);
+/**
+ * returns the key data of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the resource record
+ * \return a ldns_rdf* with the key data or NULL on failure
+ */
+ldns_rdf* ldns_rr_dnskey_key(const ldns_rr *r);
+/**
+ * sets the key data of a LDNS_RR_TYPE_DNSKEY rr
+ * \param[in] r the rr to use
+ * \param[in] f the key data to set
+ * \return true on success, false otherwise
+ */
+bool ldns_rr_dnskey_set_key(ldns_rr *r, ldns_rdf *f);
+
+/**
+ * get the length of the keydata in bits
+ * \param[in] keydata the raw key data
+ * \param[in] len the length of the keydata
+ * \param[in] alg the cryptographic algorithm this is a key for
+ * \return the keysize in bits, or 0 on error
+ */
+size_t ldns_rr_dnskey_key_size_raw(const unsigned char *keydata,
+ const size_t len,
+ const ldns_algorithm alg);
+
+/**
+ * get the length of the keydata in bits
+ * \param[in] key the key rr to use
+ * \return the keysize in bits
+ */
+size_t ldns_rr_dnskey_key_size(const ldns_rr *key);
+
+/**
+ * The type of function to be passed to ldns_rr_soa_increment_func,
+ * ldns_rr_soa_increment_func_data or ldns_rr_soa_increment_int.
+ * The function will be called with as the first argument the current serial
+ * number of the SOA RR to be updated, and as the second argument a value
+ * given when calling ldns_rr_soa_increment_func_data or
+ * ldns_rr_soa_increment_int. With ldns_rr_soa_increment_int the pointer
+ * value holds the integer value passed to ldns_rr_soa_increment_int,
+ * and it should be cast to intptr_t to be used as an integer by the
+ * serial modifying function.
+ */
+typedef uint32_t (*ldns_soa_serial_increment_func_t)(uint32_t, void*);
+
+/**
+ * Function to be used with dns_rr_soa_increment_func_int, to set the soa
+ * serial number.
+ * \param[in] _ the (unused) current serial number.
+ * \param[in] data the serial number to be set.
+ */
+uint32_t ldns_soa_serial_identity(uint32_t _, void *data);
+
+/**
+ * Function to be used with dns_rr_soa_increment_func, to increment the soa
+ * serial number with one.
+ * \param[in] s the current serial number.
+ * \param[in] _ unused.
+ */
+uint32_t ldns_soa_serial_increment(uint32_t s, void *_);
+
+/**
+ * Function to be used with dns_rr_soa_increment_func_int, to increment the soa
+ * serial number with a certain amount.
+ * \param[in] s the current serial number.
+ * \param[in] data the amount to add to the current serial number.
+ */
+uint32_t ldns_soa_serial_increment_by(uint32_t s, void *data);
+
+/**
+ * Function to be used with ldns_rr_soa_increment_func or
+ * ldns_rr_soa_increment_func_int to set the soa serial to the number of
+ * seconds since unix epoch (1-1-1970 00:00).
+ * When data is given (i.e. the function is called via
+ * ldns_rr_soa_increment_func_int), it is used as the current time.
+ * When the resulting serial number is smaller than the current serial number,
+ * the current serial number is increased by one.
+ * \param[in] s the current serial number.
+ * \param[in] data the time in seconds since 1-1-1970 00:00
+ */
+uint32_t ldns_soa_serial_unixtime(uint32_t s, void *data);
+
+/**
+ * Function to be used with ldns_rr_soa_increment_func or
+ * ldns_rr_soa_increment_func_int to set the soa serial to the current date
+ * succeeded by a two digit iteration (datecounter).
+ * When data is given (i.e. the function is called via
+ * ldns_rr_soa_increment_func_int), it is used as the current time.
+ * When the resulting serial number is smaller than the current serial number,
+ * the current serial number is increased by one.
+ * \param[in] s the current serial number.
+ * \param[in] data the time in seconds since 1-1-1970 00:00
+ */
+uint32_t ldns_soa_serial_datecounter(uint32_t s, void *data);
+
+/**
+ * Increment the serial number of the given SOA by one.
+ * \param[in] soa The soa rr to be incremented
+ */
+void ldns_rr_soa_increment(
+ ldns_rr *soa);
+
+/**
+ * Increment the serial number of the given SOA with the given function.
+ * Included functions to be used here are: ldns_rr_soa_increment,
+ * ldns_soa_serial_unixtime and ldns_soa_serial_datecounter.
+ * \param[in] soa The soa rr to be incremented
+ * \param[in] f the function to use to increment the soa rr.
+ */
+void ldns_rr_soa_increment_func(
+ ldns_rr *soa, ldns_soa_serial_increment_func_t f);
+
+/**
+ * Increment the serial number of the given SOA with the given function
+ * passing it the given data argument.
+ * \param[in] soa The soa rr to be incremented
+ * \param[in] f the function to use to increment the soa rr.
+ * \param[in] data this argument will be passed to f as the second argument.
+ */
+void ldns_rr_soa_increment_func_data(
+ ldns_rr *soa, ldns_soa_serial_increment_func_t f, void *data);
+
+/**
+ * Increment the serial number of the given SOA with the given function
+ * using data as an argument for the function.
+ * Included functions to be used here are: ldns_soa_serial_identity,
+ * ldns_rr_soa_increment_by, ldns_soa_serial_unixtime and
+ * ldns_soa_serial_datecounter.
+ * \param[in] soa The soa rr to be incremented
+ * \param[in] f the function to use to increment the soa rr.
+ * \param[in] data this argument will be passed to f as the second argument
+ * (by casting it to void*).
+ */
+void ldns_rr_soa_increment_func_int(
+ ldns_rr *soa, ldns_soa_serial_increment_func_t f, int data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_RR_FUNCTIONS_H */
diff --git a/3rdParty/Ldns/src/include/ldns/sha1.h b/3rdParty/Ldns/src/include/ldns/sha1.h
new file mode 100644
index 0000000..d5b1082
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/sha1.h
@@ -0,0 +1,38 @@
+#ifndef LDNS_SHA1_H
+#define LDNS_SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDNS_SHA1_BLOCK_LENGTH 64
+#define LDNS_SHA1_DIGEST_LENGTH 20
+
+typedef struct {
+ uint32_t state[5];
+ uint64_t count;
+ unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH];
+} ldns_sha1_ctx;
+
+void ldns_sha1_init(ldns_sha1_ctx * context);
+void ldns_sha1_transform(uint32_t state[5], const unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH]);
+void ldns_sha1_update(ldns_sha1_ctx *context, const unsigned char *data, unsigned int len);
+void ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ctx *context);
+
+/**
+ * Convenience function to digest a fixed block of data at once.
+ *
+ * \param[in] data the data to digest
+ * \param[in] data_len the length of data in bytes
+ * \param[out] digest the length of data in bytes
+ * This pointer MUST have LDNS_SHA1_DIGEST_LENGTH bytes
+ * available
+ * \return the SHA1 digest of the given data
+ */
+unsigned char *ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_SHA1_H */
diff --git a/3rdParty/Ldns/src/include/ldns/sha2.h b/3rdParty/Ldns/src/include/ldns/sha2.h
new file mode 100644
index 0000000..238767a
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/sha2.h
@@ -0,0 +1,149 @@
+/*
+ * FILE: sha2.h
+ * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
+ *
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Modified by Jelte Jansen to fit in ldns, and not clash with any
+ * system-defined SHA code.
+ * Changes:
+ * - Renamed (external) functions and constants to fit ldns style
+ * - Removed uintXX vs. u_intXX smartness, since ldns needs uintXX
+ * anyway
+ * - BYTE ORDER check replaced by simple ifdef as defined or not by
+ * configure.ac
+ * - Removed _End and _Data functions
+ * - Added ldns_shaX(data, len, digest) functions
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
+ */
+
+#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>
+
+#if LDNS_BUILD_CONFIG_HAVE_INTTYPES_H
+
+#include <inttypes.h>
+
+#endif /* LDNS_BUILD_CONFIG_HAVE_INTTYPES_H */
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define LDNS_SHA256_BLOCK_LENGTH 64
+#define LDNS_SHA256_DIGEST_LENGTH 32
+#define LDNS_SHA256_DIGEST_STRING_LENGTH (LDNS_SHA256_DIGEST_LENGTH * 2 + 1)
+#define LDNS_SHA384_BLOCK_LENGTH 128
+#define LDNS_SHA384_DIGEST_LENGTH 48
+#define LDNS_SHA384_DIGEST_STRING_LENGTH (LDNS_SHA384_DIGEST_LENGTH * 2 + 1)
+#define LDNS_SHA512_BLOCK_LENGTH 128
+#define LDNS_SHA512_DIGEST_LENGTH 64
+#define LDNS_SHA512_DIGEST_STRING_LENGTH (LDNS_SHA512_DIGEST_LENGTH * 2 + 1)
+
+
+/*** SHA-256/384/512 Context Structures *******************************/
+
+typedef struct _ldns_sha256_CTX {
+ uint32_t state[8];
+ uint64_t bitcount;
+ uint8_t buffer[LDNS_SHA256_BLOCK_LENGTH];
+} ldns_sha256_CTX;
+typedef struct _ldns_sha512_CTX {
+ uint64_t state[8];
+ uint64_t bitcount[2];
+ uint8_t buffer[LDNS_SHA512_BLOCK_LENGTH];
+} ldns_sha512_CTX;
+
+typedef ldns_sha512_CTX ldns_sha384_CTX;
+
+
+/*** SHA-256/384/512 Function Prototypes ******************************/
+void ldns_sha256_init(ldns_sha256_CTX *);
+void ldns_sha256_update(ldns_sha256_CTX*, const uint8_t*, size_t);
+void ldns_sha256_final(uint8_t[LDNS_SHA256_DIGEST_LENGTH], ldns_sha256_CTX*);
+
+void ldns_sha384_init(ldns_sha384_CTX*);
+void ldns_sha384_update(ldns_sha384_CTX*, const uint8_t*, size_t);
+void ldns_sha384_final(uint8_t[LDNS_SHA384_DIGEST_LENGTH], ldns_sha384_CTX*);
+
+void ldns_sha512_init(ldns_sha512_CTX*);
+void ldns_sha512_update(ldns_sha512_CTX*, const uint8_t*, size_t);
+void ldns_sha512_final(uint8_t[LDNS_SHA512_DIGEST_LENGTH], ldns_sha512_CTX*);
+
+/**
+ * Convenience function to digest a fixed block of data at once.
+ *
+ * \param[in] data the data to digest
+ * \param[in] data_len the length of data in bytes
+ * \param[out] digest the length of data in bytes
+ * This pointer MUST have LDNS_SHA256_DIGEST_LENGTH bytes
+ * available
+ * \return the SHA1 digest of the given data
+ */
+unsigned char *ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest);
+
+/**
+ * Convenience function to digest a fixed block of data at once.
+ *
+ * \param[in] data the data to digest
+ * \param[in] data_len the length of data in bytes
+ * \param[out] digest the length of data in bytes
+ * This pointer MUST have LDNS_SHA384_DIGEST_LENGTH bytes
+ * available
+ * \return the SHA1 digest of the given data
+ */
+unsigned char *ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest);
+
+/**
+ * Convenience function to digest a fixed block of data at once.
+ *
+ * \param[in] data the data to digest
+ * \param[in] data_len the length of data in bytes
+ * \param[out] digest the length of data in bytes
+ * This pointer MUST have LDNS_SHA512_DIGEST_LENGTH bytes
+ * available
+ * \return the SHA1 digest of the given data
+ */
+unsigned char *ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __LDNS_SHA2_H__ */
diff --git a/3rdParty/Ldns/src/include/ldns/str2host.h b/3rdParty/Ldns/src/include/ldns/str2host.h
new file mode 100644
index 0000000..09416cd
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/str2host.h
@@ -0,0 +1,251 @@
+/**
+ * str2host.h - conversion from str to the host fmt
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef LDNS_2HOST_H
+#define LDNS_2HOST_H
+
+#include <ldns/common.h>
+#include <ldns/error.h>
+#include <ldns/rr.h>
+#include <ldns/rdata.h>
+#include <ldns/packet.h>
+#include <ldns/buffer.h>
+#include <ctype.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file
+ *
+ * Defines functions to convert dns data in presentation format or text files
+ * to internal structures.
+ */
+
+/**
+ * convert a byte into wireformat
+ * \param[in] rd the rdf where to put the data
+ * \param[in] bytestr the string to be converted
+ * \return ldns_status
+ */
+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[in] shortstr the string to be converted
+ * \return ldns_status
+ */
+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[in] longstr the string to be converted
+ * \return ldns_status
+ */
+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[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[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[in] str the string to be converted
+ * return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted (NULL terminated)
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str);
+
+/**
+ * convert and algorithm value into wireformat
+ * \param[in] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_alg(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[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_unknown(ldns_rdf **rd, const char *str);
+
+/**
+ * convert string with a tsig? RR into wireformat
+ * \param[in] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_tsig(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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+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[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_dname(ldns_rdf **rd, const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_2HOST_H */
diff --git a/3rdParty/Ldns/src/include/ldns/tsig.h b/3rdParty/Ldns/src/include/ldns/tsig.h
new file mode 100644
index 0000000..676045f
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/tsig.h
@@ -0,0 +1,101 @@
+/*
+ * tsig.h -- defines for TSIG [RFC2845]
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ */
+
+#ifndef LDNS_TSIG_H
+#define LDNS_TSIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file
+ *
+ * Defines functions for TSIG usage
+ */
+
+
+/**
+ * Contains credentials for TSIG
+*/
+typedef struct ldns_tsig_credentials_struct
+{
+ char *algorithm;
+ char *keyname;
+ char *keydata;
+ /* XXX More eventually. */
+} ldns_tsig_credentials;
+
+char *ldns_tsig_algorithm(ldns_tsig_credentials *);
+char *ldns_tsig_keyname(ldns_tsig_credentials *);
+char *ldns_tsig_keydata(ldns_tsig_credentials *);
+char *ldns_tsig_keyname_clone(ldns_tsig_credentials *);
+char *ldns_tsig_keydata_clone(ldns_tsig_credentials *);
+
+/**
+ * verifies the tsig rr for the given packet and key.
+ * The wire must be given too because tsig does not sign normalized packets.
+ * \param[in] pkt the packet to verify
+ * \param[in] wire needed to verify the mac
+ * \param[in] wire_size size of wire
+ * \param[in] key_name the name of the shared key
+ * \param[in] key_data the key in base 64 format
+ * \param[in] mac original mac
+ * \return true if tsig is correct, false if not, or if tsig is not set
+ */
+bool ldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wire_size, const char *key_name, const char *key_data, ldns_rdf *mac);
+
+/**
+ * verifies the tsig rr for the given packet and key.
+ * The wire must be given too because tsig does not sign normalized packets.
+ * \param[in] pkt the packet to verify
+ * \param[in] wire needed to verify the mac
+ * \param[in] wire_size size of wire
+ * \param[in] key_name the name of the shared key
+ * \param[in] key_data the key in base 64 format
+ * \param[in] mac original mac
+ * \param[in] tsig_timers_only must be zero for the first packet and positive for subsequent packets. If zero, all digest
+ components are used to verify the _mac. If non-zero, only the TSIG timers are used to verify the mac.
+ * \return true if tsig is correct, false if not, or if tsig is not set
+ */
+bool ldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wire_size, const char *key_name, const char *key_data, ldns_rdf *mac,
+ int tsig_timers_only);
+
+/**
+ * creates a tsig rr for the given packet and key.
+ * \param[in] pkt the packet to sign
+ * \param[in] key_name the name of the shared key
+ * \param[in] key_data the key in base 64 format
+ * \param[in] fudge seconds of error permitted in time signed
+ * \param[in] algorithm_name the name of the algorithm used
+ * \param[in] query_mac is added to the digest if not NULL (so NULL is for signing queries, not NULL is for signing answers)
+ * \return status (OK if success)
+ */
+ldns_status ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge,
+ const char *algorithm_name, ldns_rdf *query_mac);
+
+/**
+ * creates a tsig rr for the given packet and key.
+ * \param[in] pkt the packet to sign
+ * \param[in] key_name the name of the shared key
+ * \param[in] key_data the key in base 64 format
+ * \param[in] fudge seconds of error permitted in time signed
+ * \param[in] algorithm_name the name of the algorithm used
+ * \param[in] query_mac is added to the digest if not NULL (so NULL is for signing queries, not NULL is for signing answers)
+ * \param[in] tsig_timers_only must be zero for the first packet and positive for subsequent packets. If zero, all digest
+ components are used to create the query_mac. If non-zero, only the TSIG timers are used to create the query_mac.
+ * \return status (OK if success)
+ */
+ldns_status ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge,
+ const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_TSIG_H */
diff --git a/3rdParty/Ldns/src/include/ldns/update.h b/3rdParty/Ldns/src/include/ldns/update.h
new file mode 100644
index 0000000..d3459d3
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/update.h
@@ -0,0 +1,115 @@
+/*
+ * update.h
+ *
+ * Functions for RFC 2136 Dynamic Update
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ */
+
+/**
+ * \file
+ *
+ * Defines functions to perform UPDATE queries
+ */
+
+
+#ifndef LDNS_UPDATE_H
+#define LDNS_UPDATE_H
+
+#include <ldns/resolver.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * create an update packet from zone name, class and the rr lists
+ * \param[in] zone_rdf name of the zone
+ * \param[in] clas zone class
+ * \param[in] pr_rrlist list of Prerequisite Section RRs
+ * \param[in] up_rrlist list of Updates Section RRs
+ * \param[in] ad_rrlist list of Additional Data Section RRs (currently unused)
+ * \return the new packet
+ */
+ldns_pkt *ldns_update_pkt_new(ldns_rdf *zone_rdf, ldns_rr_class clas, ldns_rr_list *pr_rrlist, ldns_rr_list *up_rrlist, ldns_rr_list *ad_rrlist);
+
+/**
+ * add tsig credentials to
+ * a packet from a resolver
+ * \param[in] p packet to copy to
+ * \param[in] r resolver to copy from
+ *
+ * \return status wether successfull or not
+ */
+ldns_status ldns_update_pkt_tsig_add(ldns_pkt *p, ldns_resolver *r);
+
+/* access functions */
+
+/**
+ * Get the zo count
+ * \param[in] p the packet
+ * \return the zo count
+ */
+uint16_t ldns_update_zocount(const ldns_pkt *p);
+/**
+ * Get the zo count
+ * \param[in] p the packet
+ * \return the pr count
+ */
+uint16_t ldns_update_prcount(const ldns_pkt *p);
+/**
+ * Get the zo count
+ * \param[in] p the packet
+ * \return the up count
+ */
+uint16_t ldns_update_upcount(const ldns_pkt *p);
+/**
+ * Get the zo count
+ * \param[in] p the packet
+ * \return the ad count
+ */
+uint16_t ldns_update_ad(const ldns_pkt *p);
+/**
+ * Set the zo count
+ * \param[in] p the packet
+ * \param[in] c the zo count to set
+ */
+void ldns_update_set_zo(ldns_pkt *p, uint16_t c);
+/**
+ * Set the pr count
+ * \param[in] p the packet
+ * \param[in] c the pr count to set
+ */
+void ldns_update_set_prcount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the up count
+ * \param[in] p the packet
+ * \param[in] c the up count to set
+ */
+void ldns_update_set_upcount(ldns_pkt *p, uint16_t c);
+/**
+ * Set the ad count
+ * \param[in] p the packet
+ * \param[in] c the ad count to set
+ */
+void ldns_update_set_adcount(ldns_pkt *p, uint16_t c);
+
+/* soa functions that need to be configured */
+/*
+ * Not sure if we want to keep these like this, therefore
+ * not documented
+ */
+ldns_status ldns_update_soa_mname(ldns_rdf *zone, ldns_resolver *r, ldns_rr_class c, ldns_rdf **mname);
+/*
+ * Not sure if we want to keep these like this, therefore
+ * not documented
+ */
+ldns_status ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r, ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_UPDATE_H */
diff --git a/3rdParty/Ldns/src/include/ldns/util.h b/3rdParty/Ldns/src/include/ldns/util.h
new file mode 100644
index 0000000..eb7658e
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/util.h
@@ -0,0 +1,367 @@
+/*
+ * util.h
+ *
+ * helper function header file
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ldns/common.h>
+#include <time.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define dprintf(X,Y) fprintf(stderr, (X), (Y))
+/* #define dprintf(X, Y) */
+
+#define LDNS_VERSION "1.6.12"
+#define LDNS_REVISION ((1<<16)|(6<<8)|(12))
+
+/**
+ * splint static inline workaround
+ */
+#ifdef S_SPLINT_S
+# define INLINE
+#else
+# ifdef SWIG
+# define INLINE static
+# else
+# define INLINE static inline
+# endif
+#endif
+
+/**
+ * Memory management macros
+ */
+#define LDNS_MALLOC(type) LDNS_XMALLOC(type, 1)
+
+#define LDNS_XMALLOC(type, count) ((type *) malloc((count) * sizeof(type)))
+
+#define LDNS_CALLOC(type, count) ((type *) calloc((count), sizeof(type)))
+
+#define LDNS_REALLOC(ptr, type) LDNS_XREALLOC((ptr), type, 1)
+
+#define LDNS_XREALLOC(ptr, type, count) \
+ ((type *) realloc((ptr), (count) * sizeof(type)))
+
+#define LDNS_FREE(ptr) \
+ do { free((ptr)); (ptr) = NULL; } while (0)
+
+#define LDNS_DEP printf("DEPRECATED FUNCTION!\n");
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE uint16_t
+ldns_read_uint16(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohs(*(uint16_t *) src);
+#else
+ uint8_t *p = (uint8_t *) src;
+ return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+#endif
+}
+
+INLINE uint32_t
+ldns_read_uint32(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohl(*(uint32_t *) src);
+#else
+ uint8_t *p = (uint8_t *) src;
+ return ( ((uint32_t) p[0] << 24)
+ | ((uint32_t) p[1] << 16)
+ | ((uint32_t) p[2] << 8)
+ | (uint32_t) p[3]);
+#endif
+}
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE void
+ldns_write_uint16(void *dst, uint16_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint16_t *) dst = htons(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 8) & 0xff);
+ p[1] = (uint8_t) (data & 0xff);
+#endif
+}
+
+INLINE void
+ldns_write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint32_t *) dst = htonl(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 24) & 0xff);
+ p[1] = (uint8_t) ((data >> 16) & 0xff);
+ p[2] = (uint8_t) ((data >> 8) & 0xff);
+ p[3] = (uint8_t) (data & 0xff);
+#endif
+}
+
+/* warning. */
+INLINE void
+ldns_write_uint64_as_uint48(void *dst, uint64_t data)
+{
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 40) & 0xff);
+ p[1] = (uint8_t) ((data >> 32) & 0xff);
+ p[2] = (uint8_t) ((data >> 24) & 0xff);
+ p[3] = (uint8_t) ((data >> 16) & 0xff);
+ p[4] = (uint8_t) ((data >> 8) & 0xff);
+ p[5] = (uint8_t) (data & 0xff);
+}
+
+
+/**
+ * Structure to do a Schwartzian-like transformation, for instance when
+ * sorting. If you need a transformation on the objects that are sorted,
+ * you can sue this to store the transformed values, so you do not
+ * need to do the transformation again for each comparison
+ */
+struct ldns_schwartzian_compare_struct {
+ void *original_object;
+ void *transformed_object;
+};
+
+/** A general purpose lookup table
+ *
+ * Lookup tables are arrays of (id, name) pairs,
+ * So you can for instance lookup the RCODE 3, which is "NXDOMAIN",
+ * and vice versa. The lookup tables themselves are defined wherever needed,
+ * for instance in \ref host2str.c
+ */
+struct ldns_struct_lookup_table {
+ int id;
+ const char *name;
+};
+typedef struct ldns_struct_lookup_table ldns_lookup_table;
+
+/**
+ * Looks up the table entry by name, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] name what to search for
+ * \return the item found
+ */
+ldns_lookup_table *ldns_lookup_by_name(ldns_lookup_table table[],
+ const char *name);
+
+/**
+ * Looks up the table entry by id, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] id what to search for
+ * \return the item found
+ */
+ldns_lookup_table *ldns_lookup_by_id(ldns_lookup_table table[], int id);
+
+/**
+ * Returns the value of the specified bit
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ * \param[in] bits array holding the bits
+ * \param[in] index to the wanted bit
+ * \return
+ */
+int ldns_get_bit(uint8_t bits[], size_t index);
+
+
+/**
+ * Returns the value of the specified bit
+ * The bits are counted from right to left, so bit #0 is the
+ * right most bit.
+ * \param[in] bits array holding the bits
+ * \param[in] index to the wanted bit
+ * \return 1 or 0 depending no the bit state
+ */
+int ldns_get_bit_r(uint8_t bits[], size_t index);
+
+/**
+ * sets the specified bit in the specified byte to
+ * 1 if value is true, 0 if false
+ * The bits are counted from right to left, so bit #0 is the
+ * right most bit.
+ * \param[in] byte the bit to set the bit in
+ * \param[in] bit_nr the bit to set (0 <= n <= 7)
+ * \param[in] value whether to set the bit to 1 or 0
+ * \return 1 or 0 depending no the bit state
+ */
+void ldns_set_bit(uint8_t *byte, int bit_nr, bool value);
+
+/**
+ * Returns the value of a to the power of b
+ * (or 1 of b < 1)
+ */
+/*@unused@*/
+INLINE long
+ldns_power(long a, long b) {
+ long result = 1;
+ while (b > 0) {
+ if (b & 1) {
+ result *= a;
+ if (b == 1) {
+ return result;
+ }
+ }
+ a *= a;
+ b /= 2;
+ }
+ return result;
+}
+
+/**
+ * Returns the int value of the given (hex) digit
+ * \param[in] ch the hex char to convert
+ * \return the converted decimal value
+ */
+int ldns_hexdigit_to_int(char ch);
+
+/**
+ * Returns the char (hex) representation of the given int
+ * \param[in] ch the int to convert
+ * \return the converted hex char
+ */
+char ldns_int_to_hexdigit(int ch);
+
+/**
+ * Converts a hex string to binary data
+ *
+ * \param[out] data The binary result is placed here.
+ * At least strlen(str)/2 bytes should be allocated
+ * \param[in] str The hex string to convert.
+ * This string should not contain spaces
+ * \return The number of bytes of converted data, or -1 if one of the arguments * is NULL, or -2 if the string length is not an even number
+ */
+int
+ldns_hexstring_to_data(uint8_t *data, const char *str);
+
+/**
+ * Show the internal library version
+ * \return a string with the version in it
+ */
+const char * ldns_version(void);
+
+/**
+ * Convert TM to seconds since epoch (midnight, January 1st, 1970).
+ * Like timegm(3), which is not always available.
+ * \param[in] tm a struct tm* with the date
+ * \return the seconds since epoch
+ */
+time_t mktime_from_utc(const struct tm *tm);
+
+/**
+ * The function interprets time as the number of seconds since epoch
+ * with respect to now using serial arithmitics (rfc1982).
+ * That number of seconds is then converted to broken-out time information.
+ * This is especially usefull when converting the inception and expiration
+ * fields of RRSIG records.
+ *
+ * \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
+ * to be intepreted as a serial arithmitics number relative to now.
+ * \param[in] now number of seconds since epoch (midnight, January 1st, 1970)
+ * to which the time value is compared to determine the final value.
+ * \param[out] result the struct with the broken-out time information
+ * \return result on success or NULL on error
+ */
+struct tm * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/**
+ * Seed the random function.
+ * If the file descriptor is specified, the random generator is seeded with
+ * data from that file. If not, /dev/urandom is used.
+ *
+ * applications should call this if they need entropy data within ldns
+ * If openSSL is available, it is automatically seeded from /dev/urandom
+ * or /dev/random.
+ *
+ * If you need more entropy, or have no openssl available, this function
+ * MUST be called at the start of the program
+ *
+ * If openssl *is* available, this function just adds more entropy
+ *
+ * \param[in] fd a file providing entropy data for the seed
+ * \param[in] size the number of bytes to use as entropy data. If this is 0,
+ * only the minimal amount is taken (usually 4 bytes)
+ * \return 0 if seeding succeeds, 1 if it fails
+ */
+int ldns_init_random(FILE *fd, unsigned int size);
+
+/**
+ * Get random number.
+ * \return random number.
+ *
+ */
+uint16_t ldns_get_random(void);
+
+/**
+ * Encode data as BubbleBabble
+ *
+ * \param[in] data a pointer to data to be encoded
+ * \param[in] len size the number of bytes of data
+ * \return a string of BubbleBabble
+ */
+char *ldns_bubblebabble(uint8_t *data, size_t len);
+
+#ifndef B32_NTOP
+int ldns_b32_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int b32_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int ldns_b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_ntop
+ */
+/*@unused@*/
+INLINE size_t ldns_b32_ntop_calculate_size(size_t srcsize)
+{
+ size_t result = ((((srcsize / 5) * 8) - 2) + 2);
+ return result;
+}
+#endif /* !B32_NTOP */
+#ifndef B32_PTON
+int ldns_b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int ldns_b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_pton
+ */
+/*@unused@*/
+INLINE size_t ldns_b32_pton_calculate_size(size_t srcsize)
+{
+ size_t result = ((((srcsize) / 8) * 5));
+ return result;
+}
+#endif /* !B32_PTON */
+
+INLINE time_t ldns_time(time_t *t) { return time(t); }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_UTIL_H */
diff --git a/3rdParty/Ldns/src/include/ldns/util.h.in b/3rdParty/Ldns/src/include/ldns/util.h.in
new file mode 100644
index 0000000..f9fb104
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/util.h.in
@@ -0,0 +1,367 @@
+/*
+ * util.h
+ *
+ * helper function header file
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004
+ *
+ * See the file LICENSE for the license
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+@include_inttypes_h@
+@include_systypes_h@
+@include_unistd_h@
+#include <ldns/common.h>
+#include <time.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define dprintf(X,Y) fprintf(stderr, (X), (Y))
+/* #define dprintf(X, Y) */
+
+#define LDNS_VERSION "@PACKAGE_VERSION@"
+#define LDNS_REVISION ((@LDNS_VERSION_MAJOR@<<16)|(@LDNS_VERSION_MINOR@<<8)|(@LDNS_VERSION_MICRO@))
+
+/**
+ * splint static inline workaround
+ */
+#ifdef S_SPLINT_S
+# define INLINE
+#else
+# ifdef SWIG
+# define INLINE static
+# else
+# define INLINE static inline
+# endif
+#endif
+
+/**
+ * Memory management macros
+ */
+#define LDNS_MALLOC(type) LDNS_XMALLOC(type, 1)
+
+#define LDNS_XMALLOC(type, count) ((type *) malloc((count) * sizeof(type)))
+
+#define LDNS_CALLOC(type, count) ((type *) calloc((count), sizeof(type)))
+
+#define LDNS_REALLOC(ptr, type) LDNS_XREALLOC((ptr), type, 1)
+
+#define LDNS_XREALLOC(ptr, type, count) \
+ ((type *) realloc((ptr), (count) * sizeof(type)))
+
+#define LDNS_FREE(ptr) \
+ do { free((ptr)); (ptr) = NULL; } while (0)
+
+#define LDNS_DEP printf("DEPRECATED FUNCTION!\n");
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE uint16_t
+ldns_read_uint16(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohs(*(uint16_t *) src);
+#else
+ uint8_t *p = (uint8_t *) src;
+ return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+#endif
+}
+
+INLINE uint32_t
+ldns_read_uint32(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ return ntohl(*(uint32_t *) src);
+#else
+ uint8_t *p = (uint8_t *) src;
+ return ( ((uint32_t) p[0] << 24)
+ | ((uint32_t) p[1] << 16)
+ | ((uint32_t) p[2] << 8)
+ | (uint32_t) p[3]);
+#endif
+}
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE void
+ldns_write_uint16(void *dst, uint16_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint16_t *) dst = htons(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 8) & 0xff);
+ p[1] = (uint8_t) (data & 0xff);
+#endif
+}
+
+INLINE void
+ldns_write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ * (uint32_t *) dst = htonl(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 24) & 0xff);
+ p[1] = (uint8_t) ((data >> 16) & 0xff);
+ p[2] = (uint8_t) ((data >> 8) & 0xff);
+ p[3] = (uint8_t) (data & 0xff);
+#endif
+}
+
+/* warning. */
+INLINE void
+ldns_write_uint64_as_uint48(void *dst, uint64_t data)
+{
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t) ((data >> 40) & 0xff);
+ p[1] = (uint8_t) ((data >> 32) & 0xff);
+ p[2] = (uint8_t) ((data >> 24) & 0xff);
+ p[3] = (uint8_t) ((data >> 16) & 0xff);
+ p[4] = (uint8_t) ((data >> 8) & 0xff);
+ p[5] = (uint8_t) (data & 0xff);
+}
+
+
+/**
+ * Structure to do a Schwartzian-like transformation, for instance when
+ * sorting. If you need a transformation on the objects that are sorted,
+ * you can sue this to store the transformed values, so you do not
+ * need to do the transformation again for each comparison
+ */
+struct ldns_schwartzian_compare_struct {
+ void *original_object;
+ void *transformed_object;
+};
+
+/** A general purpose lookup table
+ *
+ * Lookup tables are arrays of (id, name) pairs,
+ * So you can for instance lookup the RCODE 3, which is "NXDOMAIN",
+ * and vice versa. The lookup tables themselves are defined wherever needed,
+ * for instance in \ref host2str.c
+ */
+struct ldns_struct_lookup_table {
+ int id;
+ const char *name;
+};
+typedef struct ldns_struct_lookup_table ldns_lookup_table;
+
+/**
+ * Looks up the table entry by name, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] name what to search for
+ * \return the item found
+ */
+ldns_lookup_table *ldns_lookup_by_name(ldns_lookup_table table[],
+ const char *name);
+
+/**
+ * Looks up the table entry by id, returns NULL if not found.
+ * \param[in] table the lookup table to search in
+ * \param[in] id what to search for
+ * \return the item found
+ */
+ldns_lookup_table *ldns_lookup_by_id(ldns_lookup_table table[], int id);
+
+/**
+ * Returns the value of the specified bit
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ * \param[in] bits array holding the bits
+ * \param[in] index to the wanted bit
+ * \return
+ */
+int ldns_get_bit(uint8_t bits[], size_t index);
+
+
+/**
+ * Returns the value of the specified bit
+ * The bits are counted from right to left, so bit #0 is the
+ * right most bit.
+ * \param[in] bits array holding the bits
+ * \param[in] index to the wanted bit
+ * \return 1 or 0 depending no the bit state
+ */
+int ldns_get_bit_r(uint8_t bits[], size_t index);
+
+/**
+ * sets the specified bit in the specified byte to
+ * 1 if value is true, 0 if false
+ * The bits are counted from right to left, so bit #0 is the
+ * right most bit.
+ * \param[in] byte the bit to set the bit in
+ * \param[in] bit_nr the bit to set (0 <= n <= 7)
+ * \param[in] value whether to set the bit to 1 or 0
+ * \return 1 or 0 depending no the bit state
+ */
+void ldns_set_bit(uint8_t *byte, int bit_nr, bool value);
+
+/**
+ * Returns the value of a to the power of b
+ * (or 1 of b < 1)
+ */
+/*@unused@*/
+INLINE long
+ldns_power(long a, long b) {
+ long result = 1;
+ while (b > 0) {
+ if (b & 1) {
+ result *= a;
+ if (b == 1) {
+ return result;
+ }
+ }
+ a *= a;
+ b /= 2;
+ }
+ return result;
+}
+
+/**
+ * Returns the int value of the given (hex) digit
+ * \param[in] ch the hex char to convert
+ * \return the converted decimal value
+ */
+int ldns_hexdigit_to_int(char ch);
+
+/**
+ * Returns the char (hex) representation of the given int
+ * \param[in] ch the int to convert
+ * \return the converted hex char
+ */
+char ldns_int_to_hexdigit(int ch);
+
+/**
+ * Converts a hex string to binary data
+ *
+ * \param[out] data The binary result is placed here.
+ * At least strlen(str)/2 bytes should be allocated
+ * \param[in] str The hex string to convert.
+ * This string should not contain spaces
+ * \return The number of bytes of converted data, or -1 if one of the arguments * is NULL, or -2 if the string length is not an even number
+ */
+int
+ldns_hexstring_to_data(uint8_t *data, const char *str);
+
+/**
+ * Show the internal library version
+ * \return a string with the version in it
+ */
+const char * ldns_version(void);
+
+/**
+ * Convert TM to seconds since epoch (midnight, January 1st, 1970).
+ * Like timegm(3), which is not always available.
+ * \param[in] tm a struct tm* with the date
+ * \return the seconds since epoch
+ */
+time_t mktime_from_utc(const struct tm *tm);
+
+/**
+ * The function interprets time as the number of seconds since epoch
+ * with respect to now using serial arithmitics (rfc1982).
+ * That number of seconds is then converted to broken-out time information.
+ * This is especially usefull when converting the inception and expiration
+ * fields of RRSIG records.
+ *
+ * \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
+ * to be intepreted as a serial arithmitics number relative to now.
+ * \param[in] now number of seconds since epoch (midnight, January 1st, 1970)
+ * to which the time value is compared to determine the final value.
+ * \param[out] result the struct with the broken-out time information
+ * \return result on success or NULL on error
+ */
+struct tm * ldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
+
+/**
+ * Seed the random function.
+ * If the file descriptor is specified, the random generator is seeded with
+ * data from that file. If not, /dev/urandom is used.
+ *
+ * applications should call this if they need entropy data within ldns
+ * If openSSL is available, it is automatically seeded from /dev/urandom
+ * or /dev/random.
+ *
+ * If you need more entropy, or have no openssl available, this function
+ * MUST be called at the start of the program
+ *
+ * If openssl *is* available, this function just adds more entropy
+ *
+ * \param[in] fd a file providing entropy data for the seed
+ * \param[in] size the number of bytes to use as entropy data. If this is 0,
+ * only the minimal amount is taken (usually 4 bytes)
+ * \return 0 if seeding succeeds, 1 if it fails
+ */
+int ldns_init_random(FILE *fd, unsigned int size);
+
+/**
+ * Get random number.
+ * \return random number.
+ *
+ */
+uint16_t ldns_get_random(void);
+
+/**
+ * Encode data as BubbleBabble
+ *
+ * \param[in] data a pointer to data to be encoded
+ * \param[in] len size the number of bytes of data
+ * \return a string of BubbleBabble
+ */
+char *ldns_bubblebabble(uint8_t *data, size_t len);
+
+#ifndef B32_NTOP
+int ldns_b32_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int b32_ntop(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int ldns_b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+int b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
+ char *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_ntop
+ */
+/*@unused@*/
+INLINE size_t ldns_b32_ntop_calculate_size(size_t srcsize)
+{
+ size_t result = ((((srcsize / 5) * 8) - 2) + 2);
+ return result;
+}
+#endif /* !B32_NTOP */
+#ifndef B32_PTON
+int ldns_b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int ldns_b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_pton
+ */
+/*@unused@*/
+INLINE size_t ldns_b32_pton_calculate_size(size_t srcsize)
+{
+ size_t result = ((((srcsize) / 8) * 5));
+ return result;
+}
+#endif /* !B32_PTON */
+
+INLINE time_t ldns_time(time_t *t) { return time(t); }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_UTIL_H */
diff --git a/3rdParty/Ldns/src/include/ldns/wire2host.h b/3rdParty/Ldns/src/include/ldns/wire2host.h
new file mode 100644
index 0000000..53155b3
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/wire2host.h
@@ -0,0 +1,197 @@
+/*
+ * wire2host.h - from wire conversion routines
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Contains functions that translate dns data from the wire format (as sent
+ * by servers and clients) to the internal structures.
+ */
+
+#ifndef LDNS_WIRE2HOST_H
+#define LDNS_WIRE2HOST_H
+
+#include <ldns/rdata.h>
+#include <ldns/common.h>
+#include <ldns/error.h>
+#include <ldns/rr.h>
+#include <ldns/packet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The length of the header */
+#define LDNS_HEADER_SIZE 12
+
+/* First octet of flags */
+#define LDNS_RD_MASK 0x01U
+#define LDNS_RD_SHIFT 0
+#define LDNS_RD_WIRE(wirebuf) (*(wirebuf+2) & LDNS_RD_MASK)
+#define LDNS_RD_SET(wirebuf) (*(wirebuf+2) |= LDNS_RD_MASK)
+#define LDNS_RD_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_RD_MASK)
+
+#define LDNS_TC_MASK 0x02U
+#define LDNS_TC_SHIFT 1
+#define LDNS_TC_WIRE(wirebuf) (*(wirebuf+2) & LDNS_TC_MASK)
+#define LDNS_TC_SET(wirebuf) (*(wirebuf+2) |= LDNS_TC_MASK)
+#define LDNS_TC_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_TC_MASK)
+
+#define LDNS_AA_MASK 0x04U
+#define LDNS_AA_SHIFT 2
+#define LDNS_AA_WIRE(wirebuf) (*(wirebuf+2) & LDNS_AA_MASK)
+#define LDNS_AA_SET(wirebuf) (*(wirebuf+2) |= LDNS_AA_MASK)
+#define LDNS_AA_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_AA_MASK)
+
+#define LDNS_OPCODE_MASK 0x78U
+#define LDNS_OPCODE_SHIFT 3
+#define LDNS_OPCODE_WIRE(wirebuf) ((*(wirebuf+2) & LDNS_OPCODE_MASK) >> LDNS_OPCODE_SHIFT)
+#define LDNS_OPCODE_SET(wirebuf, opcode) \
+ (*(wirebuf+2) = ((*(wirebuf+2)) & ~LDNS_OPCODE_MASK) | ((opcode) << LDNS_OPCODE_SHIFT))
+
+#define LDNS_QR_MASK 0x80U
+#define LDNS_QR_SHIFT 7
+#define LDNS_QR_WIRE(wirebuf) (*(wirebuf+2) & LDNS_QR_MASK)
+#define LDNS_QR_SET(wirebuf) (*(wirebuf+2) |= LDNS_QR_MASK)
+#define LDNS_QR_CLR(wirebuf) (*(wirebuf+2) &= ~LDNS_QR_MASK)
+
+/* Second octet of flags */
+#define LDNS_RCODE_MASK 0x0fU
+#define LDNS_RCODE_SHIFT 0
+#define LDNS_RCODE_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RCODE_MASK)
+#define LDNS_RCODE_SET(wirebuf, rcode) \
+ (*(wirebuf+3) = ((*(wirebuf+3)) & ~LDNS_RCODE_MASK) | (rcode))
+
+#define LDNS_CD_MASK 0x10U
+#define LDNS_CD_SHIFT 4
+#define LDNS_CD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_CD_MASK)
+#define LDNS_CD_SET(wirebuf) (*(wirebuf+3) |= LDNS_CD_MASK)
+#define LDNS_CD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_CD_MASK)
+
+#define LDNS_AD_MASK 0x20U
+#define LDNS_AD_SHIFT 5
+#define LDNS_AD_WIRE(wirebuf) (*(wirebuf+3) & LDNS_AD_MASK)
+#define LDNS_AD_SET(wirebuf) (*(wirebuf+3) |= LDNS_AD_MASK)
+#define LDNS_AD_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_AD_MASK)
+
+#define LDNS_Z_MASK 0x40U
+#define LDNS_Z_SHIFT 6
+#define LDNS_Z_WIRE(wirebuf) (*(wirebuf+3) & LDNS_Z_MASK)
+#define LDNS_Z_SET(wirebuf) (*(wirebuf+3) |= LDNS_Z_MASK)
+#define LDNS_Z_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_Z_MASK)
+
+#define LDNS_RA_MASK 0x80U
+#define LDNS_RA_SHIFT 7
+#define LDNS_RA_WIRE(wirebuf) (*(wirebuf+3) & LDNS_RA_MASK)
+#define LDNS_RA_SET(wirebuf) (*(wirebuf+3) |= LDNS_RA_MASK)
+#define LDNS_RA_CLR(wirebuf) (*(wirebuf+3) &= ~LDNS_RA_MASK)
+
+/* Query ID */
+#define LDNS_ID_WIRE(wirebuf) (ldns_read_uint16(wirebuf))
+#define LDNS_ID_SET(wirebuf, id) (ldns_write_uint16(wirebuf, id))
+
+/* Counter of the question section */
+#define LDNS_QDCOUNT_OFF 4
+/*
+#define QDCOUNT(wirebuf) (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF)))
+*/
+#define LDNS_QDCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_QDCOUNT_OFF))
+
+/* Counter of the answer section */
+#define LDNS_ANCOUNT_OFF 6
+#define LDNS_ANCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_ANCOUNT_OFF))
+
+/* Counter of the authority section */
+#define LDNS_NSCOUNT_OFF 8
+#define LDNS_NSCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_NSCOUNT_OFF))
+
+/* Counter of the additional section */
+#define LDNS_ARCOUNT_OFF 10
+#define LDNS_ARCOUNT(wirebuf) (ldns_read_uint16(wirebuf+LDNS_ARCOUNT_OFF))
+
+/**
+ * converts the data on the uint8_t bytearray (in wire format) to a DNS packet.
+ * This function will initialize and allocate memory space for the packet
+ * structure.
+ *
+ * \param[in] 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
+ */
+ldns_status ldns_wire2pkt(ldns_pkt **packet, const uint8_t *data, size_t len);
+
+/**
+ * converts the data on the uint8_t bytearray (in wire format) to a DNS packet.
+ * This function will initialize and allocate memory space for the packet
+ * structure.
+ *
+ * \param[in] 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
+ */
+ldns_status ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer);
+
+/**
+ * converts the data on the uint8_t bytearray (in wire format) to a DNS
+ * dname rdata field. This function will initialize and allocate memory
+ * 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[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
+ * from the start of the buffer)
+ * \return LDNS_STATUS_OK if everything succeeds, error otherwise
+ */
+ldns_status ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos);
+
+/**
+ * converts the data on the uint8_t bytearray (in wire format) to DNS
+ * rdata fields, and adds them to the list of rdfs of the given rr.
+ * This function will initialize and allocate memory space for the dname
+ * structures.
+ * The length of the wiredata of these rdfs is added to the *pos value.
+ *
+ * All rdfs belonging to the RR are read; the rr should have no rdfs
+ * yet. An error is returned if the format cannot be parsed.
+ *
+ * \param[in] rr pointer to the ldns_rr 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
+ * from the start of the buffer)
+ * \return LDNS_STATUS_OK if everything succeeds, error otherwise
+ */
+ldns_status ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos);
+
+/**
+ * converts the data on the uint8_t bytearray (in wire format) to a DNS
+ * resource record.
+ * This function will initialize and allocate memory space for the rr
+ * 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[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
+ * from the start of the buffer)
+ * \param[in] section the section in the packet the rr is meant for
+ * \return LDNS_STATUS_OK if everything succeeds, error otherwise
+ */
+ldns_status ldns_wire2rr(ldns_rr **rr, const uint8_t *wire, size_t max, size_t *pos, ldns_pkt_section section);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_WIRE2HOST_H */
diff --git a/3rdParty/Ldns/src/include/ldns/zone.h b/3rdParty/Ldns/src/include/ldns/zone.h
new file mode 100644
index 0000000..0d129a0
--- /dev/null
+++ b/3rdParty/Ldns/src/include/ldns/zone.h
@@ -0,0 +1,176 @@
+/**
+ * zone.h
+ *
+ * zone definitions
+ * - what is it
+ * - get_glue function
+ * - search etc
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+/**
+ * \file
+ *
+ * Defines the ldns_zone structure and functions to manipulate it.
+ */
+
+
+#ifndef LDNS_ZONE_H
+#define LDNS_ZONE_H
+
+#include <ldns/common.h>
+#include <ldns/rdata.h>
+#include <ldns/rr.h>
+#include <ldns/error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * DNS Zone
+ *
+ * A list of RR's with some
+ * extra information which comes from the SOA RR
+ * Note: nothing has been done to make this efficient (yet).
+ */
+struct ldns_struct_zone
+{
+ /** the soa defines a zone */
+ ldns_rr *_soa;
+ /* basicly a zone is a list of rr's */
+ ldns_rr_list *_rrs;
+ /* we could change this to be a b-tree etc etc todo */
+};
+typedef struct ldns_struct_zone ldns_zone;
+
+/**
+ * create a new ldns_zone structure
+ * \return a pointer to a ldns_zone structure
+ */
+ldns_zone * ldns_zone_new(void);
+
+/**
+ * Return the soa record of a zone
+ * \param[in] z the zone to read from
+ * \return the soa record in the zone
+ */
+ldns_rr * ldns_zone_soa(const ldns_zone *z);
+
+/**
+ * Returns the number of resource records in the zone, NOT counting the SOA record
+ * \param[in] z the zone to read from
+ * \return the number of rr's in the zone
+ */
+size_t ldns_zone_rr_count(const ldns_zone *z);
+
+/**
+ * Set the zone's soa record
+ * \param[in] z the zone to put the new soa in
+ * \param[in] soa the soa to set
+ */
+void ldns_zone_set_soa(ldns_zone *z, ldns_rr *soa);
+
+/**
+ * Get a list of a zone's content. Note that the SOA
+ * isn't included in this list. You need to get the
+ * with ldns_zone_soa.
+ * \param[in] z the zone to read from
+ * \return the rrs from this zone
+ */
+ldns_rr_list * ldns_zone_rrs(const ldns_zone *z);
+
+/**
+ * Set the zone's contents
+ * \param[in] z the zone to put the new soa in
+ * \param[in] rrlist the rrlist to use
+ */
+void ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist);
+
+/**
+ * push an rrlist to a zone structure. This function use pointer
+ * 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
+ */
+bool ldns_zone_push_rr_list(ldns_zone *z, ldns_rr_list *list);
+
+/**
+ * push an single rr to a zone structure. This function use pointer
+ * 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
+ */
+bool ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr);
+
+/**
+ * Retrieve all resource records from the zone that are glue
+ * records. The resulting list does are pointer references
+ * to the zone's data.
+ *
+ * Due to the current zone implementation (as a list of rr's), this
+ * function is extremely slow. Another (probably better) way to do this
+ * is to use an ldns_dnssec_zone structure and the
+ * ldns_dnssec_mark_and_get_glue() function.
+ *
+ * \param[in] z the zone to look for glue
+ * \return the rr_list with the glue
+ */
+ldns_rr_list *ldns_zone_glue_rr_list(const ldns_zone *z);
+
+/**
+ * Create a new zone from a file
+ * \param[out] z the new zone
+ * \param[in] *fp the filepointer to use
+ * \param[in] *origin the zones' origin
+ * \param[in] ttl default ttl to use
+ * \param[in] c default class to use (IN)
+ *
+ * \return ldns_status mesg with an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c);
+
+/**
+ * Create a new zone from a file, keep track of the line numbering
+ * \param[out] z the new zone
+ * \param[in] *fp the filepointer to use
+ * \param[in] *origin the zones' origin
+ * \param[in] ttl default ttl to use
+ * \param[in] c default class to use (IN)
+ * \param[out] line_nr used for error msg, to get to the line number
+ *
+ * \return ldns_status mesg with an error or LDNS_STATUS_OK
+ */
+ldns_status ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c, int *line_nr);
+
+/**
+ * Frees the allocated memory for the zone, and the rr_list structure in it
+ * \param[in] zone the zone to free
+ */
+void ldns_zone_free(ldns_zone *zone);
+
+/**
+ * Frees the allocated memory for the zone, the soa rr in it,
+ * and the rr_list structure in it, including the rr's in that. etc.
+ * \param[in] zone the zone to free
+ */
+void ldns_zone_deep_free(ldns_zone *zone);
+
+/**
+ * Sort the rrs in a zone, with the current impl. this is slow
+ * \param[in] zone the zone to sort
+ */
+void ldns_zone_sort(ldns_zone *zone);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_ZONE_H */
diff --git a/3rdParty/Ldns/src/src/buffer.c b/3rdParty/Ldns/src/src/buffer.c
new file mode 100644
index 0000000..5a6b0ba
--- /dev/null
+++ b/3rdParty/Ldns/src/src/buffer.c
@@ -0,0 +1,176 @@
+/*
+ * buffer.c -- generic memory buffer .
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+#include <ldns/buffer.h>
+
+ldns_buffer *
+ldns_buffer_new(size_t capacity)
+{
+ ldns_buffer *buffer = LDNS_MALLOC(ldns_buffer);
+
+ if (!buffer) {
+ return NULL;
+ }
+
+ buffer->_data = (uint8_t *) LDNS_XMALLOC(uint8_t, capacity);
+ if (!buffer->_data) {
+ LDNS_FREE(buffer);
+ return NULL;
+ }
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity = capacity;
+ buffer->_fixed = 0;
+ buffer->_status = LDNS_STATUS_OK;
+
+ ldns_buffer_invariant(buffer);
+
+ return buffer;
+}
+
+void
+ldns_buffer_new_frm_data(ldns_buffer *buffer, void *data, size_t size)
+{
+ assert(data != NULL);
+
+ buffer->_position = 0;
+ buffer->_limit = buffer->_capacity = size;
+ buffer->_fixed = 0;
+ buffer->_data = LDNS_XMALLOC(uint8_t, size);
+ if(!buffer->_data) {
+ buffer->_status = LDNS_STATUS_MEM_ERR;
+ return;
+ }
+ memcpy(buffer->_data, data, size);
+ buffer->_status = LDNS_STATUS_OK;
+
+ ldns_buffer_invariant(buffer);
+}
+
+bool
+ldns_buffer_set_capacity(ldns_buffer *buffer, size_t capacity)
+{
+ void *data;
+
+ ldns_buffer_invariant(buffer);
+ assert(buffer->_position <= capacity);
+
+ data = (uint8_t *) LDNS_XREALLOC(buffer->_data, uint8_t, capacity);
+ if (!data) {
+ buffer->_status = LDNS_STATUS_MEM_ERR;
+ return false;
+ } else {
+ buffer->_data = data;
+ buffer->_limit = buffer->_capacity = capacity;
+ return true;
+ }
+}
+
+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;
+
+ if (new_capacity < buffer->_position + amount) {
+ new_capacity = buffer->_position + amount;
+ }
+ if (!ldns_buffer_set_capacity(buffer, new_capacity)) {
+ buffer->_status = LDNS_STATUS_MEM_ERR;
+ return false;
+ }
+ }
+ buffer->_limit = buffer->_capacity;
+ return true;
+}
+
+int
+ldns_buffer_printf(ldns_buffer *buffer, const char *format, ...)
+{
+ va_list args;
+ int written = 0;
+ size_t remaining;
+
+ if (ldns_buffer_status_ok(buffer)) {
+ ldns_buffer_invariant(buffer);
+ assert(buffer->_limit == buffer->_capacity);
+
+ remaining = ldns_buffer_remaining(buffer);
+ va_start(args, format);
+ written = vsnprintf((char *) ldns_buffer_current(buffer), remaining,
+ format, args);
+ va_end(args);
+ if (written == -1) {
+ buffer->_status = LDNS_STATUS_INTERNAL_ERR;
+ return -1;
+ } else if ((size_t) written >= remaining) {
+ if (!ldns_buffer_reserve(buffer, (size_t) written + 1)) {
+ buffer->_status = LDNS_STATUS_MEM_ERR;
+ return -1;
+ }
+ va_start(args, format);
+ written = vsnprintf((char *) ldns_buffer_current(buffer),
+ ldns_buffer_remaining(buffer), format, args);
+ va_end(args);
+ if (written == -1) {
+ buffer->_status = LDNS_STATUS_INTERNAL_ERR;
+ return -1;
+ }
+ }
+ buffer->_position += written;
+ }
+ return written;
+}
+
+void
+ldns_buffer_free(ldns_buffer *buffer)
+{
+ if (!buffer) {
+ return;
+ }
+
+ LDNS_FREE(buffer->_data);
+
+ LDNS_FREE(buffer);
+}
+
+void *
+ldns_buffer_export(ldns_buffer *buffer)
+{
+ buffer->_fixed = 1;
+ return buffer->_data;
+}
+
+int
+ldns_bgetc(ldns_buffer *buffer)
+{
+ if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) {
+ ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer));
+ /* ldns_buffer_rewind(buffer);*/
+ return EOF;
+ }
+ return (int)ldns_buffer_read_u8(buffer);
+}
+
+void
+ldns_buffer_copy(ldns_buffer* result, ldns_buffer* from)
+{
+ size_t tocopy = ldns_buffer_limit(from);
+
+ if(tocopy > ldns_buffer_capacity(result))
+ tocopy = ldns_buffer_capacity(result);
+ ldns_buffer_clear(result);
+ ldns_buffer_write(result, ldns_buffer_begin(from), tocopy);
+ ldns_buffer_flip(result);
+}
diff --git a/3rdParty/Ldns/src/src/compat/b32_ntop.c b/3rdParty/Ldns/src/src/compat/b32_ntop.c
new file mode 100644
index 0000000..038ebdc
--- /dev/null
+++ b/3rdParty/Ldns/src/src/compat/b32_ntop.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+static const char Base32[] =
+ "abcdefghijklmnopqrstuvwxyz234567";
+/* "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";*/
+/* 00000000001111111111222222222233
+ 01234567890123456789012345678901*/
+static const char Base32_extended_hex[] =
+/* "0123456789ABCDEFGHIJKLMNOPQRSTUV";*/
+ "0123456789abcdefghijklmnopqrstuv";
+static const char Pad32 = '=';
+
+/* (From RFC3548 and draft-josefsson-rfc3548bis-00.txt)
+5. Base 32 Encoding
+
+ The Base 32 encoding is designed to represent arbitrary sequences of
+ octets in a form that needs to be case insensitive but need not be
+ humanly readable.
+
+ A 33-character subset of US-ASCII is used, enabling 5 bits to be
+ represented per printable character. (The extra 33rd character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 40-bit groups of input bits as output
+ strings of 8 encoded characters. Proceeding from left to right, a
+ 40-bit input group is formed by concatenating 5 8bit input groups.
+ These 40 bits are then treated as 8 concatenated 5-bit groups, each
+ of which is translated into a single digit in the base 32 alphabet.
+ When encoding a bit stream via the base 32 encoding, the bit stream
+ must be presumed to be ordered with the most-significant-bit first.
+ That is, the first bit in the stream will be the high-order bit in
+ the first 8bit byte, and the eighth bit will be the low-order bit in
+ the first 8bit byte, and so on.
+
+ Each 5-bit group is used as an index into an array of 32 printable
+ characters. The character referenced by the index is placed in the
+ output string. These characters, identified in Table 3, below, are
+ selected from US-ASCII digits and uppercase letters.
+
+ Table 3: The Base 32 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 9 J 18 S 27 3
+ 1 B 10 K 19 T 28 4
+ 2 C 11 L 20 U 29 5
+ 3 D 12 M 21 V 30 6
+ 4 E 13 N 22 W 31 7
+ 5 F 14 O 23 X
+ 6 G 15 P 24 Y (pad) =
+ 7 H 16 Q 25 Z
+ 8 I 17 R 26 2
+
+
+ Special processing is performed if fewer than 40 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a body. When fewer than 40 input bits
+ are available in an input group, zero bits are added (on the right)
+ to form an integral number of 5-bit groups. Padding at the end of
+ the data is performed using the "=" character. Since all base 32
+ input is an integral number of octets, only the following cases can
+ arise:
+
+ (1) the final quantum of encoding input is an integral multiple of 40
+ bits; here, the final unit of encoded output will be an integral
+ multiple of 8 characters with no "=" padding,
+
+ (2) the final quantum of encoding input is exactly 8 bits; here, the
+ final unit of encoded output will be two characters followed by six
+ "=" padding characters,
+
+ (3) the final quantum of encoding input is exactly 16 bits; here, the
+ final unit of encoded output will be four characters followed by four
+ "=" padding characters,
+
+ (4) the final quantum of encoding input is exactly 24 bits; here, the
+ final unit of encoded output will be five characters followed by
+ three "=" padding characters, or
+
+ (5) the final quantum of encoding input is exactly 32 bits; here, the
+ final unit of encoded output will be seven characters followed by one
+ "=" padding character.
+
+
+6. Base 32 Encoding with Extended Hex Alphabet
+
+ The following description of base 32 is due to [7]. This encoding
+ should not be regarded as the same as the "base32" encoding, and
+ should not be referred to as only "base32".
+
+ One property with this alphabet, that the base64 and base32 alphabet
+ lack, is that encoded data maintain its sort order when the encoded
+ data is compared bit-wise.
+
+ This encoding is identical to the previous one, except for the
+ alphabet. The new alphabet is found in table 4.
+
+ Table 4: The "Extended Hex" Base 32 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 0 9 9 18 I 27 R
+ 1 1 10 A 19 J 28 S
+ 2 2 11 B 20 K 29 T
+ 3 3 12 C 21 L 30 U
+ 4 4 13 D 22 M 31 V
+ 5 5 14 E 23 N
+ 6 6 15 F 24 O (pad) =
+ 7 7 16 G 25 P
+ 8 8 17 H 26 Q
+
+*/
+
+
+int
+ldns_b32_ntop_ar(uint8_t const *src, size_t srclength, char *target, size_t targsize, const char B32_ar[]) {
+ size_t datalength = 0;
+ uint8_t input[5];
+ uint8_t output[8];
+ size_t i;
+ memset(output, 0, 8);
+
+ while (4 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ input[3] = *src++;
+ input[4] = *src++;
+ srclength -= 5;
+
+ output[0] = (input[0] & 0xf8) >> 3;
+ output[1] = ((input[0] & 0x07) << 2) + ((input[1] & 0xc0) >> 6);
+ output[2] = (input[1] & 0x3e) >> 1;
+ output[3] = ((input[1] & 0x01) << 4) + ((input[2] & 0xf0) >> 4);
+ output[4] = ((input[2] & 0x0f) << 1) + ((input[3] & 0x80) >> 7);
+ output[5] = (input[3] & 0x7c) >> 2;
+ output[6] = ((input[3] & 0x03) << 3) + ((input[4] & 0xe0) >> 5);
+ output[7] = (input[4] & 0x1f);
+
+ assert(output[0] < 32);
+ assert(output[1] < 32);
+ assert(output[2] < 32);
+ assert(output[3] < 32);
+ assert(output[4] < 32);
+ assert(output[5] < 32);
+ assert(output[6] < 32);
+ assert(output[7] < 32);
+
+ if (datalength + 8 > targsize) {
+ return (-1);
+ }
+ target[datalength++] = B32_ar[output[0]];
+ target[datalength++] = B32_ar[output[1]];
+ target[datalength++] = B32_ar[output[2]];
+ target[datalength++] = B32_ar[output[3]];
+ target[datalength++] = B32_ar[output[4]];
+ target[datalength++] = B32_ar[output[5]];
+ target[datalength++] = B32_ar[output[6]];
+ target[datalength++] = B32_ar[output[7]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = input[3] = input[4] = (uint8_t) '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = (input[0] & 0xf8) >> 3;
+ assert(output[0] < 32);
+ if (srclength >= 1) {
+ output[1] = ((input[0] & 0x07) << 2) + ((input[1] & 0xc0) >> 6);
+ assert(output[1] < 32);
+ output[2] = (input[1] & 0x3e) >> 1;
+ assert(output[2] < 32);
+ }
+ if (srclength >= 2) {
+ output[3] = ((input[1] & 0x01) << 4) + ((input[2] & 0xf0) >> 4);
+ assert(output[3] < 32);
+ }
+ if (srclength >= 3) {
+ output[4] = ((input[2] & 0x0f) << 1) + ((input[3] & 0x80) >> 7);
+ assert(output[4] < 32);
+ output[5] = (input[3] & 0x7c) >> 2;
+ assert(output[5] < 32);
+ }
+ if (srclength >= 4) {
+ output[6] = ((input[3] & 0x03) << 3) + ((input[4] & 0xe0) >> 5);
+ assert(output[6] < 32);
+ }
+
+
+ if (datalength + 1 > targsize) {
+ return (-2);
+ }
+ target[datalength++] = B32_ar[output[0]];
+ if (srclength >= 1) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[1]];
+ if (srclength == 1 && output[2] == 0) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[2]];
+ }
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ }
+ if (srclength >= 2) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[3]];
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ }
+ if (srclength >= 3) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[4]];
+ if (srclength == 3 && output[5] == 0) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[5]];
+ }
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ }
+ if (srclength >= 4) {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = B32_ar[output[6]];
+ } else {
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ }
+ if (datalength + 1 > targsize) { return (-2); }
+ target[datalength++] = Pad32;
+ }
+ if (datalength+1 > targsize) {
+ return (int) (datalength);
+ }
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (int) (datalength);
+}
+
+int
+ldns_b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+ return ldns_b32_ntop_ar(src, srclength, target, targsize, Base32);
+}
+
+/* deprecated, here for backwards compatibility */
+int
+b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+ return ldns_b32_ntop_ar(src, srclength, target, targsize, Base32);
+}
+
+int
+ldns_b32_ntop_extended_hex(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+ return ldns_b32_ntop_ar(src, srclength, target, targsize, Base32_extended_hex);
+}
+
+/* deprecated, here for backwards compatibility */
+int
+b32_ntop_extended_hex(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+ return ldns_b32_ntop_ar(src, srclength, target, targsize, Base32_extended_hex);
+}
+
diff --git a/3rdParty/Ldns/src/src/compat/b32_pton.c b/3rdParty/Ldns/src/src/compat/b32_pton.c
new file mode 100644
index 0000000..9c261e6
--- /dev/null
+++ b/3rdParty/Ldns/src/src/compat/b32_pton.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";*/
+static const char Base32[] =
+ "abcdefghijklmnopqrstuvwxyz234567";
+/* "0123456789ABCDEFGHIJKLMNOPQRSTUV";*/
+static const char Base32_extended_hex[] =
+ "0123456789abcdefghijklmnopqrstuv";
+static const char Pad32 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+5. Base 32 Encoding
+
+ The Base 32 encoding is designed to represent arbitrary sequences of
+ octets in a form that needs to be case insensitive but need not be
+ humanly readable.
+
+ A 33-character subset of US-ASCII is used, enabling 5 bits to be
+ represented per printable character. (The extra 33rd character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 40-bit groups of input bits as output
+ strings of 8 encoded characters. Proceeding from left to right, a
+ 40-bit input group is formed by concatenating 5 8bit input groups.
+ These 40 bits are then treated as 8 concatenated 5-bit groups, each
+ of which is translated into a single digit in the base 32 alphabet.
+ When encoding a bit stream via the base 32 encoding, the bit stream
+ must be presumed to be ordered with the most-significant-bit first.
+ That is, the first bit in the stream will be the high-order bit in
+ the first 8bit byte, and the eighth bit will be the low-order bit in
+ the first 8bit byte, and so on.
+
+ Each 5-bit group is used as an index into an array of 32 printable
+ characters. The character referenced by the index is placed in the
+ output string. These characters, identified in Table 3, below, are
+ selected from US-ASCII digits and uppercase letters.
+
+ Table 3: The Base 32 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 9 J 18 S 27 3
+ 1 B 10 K 19 T 28 4
+ 2 C 11 L 20 U 29 5
+ 3 D 12 M 21 V 30 6
+ 4 E 13 N 22 W 31 7
+ 5 F 14 O 23 X
+ 6 G 15 P 24 Y (pad) =
+ 7 H 16 Q 25 Z
+ 8 I 17 R 26 2
+
+
+ Special processing is performed if fewer than 40 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a body. When fewer than 40 input bits
+ are available in an input group, zero bits are added (on the right)
+ to form an integral number of 5-bit groups. Padding at the end of
+ the data is performed using the "=" character. Since all base 32
+ input is an integral number of octets, only the following cases can
+ arise:
+
+ (1) the final quantum of encoding input is an integral multiple of 40
+ bits; here, the final unit of encoded output will be an integral
+ multiple of 8 characters with no "=" padding,
+
+ (2) the final quantum of encoding input is exactly 8 bits; here, the
+ final unit of encoded output will be two characters followed by six
+ "=" padding characters,
+
+ (3) the final quantum of encoding input is exactly 16 bits; here, the
+ final unit of encoded output will be four characters followed by four
+ "=" padding characters,
+
+ (4) the final quantum of encoding input is exactly 24 bits; here, the
+ final unit of encoded output will be five characters followed by
+ three "=" padding characters, or
+
+ (5) the final quantum of encoding input is exactly 32 bits; here, the
+ final unit of encoded output will be seven characters followed by one
+ "=" padding character.
+
+
+6. Base 32 Encoding with Extended Hex Alphabet
+
+ The following description of base 32 is due to [7]. This encoding
+ should not be regarded as the same as the "base32" encoding, and
+ should not be referred to as only "base32".
+
+ One property with this alphabet, that the base32 and base32 alphabet
+ lack, is that encoded data maintain its sort order when the encoded
+ data is compared bit-wise.
+
+ This encoding is identical to the previous one, except for the
+ alphabet. The new alphabet is found in table 4.
+
+ Table 4: The "Extended Hex" Base 32 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 0 9 9 18 I 27 R
+ 1 1 10 A 19 J 28 S
+ 2 2 11 B 20 K 29 T
+ 3 3 12 C 21 L 30 U
+ 4 4 13 D 22 M 31 V
+ 5 5 14 E 23 N
+ 6 6 15 F 24 O (pad) =
+ 7 7 16 G 25 P
+ 8 8 17 H 26 Q
+
+
+
+
+*/
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 32 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+ldns_b32_pton_ar(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize, const char B32_ar[])
+{
+ int tarindex, state, ch;
+ char *pos;
+ int i = 0;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0' && (i == 0 || i < (int) hashed_owner_str_len)) {
+ i++;
+ ch = tolower(ch);
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad32)
+ break;
+
+ pos = strchr(B32_ar, ch);
+ if (pos == 0) {
+ /* A non-base32 character. */
+ return (-ch);
+ }
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize) {
+ return (-2);
+ }
+ target[tarindex] = (pos - B32_ar) << 3;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-3);
+ }
+ target[tarindex] |= (pos - B32_ar) >> 2;
+ target[tarindex+1] = ((pos - B32_ar) & 0x03)
+ << 6 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-4);
+ }
+ target[tarindex] |= (pos - B32_ar) << 1;
+ }
+ /*tarindex++;*/
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-5);
+ }
+ target[tarindex] |= (pos - B32_ar) >> 4;
+ target[tarindex+1] = ((pos - B32_ar) & 0x0f) << 4 ;
+ }
+ tarindex++;
+ state = 4;
+ break;
+ case 4:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-6);
+ }
+ target[tarindex] |= (pos - B32_ar) >> 1;
+ target[tarindex+1] = ((pos - B32_ar) & 0x01)
+ << 7 ;
+ }
+ tarindex++;
+ state = 5;
+ break;
+ case 5:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-7);
+ }
+ target[tarindex] |= (pos - B32_ar) << 2;
+ }
+ state = 6;
+ break;
+ case 6:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-8);
+ }
+ target[tarindex] |= (pos - B32_ar) >> 3;
+ target[tarindex+1] = ((pos - B32_ar) & 0x07)
+ << 5 ;
+ }
+ tarindex++;
+ state = 7;
+ break;
+ case 7:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-9);
+ }
+ target[tarindex] |= (pos - B32_ar);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-32 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad32) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-10);
+
+ case 2: /* Valid, means one byte of info */
+ case 3:
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad32) {
+ return (-11);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 4: /* Valid, means two bytes of info */
+ case 5:
+ case 6:
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!(isspace((unsigned char)ch) || ch == '=')) {
+ return (-12);
+ }
+
+ case 7: /* Valid, means three bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch)) {
+ return (-13);
+ }
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0) {
+ return (-14);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-15);
+ }
+
+ return (tarindex);
+}
+
+int
+ldns_b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+ return ldns_b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32);
+}
+
+/* deprecated, here for backwards compatibility */
+int
+b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+ return ldns_b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32);
+}
+
+int
+ldns_b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+ return ldns_b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32_extended_hex);
+}
+
+/* deprecated, here for backwards compatibility */
+int
+b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+ return ldns_b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32_extended_hex);
+}
diff --git a/3rdParty/Ldns/src/src/compat/b64_ntop.c b/3rdParty/Ldns/src/src/compat/b64_ntop.c
new file mode 100644
index 0000000..d0b52b5
--- /dev/null
+++ b/3rdParty/Ldns/src/src/compat/b64_ntop.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ uint8_t input[3];
+ uint8_t output[4];
+ size_t i;
+
+ if (srclength == 0) {
+ if (targsize > 0) {
+ target[0] = '\0';
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize) {
+ return (-1);
+ }
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = (uint8_t) '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize) {
+ return (-2);
+ }
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1) {
+ target[datalength++] = Pad64;
+ } else {
+ target[datalength++] = Base64[output[2]];
+ }
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize) {
+ return (-3);
+ }
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (int) (datalength);
+}
diff --git a/3rdParty/Ldns/src/src/compat/b64_pton.c b/3rdParty/Ldns/src/src/compat/b64_pton.c
new file mode 100644
index 0000000..aa637d2
--- /dev/null
+++ b/3rdParty/Ldns/src/src/compat/b64_pton.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+ldns_b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ if (strlen(src) == 0) {
+ return 0;
+ }
+
+ while ((ch = *src++) != '\0') {
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) {
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/3rdParty/Ldns/src/src/dname.c b/3rdParty/Ldns/src/src/dname.c
new file mode 100644
index 0000000..0e63ef2
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dname.c
@@ -0,0 +1,567 @@
+/*
+ * dname.c
+ *
+ * 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
+ * for LDNS_RDF_TYPE_DNAME.
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+ldns_rdf *
+ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
+{
+ ldns_rdf *new;
+ uint16_t new_size;
+ uint8_t *buf;
+ uint16_t left_size;
+
+ if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+
+ /* remove root label if it is present at the end of the left
+ * rd, by reducing the size with 1
+ */
+ left_size = ldns_rdf_size(rd1);
+ if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
+ left_size--;
+ }
+
+ /* we overwrite the nullbyte of rd1 */
+ new_size = left_size + ldns_rdf_size(rd2);
+ buf = LDNS_XMALLOC(uint8_t, new_size);
+ if (!buf) {
+ return NULL;
+ }
+
+ /* put the two dname's after each other */
+ memcpy(buf, ldns_rdf_data(rd1), left_size);
+ memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
+
+ new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
+
+ LDNS_FREE(buf);
+ return new;
+}
+
+ldns_status
+ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
+{
+ uint16_t left_size;
+ uint16_t size;
+ uint8_t* newd;
+
+ if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* remove root label if it is present at the end of the left
+ * rd, by reducing the size with 1
+ */
+ left_size = ldns_rdf_size(rd1);
+ if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
+ left_size--;
+ }
+ if(left_size == 0) {
+ return LDNS_STATUS_OK;
+ }
+
+ size = left_size + ldns_rdf_size(rd2);
+ newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
+ if(!newd) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ ldns_rdf_set_data(rd1, newd);
+ memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
+ ldns_rdf_size(rd2));
+ ldns_rdf_set_size(rd1, size);
+
+ return LDNS_STATUS_OK;
+}
+
+ldns_rdf *
+ldns_dname_reverse(const ldns_rdf *d)
+{
+ ldns_rdf *new;
+ ldns_rdf *tmp;
+ ldns_rdf *d_tmp;
+ ldns_status status;
+
+ d_tmp = ldns_rdf_clone(d);
+
+ new = ldns_dname_new_frm_str(".");
+ if(!new)
+ return NULL;
+
+ while(ldns_dname_label_count(d_tmp) > 0) {
+ tmp = ldns_dname_label(d_tmp, 0);
+ status = ldns_dname_cat(tmp, new);
+ if(status != LDNS_STATUS_OK) {
+ ldns_rdf_deep_free(new);
+ ldns_rdf_deep_free(d_tmp);
+ return NULL;
+ }
+ ldns_rdf_deep_free(new);
+ new = tmp;
+ tmp = ldns_dname_left_chop(d_tmp);
+ ldns_rdf_deep_free(d_tmp);
+ d_tmp = tmp;
+ }
+ ldns_rdf_deep_free(d_tmp);
+
+ return new;
+}
+
+ldns_rdf *
+ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
+{
+ uint8_t *data;
+ uint8_t label_size;
+ size_t data_size;
+
+ if (!d ||
+ ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
+ ldns_dname_label_count(d) < n) {
+ return NULL;
+ }
+
+ data = ldns_rdf_data(d);
+ data_size = ldns_rdf_size(d);
+ while (n > 0) {
+ label_size = data[0] + 1;
+ data += label_size;
+ if (data_size < label_size) {
+ /* this label is very broken */
+ return NULL;
+ }
+ data_size -= label_size;
+ n--;
+ }
+
+ return ldns_dname_new_frm_data(data_size, data);
+}
+
+ldns_rdf *
+ldns_dname_left_chop(const ldns_rdf *d)
+{
+ uint8_t label_pos;
+ ldns_rdf *chop;
+
+ if (!d) {
+ return NULL;
+ }
+
+ if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+ if (ldns_dname_label_count(d) == 0) {
+ /* root label */
+ return NULL;
+ }
+ /* 05blaat02nl00 */
+ label_pos = ldns_rdf_data(d)[0];
+
+ chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
+ ldns_rdf_data(d) + label_pos + 1);
+ return chop;
+}
+
+uint8_t
+ldns_dname_label_count(const ldns_rdf *r)
+{
+ uint16_t src_pos;
+ uint16_t len;
+ uint8_t i;
+ size_t r_size;
+
+ if (!r) {
+ return 0;
+ }
+
+ i = 0;
+ src_pos = 0;
+ r_size = ldns_rdf_size(r);
+
+ if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
+ return 0;
+ } else {
+ len = ldns_rdf_data(r)[src_pos]; /* start of the label */
+
+ /* single root label */
+ if (1 == r_size) {
+ return 0;
+ } else {
+ while ((len > 0) && src_pos < r_size) {
+ src_pos++;
+ src_pos += len;
+ len = ldns_rdf_data(r)[src_pos];
+ i++;
+ }
+ }
+ }
+ return i;
+}
+
+ldns_rdf *
+ldns_dname_new(uint16_t s, void *d)
+{
+ ldns_rdf *rd;
+
+ rd = LDNS_MALLOC(ldns_rdf);
+ if (!rd) {
+ return NULL;
+ }
+ ldns_rdf_set_size(rd, s);
+ ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
+ ldns_rdf_set_data(rd, d);
+ return rd;
+}
+
+ldns_rdf *
+ldns_dname_new_frm_str(const char *str)
+{
+ return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
+}
+
+ldns_rdf *
+ldns_dname_new_frm_data(uint16_t size, const void *data)
+{
+ return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
+}
+
+void
+ldns_dname2canonical(const ldns_rdf *rd)
+{
+ uint8_t *rdd;
+ uint16_t i;
+
+ if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
+ return;
+ }
+
+ rdd = (uint8_t*)ldns_rdf_data(rd);
+ for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
+ *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
+ }
+}
+
+bool
+ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
+{
+ uint8_t sub_lab;
+ uint8_t par_lab;
+ int8_t i, j;
+ ldns_rdf *tmp_sub = NULL;
+ ldns_rdf *tmp_par = NULL;
+ ldns_rdf *sub_clone;
+ ldns_rdf *parent_clone;
+ bool result = true;
+
+ if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_compare(sub, parent) == 0) {
+ return false;
+ }
+
+ /* would be nicer if we do not have to clone... */
+ sub_clone = ldns_dname_clone_from(sub, 0);
+ parent_clone = ldns_dname_clone_from(parent, 0);
+ ldns_dname2canonical(sub_clone);
+ ldns_dname2canonical(parent_clone);
+
+ sub_lab = ldns_dname_label_count(sub_clone);
+ par_lab = ldns_dname_label_count(parent_clone);
+
+ /* if sub sits above parent, it cannot be a child/sub domain */
+ if (sub_lab < par_lab) {
+ result = false;
+ } else {
+ /* check all labels the from the parent labels, from right to left.
+ * When they /all/ match we have found a subdomain
+ */
+ j = sub_lab - 1; /* we count from zero, thank you */
+ for (i = par_lab -1; i >= 0; i--) {
+ tmp_sub = ldns_dname_label(sub_clone, j);
+ tmp_par = ldns_dname_label(parent_clone, i);
+ if (!tmp_sub || !tmp_par) {
+ /* deep free does null check */
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ result = false;
+ break;
+ }
+
+ if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
+ /* they are not equal */
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ result = false;
+ break;
+ }
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ j--;
+ }
+ }
+ ldns_rdf_deep_free(sub_clone);
+ ldns_rdf_deep_free(parent_clone);
+ return result;
+}
+
+int
+ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
+{
+ size_t lc1, lc2, lc1f, lc2f;
+ size_t i;
+ int result = 0;
+ uint8_t *lp1, *lp2;
+
+ /* see RFC4034 for this algorithm */
+ /* this algorithm assumes the names are normalized to case */
+
+ /* only when both are not NULL we can say anything about them */
+ if (!dname1 && !dname2) {
+ return 0;
+ }
+ if (!dname1 || !dname2) {
+ return -1;
+ }
+ /* asserts must happen later as we are looking in the
+ * dname, which could be NULL. But this case is handled
+ * above
+ */
+ assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
+
+ lc1 = ldns_dname_label_count(dname1);
+ lc2 = ldns_dname_label_count(dname2);
+
+ if (lc1 == 0 && lc2 == 0) {
+ return 0;
+ }
+ if (lc1 == 0) {
+ return -1;
+ }
+ if (lc2 == 0) {
+ return 1;
+ }
+ lc1--;
+ lc2--;
+ /* we start at the last label */
+ while (true) {
+ /* find the label first */
+ lc1f = lc1;
+ lp1 = ldns_rdf_data(dname1);
+ while (lc1f > 0) {
+ lp1 += *lp1 + 1;
+ lc1f--;
+ }
+
+ /* and find the other one */
+ lc2f = lc2;
+ lp2 = ldns_rdf_data(dname2);
+ while (lc2f > 0) {
+ lp2 += *lp2 + 1;
+ lc2f--;
+ }
+
+ /* now check the label character for character. */
+ for (i = 1; i < (size_t)(*lp1 + 1); i++) {
+ if (i > *lp2) {
+ /* apparently label 1 is larger */
+ result = 1;
+ goto done;
+ }
+ if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
+ LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
+ result = -1;
+ goto done;
+ } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
+ LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
+ result = 1;
+ goto done;
+ }
+ }
+ if (*lp1 < *lp2) {
+ /* apparently label 2 is larger */
+ result = -1;
+ goto done;
+ }
+ if (lc1 == 0 && lc2 > 0) {
+ result = -1;
+ goto done;
+ } else if (lc1 > 0 && lc2 == 0) {
+ result = 1;
+ goto done;
+ } else if (lc1 == 0 && lc2 == 0) {
+ result = 0;
+ goto done;
+ }
+ lc1--;
+ lc2--;
+ }
+
+ done:
+ return result;
+}
+
+int
+ldns_dname_is_wildcard(const ldns_rdf* dname)
+{
+ return ( ldns_dname_label_count(dname) > 0 &&
+ ldns_rdf_data(dname)[0] == 1 &&
+ ldns_rdf_data(dname)[1] == '*');
+}
+
+int
+ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
+{
+ ldns_rdf *wc_chopped;
+ int result;
+ /* check whether it really is a wildcard */
+ if (ldns_dname_is_wildcard(wildcard)) {
+ /* ok, so the dname needs to be a subdomain of the wildcard
+ * without the *
+ */
+ wc_chopped = ldns_dname_left_chop(wildcard);
+ result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
+ ldns_rdf_deep_free(wc_chopped);
+ } else {
+ result = (ldns_dname_compare(dname, wildcard) == 0);
+ }
+ return result;
+}
+
+/* nsec test: does prev <= middle < next
+ * -1 = yes
+ * 0 = error/can't tell
+ * 1 = no
+ */
+int
+ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
+ const ldns_rdf *next)
+{
+ int prev_check, next_check;
+
+ assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
+
+ prev_check = ldns_dname_compare(prev, middle);
+ next_check = ldns_dname_compare(middle, next);
+ /* <= next. This cannot be the case for nsec, because then we would
+ * have gotten the nsec of next...
+ */
+ if (next_check == 0) {
+ return 0;
+ }
+
+ /* <= */
+ if ((prev_check == -1 || prev_check == 0) &&
+ /* < */
+ next_check == -1) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+
+bool
+ldns_dname_str_absolute(const char *dname_str)
+{
+ const char* s;
+ if(dname_str && strcmp(dname_str, ".") == 0)
+ return 1;
+ if(!dname_str || strlen(dname_str) < 2)
+ return 0;
+ if(dname_str[strlen(dname_str) - 1] != '.')
+ return 0;
+ if(dname_str[strlen(dname_str) - 2] != '\\')
+ return 1; /* ends in . and no \ before it */
+ /* so we have the case of ends in . and there is \ before it */
+ for(s=dname_str; *s; s++) {
+ if(*s == '\\') {
+ if(s[1] && s[2] && s[3] /* check length */
+ && isdigit(s[1]) && isdigit(s[2]) &&
+ isdigit(s[3]))
+ s += 3;
+ else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
+ return 0; /* parse error */
+ else s++; /* another character escaped */
+ }
+ else if(!*(s+1) && *s == '.')
+ return 1; /* trailing dot, unescaped */
+ }
+ return 0;
+}
+
+ldns_rdf *
+ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
+{
+ uint8_t labelcnt;
+ uint16_t src_pos;
+ uint16_t len;
+ ldns_rdf *tmpnew;
+ size_t s;
+
+ if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+
+ labelcnt = 0;
+ src_pos = 0;
+ s = ldns_rdf_size(rdf);
+
+ len = ldns_rdf_data(rdf)[src_pos]; /* label start */
+ while ((len > 0) && src_pos < s) {
+ if (labelcnt == labelpos) {
+ /* found our label */
+ tmpnew = LDNS_MALLOC(ldns_rdf);
+ if (!tmpnew) {
+ return NULL;
+ }
+ tmpnew->_type = LDNS_RDF_TYPE_DNAME;
+ tmpnew->_data = LDNS_XMALLOC(uint8_t, len + 2);
+ if (!tmpnew->_data) {
+ LDNS_FREE(tmpnew);
+ return NULL;
+ }
+ memset(tmpnew->_data, 0, len + 2);
+ memcpy(tmpnew->_data, ldns_rdf_data(rdf) + src_pos, len + 1);
+ tmpnew->_size = len + 2;
+ return tmpnew;
+ }
+ src_pos++;
+ src_pos += len;
+ len = ldns_rdf_data(rdf)[src_pos];
+ labelcnt++;
+ }
+ return NULL;
+}
diff --git a/3rdParty/Ldns/src/src/dnssec.c b/3rdParty/Ldns/src/src/dnssec.c
new file mode 100644
index 0000000..c419437
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dnssec.c
@@ -0,0 +1,1766 @@
+/*
+ * dnssec.c
+ *
+ * contains the cryptographic function needed for DNSSEC in ldns
+ * The crypto library used is openssl
+ *
+ * (c) NLnet Labs, 2004-2008
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+#include <ldns/dnssec.h>
+
+#include <strings.h>
+#include <time.h>
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#endif
+
+ldns_rr *
+ldns_dnssec_get_rrsig_for_name_and_type(const ldns_rdf *name,
+ const ldns_rr_type type,
+ const ldns_rr_list *rrs)
+{
+ size_t i;
+ ldns_rr *candidate;
+
+ if (!name || !rrs) {
+ return NULL;
+ }
+
+ for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ candidate = ldns_rr_list_rr(rrs, i);
+ if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_RRSIG) {
+ if (ldns_dname_compare(ldns_rr_owner(candidate),
+ name) == 0 &&
+ ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(candidate))
+ == type
+ ) {
+ return candidate;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+ldns_rr *
+ldns_dnssec_get_dnskey_for_rrsig(const ldns_rr *rrsig,
+ const ldns_rr_list *rrs)
+{
+ size_t i;
+ ldns_rr *candidate;
+
+ if (!rrsig || !rrs) {
+ return NULL;
+ }
+
+ for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ candidate = ldns_rr_list_rr(rrs, i);
+ if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_DNSKEY) {
+ if (ldns_dname_compare(ldns_rr_owner(candidate),
+ ldns_rr_rrsig_signame(rrsig)) == 0 &&
+ ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig)) ==
+ ldns_calc_keytag(candidate)
+ ) {
+ return candidate;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+ldns_rdf *
+ldns_nsec_get_bitmap(ldns_rr *nsec) {
+ if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) {
+ return ldns_rr_rdf(nsec, 1);
+ } else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) {
+ return ldns_rr_rdf(nsec, 5);
+ } else {
+ return NULL;
+ }
+}
+
+/*return the owner name of the closest encloser for name from the list of rrs */
+/* this is NOT the hash, but the original name! */
+ldns_rdf *
+ldns_dnssec_nsec3_closest_encloser(ldns_rdf *qname,
+ ATTR_UNUSED(ldns_rr_type qtype),
+ ldns_rr_list *nsec3s)
+{
+ /* remember parameters, they must match */
+ uint8_t algorithm;
+ uint32_t iterations;
+ uint8_t salt_length;
+ uint8_t *salt;
+
+ ldns_rdf *sname, *hashed_sname, *tmp;
+ bool flag;
+
+ bool exact_match_found;
+ bool in_range_found;
+
+ ldns_status status;
+ ldns_rdf *zone_name;
+
+ size_t nsec_i;
+ ldns_rr *nsec;
+ ldns_rdf *result = NULL;
+ qtype = qtype;
+
+ if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
+ return NULL;
+ }
+
+ nsec = ldns_rr_list_rr(nsec3s, 0);
+ algorithm = ldns_nsec3_algorithm(nsec);
+ salt_length = ldns_nsec3_salt_length(nsec);
+ salt = ldns_nsec3_salt_data(nsec);
+ iterations = ldns_nsec3_iterations(nsec);
+
+ sname = ldns_rdf_clone(qname);
+
+ flag = false;
+
+ zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
+
+ /* algorithm from nsec3-07 8.3 */
+ while (ldns_dname_label_count(sname) > 0) {
+ exact_match_found = false;
+ in_range_found = false;
+
+ hashed_sname = ldns_nsec3_hash_name(sname,
+ algorithm,
+ iterations,
+ salt_length,
+ salt);
+
+ status = ldns_dname_cat(hashed_sname, zone_name);
+ if(status != LDNS_STATUS_OK) {
+ LDNS_FREE(salt);
+ ldns_rdf_deep_free(zone_name);
+ ldns_rdf_deep_free(sname);
+ return NULL;
+ }
+
+ for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
+ nsec = ldns_rr_list_rr(nsec3s, nsec_i);
+
+ /* check values of iterations etc! */
+
+ /* exact match? */
+ if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
+ exact_match_found = true;
+ } else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
+ in_range_found = true;
+ }
+
+ }
+ if (!exact_match_found && in_range_found) {
+ flag = true;
+ } else if (exact_match_found && flag) {
+ result = ldns_rdf_clone(sname);
+ /* RFC 5155: 8.3. 2.** "The proof is complete" */
+ ldns_rdf_deep_free(hashed_sname);
+ goto done;
+ } else if (exact_match_found && !flag) {
+ /* error! */
+ ldns_rdf_deep_free(hashed_sname);
+ goto done;
+ } else {
+ flag = false;
+ }
+
+ ldns_rdf_deep_free(hashed_sname);
+ tmp = sname;
+ sname = ldns_dname_left_chop(sname);
+ ldns_rdf_deep_free(tmp);
+ }
+
+ done:
+ LDNS_FREE(salt);
+ ldns_rdf_deep_free(zone_name);
+ ldns_rdf_deep_free(sname);
+
+ return result;
+}
+
+bool
+ldns_dnssec_pkt_has_rrsigs(const ldns_pkt *pkt)
+{
+ size_t i;
+ for (i = 0; i < ldns_pkt_ancount(pkt); i++) {
+ if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_answer(pkt), i)) ==
+ LDNS_RR_TYPE_RRSIG) {
+ return true;
+ }
+ }
+ for (i = 0; i < ldns_pkt_nscount(pkt); i++) {
+ if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_authority(pkt), i)) ==
+ LDNS_RR_TYPE_RRSIG) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ldns_rr_list *
+ldns_dnssec_pkt_get_rrsigs_for_name_and_type(const ldns_pkt *pkt,
+ ldns_rdf *name,
+ ldns_rr_type type)
+{
+ uint16_t t_netorder;
+ ldns_rr_list *sigs;
+ ldns_rr_list *sigs_covered;
+ ldns_rdf *rdf_t;
+
+ sigs = ldns_pkt_rr_list_by_name_and_type(pkt,
+ name,
+ LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+
+ t_netorder = htons(type); /* rdf are in network order! */
+ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, LDNS_RDF_SIZE_WORD, &t_netorder);
+ sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
+
+ ldns_rdf_free(rdf_t);
+ ldns_rr_list_deep_free(sigs);
+
+ return sigs_covered;
+
+}
+
+ldns_rr_list *
+ldns_dnssec_pkt_get_rrsigs_for_type(const ldns_pkt *pkt, ldns_rr_type type)
+{
+ uint16_t t_netorder;
+ ldns_rr_list *sigs;
+ ldns_rr_list *sigs_covered;
+ ldns_rdf *rdf_t;
+
+ sigs = ldns_pkt_rr_list_by_type(pkt,
+ LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+
+ t_netorder = htons(type); /* rdf are in network order! */
+ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE,
+ 2,
+ &t_netorder);
+ sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
+
+ ldns_rdf_free(rdf_t);
+ ldns_rr_list_deep_free(sigs);
+
+ return sigs_covered;
+
+}
+
+/* used only on the public key RR */
+uint16_t
+ldns_calc_keytag(const ldns_rr *key)
+{
+ uint16_t ac16;
+ ldns_buffer *keybuf;
+ size_t keysize;
+
+ if (!key) {
+ return 0;
+ }
+
+ if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY &&
+ ldns_rr_get_type(key) != LDNS_RR_TYPE_KEY
+ ) {
+ return 0;
+ }
+
+ /* rdata to buf - only put the rdata in a buffer */
+ keybuf = ldns_buffer_new(LDNS_MIN_BUFLEN); /* grows */
+ if (!keybuf) {
+ return 0;
+ }
+ (void)ldns_rr_rdata2buffer_wire(keybuf, key);
+ /* the current pos in the buffer is the keysize */
+ keysize= ldns_buffer_position(keybuf);
+
+ ac16 = ldns_calc_keytag_raw(ldns_buffer_begin(keybuf), keysize);
+ ldns_buffer_free(keybuf);
+ return ac16;
+}
+
+uint16_t ldns_calc_keytag_raw(uint8_t* key, size_t keysize)
+{
+ unsigned int i;
+ uint32_t ac32;
+ uint16_t ac16;
+
+ if(keysize < 4) {
+ return 0;
+ }
+ /* look at the algorithm field, copied from 2535bis */
+ if (key[3] == LDNS_RSAMD5) {
+ ac16 = 0;
+ if (keysize > 4) {
+ memmove(&ac16, key + keysize - 3, 2);
+ }
+ ac16 = ntohs(ac16);
+ return (uint16_t) ac16;
+ } else {
+ ac32 = 0;
+ for (i = 0; (size_t)i < keysize; ++i) {
+ ac32 += (i & 1) ? key[i] : key[i] << 8;
+ }
+ ac32 += (ac32 >> 16) & 0xFFFF;
+ return (uint16_t) (ac32 & 0xFFFF);
+ }
+}
+
+#ifdef HAVE_SSL
+DSA *
+ldns_key_buf2dsa(ldns_buffer *key)
+{
+ return ldns_key_buf2dsa_raw((unsigned char*)ldns_buffer_begin(key),
+ ldns_buffer_position(key));
+}
+
+DSA *
+ldns_key_buf2dsa_raw(unsigned char* key, size_t len)
+{
+ uint8_t T;
+ uint16_t length;
+ uint16_t offset;
+ DSA *dsa;
+ BIGNUM *Q; BIGNUM *P;
+ BIGNUM *G; BIGNUM *Y;
+
+ if(len == 0)
+ return NULL;
+ T = (uint8_t)key[0];
+ length = (64 + T * 8);
+ offset = 1;
+
+ if (T > 8) {
+ return NULL;
+ }
+ if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
+ return NULL;
+
+ Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
+ offset += SHA_DIGEST_LENGTH;
+
+ P = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ G = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ Y = BN_bin2bn(key+offset, (int)length, NULL);
+ offset += length;
+
+ /* create the key and set its properties */
+ if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
+ BN_free(Q);
+ BN_free(P);
+ BN_free(G);
+ BN_free(Y);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ dsa->p = P;
+ dsa->q = Q;
+ dsa->g = G;
+ dsa->pub_key = Y;
+#endif /* splint */
+
+ return dsa;
+}
+
+RSA *
+ldns_key_buf2rsa(ldns_buffer *key)
+{
+ return ldns_key_buf2rsa_raw((unsigned char*)ldns_buffer_begin(key),
+ ldns_buffer_position(key));
+}
+
+RSA *
+ldns_key_buf2rsa_raw(unsigned char* key, size_t len)
+{
+ uint16_t offset;
+ uint16_t exp;
+ uint16_t int16;
+ RSA *rsa;
+ BIGNUM *modulus;
+ BIGNUM *exponent;
+
+ if (len == 0)
+ return NULL;
+ if (key[0] == 0) {
+ if(len < 3)
+ return NULL;
+ /* need some smart comment here XXX*/
+ /* the exponent is too large so it's places
+ * futher...???? */
+ memmove(&int16, key+1, 2);
+ exp = ntohs(int16);
+ offset = 3;
+ } else {
+ exp = key[0];
+ offset = 1;
+ }
+
+ /* key length at least one */
+ if(len < (size_t)offset + exp + 1)
+ return NULL;
+
+ /* Exponent */
+ exponent = BN_new();
+ if(!exponent) return NULL;
+ (void) BN_bin2bn(key+offset, (int)exp, exponent);
+ offset += exp;
+
+ /* Modulus */
+ modulus = BN_new();
+ if(!modulus) {
+ BN_free(exponent);
+ return NULL;
+ }
+ /* length of the buffer must match the key length! */
+ (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
+
+ rsa = RSA_new();
+ if(!rsa) {
+ BN_free(exponent);
+ BN_free(modulus);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ rsa->n = modulus;
+ rsa->e = exponent;
+#endif /* splint */
+
+ return rsa;
+}
+
+int
+ldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
+ const EVP_MD* md)
+{
+ EVP_MD_CTX* ctx;
+ ctx = EVP_MD_CTX_create();
+ if(!ctx)
+ return false;
+ if(!EVP_DigestInit_ex(ctx, md, NULL) ||
+ !EVP_DigestUpdate(ctx, data, len) ||
+ !EVP_DigestFinal_ex(ctx, dest, NULL)) {
+ EVP_MD_CTX_destroy(ctx);
+ return false;
+ }
+ EVP_MD_CTX_destroy(ctx);
+ return true;
+}
+#endif /* HAVE_SSL */
+
+ldns_rr *
+ldns_key_rr2ds(const ldns_rr *key, ldns_hash h)
+{
+ ldns_rdf *tmp;
+ ldns_rr *ds;
+ uint16_t keytag;
+ uint8_t sha1hash;
+ uint8_t *digest;
+ ldns_buffer *data_buf;
+#ifdef USE_GOST
+ const EVP_MD* md = NULL;
+#endif
+
+ if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY) {
+ return NULL;
+ }
+
+ ds = ldns_rr_new();
+ if (!ds) {
+ return NULL;
+ }
+ ldns_rr_set_type(ds, LDNS_RR_TYPE_DS);
+ ldns_rr_set_owner(ds, ldns_rdf_clone(
+ ldns_rr_owner(key)));
+ ldns_rr_set_ttl(ds, ldns_rr_ttl(key));
+ ldns_rr_set_class(ds, ldns_rr_get_class(key));
+
+ switch(h) {
+ default:
+ case LDNS_SHA1:
+ digest = LDNS_XMALLOC(uint8_t, LDNS_SHA1_DIGEST_LENGTH);
+ if (!digest) {
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ break;
+ case LDNS_SHA256:
+ digest = LDNS_XMALLOC(uint8_t, LDNS_SHA256_DIGEST_LENGTH);
+ if (!digest) {
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ break;
+ case LDNS_HASH_GOST:
+#ifdef USE_GOST
+ (void)ldns_key_EVP_load_gost_id();
+ md = EVP_get_digestbyname("md_gost94");
+ if(!md) {
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ digest = LDNS_XMALLOC(uint8_t, EVP_MD_size(md));
+ if (!digest) {
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ break;
+#else
+ /* not implemented */
+ ldns_rr_free(ds);
+ return NULL;
+#endif
+#ifdef USE_ECDSA
+ /* Make similar ``not implemented'' construct as above when
+ draft-hoffman-dnssec-ecdsa-04 becomes a standard
+ */
+ case LDNS_SHA384:
+ digest = LDNS_XMALLOC(uint8_t, SHA384_DIGEST_LENGTH);
+ if (!digest) {
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ break;
+#endif
+ }
+
+ data_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!data_buf) {
+ LDNS_FREE(digest);
+ ldns_rr_free(ds);
+ return NULL;
+ }
+
+ /* keytag */
+ keytag = htons(ldns_calc_keytag((ldns_rr*)key));
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16,
+ sizeof(uint16_t),
+ &keytag);
+ ldns_rr_push_rdf(ds, tmp);
+
+ /* copy the algorithm field */
+ if ((tmp = ldns_rr_rdf(key, 2)) == NULL) {
+ LDNS_FREE(digest);
+ ldns_buffer_free(data_buf);
+ ldns_rr_free(ds);
+ return NULL;
+ } else {
+ ldns_rr_push_rdf(ds, ldns_rdf_clone( tmp ));
+ }
+
+ /* digest hash type */
+ sha1hash = (uint8_t)h;
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
+ sizeof(uint8_t),
+ &sha1hash);
+ ldns_rr_push_rdf(ds, tmp);
+
+ /* digest */
+ /* owner name */
+ tmp = ldns_rdf_clone(ldns_rr_owner(key));
+ ldns_dname2canonical(tmp);
+ if (ldns_rdf2buffer_wire(data_buf, tmp) != LDNS_STATUS_OK) {
+ LDNS_FREE(digest);
+ ldns_buffer_free(data_buf);
+ ldns_rr_free(ds);
+ ldns_rdf_deep_free(tmp);
+ return NULL;
+ }
+ ldns_rdf_deep_free(tmp);
+
+ /* all the rdata's */
+ if (ldns_rr_rdata2buffer_wire(data_buf,
+ (ldns_rr*)key) != LDNS_STATUS_OK) {
+ LDNS_FREE(digest);
+ ldns_buffer_free(data_buf);
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ switch(h) {
+ case LDNS_SHA1:
+ (void) ldns_sha1((unsigned char *) ldns_buffer_begin(data_buf),
+ (unsigned int) ldns_buffer_position(data_buf),
+ (unsigned char *) digest);
+
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
+ LDNS_SHA1_DIGEST_LENGTH,
+ digest);
+ ldns_rr_push_rdf(ds, tmp);
+
+ break;
+ case LDNS_SHA256:
+ (void) ldns_sha256((unsigned char *) ldns_buffer_begin(data_buf),
+ (unsigned int) ldns_buffer_position(data_buf),
+ (unsigned char *) digest);
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
+ LDNS_SHA256_DIGEST_LENGTH,
+ digest);
+ ldns_rr_push_rdf(ds, tmp);
+ break;
+ case LDNS_HASH_GOST:
+#ifdef USE_GOST
+ if(!ldns_digest_evp((unsigned char *) ldns_buffer_begin(data_buf),
+ (unsigned int) ldns_buffer_position(data_buf),
+ (unsigned char *) digest, md)) {
+ LDNS_FREE(digest);
+ ldns_buffer_free(data_buf);
+ ldns_rr_free(ds);
+ return NULL;
+ }
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
+ (size_t)EVP_MD_size(md),
+ digest);
+ ldns_rr_push_rdf(ds, tmp);
+#endif
+ break;
+#ifdef USE_ECDSA
+ case LDNS_SHA384:
+ (void) SHA384((unsigned char *) ldns_buffer_begin(data_buf),
+ (unsigned int) ldns_buffer_position(data_buf),
+ (unsigned char *) digest);
+ tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
+ SHA384_DIGEST_LENGTH,
+ digest);
+ ldns_rr_push_rdf(ds, tmp);
+ break;
+#endif
+ }
+
+ LDNS_FREE(digest);
+ ldns_buffer_free(data_buf);
+ return ds;
+}
+
+ldns_rdf *
+ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[],
+ size_t size,
+ ldns_rr_type nsec_type)
+{
+ size_t i;
+ uint8_t *bitmap;
+ uint16_t bm_len = 0;
+ uint16_t i_type;
+ ldns_rdf *bitmap_rdf;
+
+ uint8_t *data = NULL;
+ uint8_t cur_data[32];
+ uint8_t cur_window = 0;
+ uint8_t cur_window_max = 0;
+ uint16_t cur_data_size = 0;
+
+ if (nsec_type != LDNS_RR_TYPE_NSEC &&
+ nsec_type != LDNS_RR_TYPE_NSEC3) {
+ return NULL;
+ }
+
+ i_type = 0;
+ for (i = 0; i < size; i++) {
+ if (i_type < rr_type_list[i])
+ i_type = rr_type_list[i];
+ }
+ if (i_type < nsec_type) {
+ i_type = nsec_type;
+ }
+
+ bm_len = i_type / 8 + 2;
+ bitmap = LDNS_XMALLOC(uint8_t, bm_len);
+ if(!bitmap) return NULL;
+ for (i = 0; i < bm_len; i++) {
+ bitmap[i] = 0;
+ }
+
+ for (i = 0; i < size; i++) {
+ i_type = rr_type_list[i];
+ ldns_set_bit(bitmap + (int) i_type / 8,
+ (int) (7 - (i_type % 8)),
+ true);
+ }
+
+ /* fold it into windows TODO: can this be done directly? */
+ memset(cur_data, 0, 32);
+ for (i = 0; i < bm_len; i++) {
+ if (i / 32 > cur_window) {
+ /* check, copy, new */
+ if (cur_window_max > 0) {
+ /* this window has stuff, add it */
+ data = LDNS_XREALLOC(data,
+ uint8_t,
+ cur_data_size + cur_window_max + 3);
+ if(!data) {
+ LDNS_FREE(bitmap);
+ return NULL;
+ }
+ data[cur_data_size] = cur_window;
+ data[cur_data_size + 1] = cur_window_max + 1;
+ memcpy(data + cur_data_size + 2,
+ cur_data,
+ cur_window_max+1);
+ cur_data_size += cur_window_max + 3;
+ }
+ cur_window++;
+ cur_window_max = 0;
+ memset(cur_data, 0, 32);
+ }
+ cur_data[i%32] = bitmap[i];
+ if (bitmap[i] > 0) {
+ cur_window_max = i%32;
+ }
+ }
+ if (cur_window_max > 0 || cur_data[0] != 0) {
+ /* this window has stuff, add it */
+ data = LDNS_XREALLOC(data,
+ uint8_t,
+ cur_data_size + cur_window_max + 3);
+ if(!data) {
+ LDNS_FREE(bitmap);
+ return NULL;
+ }
+ data[cur_data_size] = cur_window;
+ data[cur_data_size + 1] = cur_window_max + 1;
+ memcpy(data + cur_data_size + 2, cur_data, cur_window_max+1);
+ cur_data_size += cur_window_max + 3;
+ }
+
+ bitmap_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC,
+ cur_data_size,
+ data);
+
+ LDNS_FREE(bitmap);
+ LDNS_FREE(data);
+
+ return bitmap_rdf;
+}
+
+int
+ldns_dnssec_rrsets_contains_type(ldns_dnssec_rrsets *rrsets,
+ ldns_rr_type type)
+{
+ ldns_dnssec_rrsets *cur_rrset = rrsets;
+ while (cur_rrset) {
+ if (cur_rrset->type == type) {
+ return 1;
+ }
+ cur_rrset = cur_rrset->next;
+ }
+ return 0;
+}
+
+ldns_rr *
+ldns_dnssec_create_nsec(ldns_dnssec_name *from,
+ ldns_dnssec_name *to,
+ ldns_rr_type nsec_type)
+{
+ ldns_rr *nsec_rr;
+ ldns_rr_type types[65536];
+ size_t type_count = 0;
+ ldns_dnssec_rrsets *cur_rrsets;
+ int on_delegation_point;
+
+ if (!from || !to || (nsec_type != LDNS_RR_TYPE_NSEC)) {
+ return NULL;
+ }
+
+ nsec_rr = ldns_rr_new();
+ ldns_rr_set_type(nsec_rr, nsec_type);
+ ldns_rr_set_owner(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(from)));
+ ldns_rr_push_rdf(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(to)));
+
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_SOA);
+
+ cur_rrsets = from->rrsets;
+ while (cur_rrsets) {
+ /* Do not include non-authoritative rrsets on the delegation point
+ * in the type bitmap */
+ if ((on_delegation_point && (
+ cur_rrsets->type == LDNS_RR_TYPE_NS
+ || cur_rrsets->type == LDNS_RR_TYPE_DS))
+ || (!on_delegation_point &&
+ cur_rrsets->type != LDNS_RR_TYPE_RRSIG
+ && cur_rrsets->type != LDNS_RR_TYPE_NSEC)) {
+
+ types[type_count] = cur_rrsets->type;
+ type_count++;
+ }
+ cur_rrsets = cur_rrsets->next;
+
+ }
+ types[type_count] = LDNS_RR_TYPE_RRSIG;
+ type_count++;
+ types[type_count] = LDNS_RR_TYPE_NSEC;
+ type_count++;
+
+ ldns_rr_push_rdf(nsec_rr, ldns_dnssec_create_nsec_bitmap(types,
+ type_count,
+ nsec_type));
+
+ return nsec_rr;
+}
+
+ldns_rr *
+ldns_dnssec_create_nsec3(ldns_dnssec_name *from,
+ ldns_dnssec_name *to,
+ ldns_rdf *zone_name,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt)
+{
+ ldns_rr *nsec_rr;
+ ldns_rr_type types[65536];
+ size_t type_count = 0;
+ ldns_dnssec_rrsets *cur_rrsets;
+ ldns_status status;
+ int on_delegation_point;
+
+ flags = flags;
+
+ if (!from) {
+ return NULL;
+ }
+
+ nsec_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3);
+ ldns_rr_set_owner(nsec_rr,
+ ldns_nsec3_hash_name(ldns_dnssec_name_name(from),
+ algorithm,
+ iterations,
+ salt_length,
+ salt));
+ status = ldns_dname_cat(ldns_rr_owner(nsec_rr), zone_name);
+ if(status != LDNS_STATUS_OK) {
+ ldns_rr_free(nsec_rr);
+ return NULL;
+ }
+ ldns_nsec3_add_param_rdfs(nsec_rr,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt);
+
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ from->rrsets, LDNS_RR_TYPE_SOA);
+ 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
+ * delegation should have been done earlier, in function
+ * ldns_dnssec_zone_create_nsec3s, or even earlier in:
+ * ldns_dnssec_zone_sign_nsec3_flg .
+ */
+ if ((on_delegation_point && (
+ cur_rrsets->type == LDNS_RR_TYPE_NS
+ || cur_rrsets->type == LDNS_RR_TYPE_DS))
+ || (!on_delegation_point &&
+ cur_rrsets->type != LDNS_RR_TYPE_RRSIG)) {
+
+ types[type_count] = cur_rrsets->type;
+ type_count++;
+ }
+ cur_rrsets = cur_rrsets->next;
+ }
+ /* always add rrsig type if this is not an unsigned
+ * delegation
+ */
+ if (type_count > 0 &&
+ !(type_count == 1 && types[0] == LDNS_RR_TYPE_NS)) {
+ types[type_count] = LDNS_RR_TYPE_RRSIG;
+ type_count++;
+ }
+
+ /* leave next rdata empty if they weren't precomputed yet */
+ if (to && to->hashed_name) {
+ (void) ldns_rr_set_rdf(nsec_rr,
+ ldns_rdf_clone(to->hashed_name),
+ 4);
+ } else {
+ (void) ldns_rr_set_rdf(nsec_rr, NULL, 4);
+ }
+
+ ldns_rr_push_rdf(nsec_rr,
+ ldns_dnssec_create_nsec_bitmap(types,
+ type_count,
+ LDNS_RR_TYPE_NSEC3));
+
+ return nsec_rr;
+}
+
+ldns_rr *
+ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs)
+{
+ /* we do not do any check here - garbage in, garbage out */
+
+ /* the the start and end names - get the type from the
+ * before rrlist */
+
+ /* inefficient, just give it a name, a next name, and a list of rrs */
+ /* we make 1 big uberbitmap first, then windows */
+ /* todo: make something more efficient :) */
+ uint16_t i;
+ ldns_rr *i_rr;
+ uint16_t i_type;
+
+ ldns_rr *nsec = NULL;
+ ldns_rr_type i_type_list[65536];
+ size_t type_count = 0;
+
+ nsec = ldns_rr_new();
+ ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC);
+ ldns_rr_set_owner(nsec, ldns_rdf_clone(cur_owner));
+ ldns_rr_push_rdf(nsec, ldns_rdf_clone(next_owner));
+
+ for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ i_rr = ldns_rr_list_rr(rrs, i);
+ if (ldns_rdf_compare(cur_owner,
+ ldns_rr_owner(i_rr)) == 0) {
+ i_type = ldns_rr_get_type(i_rr);
+ if (i_type != LDNS_RR_TYPE_RRSIG && i_type != LDNS_RR_TYPE_NSEC) {
+ if (type_count == 0 || i_type_list[type_count-1] != i_type) {
+ i_type_list[type_count] = i_type;
+ type_count++;
+ }
+ }
+ }
+ }
+
+ i_type_list[type_count] = LDNS_RR_TYPE_RRSIG;
+ type_count++;
+ i_type_list[type_count] = LDNS_RR_TYPE_NSEC;
+ type_count++;
+
+ ldns_rr_push_rdf(nsec,
+ ldns_dnssec_create_nsec_bitmap(i_type_list,
+ type_count, LDNS_RR_TYPE_NSEC));
+
+ return nsec;
+}
+
+ldns_rdf *
+ldns_nsec3_hash_name(ldns_rdf *name,
+ uint8_t algorithm,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt)
+{
+ size_t hashed_owner_str_len;
+ ldns_rdf *cann;
+ ldns_rdf *hashed_owner;
+ unsigned char *hashed_owner_str;
+ char *hashed_owner_b32;
+ size_t hashed_owner_b32_len;
+ uint32_t cur_it;
+ /* define to contain the largest possible hash, which is
+ * sha1 at the moment */
+ unsigned char hash[LDNS_SHA1_DIGEST_LENGTH];
+ ldns_status status;
+
+ /* TODO: mnemonic list for hash algs SHA-1, default to 1 now (sha1) */
+ if (algorithm != LDNS_SHA1) {
+ return NULL;
+ }
+
+ /* prepare the owner name according to the draft section bla */
+ cann = ldns_rdf_clone(name);
+ if(!cann) {
+ fprintf(stderr, "Memory error\n");
+ return NULL;
+ }
+ ldns_dname2canonical(cann);
+
+ hashed_owner_str_len = salt_length + ldns_rdf_size(cann);
+ hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len);
+ if(!hashed_owner_str) {
+ ldns_rdf_deep_free(cann);
+ return NULL;
+ }
+ memcpy(hashed_owner_str, ldns_rdf_data(cann), ldns_rdf_size(cann));
+ memcpy(hashed_owner_str + ldns_rdf_size(cann), salt, salt_length);
+ ldns_rdf_deep_free(cann);
+
+ for (cur_it = iterations + 1; cur_it > 0; cur_it--) {
+ (void) ldns_sha1((unsigned char *) hashed_owner_str,
+ (unsigned int) hashed_owner_str_len, hash);
+
+ LDNS_FREE(hashed_owner_str);
+ hashed_owner_str_len = salt_length + LDNS_SHA1_DIGEST_LENGTH;
+ hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len);
+ if (!hashed_owner_str) {
+ return NULL;
+ }
+ memcpy(hashed_owner_str, hash, LDNS_SHA1_DIGEST_LENGTH);
+ memcpy(hashed_owner_str + LDNS_SHA1_DIGEST_LENGTH, salt, salt_length);
+ hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH + salt_length;
+ }
+
+ LDNS_FREE(hashed_owner_str);
+ hashed_owner_str = hash;
+ hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH;
+
+ hashed_owner_b32 = LDNS_XMALLOC(char,
+ ldns_b32_ntop_calculate_size(hashed_owner_str_len) + 1);
+ if(!hashed_owner_b32) {
+ return NULL;
+ }
+ hashed_owner_b32_len = (size_t) ldns_b32_ntop_extended_hex(
+ (uint8_t *) hashed_owner_str,
+ hashed_owner_str_len,
+ hashed_owner_b32,
+ ldns_b32_ntop_calculate_size(hashed_owner_str_len)+1);
+ if (hashed_owner_b32_len < 1) {
+ fprintf(stderr, "Error in base32 extended hex encoding ");
+ fprintf(stderr, "of hashed owner name (name: ");
+ ldns_rdf_print(stderr, name);
+ fprintf(stderr, ", return code: %u)\n",
+ (unsigned int) hashed_owner_b32_len);
+ LDNS_FREE(hashed_owner_b32);
+ return NULL;
+ }
+ hashed_owner_b32[hashed_owner_b32_len] = '\0';
+
+ status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32);
+ if (status != LDNS_STATUS_OK) {
+ fprintf(stderr, "Error creating rdf from %s\n", hashed_owner_b32);
+ LDNS_FREE(hashed_owner_b32);
+ return NULL;
+ }
+
+ LDNS_FREE(hashed_owner_b32);
+ return hashed_owner;
+}
+
+void
+ldns_nsec3_add_param_rdfs(ldns_rr *rr,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt)
+{
+ ldns_rdf *salt_rdf = NULL;
+ uint8_t *salt_data = NULL;
+ ldns_rdf *old;
+
+ old = ldns_rr_set_rdf(rr,
+ ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
+ 1, (void*)&algorithm),
+ 0);
+ if (old) ldns_rdf_deep_free(old);
+
+ old = ldns_rr_set_rdf(rr,
+ ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
+ 1, (void*)&flags),
+ 1);
+ if (old) ldns_rdf_deep_free(old);
+
+ old = ldns_rr_set_rdf(rr,
+ ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
+ iterations),
+ 2);
+ if (old) ldns_rdf_deep_free(old);
+
+ salt_data = LDNS_XMALLOC(uint8_t, salt_length + 1);
+ if(!salt_data) {
+ /* no way to return error */
+ return;
+ }
+ salt_data[0] = salt_length;
+ memcpy(salt_data + 1, salt, salt_length);
+ salt_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT,
+ salt_length + 1,
+ salt_data);
+ if(!salt_rdf) {
+ LDNS_FREE(salt_data);
+ /* no way to return error */
+ return;
+ }
+
+ old = ldns_rr_set_rdf(rr, salt_rdf, 3);
+ if (old) ldns_rdf_deep_free(old);
+ LDNS_FREE(salt_data);
+}
+
+static int
+rr_list_delegation_only(ldns_rdf *origin, ldns_rr_list *rr_list)
+{
+ size_t i;
+ ldns_rr *cur_rr;
+ if (!origin || !rr_list) return 0;
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ cur_rr = ldns_rr_list_rr(rr_list, i);
+ if (ldns_dname_compare(ldns_rr_owner(cur_rr), origin) == 0) {
+ return 0;
+ }
+ if (ldns_rr_get_type(cur_rr) != LDNS_RR_TYPE_NS) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* this will NOT return the NSEC3 completed, you will have to run the
+ finalize function on the rrlist later! */
+ldns_rr *
+ldns_create_nsec3(ldns_rdf *cur_owner,
+ ldns_rdf *cur_zone,
+ ldns_rr_list *rrs,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ bool emptynonterminal)
+{
+ size_t i;
+ ldns_rr *i_rr;
+ uint16_t i_type;
+
+ ldns_rr *nsec = NULL;
+ ldns_rdf *hashed_owner = NULL;
+
+ ldns_status status;
+
+ ldns_rr_type i_type_list[1024];
+ size_t type_count = 0;
+
+ hashed_owner = ldns_nsec3_hash_name(cur_owner,
+ algorithm,
+ iterations,
+ salt_length,
+ salt);
+ status = ldns_dname_cat(hashed_owner, cur_zone);
+ if(status != LDNS_STATUS_OK)
+ return NULL;
+
+ nsec = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3);
+ if(!nsec)
+ return NULL;
+ ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC3);
+ ldns_rr_set_owner(nsec, hashed_owner);
+
+ ldns_nsec3_add_param_rdfs(nsec,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt);
+ (void) ldns_rr_set_rdf(nsec, NULL, 4);
+
+
+ for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ i_rr = ldns_rr_list_rr(rrs, i);
+ if (ldns_rdf_compare(cur_owner,
+ ldns_rr_owner(i_rr)) == 0) {
+ i_type = ldns_rr_get_type(i_rr);
+ if (type_count == 0 || i_type_list[type_count-1] != i_type) {
+ i_type_list[type_count] = i_type;
+ type_count++;
+ }
+ }
+ }
+
+ /* add RRSIG anyway, but only if this is not an ENT or
+ * an unsigned delegation */
+ if (!emptynonterminal && !rr_list_delegation_only(cur_zone, rrs)) {
+ i_type_list[type_count] = LDNS_RR_TYPE_RRSIG;
+ type_count++;
+ }
+
+ /* and SOA if owner == zone */
+ if (ldns_dname_compare(cur_zone, cur_owner) == 0) {
+ i_type_list[type_count] = LDNS_RR_TYPE_SOA;
+ type_count++;
+ }
+
+ ldns_rr_push_rdf(nsec,
+ ldns_dnssec_create_nsec_bitmap(i_type_list,
+ type_count, LDNS_RR_TYPE_NSEC3));
+
+ return nsec;
+}
+
+uint8_t
+ldns_nsec3_algorithm(const ldns_rr *nsec3_rr)
+{
+ if (nsec3_rr &&
+ (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
+ ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
+ && (ldns_rr_rdf(nsec3_rr, 0) != NULL)
+ && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 0)) > 0) {
+ return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 0));
+ }
+ return 0;
+}
+
+uint8_t
+ldns_nsec3_flags(const ldns_rr *nsec3_rr)
+{
+ if (nsec3_rr &&
+ (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
+ ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
+ && (ldns_rr_rdf(nsec3_rr, 1) != NULL)
+ && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 1)) > 0) {
+ return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 1));
+ }
+ return 0;
+}
+
+bool
+ldns_nsec3_optout(const ldns_rr *nsec3_rr)
+{
+ return (ldns_nsec3_flags(nsec3_rr) & LDNS_NSEC3_VARS_OPTOUT_MASK);
+}
+
+uint16_t
+ldns_nsec3_iterations(const ldns_rr *nsec3_rr)
+{
+ if (nsec3_rr &&
+ (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
+ ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
+ && (ldns_rr_rdf(nsec3_rr, 2) != NULL)
+ && ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 2)) > 0) {
+ return ldns_rdf2native_int16(ldns_rr_rdf(nsec3_rr, 2));
+ }
+ return 0;
+
+}
+
+ldns_rdf *
+ldns_nsec3_salt(const ldns_rr *nsec3_rr)
+{
+ if (nsec3_rr &&
+ (ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
+ ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
+ ) {
+ return ldns_rr_rdf(nsec3_rr, 3);
+ }
+ return NULL;
+}
+
+uint8_t
+ldns_nsec3_salt_length(const ldns_rr *nsec3_rr)
+{
+ ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
+ if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
+ return (uint8_t) ldns_rdf_data(salt_rdf)[0];
+ }
+ return 0;
+}
+
+/* allocs data, free with LDNS_FREE() */
+uint8_t *
+ldns_nsec3_salt_data(const ldns_rr *nsec3_rr)
+{
+ uint8_t salt_length;
+ uint8_t *salt;
+
+ 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];
+ salt = LDNS_XMALLOC(uint8_t, salt_length);
+ if(!salt) return NULL;
+ memcpy(salt, &ldns_rdf_data(salt_rdf)[1], salt_length);
+ return salt;
+ }
+ return NULL;
+}
+
+ldns_rdf *
+ldns_nsec3_next_owner(const ldns_rr *nsec3_rr)
+{
+ if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
+ return NULL;
+ } else {
+ return ldns_rr_rdf(nsec3_rr, 4);
+ }
+}
+
+ldns_rdf *
+ldns_nsec3_bitmap(const ldns_rr *nsec3_rr)
+{
+ if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
+ return NULL;
+ } else {
+ return ldns_rr_rdf(nsec3_rr, 5);
+ }
+}
+
+ldns_rdf *
+ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name)
+{
+ uint8_t algorithm;
+ uint16_t iterations;
+ uint8_t salt_length;
+ uint8_t *salt = 0;
+
+ ldns_rdf *hashed_owner;
+
+ algorithm = ldns_nsec3_algorithm(nsec);
+ salt_length = ldns_nsec3_salt_length(nsec);
+ salt = ldns_nsec3_salt_data(nsec);
+ iterations = ldns_nsec3_iterations(nsec);
+
+ hashed_owner = ldns_nsec3_hash_name(name,
+ algorithm,
+ iterations,
+ salt_length,
+ salt);
+
+ LDNS_FREE(salt);
+ return hashed_owner;
+}
+
+bool
+ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type)
+{
+ uint8_t window_block_nr;
+ uint8_t bitmap_length;
+ uint16_t cur_type;
+ uint16_t pos = 0;
+ uint16_t bit_pos;
+ uint8_t *data;
+
+ if (nsec_bitmap == NULL) {
+ return false;
+ }
+ data = ldns_rdf_data(nsec_bitmap);
+ while(pos < ldns_rdf_size(nsec_bitmap)) {
+ window_block_nr = data[pos];
+ bitmap_length = data[pos + 1];
+ pos += 2;
+
+ for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
+ if (ldns_get_bit(&data[pos], bit_pos)) {
+ cur_type = 256 * (uint16_t) window_block_nr + bit_pos;
+ if (cur_type == type) {
+ return true;
+ }
+ }
+ }
+
+ pos += (uint16_t) bitmap_length;
+ }
+ return false;
+}
+
+bool
+ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name)
+{
+ ldns_rdf *nsec_owner = ldns_rr_owner(nsec);
+ ldns_rdf *hash_next;
+ char *next_hash_str;
+ ldns_rdf *nsec_next = NULL;
+ ldns_status status;
+ ldns_rdf *chopped_dname;
+ bool result;
+
+ if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) {
+ if (ldns_rr_rdf(nsec, 0) != NULL) {
+ nsec_next = ldns_rdf_clone(ldns_rr_rdf(nsec, 0));
+ } else {
+ return false;
+ }
+ } else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) {
+ hash_next = ldns_nsec3_next_owner(nsec);
+ next_hash_str = ldns_rdf2str(hash_next);
+ nsec_next = ldns_dname_new_frm_str(next_hash_str);
+ LDNS_FREE(next_hash_str);
+ chopped_dname = ldns_dname_left_chop(nsec_owner);
+ status = ldns_dname_cat(nsec_next, chopped_dname);
+ ldns_rdf_deep_free(chopped_dname);
+ if (status != LDNS_STATUS_OK) {
+ printf("error catting: %s\n", ldns_get_errorstr_by_id(status));
+ }
+ } else {
+ ldns_rdf_deep_free(nsec_next);
+ return false;
+ }
+
+ /* in the case of the last nsec */
+ if(ldns_dname_compare(nsec_owner, nsec_next) > 0) {
+ result = (ldns_dname_compare(nsec_owner, name) <= 0 ||
+ ldns_dname_compare(name, nsec_next) < 0);
+ } else {
+ result = (ldns_dname_compare(nsec_owner, name) <= 0 &&
+ ldns_dname_compare(name, nsec_next) < 0);
+ }
+
+ ldns_rdf_deep_free(nsec_next);
+ return result;
+}
+
+#ifdef HAVE_SSL
+/* sig may be null - if so look in the packet */
+
+ldns_status
+ldns_pkt_verify_time(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o,
+ ldns_rr_list *k, ldns_rr_list *s,
+ time_t check_time, ldns_rr_list *good_keys)
+{
+ ldns_rr_list *rrset;
+ ldns_rr_list *sigs;
+ ldns_rr_list *sigs_covered;
+ ldns_rdf *rdf_t;
+ ldns_rr_type t_netorder;
+
+ if (!k) {
+ return LDNS_STATUS_ERR;
+ /* return LDNS_STATUS_CRYPTO_NO_DNSKEY; */
+ }
+
+ if (t == LDNS_RR_TYPE_RRSIG) {
+ /* we don't have RRSIG(RRSIG) (yet? ;-) ) */
+ return LDNS_STATUS_ERR;
+ }
+
+ if (s) {
+ /* if s is not NULL, the sigs are given to use */
+ sigs = s;
+ } else {
+ /* otherwise get them from the packet */
+ sigs = ldns_pkt_rr_list_by_name_and_type(p, o, LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANY_NOQUESTION);
+ if (!sigs) {
+ /* no sigs */
+ return LDNS_STATUS_ERR;
+ /* return LDNS_STATUS_CRYPTO_NO_RRSIG; */
+ }
+ }
+
+ /* rrsig are subtyped, so now we need to find the correct
+ * sigs for the type t
+ */
+ t_netorder = htons(t); /* rdf are in network order! */
+ /* a type identifier is a 16-bit number, so the size is 2 bytes */
+ rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE,
+ 2,
+ &t_netorder);
+ sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
+
+ rrset = ldns_pkt_rr_list_by_name_and_type(p,
+ o,
+ t,
+ LDNS_SECTION_ANY_NOQUESTION);
+
+ if (!rrset) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (!sigs_covered) {
+ return LDNS_STATUS_ERR;
+ }
+
+ return ldns_verify_time(rrset, sigs, k, check_time, good_keys);
+}
+
+ldns_status
+ldns_pkt_verify(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o,
+ ldns_rr_list *k, ldns_rr_list *s, ldns_rr_list *good_keys)
+{
+ return ldns_pkt_verify_time(p, t, o, k, s, ldns_time(NULL), good_keys);
+}
+#endif /* HAVE_SSL */
+
+ldns_status
+ldns_dnssec_chain_nsec3_list(ldns_rr_list *nsec3_rrs)
+{
+ size_t i;
+ char *next_nsec_owner_str;
+ ldns_rdf *next_nsec_owner_label;
+ ldns_rdf *next_nsec_rdf;
+ ldns_status status = LDNS_STATUS_OK;
+
+ for (i = 0; i < ldns_rr_list_rr_count(nsec3_rrs); i++) {
+ if (i == ldns_rr_list_rr_count(nsec3_rrs) - 1) {
+ next_nsec_owner_label =
+ ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs,
+ 0)), 0);
+ next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label);
+ if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
+ == '.') {
+ next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
+ = '\0';
+ }
+ status = ldns_str2rdf_b32_ext(&next_nsec_rdf,
+ next_nsec_owner_str);
+ if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i),
+ next_nsec_rdf, 4)) {
+ /* todo: error */
+ }
+
+ ldns_rdf_deep_free(next_nsec_owner_label);
+ LDNS_FREE(next_nsec_owner_str);
+ } else {
+ next_nsec_owner_label =
+ ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs,
+ i + 1)),
+ 0);
+ next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label);
+ if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
+ == '.') {
+ next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
+ = '\0';
+ }
+ status = ldns_str2rdf_b32_ext(&next_nsec_rdf,
+ next_nsec_owner_str);
+ ldns_rdf_deep_free(next_nsec_owner_label);
+ LDNS_FREE(next_nsec_owner_str);
+ if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i),
+ next_nsec_rdf, 4)) {
+ /* todo: error */
+ }
+ }
+ }
+ return status;
+}
+
+int
+qsort_rr_compare_nsec3(const void *a, const void *b)
+{
+ const ldns_rr *rr1 = * (const ldns_rr **) a;
+ const ldns_rr *rr2 = * (const ldns_rr **) b;
+ if (rr1 == NULL && rr2 == NULL) {
+ return 0;
+ }
+ if (rr1 == NULL) {
+ return -1;
+ }
+ if (rr2 == NULL) {
+ return 1;
+ }
+ return ldns_rdf_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2));
+}
+
+void
+ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted)
+{
+ qsort(unsorted->_rrs,
+ ldns_rr_list_rr_count(unsorted),
+ sizeof(ldns_rr *),
+ qsort_rr_compare_nsec3);
+}
+
+int
+ldns_dnssec_default_add_to_signatures(ldns_rr *sig, void *n)
+{
+ sig = sig;
+ n = n;
+ return LDNS_SIGNATURE_LEAVE_ADD_NEW;
+}
+
+int
+ldns_dnssec_default_leave_signatures(ldns_rr *sig, void *n)
+{
+ sig = sig;
+ n = n;
+ return LDNS_SIGNATURE_LEAVE_NO_ADD;
+}
+
+int
+ldns_dnssec_default_delete_signatures(ldns_rr *sig, void *n)
+{
+ sig = sig;
+ n = n;
+ return LDNS_SIGNATURE_REMOVE_NO_ADD;
+}
+
+int
+ldns_dnssec_default_replace_signatures(ldns_rr *sig, void *n)
+{
+ sig = sig;
+ n = n;
+ return LDNS_SIGNATURE_REMOVE_ADD_NEW;
+}
+
+#ifdef HAVE_SSL
+ldns_rdf *
+ldns_convert_dsa_rrsig_asn12rdf(const ldns_buffer *sig,
+ const long sig_len)
+{
+ ldns_rdf *sigdata_rdf;
+ DSA_SIG *dsasig;
+ unsigned char *dsasig_data = (unsigned char*)ldns_buffer_begin(sig);
+ size_t byte_offset;
+
+ dsasig = d2i_DSA_SIG(NULL,
+ (const unsigned char **)&dsasig_data,
+ sig_len);
+ if (!dsasig) {
+ DSA_SIG_free(dsasig);
+ return NULL;
+ }
+
+ dsasig_data = LDNS_XMALLOC(unsigned char, 41);
+ if(!dsasig_data) {
+ DSA_SIG_free(dsasig);
+ return NULL;
+ }
+ dsasig_data[0] = 0;
+ byte_offset = (size_t) (20 - BN_num_bytes(dsasig->r));
+ if (byte_offset > 20) {
+ DSA_SIG_free(dsasig);
+ LDNS_FREE(dsasig_data);
+ return NULL;
+ }
+ memset(&dsasig_data[1], 0, byte_offset);
+ BN_bn2bin(dsasig->r, &dsasig_data[1 + byte_offset]);
+ byte_offset = (size_t) (20 - BN_num_bytes(dsasig->s));
+ if (byte_offset > 20) {
+ DSA_SIG_free(dsasig);
+ LDNS_FREE(dsasig_data);
+ return NULL;
+ }
+ memset(&dsasig_data[21], 0, byte_offset);
+ BN_bn2bin(dsasig->s, &dsasig_data[21 + byte_offset]);
+
+ sigdata_rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, 41, dsasig_data);
+ if(!sigdata_rdf) {
+ LDNS_FREE(dsasig_data);
+ }
+ DSA_SIG_free(dsasig);
+
+ return sigdata_rdf;
+}
+
+ldns_status
+ldns_convert_dsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+ const ldns_rdf *sig_rdf)
+{
+ /* the EVP api wants the DER encoding of the signature... */
+ BIGNUM *R, *S;
+ DSA_SIG *dsasig;
+ unsigned char *raw_sig = NULL;
+ int raw_sig_len;
+
+ if(ldns_rdf_size(sig_rdf) < 1 + 2*SHA_DIGEST_LENGTH)
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ /* extract the R and S field from the sig buffer */
+ R = BN_new();
+ if(!R) return LDNS_STATUS_MEM_ERR;
+ (void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 1,
+ SHA_DIGEST_LENGTH, R);
+ S = BN_new();
+ if(!S) {
+ BN_free(R);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ (void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 21,
+ SHA_DIGEST_LENGTH, S);
+
+ dsasig = DSA_SIG_new();
+ if (!dsasig) {
+ BN_free(R);
+ BN_free(S);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ dsasig->r = R;
+ dsasig->s = S;
+
+ raw_sig_len = i2d_DSA_SIG(dsasig, &raw_sig);
+ if (raw_sig_len < 0) {
+ DSA_SIG_free(dsasig);
+ free(raw_sig);
+ return LDNS_STATUS_SSL_ERR;
+ }
+ if (ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) {
+ ldns_buffer_write(target_buffer, raw_sig, (size_t)raw_sig_len);
+ }
+
+ DSA_SIG_free(dsasig);
+ free(raw_sig);
+
+ return ldns_buffer_status(target_buffer);
+}
+
+#ifdef USE_ECDSA
+#ifndef S_SPLINT_S
+ldns_rdf *
+ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len)
+{
+ ECDSA_SIG* ecdsa_sig;
+ unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
+ ldns_rdf* rdf;
+ ecdsa_sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&data, sig_len);
+ if(!ecdsa_sig) return NULL;
+
+ /* "r | s". */
+ data = LDNS_XMALLOC(unsigned char,
+ BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s));
+ if(!data) {
+ ECDSA_SIG_free(ecdsa_sig);
+ return NULL;
+ }
+ BN_bn2bin(ecdsa_sig->r, data);
+ BN_bn2bin(ecdsa_sig->s, data+BN_num_bytes(ecdsa_sig->r));
+ rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, (size_t)(
+ BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s)), data);
+ ECDSA_SIG_free(ecdsa_sig);
+ return rdf;
+}
+
+ldns_status
+ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
+ const ldns_rdf *sig_rdf)
+{
+ ECDSA_SIG* sig;
+ int raw_sig_len;
+ long bnsize = (long)ldns_rdf_size(sig_rdf) / 2;
+ /* if too short, or not even length, do not bother */
+ if(bnsize < 16 || (size_t)bnsize*2 != ldns_rdf_size(sig_rdf))
+ return LDNS_STATUS_ERR;
+
+ /* use the raw data to parse two evenly long BIGNUMs, "r | s". */
+ sig = ECDSA_SIG_new();
+ if(!sig) return LDNS_STATUS_MEM_ERR;
+ sig->r = BN_bin2bn((const unsigned char*)ldns_rdf_data(sig_rdf),
+ bnsize, sig->r);
+ sig->s = BN_bin2bn((const unsigned char*)ldns_rdf_data(sig_rdf)+bnsize,
+ bnsize, sig->s);
+ if(!sig->r || !sig->s) {
+ ECDSA_SIG_free(sig);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ raw_sig_len = i2d_ECDSA_SIG(sig, NULL);
+ if (ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) {
+ unsigned char* pp = (unsigned char*)
+ ldns_buffer_current(target_buffer);
+ raw_sig_len = i2d_ECDSA_SIG(sig, &pp);
+ ldns_buffer_skip(target_buffer, (ssize_t) raw_sig_len);
+ }
+ ECDSA_SIG_free(sig);
+
+ return ldns_buffer_status(target_buffer);
+}
+
+#endif /* S_SPLINT_S */
+#endif /* USE_ECDSA */
+#endif /* HAVE_SSL */
diff --git a/3rdParty/Ldns/src/src/dnssec_sign.c b/3rdParty/Ldns/src/src/dnssec_sign.c
new file mode 100644
index 0000000..1d283bc
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dnssec_sign.c
@@ -0,0 +1,1420 @@
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <ldns/dnssec.h>
+#include <ldns/dnssec_sign.h>
+
+#include <strings.h>
+#include <time.h>
+
+#ifdef HAVE_SSL
+/* this entire file is rather useless when you don't have
+ * crypto...
+ */
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#endif /* HAVE_SSL */
+
+ldns_rr *
+ldns_create_empty_rrsig(ldns_rr_list *rrset,
+ ldns_key *current_key)
+{
+ uint32_t orig_ttl;
+ ldns_rr_class orig_class;
+ time_t now;
+ ldns_rr *current_sig;
+ uint8_t label_count;
+ ldns_rdf *signame;
+
+ label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset,
+ 0)));
+ /* RFC4035 2.2: not counting the leftmost label if it is a wildcard */
+ if(ldns_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0))))
+ label_count --;
+
+ current_sig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
+
+ /* set the type on the new signature */
+ orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));
+ orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
+
+ ldns_rr_set_ttl(current_sig, orig_ttl);
+ ldns_rr_set_class(current_sig, orig_class);
+ ldns_rr_set_owner(current_sig,
+ ldns_rdf_clone(
+ ldns_rr_owner(
+ ldns_rr_list_rr(rrset,
+ 0))));
+
+ /* fill in what we know of the signature */
+
+ /* set the orig_ttl */
+ (void)ldns_rr_rrsig_set_origttl(
+ current_sig,
+ ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
+ orig_ttl));
+ /* the signers name */
+ signame = ldns_rdf_clone(ldns_key_pubkey_owner(current_key));
+ ldns_dname2canonical(signame);
+ (void)ldns_rr_rrsig_set_signame(
+ current_sig,
+ signame);
+ /* label count - get it from the first rr in the rr_list */
+ (void)ldns_rr_rrsig_set_labels(
+ current_sig,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
+ label_count));
+ /* inception, expiration */
+ now = time(NULL);
+ if (ldns_key_inception(current_key) != 0) {
+ (void)ldns_rr_rrsig_set_inception(
+ current_sig,
+ ldns_native2rdf_int32(
+ LDNS_RDF_TYPE_TIME,
+ ldns_key_inception(current_key)));
+ } else {
+ (void)ldns_rr_rrsig_set_inception(
+ current_sig,
+ ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
+ }
+ if (ldns_key_expiration(current_key) != 0) {
+ (void)ldns_rr_rrsig_set_expiration(
+ current_sig,
+ ldns_native2rdf_int32(
+ LDNS_RDF_TYPE_TIME,
+ ldns_key_expiration(current_key)));
+ } else {
+ (void)ldns_rr_rrsig_set_expiration(
+ current_sig,
+ ldns_native2rdf_int32(
+ LDNS_RDF_TYPE_TIME,
+ now + LDNS_DEFAULT_EXP_TIME));
+ }
+
+ (void)ldns_rr_rrsig_set_keytag(
+ current_sig,
+ ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
+ ldns_key_keytag(current_key)));
+
+ (void)ldns_rr_rrsig_set_algorithm(
+ current_sig,
+ ldns_native2rdf_int8(
+ LDNS_RDF_TYPE_ALG,
+ ldns_key_algorithm(current_key)));
+
+ (void)ldns_rr_rrsig_set_typecovered(
+ current_sig,
+ ldns_native2rdf_int16(
+ LDNS_RDF_TYPE_TYPE,
+ ldns_rr_get_type(ldns_rr_list_rr(rrset,
+ 0))));
+ return current_sig;
+}
+
+#ifdef HAVE_SSL
+ldns_rdf *
+ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *current_key)
+{
+ ldns_rdf *b64rdf = NULL;
+
+ switch(ldns_key_algorithm(current_key)) {
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_dss1());
+ break;
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_sha1());
+ break;
+#ifdef USE_SHA2
+ case LDNS_SIGN_RSASHA256:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_sha256());
+ break;
+ case LDNS_SIGN_RSASHA512:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_sha512());
+ break;
+#endif /* USE_SHA2 */
+#ifdef USE_GOST
+ case LDNS_SIGN_ECC_GOST:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_get_digestbyname("md_gost94"));
+ break;
+#endif /* USE_GOST */
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_sha256());
+ break;
+ case LDNS_SIGN_ECDSAP384SHA384:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_sha384());
+ break;
+#endif
+ case LDNS_SIGN_RSAMD5:
+ b64rdf = ldns_sign_public_evp(
+ sign_buf,
+ ldns_key_evp_key(current_key),
+ EVP_md5());
+ break;
+ default:
+ /* do _you_ know this alg? */
+ printf("unknown algorithm, ");
+ printf("is the one used available on this system?\n");
+ break;
+ }
+
+ return b64rdf;
+}
+
+/**
+ * use this function to sign with a public/private key alg
+ * return the created signatures
+ */
+ldns_rr_list *
+ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys)
+{
+ ldns_rr_list *signatures;
+ ldns_rr_list *rrset_clone;
+ ldns_rr *current_sig;
+ ldns_rdf *b64rdf;
+ ldns_key *current_key;
+ size_t key_count;
+ uint16_t i;
+ ldns_buffer *sign_buf;
+ ldns_rdf *new_owner;
+
+ if (!rrset || ldns_rr_list_rr_count(rrset) < 1 || !keys) {
+ return NULL;
+ }
+
+ new_owner = NULL;
+
+ signatures = ldns_rr_list_new();
+
+ /* prepare a signature and add all the know data
+ * prepare the rrset. Sign this together. */
+ rrset_clone = ldns_rr_list_clone(rrset);
+ if (!rrset_clone) {
+ return NULL;
+ }
+
+ /* make it canonical */
+ for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
+ ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i),
+ ldns_rr_ttl(ldns_rr_list_rr(rrset, 0)));
+ ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i));
+ }
+ /* sort */
+ ldns_rr_list_sort(rrset_clone);
+
+ for (key_count = 0;
+ key_count < ldns_key_list_key_count(keys);
+ key_count++) {
+ if (!ldns_key_use(ldns_key_list_key(keys, key_count))) {
+ continue;
+ }
+ sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!sign_buf) {
+ ldns_rr_list_free(rrset_clone);
+ ldns_rr_list_free(signatures);
+ ldns_rdf_free(new_owner);
+ return NULL;
+ }
+ b64rdf = NULL;
+
+ current_key = ldns_key_list_key(keys, key_count);
+ /* sign all RRs with keys that have ZSKbit, !SEPbit.
+ sign DNSKEY RRs with keys that have ZSKbit&SEPbit */
+ if (ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY) {
+ current_sig = ldns_create_empty_rrsig(rrset_clone,
+ current_key);
+
+ /* right now, we have: a key, a semi-sig and an rrset. For
+ * which we can create the sig and base64 encode that and
+ * add that to the signature */
+
+ if (ldns_rrsig2buffer_wire(sign_buf, current_sig)
+ != LDNS_STATUS_OK) {
+ ldns_buffer_free(sign_buf);
+ /* ERROR */
+ ldns_rr_list_deep_free(rrset_clone);
+ return NULL;
+ }
+
+ /* add the rrset in sign_buf */
+ if (ldns_rr_list2buffer_wire(sign_buf, rrset_clone)
+ != LDNS_STATUS_OK) {
+ ldns_buffer_free(sign_buf);
+ ldns_rr_list_deep_free(rrset_clone);
+ return NULL;
+ }
+
+ b64rdf = ldns_sign_public_buffer(sign_buf, current_key);
+
+ if (!b64rdf) {
+ /* signing went wrong */
+ ldns_rr_list_deep_free(rrset_clone);
+ return NULL;
+ }
+
+ ldns_rr_rrsig_set_sig(current_sig, b64rdf);
+
+ /* push the signature to the signatures list */
+ ldns_rr_list_push_rr(signatures, current_sig);
+ }
+ ldns_buffer_free(sign_buf); /* restart for the next key */
+ }
+ ldns_rr_list_deep_free(rrset_clone);
+
+ 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)
+{
+ unsigned char *sha1_hash;
+ ldns_rdf *sigdata_rdf;
+ ldns_buffer *b64sig;
+
+ DSA_SIG *sig;
+ uint8_t *data;
+ size_t pad;
+
+ b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!b64sig) {
+ return NULL;
+ }
+
+ sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
+ ldns_buffer_position(to_sign), NULL);
+ if (!sha1_hash) {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ sig = DSA_do_sign(sha1_hash, SHA_DIGEST_LENGTH, key);
+ if(!sig) {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ data = LDNS_XMALLOC(uint8_t, 1 + 2 * SHA_DIGEST_LENGTH);
+ if(!data) {
+ ldns_buffer_free(b64sig);
+ DSA_SIG_free(sig);
+ return NULL;
+ }
+
+ data[0] = 1;
+ pad = 20 - (size_t) BN_num_bytes(sig->r);
+ if (pad > 0) {
+ memset(data + 1, 0, pad);
+ }
+ BN_bn2bin(sig->r, (unsigned char *) (data + 1) + pad);
+
+ pad = 20 - (size_t) BN_num_bytes(sig->s);
+ if (pad > 0) {
+ memset(data + 1 + SHA_DIGEST_LENGTH, 0, pad);
+ }
+ BN_bn2bin(sig->s, (unsigned char *) (data + 1 + SHA_DIGEST_LENGTH + pad));
+
+ sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
+ 1 + 2 * SHA_DIGEST_LENGTH,
+ data);
+
+ ldns_buffer_free(b64sig);
+ LDNS_FREE(data);
+ DSA_SIG_free(sig);
+
+ return sigdata_rdf;
+}
+
+#ifdef USE_ECDSA
+#ifndef S_SPLINT_S
+static int
+ldns_pkey_is_ecdsa(EVP_PKEY* pkey)
+{
+ EC_KEY* ec;
+ const EC_GROUP* g;
+ if(EVP_PKEY_type(pkey->type) != EVP_PKEY_EC)
+ return 0;
+ ec = EVP_PKEY_get1_EC_KEY(pkey);
+ g = EC_KEY_get0_group(ec);
+ if(!g) {
+ EC_KEY_free(ec);
+ return 0;
+ }
+ if(EC_GROUP_get_curve_name(g) == NID_secp224r1 ||
+ EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1 ||
+ EC_GROUP_get_curve_name(g) == NID_secp384r1) {
+ EC_KEY_free(ec);
+ return 1;
+ }
+ /* downref the eckey, the original is still inside the pkey */
+ EC_KEY_free(ec);
+ return 0;
+}
+#endif /* splint */
+#endif /* USE_ECDSA */
+
+ldns_rdf *
+ldns_sign_public_evp(ldns_buffer *to_sign,
+ EVP_PKEY *key,
+ const EVP_MD *digest_type)
+{
+ unsigned int siglen;
+ ldns_rdf *sigdata_rdf;
+ ldns_buffer *b64sig;
+ EVP_MD_CTX ctx;
+ const EVP_MD *md_type;
+ int r;
+
+ siglen = 0;
+ b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!b64sig) {
+ return NULL;
+ }
+
+ /* initializes a signing context */
+ md_type = digest_type;
+ if(!md_type) {
+ /* unknown message difest */
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ EVP_MD_CTX_init(&ctx);
+ r = EVP_SignInit(&ctx, md_type);
+ if(r == 1) {
+ r = EVP_SignUpdate(&ctx, (unsigned char*)
+ ldns_buffer_begin(to_sign),
+ ldns_buffer_position(to_sign));
+ } else {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+ if(r == 1) {
+ r = EVP_SignFinal(&ctx, (unsigned char*)
+ ldns_buffer_begin(b64sig), &siglen, key);
+ } else {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+ if(r != 1) {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ /* unfortunately, OpenSSL output is differenct from DNS DSA format */
+#ifndef S_SPLINT_S
+ if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) {
+ sigdata_rdf = ldns_convert_dsa_rrsig_asn12rdf(b64sig, siglen);
+#ifdef USE_ECDSA
+ } else if(EVP_PKEY_type(key->type) == EVP_PKEY_EC &&
+ ldns_pkey_is_ecdsa(key)) {
+ sigdata_rdf = ldns_convert_ecdsa_rrsig_asn12rdf(b64sig, siglen);
+#endif
+ } else {
+ /* ok output for other types is the same */
+ sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
+ ldns_buffer_begin(b64sig));
+ }
+#endif /* splint */
+ ldns_buffer_free(b64sig);
+ EVP_MD_CTX_cleanup(&ctx);
+ return sigdata_rdf;
+}
+
+ldns_rdf *
+ldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key)
+{
+ unsigned char *sha1_hash;
+ unsigned int siglen;
+ ldns_rdf *sigdata_rdf;
+ ldns_buffer *b64sig;
+ int result;
+
+ siglen = 0;
+ b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!b64sig) {
+ return NULL;
+ }
+
+ sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
+ ldns_buffer_position(to_sign), NULL);
+ if (!sha1_hash) {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ result = RSA_sign(NID_sha1, sha1_hash, SHA_DIGEST_LENGTH,
+ (unsigned char*)ldns_buffer_begin(b64sig),
+ &siglen, key);
+ if (result != 1) {
+ return NULL;
+ }
+
+ if (result != 1) {
+ return NULL;
+ }
+
+ sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
+ ldns_buffer_begin(b64sig));
+ ldns_buffer_free(b64sig); /* can't free this buffer ?? */
+ return sigdata_rdf;
+}
+
+ldns_rdf *
+ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key)
+{
+ unsigned char *md5_hash;
+ unsigned int siglen;
+ ldns_rdf *sigdata_rdf;
+ ldns_buffer *b64sig;
+
+ b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!b64sig) {
+ return NULL;
+ }
+
+ md5_hash = MD5((unsigned char*)ldns_buffer_begin(to_sign),
+ ldns_buffer_position(to_sign), NULL);
+ if (!md5_hash) {
+ ldns_buffer_free(b64sig);
+ return NULL;
+ }
+
+ RSA_sign(NID_md5, md5_hash, MD5_DIGEST_LENGTH,
+ (unsigned char*)ldns_buffer_begin(b64sig),
+ &siglen, key);
+
+ sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
+ ldns_buffer_begin(b64sig));
+ ldns_buffer_free(b64sig);
+ return sigdata_rdf;
+}
+#endif /* HAVE_SSL */
+
+/**
+ * Pushes all rrs from the rrsets of type A and AAAA on gluelist.
+ */
+static ldns_status
+ldns_dnssec_addresses_on_glue_list(
+ ldns_dnssec_rrsets *cur_rrset,
+ ldns_rr_list *glue_list)
+{
+ ldns_dnssec_rrs *cur_rrs;
+ while (cur_rrset) {
+ if (cur_rrset->type == LDNS_RR_TYPE_A
+ || cur_rrset->type == LDNS_RR_TYPE_AAAA) {
+ for (cur_rrs = cur_rrset->rrs;
+ cur_rrs;
+ cur_rrs = cur_rrs->next) {
+ if (cur_rrs->rr) {
+ if (!ldns_rr_list_push_rr(glue_list,
+ cur_rrs->rr)) {
+ return LDNS_STATUS_MEM_ERR;
+ /* ldns_rr_list_push_rr()
+ * returns false when unable
+ * to increase the capacity
+ * of the ldsn_rr_list
+ */
+ }
+ }
+ }
+ }
+ cur_rrset = cur_rrset->next;
+ }
+ 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 seperately.
+ *
+ * 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)
+{
+ ldns_rbnode_t *node;
+ ldns_dnssec_name *name;
+ ldns_rdf *owner;
+ ldns_rdf *cut = NULL; /* keeps track of zone cuts */
+ /* 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 */
+ ldns_status s;
+
+ if (!zone || !zone->names) {
+ return LDNS_STATUS_NULL;
+ }
+ for (node = ldns_rbtree_first(zone->names);
+ node != LDNS_RBTREE_NULL;
+ node = ldns_rbtree_next(node)) {
+ name = (ldns_dnssec_name *) node->data;
+ owner = ldns_dnssec_name_name(name);
+
+ if (cut) {
+ /* The previous node was a zone cut, or a subdomain
+ * below a zone cut. Is this node (still) a subdomain
+ * below the cut? Then the name is occluded. Unless
+ * the name contains a SOA, after which we are
+ * authoritative again.
+ *
+ * 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!
+ */
+ if (ldns_dname_is_subdomain(owner, cut) &&
+ !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_SOA)) {
+
+ if (below_delegation && glue_list) {
+ s = ldns_dnssec_addresses_on_glue_list(
+ name->rrsets, glue_list);
+ if (s != LDNS_STATUS_OK) {
+ return s;
+ }
+ }
+ name->is_glue = true; /* Mark occluded name! */
+ continue;
+ } else {
+ cut = NULL;
+ }
+ }
+
+ /* The node is not below a zone cut. Is it a zone cut itself?
+ * Everything below a SOA is authoritative of course; Except
+ * when the name also contains a DNAME :).
+ */
+ if (ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_SOA)) {
+ cut = owner;
+ below_delegation = 1;
+ if (glue_list) { /* record glue on the zone cut */
+ s = ldns_dnssec_addresses_on_glue_list(
+ name->rrsets, glue_list);
+ if (s != LDNS_STATUS_OK) {
+ return s;
+ }
+ }
+ } else if (ldns_dnssec_rrsets_contains_type(
+ name->rrsets, LDNS_RR_TYPE_DNAME)) {
+ cut = owner;
+ below_delegation = 0;
+ }
+ }
+ 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 seperately.
+ *
+ * \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)
+{
+ return ldns_dnssec_zone_mark_and_get_glue(zone, NULL);
+}
+
+ldns_rbnode_t *
+ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *next_node = NULL;
+ ldns_dnssec_name *next_name = NULL;
+ bool done = false;
+
+ if (node == LDNS_RBTREE_NULL) {
+ return NULL;
+ }
+ next_node = node;
+ while (!done) {
+ if (next_node == LDNS_RBTREE_NULL) {
+ return NULL;
+ } else {
+ next_name = (ldns_dnssec_name *)next_node->data;
+ if (!next_name->is_glue) {
+ done = true;
+ } else {
+ next_node = ldns_rbtree_next(next_node);
+ }
+ }
+ }
+ return next_node;
+}
+
+ldns_status
+ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs)
+{
+
+ ldns_rbnode_t *first_node, *cur_node, *next_node;
+ ldns_dnssec_name *cur_name, *next_name;
+ ldns_rr *nsec_rr;
+ 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)
+ */
+ 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));
+ } else {
+ nsec_ttl = LDNS_DEFAULT_TTL;
+ }
+
+ first_node = ldns_dnssec_name_node_next_nonglue(
+ ldns_rbtree_first(zone->names));
+ cur_node = first_node;
+ if (cur_node) {
+ next_node = ldns_dnssec_name_node_next_nonglue(
+ ldns_rbtree_next(cur_node));
+ } else {
+ next_node = NULL;
+ }
+
+ while (cur_node && next_node) {
+ cur_name = (ldns_dnssec_name *)cur_node->data;
+ next_name = (ldns_dnssec_name *)next_node->data;
+ nsec_rr = ldns_dnssec_create_nsec(cur_name,
+ next_name,
+ LDNS_RR_TYPE_NSEC);
+ ldns_rr_set_ttl(nsec_rr, nsec_ttl);
+ if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
+ ldns_rr_free(nsec_rr);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_rr_list_push_rr(new_rrs, nsec_rr);
+ cur_node = next_node;
+ if (cur_node) {
+ next_node = ldns_dnssec_name_node_next_nonglue(
+ ldns_rbtree_next(cur_node));
+ }
+ }
+
+ if (cur_node && !next_node) {
+ cur_name = (ldns_dnssec_name *)cur_node->data;
+ next_name = (ldns_dnssec_name *)first_node->data;
+ nsec_rr = ldns_dnssec_create_nsec(cur_name,
+ next_name,
+ LDNS_RR_TYPE_NSEC);
+ ldns_rr_set_ttl(nsec_rr, nsec_ttl);
+ if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
+ ldns_rr_free(nsec_rr);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_rr_list_push_rr(new_rrs, nsec_rr);
+ } else {
+ printf("error\n");
+ }
+
+ return LDNS_STATUS_OK;
+}
+
+#ifdef HAVE_SSL
+/* in dnssec_zone.c */
+extern int ldns_dname_compare_v(const void *a, const void *b);
+
+ldns_status
+ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ ldns_rbtree_t **map)
+{
+ ldns_rbnode_t *first_name_node;
+ ldns_rbnode_t *current_name_node;
+ ldns_dnssec_name *current_name;
+ ldns_status result = LDNS_STATUS_OK;
+ ldns_rr *nsec_rr;
+ ldns_rr_list *nsec3_list;
+ uint32_t nsec_ttl;
+ ldns_dnssec_rrsets *soa;
+ ldns_rbnode_t *hashmap_node;
+
+ if (!zone || !new_rrs || !zone->names) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* the TTL of NSEC rrs should be set to the minimum TTL of
+ * the zone SOA (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));
+ } else {
+ nsec_ttl = LDNS_DEFAULT_TTL;
+ }
+
+ if (map) {
+ if ((*map = ldns_rbtree_create(ldns_dname_compare_v))
+ == NULL) {
+ map = NULL;
+ };
+ }
+ nsec3_list = ldns_rr_list_new();
+
+ first_name_node = ldns_dnssec_name_node_next_nonglue(
+ ldns_rbtree_first(zone->names));
+
+ current_name_node = first_name_node;
+
+ while (current_name_node &&
+ current_name_node != LDNS_RBTREE_NULL) {
+ current_name = (ldns_dnssec_name *) current_name_node->data;
+ nsec_rr = ldns_dnssec_create_nsec3(current_name,
+ NULL,
+ zone->soa->name,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt);
+ /* by default, our nsec based generator adds rrsigs
+ * remove the bitmap for empty nonterminals */
+ if (!current_name->rrsets) {
+ ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
+ }
+ ldns_rr_set_ttl(nsec_rr, nsec_ttl);
+ result = ldns_dnssec_name_add_rr(current_name, nsec_rr);
+ ldns_rr_list_push_rr(new_rrs, nsec_rr);
+ ldns_rr_list_push_rr(nsec3_list, nsec_rr);
+ if (map) {
+ hashmap_node = LDNS_MALLOC(ldns_rbnode_t);
+ if (hashmap_node && ldns_rr_owner(nsec_rr)) {
+ hashmap_node->key = ldns_dname_label(
+ ldns_rr_owner(nsec_rr), 0);
+ if (hashmap_node->key) {
+ hashmap_node->data = current_name->name;
+ (void) ldns_rbtree_insert(
+ *map, hashmap_node);
+ }
+ }
+ }
+ current_name_node = ldns_dnssec_name_node_next_nonglue(
+ ldns_rbtree_next(current_name_node));
+ }
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+
+ ldns_rr_list_sort_nsec3(nsec3_list);
+ result = ldns_dnssec_chain_nsec3_list(nsec3_list);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+
+ ldns_rr_list_free(nsec3_list);
+ return result;
+}
+
+ldns_status
+ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt)
+{
+ return ldns_dnssec_zone_create_nsec3s_mkmap(zone, new_rrs, algorithm,
+ flags, iterations, salt_length, salt, NULL);
+
+}
+#endif /* HAVE_SSL */
+
+ldns_dnssec_rrs *
+ldns_dnssec_remove_signatures(ldns_dnssec_rrs *signatures,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg)
+{
+ ldns_dnssec_rrs *base_rrs = signatures;
+ ldns_dnssec_rrs *cur_rr = base_rrs;
+ ldns_dnssec_rrs *prev_rr = NULL;
+ ldns_dnssec_rrs *next_rr;
+
+ uint16_t keytag;
+ size_t i;
+
+ key_list = key_list;
+
+ if (!cur_rr) {
+ switch(func(NULL, arg)) {
+ case LDNS_SIGNATURE_LEAVE_ADD_NEW:
+ case LDNS_SIGNATURE_REMOVE_ADD_NEW:
+ break;
+ case LDNS_SIGNATURE_LEAVE_NO_ADD:
+ case LDNS_SIGNATURE_REMOVE_NO_ADD:
+ ldns_key_list_set_use(key_list, false);
+ break;
+ default:
+ fprintf(stderr, "[XX] unknown return value from callback\n");
+ break;
+ }
+ return NULL;
+ }
+ (void)func(cur_rr->rr, arg);
+
+ while (cur_rr) {
+ next_rr = cur_rr->next;
+
+ switch (func(cur_rr->rr, arg)) {
+ case LDNS_SIGNATURE_LEAVE_ADD_NEW:
+ prev_rr = cur_rr;
+ break;
+ case LDNS_SIGNATURE_LEAVE_NO_ADD:
+ keytag = ldns_rdf2native_int16(
+ ldns_rr_rrsig_keytag(cur_rr->rr));
+ for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
+ if (ldns_key_keytag(ldns_key_list_key(key_list, i)) ==
+ keytag) {
+ ldns_key_set_use(ldns_key_list_key(key_list, i),
+ false);
+ }
+ }
+ prev_rr = cur_rr;
+ break;
+ case LDNS_SIGNATURE_REMOVE_NO_ADD:
+ keytag = ldns_rdf2native_int16(
+ ldns_rr_rrsig_keytag(cur_rr->rr));
+ for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
+ if (ldns_key_keytag(ldns_key_list_key(key_list, i))
+ == keytag) {
+ ldns_key_set_use(ldns_key_list_key(key_list, i),
+ false);
+ }
+ }
+ if (prev_rr) {
+ prev_rr->next = next_rr;
+ } else {
+ base_rrs = next_rr;
+ }
+ LDNS_FREE(cur_rr);
+ break;
+ case LDNS_SIGNATURE_REMOVE_ADD_NEW:
+ if (prev_rr) {
+ prev_rr->next = next_rr;
+ } else {
+ base_rrs = next_rr;
+ }
+ LDNS_FREE(cur_rr);
+ break;
+ default:
+ fprintf(stderr, "[XX] unknown return value from callback\n");
+ break;
+ }
+ cur_rr = next_rr;
+ }
+
+ return base_rrs;
+}
+
+#ifdef HAVE_SSL
+ldns_status
+ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void*),
+ void *arg)
+{
+ return ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list,
+ func, arg, 0);
+}
+
+/** If there are KSKs use only them and mark ZSKs unused */
+static void
+ldns_key_list_filter_for_dnskey(ldns_key_list *key_list)
+{
+ int saw_ksk = 0;
+ size_t i;
+ for(i=0; i<ldns_key_list_key_count(key_list); i++)
+ if((ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY)) {
+ saw_ksk = 1;
+ break;
+ }
+ if(!saw_ksk)
+ return;
+ for(i=0; i<ldns_key_list_key_count(key_list); i++)
+ if(!(ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY))
+ ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
+}
+
+/** If there are no ZSKs use KSK as ZSK */
+static void
+ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list)
+{
+ int saw_zsk = 0;
+ size_t i;
+ for(i=0; i<ldns_key_list_key_count(key_list); i++)
+ if(!(ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY)) {
+ saw_zsk = 1;
+ break;
+ }
+ if(!saw_zsk)
+ return;
+ /* else filter all KSKs */
+ for(i=0; i<ldns_key_list_key_count(key_list); i++)
+ if((ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY))
+ ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
+}
+
+ldns_status
+ldns_dnssec_zone_create_rrsigs_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void*),
+ void *arg,
+ int flags)
+{
+ ldns_status result = LDNS_STATUS_OK;
+
+ ldns_rbnode_t *cur_node;
+ ldns_rr_list *rr_list;
+
+ ldns_dnssec_name *cur_name;
+ ldns_dnssec_rrsets *cur_rrset;
+ ldns_dnssec_rrs *cur_rr;
+
+ ldns_rr_list *siglist;
+
+ size_t i;
+
+ int on_delegation_point = 0; /* handle partially occluded names */
+
+ ldns_rr_list *pubkey_list = ldns_rr_list_new();
+ zone = zone;
+ new_rrs = new_rrs;
+ key_list = key_list;
+ for (i = 0; i<ldns_key_list_key_count(key_list); i++) {
+ ldns_rr_list_push_rr(pubkey_list,
+ ldns_key2rr(ldns_key_list_key(key_list, i)));
+ }
+ /* TODO: callback to see is list should be signed */
+ /* TODO: remove 'old' signatures from signature list */
+ cur_node = ldns_rbtree_first(zone->names);
+ while (cur_node != LDNS_RBTREE_NULL) {
+ cur_name = (ldns_dnssec_name *) cur_node->data;
+
+ if (!cur_name->is_glue) {
+ on_delegation_point = ldns_dnssec_rrsets_contains_type(
+ cur_name->rrsets, LDNS_RR_TYPE_NS)
+ && !ldns_dnssec_rrsets_contains_type(
+ cur_name->rrsets, LDNS_RR_TYPE_SOA);
+ cur_rrset = cur_name->rrsets;
+ while (cur_rrset) {
+ /* reset keys to use */
+ ldns_key_list_set_use(key_list, true);
+
+ /* walk through old sigs, remove the old,
+ and mark which keys (not) to use) */
+ cur_rrset->signatures =
+ ldns_dnssec_remove_signatures(cur_rrset->signatures,
+ key_list,
+ func,
+ arg);
+ if(!(flags&LDNS_SIGN_DNSKEY_WITH_ZSK) &&
+ cur_rrset->type == LDNS_RR_TYPE_DNSKEY)
+ ldns_key_list_filter_for_dnskey(key_list);
+
+ if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY)
+ ldns_key_list_filter_for_non_dnskey(key_list);
+
+ /* TODO: just set count to zero? */
+ rr_list = ldns_rr_list_new();
+
+ cur_rr = cur_rrset->rrs;
+ while (cur_rr) {
+ ldns_rr_list_push_rr(rr_list, cur_rr->rr);
+ cur_rr = cur_rr->next;
+ }
+
+ /* only sign non-delegation RRsets */
+ /* (glue should have been marked earlier,
+ * except on the delegation points itself) */
+ if (!on_delegation_point ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_DS ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_NSEC ||
+ ldns_rr_list_type(rr_list)
+ == LDNS_RR_TYPE_NSEC3) {
+ siglist = ldns_sign_public(rr_list, key_list);
+ for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
+ if (cur_rrset->signatures) {
+ result = ldns_dnssec_rrs_add_rr(cur_rrset->signatures,
+ ldns_rr_list_rr(siglist,
+ i));
+ } else {
+ cur_rrset->signatures = ldns_dnssec_rrs_new();
+ cur_rrset->signatures->rr =
+ ldns_rr_list_rr(siglist, i);
+ ldns_rr_list_push_rr(new_rrs,
+ ldns_rr_list_rr(siglist,
+ i));
+ }
+ }
+ ldns_rr_list_free(siglist);
+ }
+
+ ldns_rr_list_free(rr_list);
+
+ cur_rrset = cur_rrset->next;
+ }
+
+ /* sign the nsec */
+ ldns_key_list_set_use(key_list, true);
+ cur_name->nsec_signatures =
+ ldns_dnssec_remove_signatures(cur_name->nsec_signatures,
+ key_list,
+ func,
+ arg);
+ ldns_key_list_filter_for_non_dnskey(key_list);
+
+ rr_list = ldns_rr_list_new();
+ ldns_rr_list_push_rr(rr_list, cur_name->nsec);
+ siglist = ldns_sign_public(rr_list, key_list);
+
+ for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
+ if (cur_name->nsec_signatures) {
+ result = ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures,
+ ldns_rr_list_rr(siglist, i));
+ } else {
+ cur_name->nsec_signatures = ldns_dnssec_rrs_new();
+ cur_name->nsec_signatures->rr =
+ ldns_rr_list_rr(siglist, i);
+ ldns_rr_list_push_rr(new_rrs,
+ ldns_rr_list_rr(siglist, i));
+ }
+ }
+
+ ldns_rr_list_free(siglist);
+ ldns_rr_list_free(rr_list);
+ }
+ cur_node = ldns_rbtree_next(cur_node);
+ }
+
+ ldns_rr_list_deep_free(pubkey_list);
+ return result;
+}
+
+ldns_status
+ldns_dnssec_zone_sign(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg)
+{
+ return ldns_dnssec_zone_sign_flg(zone, new_rrs, key_list, func, arg, 0);
+}
+
+ldns_status
+ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ int flags)
+{
+ ldns_status result = LDNS_STATUS_OK;
+
+ if (!zone || !new_rrs || !key_list) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* 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) {
+ 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,
+ func,
+ arg,
+ flags);
+
+ return result;
+}
+
+ldns_status
+ldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt)
+{
+ return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
+ func, arg, algorithm, flags, iterations, salt_length, salt, 0,
+ NULL);
+}
+
+ldns_status
+ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ int signflags,
+ ldns_rbtree_t **map)
+{
+ ldns_rr *nsec3, *nsec3param;
+ ldns_status result = LDNS_STATUS_OK;
+
+ /* zone is already sorted */
+ result = ldns_dnssec_zone_mark_glue(zone);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+
+ /* TODO if there are already nsec3s presents and their
+ * parameters are the same as these, we don't have to recreate
+ */
+ if (zone->names) {
+ /* add empty nonterminals */
+ result = ldns_dnssec_zone_add_empty_nonterminals(zone);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+
+ nsec3 = ((ldns_dnssec_name *)zone->names->root->data)->nsec;
+ if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) {
+ /* no need to recreate */
+ } else {
+ if (!ldns_dnssec_zone_find_rrset(zone,
+ zone->soa->name,
+ LDNS_RR_TYPE_NSEC3PARAM)) {
+ /* create and add the nsec3param rr */
+ nsec3param =
+ ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAM);
+ ldns_rr_set_owner(nsec3param,
+ ldns_rdf_clone(zone->soa->name));
+ ldns_nsec3_add_param_rdfs(nsec3param,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt);
+ /* always set bit 7 of the flags to zero, according to
+ * rfc5155 section 11 */
+ ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3param, 1)), 7, 0);
+ result = ldns_dnssec_zone_add_rr(zone, nsec3param);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+ ldns_rr_list_push_rr(new_rrs, nsec3param);
+ }
+ result = ldns_dnssec_zone_create_nsec3s_mkmap(zone,
+ new_rrs,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt,
+ map);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+ }
+
+ result = ldns_dnssec_zone_create_rrsigs_flg(zone,
+ new_rrs,
+ key_list,
+ func,
+ arg,
+ signflags);
+ }
+
+ return result;
+}
+
+ldns_status
+ldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone,
+ ldns_rr_list *new_rrs,
+ ldns_key_list *key_list,
+ int (*func)(ldns_rr *, void *),
+ void *arg,
+ uint8_t algorithm,
+ uint8_t flags,
+ uint16_t iterations,
+ uint8_t salt_length,
+ uint8_t *salt,
+ int signflags)
+{
+ return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
+ func, arg, algorithm, flags, iterations, salt_length, salt,
+ signflags, NULL);
+}
+
+ldns_zone *
+ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
+{
+ ldns_dnssec_zone *dnssec_zone;
+ ldns_zone *signed_zone;
+ ldns_rr_list *new_rrs;
+ size_t i;
+
+ signed_zone = ldns_zone_new();
+ dnssec_zone = ldns_dnssec_zone_new();
+
+ (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
+ ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
+
+ for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
+ (void) ldns_dnssec_zone_add_rr(dnssec_zone,
+ ldns_rr_list_rr(ldns_zone_rrs(zone),
+ i));
+ ldns_zone_push_rr(signed_zone,
+ ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
+ i)));
+ }
+
+ new_rrs = ldns_rr_list_new();
+ (void) ldns_dnssec_zone_sign(dnssec_zone,
+ new_rrs,
+ key_list,
+ ldns_dnssec_default_replace_signatures,
+ NULL);
+
+ for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
+ ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
+ ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
+ }
+
+ ldns_rr_list_deep_free(new_rrs);
+ ldns_dnssec_zone_free(dnssec_zone);
+
+ return signed_zone;
+}
+
+ldns_zone *
+ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt)
+{
+ ldns_dnssec_zone *dnssec_zone;
+ ldns_zone *signed_zone;
+ ldns_rr_list *new_rrs;
+ size_t i;
+
+ signed_zone = ldns_zone_new();
+ dnssec_zone = ldns_dnssec_zone_new();
+
+ (void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
+ ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
+
+ for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
+ (void) ldns_dnssec_zone_add_rr(dnssec_zone,
+ ldns_rr_list_rr(ldns_zone_rrs(zone),
+ i));
+ ldns_zone_push_rr(signed_zone,
+ ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
+ i)));
+ }
+
+ new_rrs = ldns_rr_list_new();
+ (void) ldns_dnssec_zone_sign_nsec3(dnssec_zone,
+ new_rrs,
+ key_list,
+ ldns_dnssec_default_replace_signatures,
+ NULL,
+ algorithm,
+ flags,
+ iterations,
+ salt_length,
+ salt);
+
+ for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
+ ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
+ ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
+ }
+
+ ldns_rr_list_deep_free(new_rrs);
+ ldns_dnssec_zone_free(dnssec_zone);
+
+ return signed_zone;
+}
+#endif /* HAVE_SSL */
+
+
diff --git a/3rdParty/Ldns/src/src/dnssec_verify.c b/3rdParty/Ldns/src/src/dnssec_verify.c
new file mode 100644
index 0000000..18af5d2
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dnssec_verify.c
@@ -0,0 +1,2642 @@
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+#include <time.h>
+
+#ifdef HAVE_SSL
+/* this entire file is rather useless when you don't have
+ * crypto...
+ */
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+
+ldns_dnssec_data_chain *
+ldns_dnssec_data_chain_new()
+{
+ 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.
+
+ nc->rrset = NULL;
+ nc->parent_type = 0;
+ nc->parent = NULL;
+ nc->signatures = NULL;
+ nc->packet_rcode = 0;
+ nc->packet_qtype = 0;
+ nc->packet_nodata = false;
+
+ */
+ return nc;
+}
+
+void
+ldns_dnssec_data_chain_free(ldns_dnssec_data_chain *chain)
+{
+ LDNS_FREE(chain);
+}
+
+void
+ldns_dnssec_data_chain_deep_free(ldns_dnssec_data_chain *chain)
+{
+ ldns_rr_list_deep_free(chain->rrset);
+ ldns_rr_list_deep_free(chain->signatures);
+ if (chain->parent) {
+ ldns_dnssec_data_chain_deep_free(chain->parent);
+ }
+ LDNS_FREE(chain);
+}
+
+void
+ldns_dnssec_data_chain_print_fmt(FILE *out, const ldns_output_format *fmt,
+ const ldns_dnssec_data_chain *chain)
+{
+ ldns_lookup_table *rcode;
+ const ldns_rr_descriptor *rr_descriptor;
+ if (chain) {
+ ldns_dnssec_data_chain_print_fmt(out, fmt, chain->parent);
+ if (ldns_rr_list_rr_count(chain->rrset) > 0) {
+ rcode = ldns_lookup_by_id(ldns_rcodes,
+ (int) chain->packet_rcode);
+ if (rcode) {
+ fprintf(out, ";; rcode: %s\n", rcode->name);
+ }
+
+ rr_descriptor = ldns_rr_descript(chain->packet_qtype);
+ if (rr_descriptor && rr_descriptor->_name) {
+ fprintf(out, ";; qtype: %s\n", rr_descriptor->_name);
+ } else if (chain->packet_qtype != 0) {
+ fprintf(out, "TYPE%u",
+ chain->packet_qtype);
+ }
+ if (chain->packet_nodata) {
+ fprintf(out, ";; NODATA response\n");
+ }
+ fprintf(out, "rrset:\n");
+ ldns_rr_list_print_fmt(out, fmt, chain->rrset);
+ fprintf(out, "sigs:\n");
+ ldns_rr_list_print_fmt(out, fmt, chain->signatures);
+ fprintf(out, "---\n");
+ } else {
+ fprintf(out, "<no data>\n");
+ }
+ }
+}
+void
+ldns_dnssec_data_chain_print(FILE *out, const ldns_dnssec_data_chain *chain)
+{
+ ldns_dnssec_data_chain_print_fmt(
+ out, ldns_output_format_default, chain);
+}
+
+
+static void
+ldns_dnssec_build_data_chain_dnskey(ldns_resolver *res,
+ uint16_t qflags,
+ const ldns_pkt *pkt,
+ ldns_rr_list *signatures,
+ ldns_dnssec_data_chain *new_chain,
+ ldns_rdf *key_name,
+ ldns_rr_class c) {
+ ldns_rr_list *keys;
+ ldns_pkt *my_pkt;
+ if (signatures && ldns_rr_list_rr_count(signatures) > 0) {
+ new_chain->signatures = ldns_rr_list_clone(signatures);
+ new_chain->parent_type = 0;
+
+ keys = ldns_pkt_rr_list_by_name_and_type(
+ pkt,
+ key_name,
+ LDNS_RR_TYPE_DNSKEY,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+ if (!keys) {
+ my_pkt = ldns_resolver_query(res,
+ key_name,
+ LDNS_RR_TYPE_DNSKEY,
+ c,
+ qflags);
+ if (my_pkt) {
+ keys = ldns_pkt_rr_list_by_name_and_type(
+ my_pkt,
+ key_name,
+ LDNS_RR_TYPE_DNSKEY,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+ new_chain->parent = ldns_dnssec_build_data_chain(res,
+ qflags,
+ keys,
+ my_pkt,
+ NULL);
+ new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY;
+ ldns_pkt_free(my_pkt);
+ }
+ } else {
+ new_chain->parent = ldns_dnssec_build_data_chain(res,
+ qflags,
+ keys,
+ pkt,
+ NULL);
+ new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY;
+ }
+ ldns_rr_list_deep_free(keys);
+ }
+}
+
+static void
+ldns_dnssec_build_data_chain_other(ldns_resolver *res,
+ uint16_t qflags,
+ ldns_dnssec_data_chain *new_chain,
+ ldns_rdf *key_name,
+ ldns_rr_class c,
+ ldns_rr_list *dss)
+{
+ /* 'self-signed', parent is a DS */
+
+ /* okay, either we have other keys signing the current one,
+ * or the current
+ * one should have a DS record in the parent zone.
+ * How do we find this out? Try both?
+ *
+ * request DNSKEYS for current zone,
+ * add all signatures to current level
+ */
+ ldns_pkt *my_pkt;
+ ldns_rr_list *signatures2;
+
+ new_chain->parent_type = 1;
+
+ my_pkt = ldns_resolver_query(res,
+ key_name,
+ LDNS_RR_TYPE_DS,
+ c,
+ qflags);
+ if (my_pkt) {
+ dss = ldns_pkt_rr_list_by_name_and_type(my_pkt,
+ key_name,
+ LDNS_RR_TYPE_DS,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+ if (dss) {
+ new_chain->parent = ldns_dnssec_build_data_chain(res,
+ qflags,
+ dss,
+ my_pkt,
+ NULL);
+ new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS;
+ ldns_rr_list_deep_free(dss);
+ }
+ ldns_pkt_free(my_pkt);
+ }
+
+ my_pkt = ldns_resolver_query(res,
+ key_name,
+ LDNS_RR_TYPE_DNSKEY,
+ c,
+ qflags);
+ if (my_pkt) {
+ signatures2 = ldns_pkt_rr_list_by_name_and_type(my_pkt,
+ key_name,
+ LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANSWER);
+ if (signatures2) {
+ if (new_chain->signatures) {
+ printf("There were already sigs!\n");
+ ldns_rr_list_deep_free(new_chain->signatures);
+ printf("replacing the old sigs\n");
+ }
+ new_chain->signatures = signatures2;
+ }
+ ldns_pkt_free(my_pkt);
+ }
+}
+
+ldns_dnssec_data_chain *
+ldns_dnssec_build_data_chain_nokeyname(ldns_resolver *res,
+ uint16_t qflags,
+ ldns_rr *orig_rr,
+ const ldns_rr_list *rrset,
+ ldns_dnssec_data_chain *new_chain)
+{
+ ldns_rdf *possible_parent_name;
+ ldns_pkt *my_pkt;
+ /* apparently we were not able to find a signing key, so
+ we assume the chain ends here
+ */
+ /* try parents for auth denial of DS */
+ if (orig_rr) {
+ possible_parent_name = ldns_rr_owner(orig_rr);
+ } else if (rrset && ldns_rr_list_rr_count(rrset) > 0) {
+ possible_parent_name = ldns_rr_owner(ldns_rr_list_rr(rrset, 0));
+ } else {
+ /* no information to go on, give up */
+ return new_chain;
+ }
+
+ my_pkt = ldns_resolver_query(res,
+ possible_parent_name,
+ LDNS_RR_TYPE_DS,
+ LDNS_RR_CLASS_IN,
+ qflags);
+ if (!my_pkt) {
+ return new_chain;
+ }
+
+ if (ldns_pkt_ancount(my_pkt) > 0) {
+ /* add error, no sigs but DS in parent */
+ /*ldns_pkt_print(stdout, my_pkt);*/
+ ldns_pkt_free(my_pkt);
+ } else {
+ /* are there signatures? */
+ new_chain->parent = ldns_dnssec_build_data_chain(res,
+ qflags,
+ NULL,
+ my_pkt,
+ NULL);
+
+ new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS;
+
+ }
+ return new_chain;
+}
+
+
+ldns_dnssec_data_chain *
+ldns_dnssec_build_data_chain(ldns_resolver *res,
+ uint16_t qflags,
+ const ldns_rr_list *rrset,
+ const ldns_pkt *pkt,
+ ldns_rr *orig_rr)
+{
+ ldns_rr_list *signatures = NULL;
+ ldns_rr_list *dss = NULL;
+
+ ldns_rr_list *my_rrset;
+
+ ldns_pkt *my_pkt;
+
+ ldns_rdf *name = NULL, *key_name = NULL;
+ ldns_rr_type type = 0;
+ ldns_rr_class c = 0;
+
+ bool other_rrset = false;
+
+ ldns_dnssec_data_chain *new_chain = ldns_dnssec_data_chain_new();
+
+ if (!ldns_dnssec_pkt_has_rrsigs(pkt)) {
+ /* hmm. no dnssec data in the packet. go up to try and deny
+ * DS? */
+ return new_chain;
+ }
+
+ if (orig_rr) {
+ new_chain->rrset = ldns_rr_list_new();
+ ldns_rr_list_push_rr(new_chain->rrset, orig_rr);
+ new_chain->parent = ldns_dnssec_build_data_chain(res,
+ qflags,
+ rrset,
+ pkt,
+ NULL);
+ new_chain->packet_rcode = ldns_pkt_get_rcode(pkt);
+ new_chain->packet_qtype = ldns_rr_get_type(orig_rr);
+ if (ldns_pkt_ancount(pkt) == 0) {
+ new_chain->packet_nodata = true;
+ }
+ return new_chain;
+ }
+
+ if (!rrset || ldns_rr_list_rr_count(rrset) < 1) {
+ /* hmm, no data, do we have denial? only works if pkt was given,
+ otherwise caller has to do the check himself */
+ new_chain->packet_nodata = true;
+ if (pkt) {
+ my_rrset = ldns_pkt_rr_list_by_type(pkt,
+ LDNS_RR_TYPE_NSEC,
+ LDNS_SECTION_ANY_NOQUESTION
+ );
+ if (my_rrset) {
+ if (ldns_rr_list_rr_count(my_rrset) > 0) {
+ type = LDNS_RR_TYPE_NSEC;
+ other_rrset = true;
+ } else {
+ ldns_rr_list_deep_free(my_rrset);
+ my_rrset = NULL;
+ }
+ } else {
+ /* nothing, try nsec3 */
+ my_rrset = ldns_pkt_rr_list_by_type(pkt,
+ LDNS_RR_TYPE_NSEC3,
+ LDNS_SECTION_ANY_NOQUESTION);
+ if (my_rrset) {
+ if (ldns_rr_list_rr_count(my_rrset) > 0) {
+ type = LDNS_RR_TYPE_NSEC3;
+ other_rrset = true;
+ } else {
+ ldns_rr_list_deep_free(my_rrset);
+ my_rrset = NULL;
+ }
+ } else {
+ /* nothing, stop */
+ /* try parent zone? for denied insecure? */
+ return new_chain;
+ }
+ }
+ } else {
+ return new_chain;
+ }
+ } else {
+ my_rrset = (ldns_rr_list *) rrset;
+ }
+
+ if (my_rrset && ldns_rr_list_rr_count(my_rrset) > 0) {
+ new_chain->rrset = ldns_rr_list_clone(my_rrset);
+ name = ldns_rr_owner(ldns_rr_list_rr(my_rrset, 0));
+ type = ldns_rr_get_type(ldns_rr_list_rr(my_rrset, 0));
+ c = ldns_rr_get_class(ldns_rr_list_rr(my_rrset, 0));
+ }
+
+ if (other_rrset) {
+ ldns_rr_list_deep_free(my_rrset);
+ }
+
+ /* normally there will only be 1 signature 'set'
+ but there can be more than 1 denial (wildcards)
+ so check for NSEC
+ */
+ if (type == LDNS_RR_TYPE_NSEC || type == LDNS_RR_TYPE_NSEC3) {
+ /* just throw in all signatures, the tree builder must sort
+ this out */
+ if (pkt) {
+ signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type);
+ } else {
+ my_pkt = ldns_resolver_query(res, name, type, c, qflags);
+ if (my_pkt) {
+ signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type);
+ ldns_pkt_free(my_pkt);
+ }
+ }
+ } else {
+ if (pkt) {
+ signatures =
+ ldns_dnssec_pkt_get_rrsigs_for_name_and_type(pkt,
+ name,
+ type);
+ }
+ if (!signatures) {
+ my_pkt = ldns_resolver_query(res, name, type, c, qflags);
+ if (my_pkt) {
+ signatures =
+ ldns_dnssec_pkt_get_rrsigs_for_name_and_type(my_pkt,
+ name,
+ type);
+ ldns_pkt_free(my_pkt);
+ }
+ }
+ }
+
+ if (signatures && ldns_rr_list_rr_count(signatures) > 0) {
+ key_name = ldns_rr_rdf(ldns_rr_list_rr(signatures, 0), 7);
+ }
+
+ if (!key_name) {
+ return ldns_dnssec_build_data_chain_nokeyname(res,
+ qflags,
+ orig_rr,
+ rrset,
+ new_chain);
+ }
+
+ if (type != LDNS_RR_TYPE_DNSKEY) {
+ ldns_dnssec_build_data_chain_dnskey(res,
+ qflags,
+ pkt,
+ signatures,
+ new_chain,
+ key_name,
+ c
+ );
+ } else {
+ ldns_dnssec_build_data_chain_other(res,
+ qflags,
+ new_chain,
+ key_name,
+ c,
+ dss
+
+ );
+ }
+ if (signatures) {
+ ldns_rr_list_deep_free(signatures);
+ }
+
+ return new_chain;
+}
+
+ldns_dnssec_trust_tree *
+ldns_dnssec_trust_tree_new()
+{
+ ldns_dnssec_trust_tree *new_tree = LDNS_XMALLOC(ldns_dnssec_trust_tree,
+ 1);
+ if(!new_tree) return NULL;
+ new_tree->rr = NULL;
+ new_tree->rrset = NULL;
+ new_tree->parent_count = 0;
+
+ return new_tree;
+}
+
+void
+ldns_dnssec_trust_tree_free(ldns_dnssec_trust_tree *tree)
+{
+ size_t i;
+ if (tree) {
+ for (i = 0; i < tree->parent_count; i++) {
+ ldns_dnssec_trust_tree_free(tree->parents[i]);
+ }
+ }
+ LDNS_FREE(tree);
+}
+
+size_t
+ldns_dnssec_trust_tree_depth(ldns_dnssec_trust_tree *tree)
+{
+ size_t result = 0;
+ size_t parent = 0;
+ size_t i;
+
+ for (i = 0; i < tree->parent_count; i++) {
+ parent = ldns_dnssec_trust_tree_depth(tree->parents[i]);
+ if (parent > result) {
+ result = parent;
+ }
+ }
+ return 1 + result;
+}
+
+/* TODO ldns_ */
+static void
+print_tabs(FILE *out, size_t nr, uint8_t *map, size_t treedepth)
+{
+ size_t i;
+ for (i = 0; i < nr; i++) {
+ if (i == nr - 1) {
+ fprintf(out, "|---");
+ } else if (map && i < treedepth && map[i] == 1) {
+ fprintf(out, "| ");
+ } else {
+ fprintf(out, " ");
+ }
+ }
+}
+
+void
+ldns_dnssec_trust_tree_print_sm_fmt(FILE *out,
+ const ldns_output_format *fmt,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended,
+ uint8_t *sibmap,
+ size_t treedepth)
+{
+ size_t i;
+ const ldns_rr_descriptor *descriptor;
+ bool mapset = false;
+
+ if (!sibmap) {
+ treedepth = ldns_dnssec_trust_tree_depth(tree);
+ sibmap = malloc(treedepth);
+ if(!sibmap)
+ return; /* mem err */
+ memset(sibmap, 0, treedepth);
+ mapset = true;
+ }
+
+ if (tree) {
+ if (tree->rr) {
+ print_tabs(out, tabs, sibmap, treedepth);
+ ldns_rdf_print(out, ldns_rr_owner(tree->rr));
+ descriptor = ldns_rr_descript(ldns_rr_get_type(tree->rr));
+
+ if (descriptor->_name) {
+ fprintf(out, " (%s", descriptor->_name);
+ } else {
+ fprintf(out, " (TYPE%d",
+ ldns_rr_get_type(tree->rr));
+ }
+ if (tabs > 0) {
+ if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DNSKEY) {
+ fprintf(out, " keytag: %u",
+ (unsigned int) ldns_calc_keytag(tree->rr));
+ fprintf(out, " alg: ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2));
+ fprintf(out, " flags: ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
+ } else if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DS) {
+ fprintf(out, " keytag: ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
+ fprintf(out, " digest type: ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2));
+ }
+ if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NSEC) {
+ fprintf(out, " ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
+ fprintf(out, " ");
+ ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 1));
+ }
+ }
+
+ fprintf(out, ")\n");
+ for (i = 0; i < tree->parent_count; i++) {
+ if (tree->parent_count > 1 && i < tree->parent_count - 1) {
+ sibmap[tabs] = 1;
+ } else {
+ sibmap[tabs] = 0;
+ }
+ /* only print errors */
+ if (ldns_rr_get_type(tree->parents[i]->rr) ==
+ LDNS_RR_TYPE_NSEC ||
+ ldns_rr_get_type(tree->parents[i]->rr) ==
+ LDNS_RR_TYPE_NSEC3) {
+ if (tree->parent_status[i] == LDNS_STATUS_OK) {
+ print_tabs(out, tabs + 1, sibmap, treedepth);
+ if (tabs == 0 &&
+ ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS &&
+ ldns_rr_rd_count(tree->rr) > 0) {
+ fprintf(out, "Existence of DS is denied by:\n");
+ } else {
+ fprintf(out, "Existence is denied by:\n");
+ }
+ } else {
+ /* NS records aren't signed */
+ if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS) {
+ fprintf(out, "Existence of DS is denied by:\n");
+ } else {
+ print_tabs(out, tabs + 1, sibmap, treedepth);
+ fprintf(out,
+ "Error in denial of existence: %s\n",
+ ldns_get_errorstr_by_id(
+ tree->parent_status[i]));
+ }
+ }
+ } else
+ if (tree->parent_status[i] != LDNS_STATUS_OK) {
+ print_tabs(out, tabs + 1, sibmap, treedepth);
+ fprintf(out,
+ "%s:\n",
+ ldns_get_errorstr_by_id(
+ tree->parent_status[i]));
+ if (tree->parent_status[i]
+ == LDNS_STATUS_SSL_ERR) {
+ printf("; SSL Error: ");
+ ERR_load_crypto_strings();
+ ERR_print_errors_fp(stdout);
+ printf("\n");
+ }
+ ldns_rr_print_fmt(out, fmt,
+ tree->
+ parent_signature[i]);
+ printf("For RRset:\n");
+ ldns_rr_list_print_fmt(out, fmt,
+ tree->rrset);
+ printf("With key:\n");
+ ldns_rr_print_fmt(out, fmt,
+ tree->parents[i]->rr);
+ }
+ ldns_dnssec_trust_tree_print_sm_fmt(out, fmt,
+ tree->parents[i],
+ tabs+1,
+ extended,
+ sibmap,
+ treedepth);
+ }
+ } else {
+ print_tabs(out, tabs, sibmap, treedepth);
+ fprintf(out, "<no data>\n");
+ }
+ } else {
+ fprintf(out, "<null pointer>\n");
+ }
+
+ if (mapset) {
+ free(sibmap);
+ }
+}
+
+void
+ldns_dnssec_trust_tree_print_sm(FILE *out,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended,
+ uint8_t *sibmap,
+ size_t treedepth)
+{
+ ldns_dnssec_trust_tree_print_sm_fmt(out, ldns_output_format_default,
+ tree, tabs, extended, sibmap, treedepth);
+}
+
+void
+ldns_dnssec_trust_tree_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended)
+{
+ ldns_dnssec_trust_tree_print_sm_fmt(out, fmt,
+ tree, tabs, extended, NULL, 0);
+}
+
+void
+ldns_dnssec_trust_tree_print(FILE *out,
+ ldns_dnssec_trust_tree *tree,
+ size_t tabs,
+ bool extended)
+{
+ ldns_dnssec_trust_tree_print_fmt(out, ldns_output_format_default,
+ tree, tabs, extended);
+}
+
+
+ldns_status
+ldns_dnssec_trust_tree_add_parent(ldns_dnssec_trust_tree *tree,
+ const ldns_dnssec_trust_tree *parent,
+ const ldns_rr *signature,
+ const ldns_status parent_status)
+{
+ if (tree
+ && parent
+ && tree->parent_count < LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS) {
+ /*
+ printf("Add parent for: ");
+ ldns_rr_print(stdout, tree->rr);
+ printf("parent: ");
+ ldns_rr_print(stdout, parent->rr);
+ */
+ tree->parents[tree->parent_count] =
+ (ldns_dnssec_trust_tree *) parent;
+ tree->parent_status[tree->parent_count] = parent_status;
+ tree->parent_signature[tree->parent_count] = (ldns_rr *) signature;
+ tree->parent_count++;
+ return LDNS_STATUS_OK;
+ } else {
+ return LDNS_STATUS_ERR;
+ }
+}
+
+/* if rr is null, take the first from the rrset */
+ldns_dnssec_trust_tree *
+ldns_dnssec_derive_trust_tree_time(
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *rr,
+ time_t check_time
+ )
+{
+ ldns_rr_list *cur_rrset;
+ ldns_rr_list *cur_sigs;
+ ldns_rr *cur_rr = NULL;
+ ldns_rr *cur_sig_rr;
+ size_t i, j;
+
+ ldns_dnssec_trust_tree *new_tree = ldns_dnssec_trust_tree_new();
+ if(!new_tree)
+ return NULL;
+
+ if (data_chain && data_chain->rrset) {
+ cur_rrset = data_chain->rrset;
+
+ cur_sigs = data_chain->signatures;
+
+ if (rr) {
+ cur_rr = rr;
+ }
+
+ if (!cur_rr && ldns_rr_list_rr_count(cur_rrset) > 0) {
+ cur_rr = ldns_rr_list_rr(cur_rrset, 0);
+ }
+
+ if (cur_rr) {
+ new_tree->rr = cur_rr;
+ new_tree->rrset = cur_rrset;
+ /* there are three possibilities:
+ 1 - 'normal' rrset, signed by a key
+ 2 - dnskey signed by other dnskey
+ 3 - dnskey proven by higher level DS
+ (data denied by nsec is a special case that can
+ occur in multiple places)
+
+ */
+ if (cur_sigs) {
+ for (i = 0; i < ldns_rr_list_rr_count(cur_sigs); i++) {
+ /* find the appropriate key in the parent list */
+ cur_sig_rr = ldns_rr_list_rr(cur_sigs, i);
+
+ if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_NSEC) {
+ if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr),
+ ldns_rr_owner(cur_rr)))
+ {
+ /* find first that does match */
+
+ for (j = 0;
+ j < ldns_rr_list_rr_count(cur_rrset) &&
+ ldns_dname_compare(ldns_rr_owner(cur_sig_rr),ldns_rr_owner(cur_rr)) != 0;
+ j++) {
+ cur_rr = ldns_rr_list_rr(cur_rrset, j);
+
+ }
+ if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr),
+ ldns_rr_owner(cur_rr)))
+ {
+ break;
+ }
+ }
+
+ }
+ /* option 1 */
+ if (data_chain->parent) {
+ ldns_dnssec_derive_trust_tree_normal_rrset_time(
+ new_tree,
+ data_chain,
+ cur_sig_rr,
+ check_time);
+ }
+
+ /* option 2 */
+ ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
+ new_tree,
+ data_chain,
+ cur_rr,
+ cur_sig_rr,
+ check_time);
+ }
+
+ ldns_dnssec_derive_trust_tree_ds_rrset_time(
+ new_tree, data_chain,
+ cur_rr, check_time);
+ } else {
+ /* no signatures? maybe it's nsec data */
+
+ /* just add every rr from parent as new parent */
+ ldns_dnssec_derive_trust_tree_no_sig_time(
+ new_tree, data_chain, check_time);
+ }
+ }
+ }
+
+ return new_tree;
+}
+
+ldns_dnssec_trust_tree *
+ldns_dnssec_derive_trust_tree(ldns_dnssec_data_chain *data_chain, ldns_rr *rr)
+{
+ return ldns_dnssec_derive_trust_tree_time(data_chain, rr, ldns_time(NULL));
+}
+
+void
+ldns_dnssec_derive_trust_tree_normal_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_sig_rr,
+ time_t check_time)
+{
+ size_t i, j;
+ ldns_rr_list *cur_rrset = ldns_rr_list_clone(data_chain->rrset);
+ ldns_dnssec_trust_tree *cur_parent_tree;
+ ldns_rr *cur_parent_rr;
+ uint16_t cur_keytag;
+ ldns_rr_list *tmp_rrset = NULL;
+ ldns_status cur_status;
+
+ cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr));
+
+ for (j = 0; j < ldns_rr_list_rr_count(data_chain->parent->rrset); j++) {
+ cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j);
+ if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) {
+ if (ldns_calc_keytag(cur_parent_rr) == cur_keytag) {
+
+ /* TODO: check wildcard nsec too */
+ if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) {
+ tmp_rrset = cur_rrset;
+ if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0))
+ == LDNS_RR_TYPE_NSEC ||
+ ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0))
+ == LDNS_RR_TYPE_NSEC3) {
+ /* might contain different names!
+ sort and split */
+ ldns_rr_list_sort(cur_rrset);
+ if (tmp_rrset && tmp_rrset != cur_rrset) {
+ ldns_rr_list_deep_free(tmp_rrset);
+ tmp_rrset = NULL;
+ }
+ tmp_rrset = ldns_rr_list_pop_rrset(cur_rrset);
+
+ /* with nsecs, this might be the wrong one */
+ while (tmp_rrset &&
+ ldns_rr_list_rr_count(cur_rrset) > 0 &&
+ ldns_dname_compare(
+ ldns_rr_owner(ldns_rr_list_rr(
+ tmp_rrset, 0)),
+ ldns_rr_owner(cur_sig_rr)) != 0) {
+ ldns_rr_list_deep_free(tmp_rrset);
+ tmp_rrset =
+ ldns_rr_list_pop_rrset(cur_rrset);
+ }
+ }
+ cur_status = ldns_verify_rrsig_time(
+ tmp_rrset,
+ cur_sig_rr,
+ cur_parent_rr,
+ check_time);
+ /* avoid dupes */
+ for (i = 0; i < new_tree->parent_count; i++) {
+ if (cur_parent_rr == new_tree->parents[i]->rr) {
+ goto done;
+ }
+ }
+
+ cur_parent_tree =
+ ldns_dnssec_derive_trust_tree_time(
+ data_chain->parent,
+ cur_parent_rr,
+ check_time);
+ (void)ldns_dnssec_trust_tree_add_parent(new_tree,
+ cur_parent_tree,
+ cur_sig_rr,
+ cur_status);
+ }
+ }
+ }
+ }
+ done:
+ if (tmp_rrset && tmp_rrset != cur_rrset) {
+ ldns_rr_list_deep_free(tmp_rrset);
+ }
+ ldns_rr_list_deep_free(cur_rrset);
+}
+
+void
+ldns_dnssec_derive_trust_tree_normal_rrset(ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_sig_rr)
+{
+ ldns_dnssec_derive_trust_tree_normal_rrset_time(
+ new_tree, data_chain, cur_sig_rr, ldns_time(NULL));
+}
+
+void
+ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr,
+ ldns_rr *cur_sig_rr,
+ time_t check_time)
+{
+ size_t j;
+ ldns_rr_list *cur_rrset = data_chain->rrset;
+ ldns_dnssec_trust_tree *cur_parent_tree;
+ ldns_rr *cur_parent_rr;
+ uint16_t cur_keytag;
+ ldns_status cur_status;
+
+ cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr));
+
+ for (j = 0; j < ldns_rr_list_rr_count(cur_rrset); j++) {
+ cur_parent_rr = ldns_rr_list_rr(cur_rrset, j);
+ if (cur_parent_rr != cur_rr &&
+ ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) {
+ if (ldns_calc_keytag(cur_parent_rr) == cur_keytag
+ ) {
+ cur_parent_tree = ldns_dnssec_trust_tree_new();
+ cur_parent_tree->rr = cur_parent_rr;
+ cur_parent_tree->rrset = cur_rrset;
+ cur_status = ldns_verify_rrsig_time(
+ cur_rrset, cur_sig_rr,
+ cur_parent_rr, check_time);
+ (void) ldns_dnssec_trust_tree_add_parent(new_tree,
+ cur_parent_tree, cur_sig_rr, cur_status);
+ }
+ }
+ }
+}
+
+void
+ldns_dnssec_derive_trust_tree_dnskey_rrset(ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr,
+ ldns_rr *cur_sig_rr)
+{
+ ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
+ new_tree, data_chain, cur_rr, cur_sig_rr, ldns_time(NULL));
+}
+
+void
+ldns_dnssec_derive_trust_tree_ds_rrset_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr,
+ time_t check_time)
+{
+ size_t j, h;
+ ldns_rr_list *cur_rrset = data_chain->rrset;
+ ldns_dnssec_trust_tree *cur_parent_tree;
+ ldns_rr *cur_parent_rr;
+
+ /* try the parent to see whether there are DSs there */
+ if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_DNSKEY &&
+ data_chain->parent &&
+ data_chain->parent->rrset
+ ) {
+ for (j = 0;
+ j < ldns_rr_list_rr_count(data_chain->parent->rrset);
+ j++) {
+ cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j);
+ if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DS) {
+ for (h = 0; h < ldns_rr_list_rr_count(cur_rrset); h++) {
+ cur_rr = ldns_rr_list_rr(cur_rrset, h);
+ if (ldns_rr_compare_ds(cur_rr, cur_parent_rr)) {
+ cur_parent_tree =
+ ldns_dnssec_derive_trust_tree_time(
+ data_chain->parent,
+ cur_parent_rr,
+ check_time);
+ (void) ldns_dnssec_trust_tree_add_parent(
+ new_tree,
+ cur_parent_tree,
+ NULL,
+ LDNS_STATUS_OK);
+ } else {
+ /*ldns_rr_print(stdout, cur_parent_rr);*/
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+ldns_dnssec_derive_trust_tree_ds_rrset(ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ ldns_rr *cur_rr)
+{
+ ldns_dnssec_derive_trust_tree_ds_rrset_time(
+ new_tree, data_chain, cur_rr, ldns_time(NULL));
+}
+
+void
+ldns_dnssec_derive_trust_tree_no_sig_time(
+ ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain,
+ time_t check_time)
+{
+ size_t i;
+ ldns_rr_list *cur_rrset;
+ ldns_rr *cur_parent_rr;
+ ldns_dnssec_trust_tree *cur_parent_tree;
+ ldns_status result;
+
+ if (data_chain->parent && data_chain->parent->rrset) {
+ cur_rrset = data_chain->parent->rrset;
+ /* nsec? */
+ if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) {
+ if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) ==
+ LDNS_RR_TYPE_NSEC3) {
+ result = ldns_dnssec_verify_denial_nsec3(
+ new_tree->rr,
+ cur_rrset,
+ data_chain->parent->signatures,
+ data_chain->packet_rcode,
+ data_chain->packet_qtype,
+ data_chain->packet_nodata);
+ } else if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) ==
+ LDNS_RR_TYPE_NSEC) {
+ result = ldns_dnssec_verify_denial(
+ new_tree->rr,
+ cur_rrset,
+ data_chain->parent->signatures);
+ } else {
+ /* unsigned zone, unsigned parent */
+ result = LDNS_STATUS_OK;
+ }
+ } else {
+ result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+ }
+ for (i = 0; i < ldns_rr_list_rr_count(cur_rrset); i++) {
+ cur_parent_rr = ldns_rr_list_rr(cur_rrset, i);
+ cur_parent_tree =
+ ldns_dnssec_derive_trust_tree_time(
+ data_chain->parent,
+ cur_parent_rr,
+ check_time);
+ (void) ldns_dnssec_trust_tree_add_parent(new_tree,
+ cur_parent_tree, NULL, result);
+ }
+ }
+}
+
+void
+ldns_dnssec_derive_trust_tree_no_sig(ldns_dnssec_trust_tree *new_tree,
+ ldns_dnssec_data_chain *data_chain)
+{
+ ldns_dnssec_derive_trust_tree_no_sig_time(
+ new_tree, data_chain, ldns_time(NULL));
+}
+
+/*
+ * returns OK if there is a path from tree to key with only OK
+ * the (first) error in between otherwise
+ * or NOT_FOUND if the key wasn't present at all
+ */
+ldns_status
+ldns_dnssec_trust_tree_contains_keys(ldns_dnssec_trust_tree *tree,
+ ldns_rr_list *trusted_keys)
+{
+ size_t i;
+ ldns_status result = LDNS_STATUS_CRYPTO_NO_DNSKEY;
+ bool equal;
+ ldns_status parent_result;
+
+ if (tree && trusted_keys && ldns_rr_list_rr_count(trusted_keys) > 0)
+ { if (tree->rr) {
+ for (i = 0; i < ldns_rr_list_rr_count(trusted_keys); i++) {
+ equal = ldns_rr_compare_ds(
+ tree->rr,
+ ldns_rr_list_rr(trusted_keys, i));
+ if (equal) {
+ result = LDNS_STATUS_OK;
+ return result;
+ }
+ }
+ }
+ for (i = 0; i < tree->parent_count; i++) {
+ parent_result =
+ ldns_dnssec_trust_tree_contains_keys(tree->parents[i],
+ trusted_keys);
+ if (parent_result != LDNS_STATUS_CRYPTO_NO_DNSKEY) {
+ if (tree->parent_status[i] != LDNS_STATUS_OK) {
+ result = tree->parent_status[i];
+ } else {
+ if (ldns_rr_get_type(tree->rr)
+ == LDNS_RR_TYPE_NSEC &&
+ parent_result == LDNS_STATUS_OK
+ ) {
+ result =
+ LDNS_STATUS_DNSSEC_EXISTENCE_DENIED;
+ } else {
+ result = parent_result;
+ }
+ }
+ }
+ }
+ } else {
+ result = LDNS_STATUS_ERR;
+ }
+
+ return result;
+}
+
+ldns_status
+ldns_verify_time(
+ ldns_rr_list *rrset,
+ ldns_rr_list *rrsig,
+ const ldns_rr_list *keys,
+ time_t check_time,
+ ldns_rr_list *good_keys
+ )
+{
+ uint16_t i;
+ ldns_status verify_result = LDNS_STATUS_ERR;
+
+ if (!rrset || !rrsig || !keys) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrset) < 1) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrsig) < 1) {
+ return LDNS_STATUS_CRYPTO_NO_RRSIG;
+ }
+
+ if (ldns_rr_list_rr_count(keys) < 1) {
+ verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
+ } else {
+ for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) {
+ ldns_status s = ldns_verify_rrsig_keylist_time(
+ rrset, ldns_rr_list_rr(rrsig, i),
+ keys, check_time, good_keys);
+ /* try a little to get more descriptive error */
+ if(s == LDNS_STATUS_OK) {
+ verify_result = LDNS_STATUS_OK;
+ } else if(verify_result == LDNS_STATUS_ERR)
+ verify_result = s;
+ else if(s != LDNS_STATUS_ERR && verify_result ==
+ LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY)
+ verify_result = s;
+ }
+ }
+ return verify_result;
+}
+
+ldns_status
+ldns_verify(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys,
+ ldns_rr_list *good_keys)
+{
+ return ldns_verify_time(rrset, rrsig, keys, ldns_time(NULL), good_keys);
+}
+
+ldns_status
+ldns_verify_notime(ldns_rr_list *rrset, ldns_rr_list *rrsig,
+ const ldns_rr_list *keys, ldns_rr_list *good_keys)
+{
+ uint16_t i;
+ ldns_status verify_result = LDNS_STATUS_ERR;
+
+ if (!rrset || !rrsig || !keys) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrset) < 1) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrsig) < 1) {
+ return LDNS_STATUS_CRYPTO_NO_RRSIG;
+ }
+
+ if (ldns_rr_list_rr_count(keys) < 1) {
+ verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
+ } else {
+ for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) {
+ ldns_status s = ldns_verify_rrsig_keylist_notime(rrset,
+ ldns_rr_list_rr(rrsig, i), keys, good_keys);
+
+ /* try a little to get more descriptive error */
+ if (s == LDNS_STATUS_OK) {
+ verify_result = LDNS_STATUS_OK;
+ } else if (verify_result == LDNS_STATUS_ERR) {
+ verify_result = s;
+ } else if (s != LDNS_STATUS_ERR && verify_result ==
+ LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) {
+ verify_result = s;
+ }
+ }
+ }
+ return verify_result;
+}
+
+ldns_rr_list *
+ldns_fetch_valid_domain_keys_time(const ldns_resolver *res,
+ const ldns_rdf *domain,
+ const ldns_rr_list *keys,
+ time_t check_time,
+ ldns_status *status)
+{
+ ldns_rr_list * trusted_keys = NULL;
+ ldns_rr_list * ds_keys = NULL;
+ ldns_rdf * prev_parent_domain;
+ ldns_rdf * parent_domain;
+ ldns_rr_list * parent_keys = NULL;
+
+ if (res && domain && keys) {
+
+ if ((trusted_keys = ldns_validate_domain_dnskey_time(res,
+ domain, keys, check_time))) {
+ *status = LDNS_STATUS_OK;
+ } else {
+ /* No trusted keys in this domain, we'll have to find some in the parent domain */
+ *status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
+
+ parent_domain = ldns_dname_left_chop(domain);
+ while (ldns_rdf_size(parent_domain) > 0) {
+ /* Fail if we are at the root */
+
+ if ((parent_keys =
+ ldns_fetch_valid_domain_keys_time(res,
+ parent_domain,
+ keys,
+ check_time,
+ status))) {
+ /* Check DS records */
+ if ((ds_keys =
+ ldns_validate_domain_ds_time(res,
+ domain,
+ parent_keys,
+ check_time))) {
+ trusted_keys =
+ ldns_fetch_valid_domain_keys_time(
+ res,
+ domain,
+ ds_keys,
+ check_time,
+ status);
+ ldns_rr_list_deep_free(ds_keys);
+ } else {
+ /* No valid DS at the parent -- fail */
+ *status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DS ;
+ }
+ ldns_rr_list_deep_free(parent_keys);
+ break;
+ } else {
+ parent_domain = ldns_dname_left_chop((
+ prev_parent_domain
+ = parent_domain
+ ));
+ ldns_rdf_deep_free(prev_parent_domain);
+ }
+ }
+ ldns_rdf_deep_free(parent_domain);
+ }
+ }
+ return trusted_keys;
+}
+
+ldns_rr_list *
+ldns_fetch_valid_domain_keys(const ldns_resolver *res,
+ const ldns_rdf *domain,
+ const ldns_rr_list *keys,
+ ldns_status *status)
+{
+ return ldns_fetch_valid_domain_keys_time(
+ res, domain, keys, ldns_time(NULL), status);
+}
+
+ldns_rr_list *
+ldns_validate_domain_dnskey_time(
+ const ldns_resolver * res,
+ const ldns_rdf * domain,
+ const ldns_rr_list * keys,
+ time_t check_time
+ )
+{
+ ldns_pkt * keypkt;
+ ldns_rr * cur_key;
+ uint16_t key_i; uint16_t key_j; uint16_t key_k;
+ uint16_t sig_i; ldns_rr * cur_sig;
+
+ ldns_rr_list * domain_keys = NULL;
+ ldns_rr_list * domain_sigs = NULL;
+ ldns_rr_list * trusted_keys = NULL;
+
+ /* Fetch keys for the domain */
+ keypkt = ldns_resolver_query(res, domain,
+ LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, LDNS_RD);
+ if (keypkt) {
+ domain_keys = ldns_pkt_rr_list_by_type(keypkt,
+ LDNS_RR_TYPE_DNSKEY,
+ LDNS_SECTION_ANSWER);
+ domain_sigs = ldns_pkt_rr_list_by_type(keypkt,
+ LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANSWER);
+
+ /* Try to validate the record using our keys */
+ for (key_i=0; key_i< ldns_rr_list_rr_count(domain_keys); key_i++) {
+
+ cur_key = ldns_rr_list_rr(domain_keys, key_i);
+ for (key_j=0; key_j<ldns_rr_list_rr_count(keys); key_j++) {
+ if (ldns_rr_compare_ds(ldns_rr_list_rr(keys, key_j),
+ cur_key)) {
+
+ /* Current key is trusted -- validate */
+ trusted_keys = ldns_rr_list_new();
+
+ for (sig_i=0;
+ sig_i<ldns_rr_list_rr_count(domain_sigs);
+ sig_i++) {
+ cur_sig = ldns_rr_list_rr(domain_sigs, sig_i);
+ /* Avoid non-matching sigs */
+ if (ldns_rdf2native_int16(
+ ldns_rr_rrsig_keytag(cur_sig))
+ == ldns_calc_keytag(cur_key)) {
+ if (ldns_verify_rrsig_time(
+ domain_keys,
+ cur_sig,
+ cur_key,
+ check_time)
+ == LDNS_STATUS_OK) {
+
+ /* Push the whole rrset
+ -- we can't do much more */
+ for (key_k=0;
+ key_k<ldns_rr_list_rr_count(
+ domain_keys);
+ key_k++) {
+ ldns_rr_list_push_rr(
+ trusted_keys,
+ ldns_rr_clone(
+ ldns_rr_list_rr(
+ domain_keys,
+ key_k)));
+ }
+
+ ldns_rr_list_deep_free(domain_keys);
+ ldns_rr_list_deep_free(domain_sigs);
+ ldns_pkt_free(keypkt);
+ return trusted_keys;
+ }
+ }
+ }
+
+ /* Only push our trusted key */
+ ldns_rr_list_push_rr(trusted_keys,
+ ldns_rr_clone(cur_key));
+ }
+ }
+ }
+
+ ldns_rr_list_deep_free(domain_keys);
+ ldns_rr_list_deep_free(domain_sigs);
+ ldns_pkt_free(keypkt);
+
+ } else {
+ /* LDNS_STATUS_CRYPTO_NO_DNSKEY */
+ }
+
+ return trusted_keys;
+}
+
+ldns_rr_list *
+ldns_validate_domain_dnskey(const ldns_resolver * res,
+ const ldns_rdf * domain,
+ const ldns_rr_list * keys)
+{
+ return ldns_validate_domain_dnskey_time(
+ res, domain, keys, ldns_time(NULL));
+}
+
+ldns_rr_list *
+ldns_validate_domain_ds_time(
+ const ldns_resolver *res,
+ const ldns_rdf * domain,
+ const ldns_rr_list * keys,
+ time_t check_time)
+{
+ ldns_pkt * dspkt;
+ uint16_t key_i;
+ ldns_rr_list * rrset = NULL;
+ ldns_rr_list * sigs = NULL;
+ ldns_rr_list * trusted_keys = NULL;
+
+ /* Fetch DS for the domain */
+ dspkt = ldns_resolver_query(res, domain,
+ LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, LDNS_RD);
+ if (dspkt) {
+ rrset = ldns_pkt_rr_list_by_type(dspkt,
+ LDNS_RR_TYPE_DS,
+ LDNS_SECTION_ANSWER);
+ sigs = ldns_pkt_rr_list_by_type(dspkt,
+ LDNS_RR_TYPE_RRSIG,
+ LDNS_SECTION_ANSWER);
+
+ /* Validate sigs */
+ if (ldns_verify_time(rrset, sigs, keys, check_time, NULL)
+ == LDNS_STATUS_OK) {
+ trusted_keys = ldns_rr_list_new();
+ for (key_i=0; key_i<ldns_rr_list_rr_count(rrset); key_i++) {
+ ldns_rr_list_push_rr(trusted_keys,
+ ldns_rr_clone(ldns_rr_list_rr(rrset,
+ key_i)
+ )
+ );
+ }
+ }
+
+ ldns_rr_list_deep_free(rrset);
+ ldns_rr_list_deep_free(sigs);
+ ldns_pkt_free(dspkt);
+
+ } else {
+ /* LDNS_STATUS_CRYPTO_NO_DS */
+ }
+
+ return trusted_keys;
+}
+
+ldns_rr_list *
+ldns_validate_domain_ds(const ldns_resolver *res,
+ const ldns_rdf * domain,
+ const ldns_rr_list * keys)
+{
+ return ldns_validate_domain_ds_time(res, domain, keys, ldns_time(NULL));
+}
+
+ldns_status
+ldns_verify_trusted_time(
+ ldns_resolver *res,
+ ldns_rr_list *rrset,
+ ldns_rr_list * rrsigs,
+ time_t check_time,
+ ldns_rr_list * validating_keys
+ )
+{
+ uint16_t sig_i; uint16_t key_i;
+ ldns_rr * cur_sig; ldns_rr * cur_key;
+ ldns_rr_list * trusted_keys = NULL;
+ ldns_status result = LDNS_STATUS_ERR;
+
+ if (!res || !rrset || !rrsigs) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrset) < 1) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_list_rr_count(rrsigs) < 1) {
+ return LDNS_STATUS_CRYPTO_NO_RRSIG;
+ }
+
+ /* Look at each sig */
+ for (sig_i=0; sig_i < ldns_rr_list_rr_count(rrsigs); sig_i++) {
+
+ cur_sig = ldns_rr_list_rr(rrsigs, sig_i);
+ /* Get a valid signer key and validate the sig */
+ if ((trusted_keys = ldns_fetch_valid_domain_keys_time(
+ res,
+ ldns_rr_rrsig_signame(cur_sig),
+ ldns_resolver_dnssec_anchors(res),
+ check_time,
+ &result))) {
+
+ for (key_i = 0;
+ key_i < ldns_rr_list_rr_count(trusted_keys);
+ key_i++) {
+ cur_key = ldns_rr_list_rr(trusted_keys, key_i);
+
+ if ((result = ldns_verify_rrsig_time(rrset,
+ cur_sig,
+ cur_key,
+ check_time))
+ == LDNS_STATUS_OK) {
+ if (validating_keys) {
+ ldns_rr_list_push_rr(validating_keys,
+ ldns_rr_clone(cur_key));
+ }
+ ldns_rr_list_deep_free(trusted_keys);
+ return LDNS_STATUS_OK;
+ }
+ }
+ }
+ }
+
+ ldns_rr_list_deep_free(trusted_keys);
+ return result;
+}
+
+ldns_status
+ldns_verify_trusted(
+ ldns_resolver *res,
+ ldns_rr_list *rrset,
+ ldns_rr_list * rrsigs,
+ ldns_rr_list * validating_keys)
+{
+ return ldns_verify_trusted_time(
+ res, rrset, rrsigs, ldns_time(NULL), validating_keys);
+}
+
+
+ldns_status
+ldns_dnssec_verify_denial(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs)
+{
+ ldns_rdf *rr_name;
+ ldns_rdf *wildcard_name;
+ ldns_rdf *chopped_dname;
+ ldns_rr *cur_nsec;
+ size_t i;
+ ldns_status result;
+ /* needed for wildcard check on exact match */
+ ldns_rr *rrsig;
+ bool name_covered = false;
+ bool type_covered = false;
+ bool wildcard_covered = false;
+ bool wildcard_type_covered = 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);
+ if (result != LDNS_STATUS_OK) {
+ return result;
+ }
+
+ ldns_rdf_deep_free(chopped_dname);
+
+ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
+ cur_nsec = ldns_rr_list_rr(nsecs, i);
+ if (ldns_dname_compare(rr_name, ldns_rr_owner(cur_nsec)) == 0) {
+ /* see section 5.4 of RFC4035, if the label count of the NSEC's
+ RRSIG is equal, then it is proven that wildcard expansion
+ could not have been used to match the request */
+ rrsig = ldns_dnssec_get_rrsig_for_name_and_type(
+ ldns_rr_owner(cur_nsec),
+ ldns_rr_get_type(cur_nsec),
+ rrsigs);
+ if (rrsig && ldns_rdf2native_int8(ldns_rr_rrsig_labels(rrsig))
+ == ldns_dname_label_count(rr_name)) {
+ wildcard_covered = true;
+ }
+
+ if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(cur_nsec),
+ ldns_rr_get_type(rr))) {
+ type_covered = true;
+ }
+ }
+ if (ldns_nsec_covers_name(cur_nsec, rr_name)) {
+ name_covered = true;
+ }
+
+ if (ldns_dname_compare(wildcard_name,
+ ldns_rr_owner(cur_nsec)) == 0) {
+ if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(cur_nsec),
+ ldns_rr_get_type(rr))) {
+ wildcard_type_covered = true;
+ }
+ }
+
+ if (ldns_nsec_covers_name(cur_nsec, wildcard_name)) {
+ wildcard_covered = true;
+ }
+
+ }
+
+ ldns_rdf_deep_free(wildcard_name);
+
+ if (type_covered || !name_covered) {
+ return LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+ }
+
+ if (wildcard_type_covered || !wildcard_covered) {
+ return LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED;
+ }
+
+ return LDNS_STATUS_OK;
+}
+
+#ifdef HAVE_SSL
+ldns_status
+ldns_dnssec_verify_denial_nsec3_match(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs,
+ ldns_pkt_rcode packet_rcode,
+ ldns_rr_type packet_qtype,
+ bool packet_nodata,
+ ldns_rr **match)
+{
+ ldns_rdf *closest_encloser;
+ ldns_rdf *wildcard;
+ ldns_rdf *hashed_wildcard_name;
+ bool wildcard_covered = false;
+ ldns_rdf *zone_name;
+ ldns_rdf *hashed_name;
+ size_t i;
+ ldns_status result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+
+ rrsigs = rrsigs;
+
+ if (match) {
+ *match = NULL;
+ }
+
+ zone_name = ldns_dname_left_chop(ldns_rr_owner(ldns_rr_list_rr(nsecs,0)));
+
+ /* section 8.4 */
+ if (packet_rcode == LDNS_RCODE_NXDOMAIN) {
+ closest_encloser = ldns_dnssec_nsec3_closest_encloser(
+ ldns_rr_owner(rr),
+ ldns_rr_get_type(rr),
+ nsecs);
+ if(!closest_encloser) {
+ result = LDNS_STATUS_NSEC3_ERR;
+ goto done;
+ }
+
+ wildcard = ldns_dname_new_frm_str("*");
+ (void) ldns_dname_cat(wildcard, closest_encloser);
+
+ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
+ hashed_wildcard_name =
+ ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs, 0),
+ wildcard
+ );
+ (void) ldns_dname_cat(hashed_wildcard_name, zone_name);
+
+ if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, i),
+ hashed_wildcard_name)) {
+ wildcard_covered = true;
+ if (match) {
+ *match = ldns_rr_list_rr(nsecs, i);
+ }
+ }
+ ldns_rdf_deep_free(hashed_wildcard_name);
+ }
+
+ ldns_rdf_deep_free(closest_encloser);
+ ldns_rdf_deep_free(wildcard);
+
+ if (!wildcard_covered) {
+ result = LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED;
+ } else if (closest_encloser && wildcard_covered) {
+ result = LDNS_STATUS_OK;
+ } else {
+ result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+ }
+ } else if (packet_nodata && packet_qtype != LDNS_RR_TYPE_DS) {
+ /* section 8.5 */
+ hashed_name = ldns_nsec3_hash_name_frm_nsec3(
+ ldns_rr_list_rr(nsecs, 0),
+ ldns_rr_owner(rr));
+ (void) ldns_dname_cat(hashed_name, zone_name);
+ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
+ if (ldns_dname_compare(hashed_name,
+ ldns_rr_owner(ldns_rr_list_rr(nsecs, i)))
+ == 0) {
+ if (!ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ packet_qtype)
+ &&
+ !ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ LDNS_RR_TYPE_CNAME)) {
+ result = LDNS_STATUS_OK;
+ if (match) {
+ *match = ldns_rr_list_rr(nsecs, i);
+ }
+ goto done;
+ }
+ }
+ }
+ result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+ /* wildcard no data? section 8.7 */
+ closest_encloser = ldns_dnssec_nsec3_closest_encloser(
+ ldns_rr_owner(rr),
+ ldns_rr_get_type(rr),
+ nsecs);
+ if(!closest_encloser) {
+ result = LDNS_STATUS_NSEC3_ERR;
+ goto done;
+ }
+ wildcard = ldns_dname_new_frm_str("*");
+ (void) ldns_dname_cat(wildcard, closest_encloser);
+ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
+ hashed_wildcard_name =
+ ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs, 0),
+ wildcard);
+ (void) ldns_dname_cat(hashed_wildcard_name, zone_name);
+
+ if (ldns_dname_compare(hashed_wildcard_name,
+ ldns_rr_owner(ldns_rr_list_rr(nsecs, i)))
+ == 0) {
+ if (!ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ packet_qtype)
+ &&
+ !ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ LDNS_RR_TYPE_CNAME)) {
+ result = LDNS_STATUS_OK;
+ if (match) {
+ *match = ldns_rr_list_rr(nsecs, i);
+ }
+ }
+ }
+ ldns_rdf_deep_free(hashed_wildcard_name);
+ if (result == LDNS_STATUS_OK) {
+ break;
+ }
+ }
+ ldns_rdf_deep_free(closest_encloser);
+ ldns_rdf_deep_free(wildcard);
+ } else if (packet_nodata && packet_qtype == LDNS_RR_TYPE_DS) {
+ /* section 8.6 */
+ /* note: up to XXX this is the same as for 8.5 */
+ hashed_name = ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs,
+ 0),
+ ldns_rr_owner(rr)
+ );
+ (void) ldns_dname_cat(hashed_name, zone_name);
+ for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
+ if (ldns_dname_compare(hashed_name,
+ ldns_rr_owner(ldns_rr_list_rr(nsecs,
+ i)))
+ == 0) {
+ if (!ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ LDNS_RR_TYPE_DS)
+ &&
+ !ldns_nsec_bitmap_covers_type(
+ ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
+ LDNS_RR_TYPE_CNAME)) {
+ result = LDNS_STATUS_OK;
+ if (match) {
+ *match = ldns_rr_list_rr(nsecs, i);
+ }
+ goto done;
+ }
+ }
+ }
+
+ /* XXX see note above */
+ result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
+ }
+
+ done:
+ ldns_rdf_deep_free(zone_name);
+ return result;
+}
+
+ldns_status
+ldns_dnssec_verify_denial_nsec3(ldns_rr *rr,
+ ldns_rr_list *nsecs,
+ ldns_rr_list *rrsigs,
+ ldns_pkt_rcode packet_rcode,
+ ldns_rr_type packet_qtype,
+ bool packet_nodata)
+{
+ return ldns_dnssec_verify_denial_nsec3_match(
+ rr, nsecs, rrsigs, packet_rcode,
+ packet_qtype, packet_nodata, NULL
+ );
+}
+
+
+#endif /* HAVE_SSL */
+
+#ifdef USE_GOST
+EVP_PKEY*
+ldns_gost2pkey_raw(unsigned char* key, size_t keylen)
+{
+ /* prefix header for X509 encoding */
+ uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
+ 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
+ unsigned char encoded[37+64];
+ const unsigned char* pp;
+ if(keylen != 64) {
+ /* key wrong size */
+ return NULL;
+ }
+
+ /* create evp_key */
+ memmove(encoded, asn, 37);
+ memmove(encoded+37, key, 64);
+ pp = (unsigned char*)&encoded[0];
+
+ return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
+}
+
+static ldns_status
+ldns_verify_rrsig_gost_raw(unsigned char* sig, size_t siglen,
+ ldns_buffer* rrset, unsigned char* key, size_t keylen)
+{
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ (void) ldns_key_EVP_load_gost_id();
+ evp_key = ldns_gost2pkey_raw(key, keylen);
+ if(!evp_key) {
+ /* could not convert key */
+ return LDNS_STATUS_CRYPTO_BOGUS;
+ }
+
+ /* verify signature */
+ result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset,
+ evp_key, EVP_get_digestbyname("md_gost94"));
+ EVP_PKEY_free(evp_key);
+
+ return result;
+}
+#endif
+
+#ifdef USE_ECDSA
+EVP_PKEY*
+ldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
+{
+ unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
+ const unsigned char* pp = buf;
+ EVP_PKEY *evp_key;
+ EC_KEY *ec;
+ /* check length, which uncompressed must be 2 bignums */
+ if(algo == LDNS_ECDSAP256SHA256) {
+ if(keylen != 2*256/8) return NULL;
+ ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ } else if(algo == LDNS_ECDSAP384SHA384) {
+ if(keylen != 2*384/8) return NULL;
+ ec = EC_KEY_new_by_curve_name(NID_secp384r1);
+ } else ec = NULL;
+ if(!ec) return NULL;
+ if(keylen+1 > sizeof(buf))
+ return NULL; /* sanity check */
+ /* prepend the 0x02 (from docs) (or actually 0x04 from implementation
+ * of openssl) for uncompressed data */
+ buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+ memmove(buf+1, key, keylen);
+ if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ evp_key = EVP_PKEY_new();
+ if(!evp_key) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+ EVP_PKEY_free(evp_key);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ return evp_key;
+}
+
+static ldns_status
+ldns_verify_rrsig_ecdsa_raw(unsigned char* sig, size_t siglen,
+ ldns_buffer* rrset, unsigned char* key, size_t keylen, uint8_t algo)
+{
+ EVP_PKEY *evp_key;
+ ldns_status result;
+ const EVP_MD *d;
+
+ evp_key = ldns_ecdsa2pkey_raw(key, keylen, algo);
+ if(!evp_key) {
+ /* could not convert key */
+ return LDNS_STATUS_CRYPTO_BOGUS;
+ }
+ if(algo == LDNS_ECDSAP256SHA256)
+ d = EVP_sha256();
+ else d = EVP_sha384(); /* LDNS_ECDSAP384SHA384 */
+ result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, d);
+ EVP_PKEY_free(evp_key);
+ return result;
+}
+#endif
+
+ldns_status
+ldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf, ldns_buffer *verify_buf,
+ ldns_buffer *key_buf, uint8_t algo)
+{
+ return ldns_verify_rrsig_buffers_raw(
+ (unsigned char*)ldns_buffer_begin(rawsig_buf),
+ ldns_buffer_position(rawsig_buf),
+ verify_buf,
+ (unsigned char*)ldns_buffer_begin(key_buf),
+ ldns_buffer_position(key_buf), algo);
+}
+
+ldns_status
+ldns_verify_rrsig_buffers_raw(unsigned char* sig, size_t siglen,
+ ldns_buffer *verify_buf, unsigned char* key, size_t keylen,
+ uint8_t algo)
+{
+ /* check for right key */
+ switch(algo) {
+ case LDNS_DSA:
+ case LDNS_DSA_NSEC3:
+ return ldns_verify_rrsig_dsa_raw(sig,
+ siglen,
+ verify_buf,
+ key,
+ keylen);
+ break;
+ case LDNS_RSASHA1:
+ case LDNS_RSASHA1_NSEC3:
+ return ldns_verify_rrsig_rsasha1_raw(sig,
+ siglen,
+ verify_buf,
+ key,
+ keylen);
+ break;
+#ifdef USE_SHA2
+ case LDNS_RSASHA256:
+ return ldns_verify_rrsig_rsasha256_raw(sig,
+ siglen,
+ verify_buf,
+ key,
+ keylen);
+ break;
+ case LDNS_RSASHA512:
+ return ldns_verify_rrsig_rsasha512_raw(sig,
+ siglen,
+ verify_buf,
+ key,
+ keylen);
+ break;
+#endif
+#ifdef USE_GOST
+ case LDNS_ECC_GOST:
+ return ldns_verify_rrsig_gost_raw(sig, siglen, verify_buf,
+ key, keylen);
+ break;
+#endif
+#ifdef USE_ECDSA
+ case LDNS_ECDSAP256SHA256:
+ case LDNS_ECDSAP384SHA384:
+ return ldns_verify_rrsig_ecdsa_raw(sig, siglen, verify_buf,
+ key, keylen, algo);
+ break;
+#endif
+ case LDNS_RSAMD5:
+ return ldns_verify_rrsig_rsamd5_raw(sig,
+ siglen,
+ verify_buf,
+ key,
+ keylen);
+ break;
+ default:
+ /* do you know this alg?! */
+ return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
+ }
+}
+
+
+/**
+ * Reset the ttl in the rrset with the orig_ttl from the sig
+ * and update owner name if it was wildcard
+ * Also canonicalizes the rrset.
+ * @param rrset: rrset to modify
+ * @param sig: signature to take TTL and wildcard values from
+ */
+static void
+ldns_rrset_use_signature_ttl(ldns_rr_list* rrset_clone, ldns_rr* rrsig)
+{
+ uint32_t orig_ttl;
+ uint16_t i;
+ uint8_t label_count;
+ ldns_rdf *wildcard_name;
+ ldns_rdf *wildcard_chopped;
+ ldns_rdf *wildcard_chopped_tmp;
+
+ if ((rrsig == NULL) || ldns_rr_rd_count(rrsig) < 4) {
+ return;
+ }
+
+ orig_ttl = ldns_rdf2native_int32( ldns_rr_rdf(rrsig, 3));
+ label_count = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 2));
+
+ for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
+ if (label_count <
+ ldns_dname_label_count(
+ ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)))) {
+ (void) ldns_str2rdf_dname(&wildcard_name, "*");
+ wildcard_chopped = ldns_rdf_clone(ldns_rr_owner(
+ ldns_rr_list_rr(rrset_clone, i)));
+ while (label_count < ldns_dname_label_count(wildcard_chopped)) {
+ wildcard_chopped_tmp = ldns_dname_left_chop(
+ wildcard_chopped);
+ ldns_rdf_deep_free(wildcard_chopped);
+ wildcard_chopped = wildcard_chopped_tmp;
+ }
+ (void) ldns_dname_cat(wildcard_name, wildcard_chopped);
+ ldns_rdf_deep_free(wildcard_chopped);
+ ldns_rdf_deep_free(ldns_rr_owner(ldns_rr_list_rr(
+ rrset_clone, i)));
+ ldns_rr_set_owner(ldns_rr_list_rr(rrset_clone, i),
+ wildcard_name);
+ }
+ ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i), orig_ttl);
+ /* convert to lowercase */
+ ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i));
+ }
+}
+
+/**
+ * Make raw signature buffer out of rrsig
+ * @param rawsig_buf: raw signature buffer for result
+ * @param rrsig: signature to convert
+ * @return OK or more specific error.
+ */
+static ldns_status
+ldns_rrsig2rawsig_buffer(ldns_buffer* rawsig_buf, ldns_rr* rrsig)
+{
+ uint8_t sig_algo;
+
+ if (rrsig == NULL) {
+ return LDNS_STATUS_CRYPTO_NO_RRSIG;
+ }
+ if (ldns_rr_rdf(rrsig, 1) == NULL) {
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+ }
+ sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1));
+ /* check for known and implemented algo's now (otherwise
+ * the function could return a wrong error
+ */
+ /* create a buffer with signature rdata */
+ /* for some algorithms we need other data than for others... */
+ /* (the DSA API wants DER encoding for instance) */
+
+ switch(sig_algo) {
+ case LDNS_RSAMD5:
+ case LDNS_RSASHA1:
+ case LDNS_RSASHA1_NSEC3:
+#ifdef USE_SHA2
+ case LDNS_RSASHA256:
+ case LDNS_RSASHA512:
+#endif
+#ifdef USE_GOST
+ case LDNS_ECC_GOST:
+#endif
+ if (ldns_rr_rdf(rrsig, 8) == NULL) {
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+ }
+ if (ldns_rdf2buffer_wire(rawsig_buf, ldns_rr_rdf(rrsig, 8))
+ != LDNS_STATUS_OK) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ break;
+ case LDNS_DSA:
+ case LDNS_DSA_NSEC3:
+ /* EVP takes rfc2459 format, which is a tad longer than dns format */
+ if (ldns_rr_rdf(rrsig, 8) == NULL) {
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+ }
+ if (ldns_convert_dsa_rrsig_rdf2asn1(
+ rawsig_buf, ldns_rr_rdf(rrsig, 8))
+ != LDNS_STATUS_OK) {
+ /*
+ if (ldns_rdf2buffer_wire(rawsig_buf,
+ ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) {
+ */
+ return LDNS_STATUS_MEM_ERR;
+ }
+ break;
+#ifdef USE_ECDSA
+ case LDNS_ECDSAP256SHA256:
+ case LDNS_ECDSAP384SHA384:
+ /* EVP produces an ASN prefix on the signature, which is
+ * not used in the DNS */
+ if (ldns_rr_rdf(rrsig, 8) == NULL) {
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+ }
+ if (ldns_convert_ecdsa_rrsig_rdf2asn1(
+ rawsig_buf, ldns_rr_rdf(rrsig, 8))
+ != LDNS_STATUS_OK) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ break;
+#endif
+ case LDNS_DH:
+ case LDNS_ECC:
+ case LDNS_INDIRECT:
+ return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL;
+ default:
+ return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
+ }
+ return LDNS_STATUS_OK;
+}
+
+/**
+ * Check RRSIG timestamps against the given 'now' time.
+ * @param rrsig: signature to check.
+ * @param now: the current time in seconds epoch.
+ * @return status code LDNS_STATUS_OK if all is fine.
+ */
+static ldns_status
+ldns_rrsig_check_timestamps(ldns_rr* rrsig, time_t now)
+{
+ int32_t inception, expiration;
+
+ /* check the signature time stamps */
+ inception = (int32_t)ldns_rdf2native_time_t(
+ ldns_rr_rrsig_inception(rrsig));
+ expiration = (int32_t)ldns_rdf2native_time_t(
+ ldns_rr_rrsig_expiration(rrsig));
+
+ if (expiration - inception < 0) {
+ /* bad sig, expiration before inception?? Tsssg */
+ return LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION;
+ }
+ if (now - inception < 0) {
+ /* bad sig, inception date has not yet come to pass */
+ return LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED;
+ }
+ if (expiration - now < 0) {
+ /* bad sig, expiration date has passed */
+ return LDNS_STATUS_CRYPTO_SIG_EXPIRED;
+ }
+ return LDNS_STATUS_OK;
+}
+
+/**
+ * Prepare for verification.
+ * @param rawsig_buf: raw signature buffer made ready.
+ * @param verify_buf: data for verification buffer made ready.
+ * @param rrset_clone: made ready.
+ * @param rrsig: signature to prepare for.
+ * @return LDNS_STATUS_OK is all went well. Otherwise specific error.
+ */
+static ldns_status
+ldns_prepare_for_verify(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf,
+ ldns_rr_list* rrset_clone, ldns_rr* rrsig)
+{
+ ldns_status result;
+
+ /* canonicalize the sig */
+ ldns_dname2canonical(ldns_rr_owner(rrsig));
+
+ /* check if the typecovered is equal to the type checked */
+ if (ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rrsig)) !=
+ ldns_rr_get_type(ldns_rr_list_rr(rrset_clone, 0)))
+ return LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR;
+
+ /* create a buffer with b64 signature rdata */
+ result = ldns_rrsig2rawsig_buffer(rawsig_buf, rrsig);
+ if(result != LDNS_STATUS_OK)
+ return result;
+
+ /* use TTL from signature. Use wildcard names for wildcards */
+ /* also canonicalizes rrset_clone */
+ ldns_rrset_use_signature_ttl(rrset_clone, rrsig);
+
+ /* sort the rrset in canonical order */
+ ldns_rr_list_sort(rrset_clone);
+
+ /* put the signature rr (without the b64) to the verify_buf */
+ if (ldns_rrsig2buffer_wire(verify_buf, rrsig) != LDNS_STATUS_OK)
+ return LDNS_STATUS_MEM_ERR;
+
+ /* add the rrset in verify_buf */
+ if(ldns_rr_list2buffer_wire(verify_buf, rrset_clone)
+ != LDNS_STATUS_OK)
+ return LDNS_STATUS_MEM_ERR;
+
+ return LDNS_STATUS_OK;
+}
+
+/**
+ * Check if a key matches a signature.
+ * Checks keytag, sigalgo and signature.
+ * @param rawsig_buf: raw signature buffer for verify
+ * @param verify_buf: raw data buffer for verify
+ * @param rrsig: the rrsig
+ * @param key: key to attempt.
+ * @return LDNS_STATUS_OK if OK, else some specific error.
+ */
+static ldns_status
+ldns_verify_test_sig_key(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf,
+ ldns_rr* rrsig, ldns_rr* key)
+{
+ uint8_t sig_algo;
+
+ if (rrsig == NULL) {
+ return LDNS_STATUS_CRYPTO_NO_RRSIG;
+ }
+ if (ldns_rr_rdf(rrsig, 1) == NULL) {
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
+ }
+ sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1));
+
+ /* before anything, check if the keytags match */
+ if (ldns_calc_keytag(key)
+ ==
+ ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig))
+ ) {
+ ldns_buffer* key_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ ldns_status result = LDNS_STATUS_ERR;
+
+ /* put the key-data in a buffer, that's the third rdf, with
+ * the base64 encoded key data */
+ if (ldns_rr_rdf(key, 3) == NULL) {
+ ldns_buffer_free(key_buf);
+ return LDNS_STATUS_MISSING_RDATA_FIELDS_KEY;
+ }
+ if (ldns_rdf2buffer_wire(key_buf, ldns_rr_rdf(key, 3))
+ != LDNS_STATUS_OK) {
+ ldns_buffer_free(key_buf);
+ /* returning is bad might screw up
+ good keys later in the list
+ what to do? */
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_rr_rdf(key, 2) == NULL) {
+ result = LDNS_STATUS_MISSING_RDATA_FIELDS_KEY;
+ }
+ else if (sig_algo == ldns_rdf2native_int8(
+ ldns_rr_rdf(key, 2))) {
+ result = ldns_verify_rrsig_buffers(rawsig_buf,
+ verify_buf, key_buf, sig_algo);
+ } else {
+ /* No keys with the corresponding algorithm are found */
+ result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+ }
+
+ ldns_buffer_free(key_buf);
+ return result;
+ }
+ else {
+ /* No keys with the corresponding keytag are found */
+ return LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+ }
+}
+
+/*
+ * to verify:
+ * - create the wire fmt of the b64 key rdata
+ * - create the wire fmt of the sorted rrset
+ * - create the wire fmt of the b64 sig rdata
+ * - create the wire fmt of the sig without the b64 rdata
+ * - cat the sig data (without b64 rdata) to the rrset
+ * - verify the rrset+sig, with the b64 data and the b64 key data
+ */
+ldns_status
+ldns_verify_rrsig_keylist_time(
+ ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ const ldns_rr_list *keys,
+ time_t check_time,
+ ldns_rr_list *good_keys)
+{
+ ldns_status result;
+ ldns_rr_list *valid = ldns_rr_list_new();
+ if (!valid)
+ return LDNS_STATUS_MEM_ERR;
+
+ result = ldns_verify_rrsig_keylist_notime(rrset, rrsig, keys, valid);
+ if(result != LDNS_STATUS_OK) {
+ ldns_rr_list_free(valid);
+ return result;
+ }
+
+ /* check timestamps last; its OK except time */
+ result = ldns_rrsig_check_timestamps(rrsig, check_time);
+ if(result != LDNS_STATUS_OK) {
+ ldns_rr_list_free(valid);
+ return result;
+ }
+
+ ldns_rr_list_cat(good_keys, valid);
+ ldns_rr_list_free(valid);
+ return LDNS_STATUS_OK;
+}
+
+/*
+ * to verify:
+ * - create the wire fmt of the b64 key rdata
+ * - create the wire fmt of the sorted rrset
+ * - create the wire fmt of the b64 sig rdata
+ * - create the wire fmt of the sig without the b64 rdata
+ * - cat the sig data (without b64 rdata) to the rrset
+ * - verify the rrset+sig, with the b64 data and the b64 key data
+ */
+ldns_status
+ldns_verify_rrsig_keylist(ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys)
+{
+ return ldns_verify_rrsig_keylist_time(
+ rrset, rrsig, keys, ldns_time(NULL), good_keys);
+}
+
+ldns_status
+ldns_verify_rrsig_keylist_notime(ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ const ldns_rr_list *keys,
+ ldns_rr_list *good_keys)
+{
+ ldns_buffer *rawsig_buf;
+ ldns_buffer *verify_buf;
+ uint16_t i;
+ ldns_status result, status;
+ ldns_rr_list *rrset_clone;
+ ldns_rr_list *validkeys;
+
+ if (!rrset) {
+ return LDNS_STATUS_ERR;
+ }
+
+ validkeys = ldns_rr_list_new();
+ if (!validkeys) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ /* clone the rrset so that we can fiddle with it */
+ rrset_clone = ldns_rr_list_clone(rrset);
+
+ /* create the buffers which will certainly hold the raw data */
+ rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ verify_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ result = ldns_prepare_for_verify(rawsig_buf, verify_buf,
+ rrset_clone, rrsig);
+ if(result != LDNS_STATUS_OK) {
+ ldns_buffer_free(verify_buf);
+ ldns_buffer_free(rawsig_buf);
+ ldns_rr_list_deep_free(rrset_clone);
+ ldns_rr_list_free(validkeys);
+ return result;
+ }
+
+ result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+ for(i = 0; i < ldns_rr_list_rr_count(keys); i++) {
+ status = ldns_verify_test_sig_key(rawsig_buf, verify_buf,
+ rrsig, ldns_rr_list_rr(keys, i));
+ if (status == LDNS_STATUS_OK) {
+ /* one of the keys has matched, don't break
+ * here, instead put the 'winning' key in
+ * the validkey list and return the list
+ * later */
+ if (!ldns_rr_list_push_rr(validkeys,
+ ldns_rr_list_rr(keys,i))) {
+ /* couldn't push the key?? */
+ ldns_buffer_free(rawsig_buf);
+ ldns_buffer_free(verify_buf);
+ ldns_rr_list_deep_free(rrset_clone);
+ ldns_rr_list_free(validkeys);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ result = status;
+ }
+
+ if (result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) {
+ result = status;
+ }
+ }
+
+ /* no longer needed */
+ ldns_rr_list_deep_free(rrset_clone);
+ ldns_buffer_free(rawsig_buf);
+ ldns_buffer_free(verify_buf);
+
+ if (ldns_rr_list_rr_count(validkeys) == 0) {
+ /* no keys were added, return last error */
+ ldns_rr_list_free(validkeys);
+ return result;
+ }
+
+ /* do not check timestamps */
+
+ ldns_rr_list_cat(good_keys, validkeys);
+ ldns_rr_list_free(validkeys);
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_verify_rrsig_time(
+ ldns_rr_list *rrset,
+ ldns_rr *rrsig,
+ ldns_rr *key,
+ time_t check_time)
+{
+ ldns_buffer *rawsig_buf;
+ ldns_buffer *verify_buf;
+ ldns_status result;
+ ldns_rr_list *rrset_clone;
+
+ if (!rrset) {
+ return LDNS_STATUS_NO_DATA;
+ }
+ /* clone the rrset so that we can fiddle with it */
+ rrset_clone = ldns_rr_list_clone(rrset);
+ /* create the buffers which will certainly hold the raw data */
+ rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ verify_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ result = ldns_prepare_for_verify(rawsig_buf, verify_buf,
+ rrset_clone, rrsig);
+ if(result != LDNS_STATUS_OK) {
+ ldns_rr_list_deep_free(rrset_clone);
+ ldns_buffer_free(rawsig_buf);
+ ldns_buffer_free(verify_buf);
+ return result;
+ }
+ result = ldns_verify_test_sig_key(rawsig_buf, verify_buf,
+ rrsig, key);
+ /* no longer needed */
+ ldns_rr_list_deep_free(rrset_clone);
+ ldns_buffer_free(rawsig_buf);
+ ldns_buffer_free(verify_buf);
+
+ /* check timestamp last, apart from time its OK */
+ if(result == LDNS_STATUS_OK)
+ result = ldns_rrsig_check_timestamps(rrsig, check_time);
+
+ return result;
+}
+
+ldns_status
+ldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key)
+{
+ return ldns_verify_rrsig_time(rrset, rrsig, key, ldns_time(NULL));
+}
+
+
+ldns_status
+ldns_verify_rrsig_evp(ldns_buffer *sig,
+ ldns_buffer *rrset,
+ EVP_PKEY *key,
+ const EVP_MD *digest_type)
+{
+ return ldns_verify_rrsig_evp_raw(
+ (unsigned char*)ldns_buffer_begin(sig),
+ ldns_buffer_position(sig),
+ rrset,
+ key,
+ digest_type);
+}
+
+ldns_status
+ldns_verify_rrsig_evp_raw(unsigned char *sig, size_t siglen,
+ ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type)
+{
+ EVP_MD_CTX ctx;
+ int res;
+
+ EVP_MD_CTX_init(&ctx);
+
+ EVP_VerifyInit(&ctx, digest_type);
+ EVP_VerifyUpdate(&ctx,
+ ldns_buffer_begin(rrset),
+ ldns_buffer_position(rrset));
+ res = EVP_VerifyFinal(&ctx, sig, (unsigned int) siglen, key);
+
+ EVP_MD_CTX_cleanup(&ctx);
+
+ if (res == 1) {
+ return LDNS_STATUS_OK;
+ } else if (res == 0) {
+ return LDNS_STATUS_CRYPTO_BOGUS;
+ }
+ /* TODO how to communicate internal SSL error?
+ let caller use ssl's get_error() */
+ return LDNS_STATUS_SSL_ERR;
+}
+
+ldns_status
+ldns_verify_rrsig_dsa(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
+{
+ return ldns_verify_rrsig_dsa_raw(
+ (unsigned char*) ldns_buffer_begin(sig),
+ ldns_buffer_position(sig),
+ rrset,
+ (unsigned char*) ldns_buffer_begin(key),
+ ldns_buffer_position(key));
+}
+
+ldns_status
+ldns_verify_rrsig_rsasha1(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
+{
+ return ldns_verify_rrsig_rsasha1_raw(
+ (unsigned char*)ldns_buffer_begin(sig),
+ ldns_buffer_position(sig),
+ rrset,
+ (unsigned char*) ldns_buffer_begin(key),
+ ldns_buffer_position(key));
+}
+
+ldns_status
+ldns_verify_rrsig_rsamd5(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
+{
+ return ldns_verify_rrsig_rsamd5_raw(
+ (unsigned char*)ldns_buffer_begin(sig),
+ ldns_buffer_position(sig),
+ rrset,
+ (unsigned char*) ldns_buffer_begin(key),
+ ldns_buffer_position(key));
+}
+
+ldns_status
+ldns_verify_rrsig_dsa_raw(unsigned char* sig, size_t siglen,
+ ldns_buffer* rrset, unsigned char* key, size_t keylen)
+{
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ evp_key = EVP_PKEY_new();
+ if (EVP_PKEY_assign_DSA(evp_key, ldns_key_buf2dsa_raw(key, keylen))) {
+ result = ldns_verify_rrsig_evp_raw(sig,
+ siglen,
+ rrset,
+ evp_key,
+ EVP_dss1());
+ } else {
+ result = LDNS_STATUS_SSL_ERR;
+ }
+ EVP_PKEY_free(evp_key);
+ return result;
+
+}
+
+ldns_status
+ldns_verify_rrsig_rsasha1_raw(unsigned char* sig, size_t siglen,
+ ldns_buffer* rrset, unsigned char* key, size_t keylen)
+{
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ evp_key = EVP_PKEY_new();
+ if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
+ result = ldns_verify_rrsig_evp_raw(sig,
+ siglen,
+ rrset,
+ evp_key,
+ EVP_sha1());
+ } else {
+ result = LDNS_STATUS_SSL_ERR;
+ }
+ EVP_PKEY_free(evp_key);
+
+ return result;
+}
+
+ldns_status
+ldns_verify_rrsig_rsasha256_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen)
+{
+#ifdef USE_SHA2
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ evp_key = EVP_PKEY_new();
+ if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
+ result = ldns_verify_rrsig_evp_raw(sig,
+ siglen,
+ rrset,
+ evp_key,
+ EVP_sha256());
+ } else {
+ result = LDNS_STATUS_SSL_ERR;
+ }
+ EVP_PKEY_free(evp_key);
+
+ return result;
+#else
+ /* touch these to prevent compiler warnings */
+ (void) sig;
+ (void) siglen;
+ (void) rrset;
+ (void) key;
+ (void) keylen;
+ return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
+#endif
+}
+
+ldns_status
+ldns_verify_rrsig_rsasha512_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen)
+{
+#ifdef USE_SHA2
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ evp_key = EVP_PKEY_new();
+ if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
+ result = ldns_verify_rrsig_evp_raw(sig,
+ siglen,
+ rrset,
+ evp_key,
+ EVP_sha512());
+ } else {
+ result = LDNS_STATUS_SSL_ERR;
+ }
+ EVP_PKEY_free(evp_key);
+
+ return result;
+#else
+ /* touch these to prevent compiler warnings */
+ (void) sig;
+ (void) siglen;
+ (void) rrset;
+ (void) key;
+ (void) keylen;
+ return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
+#endif
+}
+
+
+ldns_status
+ldns_verify_rrsig_rsamd5_raw(unsigned char* sig,
+ size_t siglen,
+ ldns_buffer* rrset,
+ unsigned char* key,
+ size_t keylen)
+{
+ EVP_PKEY *evp_key;
+ ldns_status result;
+
+ evp_key = EVP_PKEY_new();
+ if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
+ result = ldns_verify_rrsig_evp_raw(sig,
+ siglen,
+ rrset,
+ evp_key,
+ EVP_md5());
+ } else {
+ result = LDNS_STATUS_SSL_ERR;
+ }
+ EVP_PKEY_free(evp_key);
+
+ return result;
+}
+
+#endif
diff --git a/3rdParty/Ldns/src/src/dnssec_zone.c b/3rdParty/Ldns/src/src/dnssec_zone.c
new file mode 100644
index 0000000..89bdf8d
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dnssec_zone.c
@@ -0,0 +1,921 @@
+/*
+ * special zone file structures and functions for better dnssec handling
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+ldns_dnssec_rrs *
+ldns_dnssec_rrs_new()
+{
+ ldns_dnssec_rrs *new_rrs;
+ new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
+ if(!new_rrs) return NULL;
+ new_rrs->rr = NULL;
+ new_rrs->next = NULL;
+ return new_rrs;
+}
+
+INLINE void
+ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
+{
+ ldns_dnssec_rrs *next;
+ while (rrs) {
+ next = rrs->next;
+ if (deep) {
+ ldns_rr_free(rrs->rr);
+ }
+ LDNS_FREE(rrs);
+ rrs = next;
+ }
+}
+
+void
+ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
+{
+ ldns_dnssec_rrs_free_internal(rrs, 0);
+}
+
+void
+ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
+{
+ ldns_dnssec_rrs_free_internal(rrs, 1);
+}
+
+ldns_status
+ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
+{
+ int cmp;
+ ldns_dnssec_rrs *new_rrs;
+ if (!rrs || !rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* this could be done more efficiently; name and type should already
+ be equal */
+ cmp = ldns_rr_compare(rrs->rr,
+ rr);
+ /* should we error on equal? */
+ if (cmp <= 0) {
+ if (rrs->next) {
+ return ldns_dnssec_rrs_add_rr(rrs->next, rr);
+ } else {
+ new_rrs = ldns_dnssec_rrs_new();
+ new_rrs->rr = rr;
+ rrs->next = new_rrs;
+ }
+ } else if (cmp > 0) {
+ /* put the current old rr in the new next, put the new
+ rr in the current container */
+ new_rrs = ldns_dnssec_rrs_new();
+ new_rrs->rr = rrs->rr;
+ new_rrs->next = rrs->next;
+ rrs->rr = rr;
+ rrs->next = new_rrs;
+ }
+ return LDNS_STATUS_OK;
+}
+
+void
+ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_rrs *rrs)
+{
+ if (!rrs) {
+ if ((fmt->flags & LDNS_COMMENT_LAYOUT))
+ fprintf(out, "; <void>");
+ } else {
+ if (rrs->rr) {
+ ldns_rr_print_fmt(out, fmt, rrs->rr);
+ }
+ if (rrs->next) {
+ ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
+ }
+ }
+}
+
+void
+ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs)
+{
+ ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
+}
+
+
+ldns_dnssec_rrsets *
+ldns_dnssec_rrsets_new()
+{
+ ldns_dnssec_rrsets *new_rrsets;
+ new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
+ if(!new_rrsets) return NULL;
+ new_rrsets->rrs = NULL;
+ new_rrsets->type = 0;
+ new_rrsets->signatures = NULL;
+ new_rrsets->next = NULL;
+ return new_rrsets;
+}
+
+INLINE void
+ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
+{
+ if (rrsets) {
+ if (rrsets->rrs) {
+ ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
+ }
+ if (rrsets->next) {
+ ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
+ }
+ if (rrsets->signatures) {
+ ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
+ }
+ LDNS_FREE(rrsets);
+ }
+}
+
+void
+ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
+{
+ ldns_dnssec_rrsets_free_internal(rrsets, 0);
+}
+
+void
+ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
+{
+ ldns_dnssec_rrsets_free_internal(rrsets, 1);
+}
+
+ldns_rr_type
+ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
+{
+ if (rrsets) {
+ return rrsets->type;
+ } else {
+ return 0;
+ }
+}
+
+ldns_status
+ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
+ ldns_rr_type type)
+{
+ if (rrsets) {
+ rrsets->type = type;
+ return LDNS_STATUS_OK;
+ }
+ return LDNS_STATUS_ERR;
+}
+
+ldns_dnssec_rrsets *
+ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
+{
+ ldns_dnssec_rrsets *new_rrsets;
+ ldns_rr_type rr_type;
+ bool rrsig;
+
+ new_rrsets = ldns_dnssec_rrsets_new();
+ rr_type = ldns_rr_get_type(rr);
+ if (rr_type == LDNS_RR_TYPE_RRSIG) {
+ rrsig = true;
+ rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
+ } else {
+ rrsig = false;
+ }
+ if (!rrsig) {
+ new_rrsets->rrs = ldns_dnssec_rrs_new();
+ new_rrsets->rrs->rr = rr;
+ } else {
+ new_rrsets->signatures = ldns_dnssec_rrs_new();
+ new_rrsets->signatures->rr = rr;
+ }
+ new_rrsets->type = rr_type;
+ return new_rrsets;
+}
+
+ldns_status
+ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
+{
+ ldns_dnssec_rrsets *new_rrsets;
+ ldns_rr_type rr_type;
+ bool rrsig = false;
+ ldns_status result = LDNS_STATUS_OK;
+
+ if (!rrsets || !rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ rr_type = ldns_rr_get_type(rr);
+
+ if (rr_type == LDNS_RR_TYPE_RRSIG) {
+ rrsig = true;
+ rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
+ }
+
+ if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
+ if (!rrsig) {
+ rrsets->rrs = ldns_dnssec_rrs_new();
+ rrsets->rrs->rr = rr;
+ rrsets->type = rr_type;
+ } else {
+ rrsets->signatures = ldns_dnssec_rrs_new();
+ rrsets->signatures->rr = rr;
+ rrsets->type = rr_type;
+ }
+ return LDNS_STATUS_OK;
+ }
+
+ if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
+ if (rrsets->next) {
+ result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
+ } else {
+ new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
+ rrsets->next = new_rrsets;
+ }
+ } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
+ /* move the current one into the new next,
+ replace field of current with data from new rr */
+ new_rrsets = ldns_dnssec_rrsets_new();
+ new_rrsets->rrs = rrsets->rrs;
+ new_rrsets->type = rrsets->type;
+ new_rrsets->signatures = rrsets->signatures;
+ new_rrsets->next = rrsets->next;
+ if (!rrsig) {
+ rrsets->rrs = ldns_dnssec_rrs_new();
+ rrsets->rrs->rr = rr;
+ rrsets->signatures = NULL;
+ } else {
+ rrsets->rrs = NULL;
+ rrsets->signatures = ldns_dnssec_rrs_new();
+ rrsets->signatures->rr = rr;
+ }
+ rrsets->type = rr_type;
+ rrsets->next = new_rrsets;
+ } else {
+ /* equal, add to current rrsets */
+ if (rrsig) {
+ if (rrsets->signatures) {
+ result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
+ } else {
+ rrsets->signatures = ldns_dnssec_rrs_new();
+ rrsets->signatures->rr = rr;
+ }
+ } else {
+ if (rrsets->rrs) {
+ result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
+ } else {
+ rrsets->rrs = ldns_dnssec_rrs_new();
+ rrsets->rrs->rr = rr;
+ }
+ }
+ }
+
+ return result;
+}
+
+void
+ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_rrsets *rrsets,
+ bool follow,
+ bool show_soa)
+{
+ if (!rrsets) {
+ if ((fmt->flags & LDNS_COMMENT_LAYOUT))
+ fprintf(out, "; <void>\n");
+ } else {
+ if (rrsets->rrs &&
+ (show_soa ||
+ ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
+ )
+ ) {
+ ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
+ if (rrsets->signatures) {
+ ldns_dnssec_rrs_print_fmt(out, fmt,
+ rrsets->signatures);
+ }
+ }
+ if (follow && rrsets->next) {
+ ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
+ rrsets->next, follow, show_soa);
+ }
+ }
+}
+
+void
+ldns_dnssec_rrsets_print_soa(FILE *out,
+ ldns_dnssec_rrsets *rrsets,
+ bool follow,
+ bool show_soa)
+{
+ ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default,
+ rrsets, follow, show_soa);
+}
+
+
+void
+ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_rrsets *rrsets,
+ bool follow)
+{
+ ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
+}
+
+void
+ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
+{
+ ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
+ rrsets, follow);
+}
+
+ldns_dnssec_name *
+ldns_dnssec_name_new()
+{
+ ldns_dnssec_name *new_name;
+
+ new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
+ if (!new_name) {
+ return NULL;
+ }
+ /*
+ * not needed anymore because CALLOC initalizes everything to zero.
+
+ new_name->name = NULL;
+ new_name->rrsets = NULL;
+ new_name->name_alloced = false;
+ new_name->nsec = NULL;
+ new_name->nsec_signatures = NULL;
+
+ new_name->is_glue = false;
+ new_name->hashed_name = NULL;
+
+ */
+ return new_name;
+}
+
+ldns_dnssec_name *
+ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
+{
+ ldns_dnssec_name *new_name = ldns_dnssec_name_new();
+
+ new_name->name = ldns_rr_owner(rr);
+ if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
+ ldns_dnssec_name_free(new_name);
+ return NULL;
+ }
+
+ return new_name;
+}
+
+INLINE void
+ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
+ int deep)
+{
+ if (name) {
+ if (name->name_alloced) {
+ ldns_rdf_deep_free(name->name);
+ }
+ if (name->rrsets) {
+ ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
+ }
+ if (name->nsec && deep) {
+ ldns_rr_free(name->nsec);
+ }
+ if (name->nsec_signatures) {
+ ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
+ }
+ if (name->hashed_name) {
+ if (deep) {
+ ldns_rdf_deep_free(name->hashed_name);
+ }
+ }
+ LDNS_FREE(name);
+ }
+}
+
+void
+ldns_dnssec_name_free(ldns_dnssec_name *name)
+{
+ ldns_dnssec_name_free_internal(name, 0);
+}
+
+void
+ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
+{
+ ldns_dnssec_name_free_internal(name, 1);
+}
+
+ldns_rdf *
+ldns_dnssec_name_name(ldns_dnssec_name *name)
+{
+ if (name) {
+ return name->name;
+ }
+ return NULL;
+}
+
+bool
+ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
+{
+ if (name) {
+ return name->is_glue;
+ }
+ return false;
+}
+
+void
+ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
+ ldns_rdf *dname)
+{
+ if (rrset && dname) {
+ rrset->name = dname;
+ }
+}
+
+ldns_rr *
+ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
+{
+ if (rrset) {
+ return rrset->nsec;
+ }
+ return NULL;
+}
+
+void
+ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
+{
+ if (rrset && nsec) {
+ rrset->nsec = nsec;
+ }
+}
+
+int
+ldns_dnssec_name_cmp(const void *a, const void *b)
+{
+ ldns_dnssec_name *na = (ldns_dnssec_name *) a;
+ ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
+
+ if (na && nb) {
+ return ldns_dname_compare(ldns_dnssec_name_name(na),
+ ldns_dnssec_name_name(nb));
+ } else if (na) {
+ return 1;
+ } else if (nb) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+ldns_status
+ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
+ ldns_rr *rr)
+{
+ ldns_status result = LDNS_STATUS_OK;
+ ldns_rdf *name_name;
+ bool hashed_name = false;
+ ldns_rr_type rr_type;
+ ldns_rr_type typecovered = 0;
+
+ /* special handling for NSEC3 and NSECX covering RRSIGS */
+
+ if (!name || !rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ rr_type = ldns_rr_get_type(rr);
+
+ if (rr_type == LDNS_RR_TYPE_RRSIG) {
+ typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
+ }
+
+#ifdef HAVE_SSL
+ if (rr_type == LDNS_RR_TYPE_NSEC3 ||
+ typecovered == LDNS_RR_TYPE_NSEC3) {
+ name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
+ ldns_dnssec_name_name(name));
+ hashed_name = true;
+ } else {
+ name_name = ldns_dnssec_name_name(name);
+ }
+#else
+ name_name = ldns_dnssec_name_name(name);
+#endif /* HAVE_SSL */
+
+ if (rr_type == LDNS_RR_TYPE_NSEC ||
+ rr_type == LDNS_RR_TYPE_NSEC3) {
+ /* XX check if is already set (and error?) */
+ name->nsec = rr;
+ } else if (typecovered == LDNS_RR_TYPE_NSEC ||
+ typecovered == LDNS_RR_TYPE_NSEC3) {
+ if (name->nsec_signatures) {
+ result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
+ } else {
+ name->nsec_signatures = ldns_dnssec_rrs_new();
+ name->nsec_signatures->rr = rr;
+ }
+ } else {
+ /* it's a 'normal' RR, add it to the right rrset */
+ if (name->rrsets) {
+ result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
+ } else {
+ name->rrsets = ldns_dnssec_rrsets_new();
+ result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
+ }
+ }
+
+ if (hashed_name) {
+ ldns_rdf_deep_free(name_name);
+ }
+
+ return result;
+}
+
+ldns_dnssec_rrsets *
+ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
+ ldns_rr_type type) {
+ ldns_dnssec_rrsets *result;
+
+ result = name->rrsets;
+ while (result) {
+ if (result->type == type) {
+ return result;
+ } else {
+ result = result->next;
+ }
+ }
+ return NULL;
+}
+
+ldns_dnssec_rrsets *
+ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
+ ldns_rdf *dname,
+ ldns_rr_type type)
+{
+ ldns_rbnode_t *node;
+
+ if (!zone || !dname) {
+ return NULL;
+ }
+
+ node = ldns_rbtree_search(zone->names, dname);
+ if (node) {
+ return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
+ type);
+ } else {
+ return NULL;
+ }
+}
+
+void
+ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_name *name,
+ bool show_soa)
+{
+ if (name) {
+ if(name->rrsets) {
+ ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
+ name->rrsets, true, show_soa);
+ } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
+ fprintf(out, ";; Empty nonterminal: ");
+ ldns_rdf_print(out, name->name);
+ fprintf(out, "\n");
+ }
+ if(name->nsec) {
+ ldns_rr_print_fmt(out, fmt, name->nsec);
+ }
+ if (name->nsec_signatures) {
+ ldns_dnssec_rrs_print_fmt(out, fmt,
+ name->nsec_signatures);
+ }
+ } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
+ fprintf(out, "; <void>\n");
+ }
+}
+
+void
+ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
+{
+ ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default,
+ name, show_soa);
+}
+
+void
+ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_name *name)
+{
+ ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
+}
+
+void
+ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
+{
+ ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
+}
+
+
+ldns_dnssec_zone *
+ldns_dnssec_zone_new()
+{
+ ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
+ if(!zone) return NULL;
+ zone->soa = NULL;
+ zone->names = NULL;
+
+ return zone;
+}
+
+void
+ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
+ (void) arg;
+ ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
+ free(node);
+}
+
+void
+ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
+ (void) arg;
+ ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
+ free(node);
+}
+
+void
+ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
+{
+ if (zone) {
+ if (zone->names) {
+ /* destroy all name structures within the tree */
+ ldns_traverse_postorder(zone->names,
+ ldns_dnssec_name_node_free,
+ NULL);
+ free(zone->names);
+ }
+ LDNS_FREE(zone);
+ }
+}
+
+void
+ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
+{
+ if (zone) {
+ if (zone->names) {
+ /* destroy all name structures within the tree */
+ ldns_traverse_postorder(zone->names,
+ ldns_dnssec_name_node_deep_free,
+ NULL);
+ free(zone->names);
+ }
+ LDNS_FREE(zone);
+ }
+}
+
+/* use for dname comparison in tree */
+int
+ldns_dname_compare_v(const void *a, const void *b) {
+ return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
+}
+
+#ifdef HAVE_SSL
+ldns_rbnode_t *
+ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
+ ldns_rr *rr) {
+ ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
+ ldns_dnssec_name *current_name;
+ ldns_rdf *hashed_name;
+
+ hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
+
+ while (current_node != LDNS_RBTREE_NULL) {
+ current_name = (ldns_dnssec_name *) current_node->data;
+ if (!current_name->hashed_name) {
+ current_name->hashed_name =
+ ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
+ }
+ if (ldns_dname_compare(hashed_name,
+ current_name->hashed_name)
+ == 0) {
+ ldns_rdf_deep_free(hashed_name);
+ return current_node;
+ }
+ current_node = ldns_rbtree_next(current_node);
+ }
+ ldns_rdf_deep_free(hashed_name);
+ return NULL;
+}
+
+ldns_status
+ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
+{
+ ldns_status result = LDNS_STATUS_OK;
+ ldns_dnssec_name *cur_name;
+ ldns_rbnode_t *cur_node;
+ ldns_rr_type type_covered = 0;
+
+ if (!zone || !rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (!zone->names) {
+ zone->names = ldns_rbtree_create(ldns_dname_compare_v);
+ if(!zone->names) return LDNS_STATUS_MEM_ERR;
+ }
+
+ /* we need the original of the hashed name if this is
+ an NSEC3, or an RRSIG that covers an NSEC3 */
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
+ type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
+ }
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
+ type_covered == LDNS_RR_TYPE_NSEC3) {
+ cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
+ rr);
+ if (!cur_node) {
+ return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
+ }
+ } else {
+ cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
+ }
+
+ if (!cur_node) {
+ /* add */
+ cur_name = ldns_dnssec_name_new_frm_rr(rr);
+ if(!cur_name) return LDNS_STATUS_MEM_ERR;
+ cur_node = LDNS_MALLOC(ldns_rbnode_t);
+ if(!cur_node) {
+ ldns_dnssec_name_free(cur_name);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ cur_node->key = ldns_rr_owner(rr);
+ cur_node->data = cur_name;
+ (void)ldns_rbtree_insert(zone->names, cur_node);
+ } else {
+ cur_name = (ldns_dnssec_name *) cur_node->data;
+ result = ldns_dnssec_name_add_rr(cur_name, rr);
+ }
+
+ if (result != LDNS_STATUS_OK) {
+ fprintf(stderr, "error adding rr: ");
+ ldns_rr_print(stderr, rr);
+ }
+
+ /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
+ zone->soa = cur_name;
+ }
+
+ return result;
+}
+#endif /* HAVE_SSL */
+
+void
+ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_rbtree_t *tree,
+ bool print_soa)
+{
+ ldns_rbnode_t *node;
+ ldns_dnssec_name *name;
+
+ node = ldns_rbtree_first(tree);
+ while (node != LDNS_RBTREE_NULL) {
+ name = (ldns_dnssec_name *) node->data;
+ ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
+ if ((fmt->flags & LDNS_COMMENT_LAYOUT))
+ fprintf(out, ";\n");
+ node = ldns_rbtree_next(node);
+ }
+}
+
+void
+ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
+{
+ ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
+ tree, print_soa);
+}
+
+void
+ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
+ ldns_dnssec_zone *zone)
+{
+ if (zone) {
+ if (zone->soa) {
+ if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
+ fprintf(out, ";; Zone: ");
+ ldns_rdf_print(out, ldns_dnssec_name_name(
+ zone->soa));
+ fprintf(out, "\n;\n");
+ }
+ ldns_dnssec_rrsets_print_fmt(out, fmt,
+ ldns_dnssec_name_find_rrset(
+ zone->soa,
+ LDNS_RR_TYPE_SOA),
+ false);
+ if ((fmt->flags & LDNS_COMMENT_LAYOUT))
+ fprintf(out, ";\n");
+ }
+
+ if (zone->names) {
+ ldns_dnssec_zone_names_print_fmt(out, fmt,
+ zone->names, false);
+ }
+ }
+}
+
+void
+ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
+{
+ ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
+}
+
+ldns_status
+ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
+{
+ ldns_dnssec_name *new_name;
+ ldns_rdf *cur_name;
+ ldns_rdf *next_name;
+ ldns_rbnode_t *cur_node, *next_node, *new_node;
+
+ /* for the detection */
+ uint16_t i, cur_label_count, next_label_count;
+ uint16_t soa_label_count = 0;
+ ldns_rdf *l1, *l2;
+ int lpos;
+
+ if (!zone) {
+ return LDNS_STATUS_ERR;
+ }
+ if (zone->soa && zone->soa->name) {
+ soa_label_count = ldns_dname_label_count(zone->soa->name);
+ }
+
+ cur_node = ldns_rbtree_first(zone->names);
+ while (cur_node != LDNS_RBTREE_NULL) {
+ next_node = ldns_rbtree_next(cur_node);
+
+ /* skip glue */
+ while (next_node != LDNS_RBTREE_NULL &&
+ next_node->data &&
+ ((ldns_dnssec_name *)next_node->data)->is_glue
+ ) {
+ next_node = ldns_rbtree_next(next_node);
+ }
+
+ if (next_node == LDNS_RBTREE_NULL) {
+ next_node = ldns_rbtree_first(zone->names);
+ }
+
+ cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
+ next_name = ((ldns_dnssec_name *)next_node->data)->name;
+ cur_label_count = ldns_dname_label_count(cur_name);
+ next_label_count = ldns_dname_label_count(next_name);
+
+ /* Since the names are in canonical order, we can
+ * recognize empty non-terminals by their labels;
+ * every label after the first one on the next owner
+ * name is a non-terminal if it either does not exist
+ * in the current name or is different from the same
+ * label in the current name (counting from the end)
+ */
+ for (i = 1; i < next_label_count - soa_label_count; i++) {
+ lpos = (int)cur_label_count - (int)next_label_count + (int)i;
+ if (lpos >= 0) {
+ l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
+ } else {
+ l1 = NULL;
+ }
+ l2 = ldns_dname_clone_from(next_name, i);
+
+ if (!l1 || ldns_dname_compare(l1, l2) != 0) {
+ /* We have an empty nonterminal, add it to the
+ * tree
+ */
+ new_name = ldns_dnssec_name_new();
+ if (!new_name) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ new_name->name = ldns_dname_clone_from(next_name,
+ i);
+ if (!new_name->name) {
+ ldns_dnssec_name_free(new_name);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ new_name->name_alloced = true;
+ new_node = LDNS_MALLOC(ldns_rbnode_t);
+ if (!new_node) {
+ ldns_dnssec_name_free(new_name);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ new_node->key = new_name->name;
+ new_node->data = new_name;
+ (void)ldns_rbtree_insert(zone->names, new_node);
+ }
+ ldns_rdf_deep_free(l1);
+ ldns_rdf_deep_free(l2);
+ }
+
+ /* we might have inserted a new node after
+ * the current one so we can't just use next()
+ */
+ if (next_node != ldns_rbtree_first(zone->names)) {
+ cur_node = next_node;
+ } else {
+ cur_node = LDNS_RBTREE_NULL;
+ }
+ }
+ return LDNS_STATUS_OK;
+}
diff --git a/3rdParty/Ldns/src/src/error.c b/3rdParty/Ldns/src/src/error.c
new file mode 100644
index 0000000..a619502
--- /dev/null
+++ b/3rdParty/Ldns/src/src/error.c
@@ -0,0 +1,107 @@
+/*
+ * a error2str function to make sense of all the
+ * error codes we have laying ardoun
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+ldns_lookup_table ldns_error_str[] = {
+ { LDNS_STATUS_OK, "All OK" },
+ { LDNS_STATUS_EMPTY_LABEL, "Empty label" },
+ { LDNS_STATUS_LABEL_OVERFLOW, "Label length overflow" },
+ { LDNS_STATUS_DOMAINNAME_OVERFLOW, "Domainname length overflow" },
+ { LDNS_STATUS_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" },
+ { LDNS_STATUS_DDD_OVERFLOW, "\\DDD sequence overflow (>255)" },
+ { LDNS_STATUS_PACKET_OVERFLOW, "Packet size overflow" },
+ { LDNS_STATUS_INVALID_POINTER, "Invalid compression pointer" },
+ { LDNS_STATUS_MEM_ERR, "General memory error" },
+ { LDNS_STATUS_INTERNAL_ERR, "Internal error, this should not happen" },
+ { LDNS_STATUS_SSL_ERR, "Error in SSL library" },
+ { LDNS_STATUS_ERR, "General LDNS error" },
+ { LDNS_STATUS_INVALID_INT, "Conversion error, integer expected" },
+ { LDNS_STATUS_INVALID_IP4, "Conversion error, ip4 addr expected" },
+ { LDNS_STATUS_INVALID_IP6, "Conversion error, ip6 addr expected" },
+ { LDNS_STATUS_INVALID_STR, "Conversion error, string expected" },
+ { LDNS_STATUS_INVALID_B64, "Conversion error, b64 encoding expected" },
+ { LDNS_STATUS_INVALID_HEX, "Conversion error, hex encoding expected" },
+ { LDNS_STATUS_INVALID_TIME, "Conversion error, time encoding expected" },
+ { LDNS_STATUS_NETWORK_ERR, "Could not send or receive, because of network error" },
+ { LDNS_STATUS_ADDRESS_ERR, "Could not start AXFR, because of address error" },
+ { LDNS_STATUS_FILE_ERR, "Could not open the files" },
+ { LDNS_STATUS_UNKNOWN_INET, "Uknown address family" },
+ { LDNS_STATUS_NOT_IMPL, "This function is not implemented (yet), please notify the developers - or not..." },
+ { LDNS_STATUS_NULL, "Supplied value pointer null" },
+ { LDNS_STATUS_CRYPTO_UNKNOWN_ALGO, "Unknown cryptographic algorithm" },
+ { LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL, "Cryptographic algorithm not implemented" },
+ { LDNS_STATUS_CRYPTO_NO_RRSIG, "No DNSSEC signature(s)" },
+ { LDNS_STATUS_CRYPTO_NO_DNSKEY, "No DNSSEC public key(s)" },
+ { LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR, "The signature does not cover this RRset" },
+ { LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY, "No signatures found for trusted DNSSEC public key(s)" },
+ { LDNS_STATUS_CRYPTO_NO_DS, "No DS record(s)" },
+ { LDNS_STATUS_CRYPTO_NO_TRUSTED_DS, "Could not validate DS record(s)" },
+ { LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY, "No keys with the keytag and algorithm from the RRSIG found" },
+ { LDNS_STATUS_CRYPTO_VALIDATED, "Valid DNSSEC signature" },
+ { LDNS_STATUS_CRYPTO_BOGUS, "Bogus DNSSEC signature" },
+ { LDNS_STATUS_CRYPTO_SIG_EXPIRED, "DNSSEC signature has expired" },
+ { LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED, "DNSSEC signature not incepted yet" },
+ { LDNS_STATUS_CRYPTO_TSIG_BOGUS, "Bogus TSIG signature" },
+ { LDNS_STATUS_CRYPTO_TSIG_ERR, "Could not create TSIG signature" },
+ { LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION, "DNSSEC signature has expiration date earlier than inception date" },
+ { LDNS_STATUS_ENGINE_KEY_NOT_LOADED, "Unable to load private key from engine" },
+ { LDNS_STATUS_NSEC3_ERR, "Error in NSEC3 denial of existence proof" },
+ { LDNS_STATUS_RES_NO_NS, "No (valid) nameservers defined in the resolver" },
+ { LDNS_STATUS_RES_QUERY, "No correct query given to resolver" },
+ { LDNS_STATUS_WIRE_INCOMPLETE_HEADER, "header section incomplete" },
+ { LDNS_STATUS_WIRE_INCOMPLETE_QUESTION, "question section incomplete" },
+ { LDNS_STATUS_WIRE_INCOMPLETE_ANSWER, "answer section incomplete" },
+ { LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY, "authority section incomplete" },
+ { LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL, "additional section incomplete" },
+ { LDNS_STATUS_NO_DATA, "No data" },
+ { LDNS_STATUS_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" },
+ { LDNS_STATUS_SYNTAX_TYPE_ERR, "Syntax error, could not parse the RR's type" },
+ { LDNS_STATUS_SYNTAX_CLASS_ERR, "Syntax error, could not parse the RR's class" },
+ { LDNS_STATUS_SYNTAX_TTL_ERR, "Syntax error, could not parse the RR's TTL" },
+ { LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL, "Syntax error, $INCLUDE not implemented" },
+ { LDNS_STATUS_SYNTAX_RDATA_ERR, "Syntax error, could not parse the RR's rdata" },
+ { LDNS_STATUS_SYNTAX_DNAME_ERR, "Syntax error, could not parse the RR's dname(s)" },
+ { LDNS_STATUS_SYNTAX_VERSION_ERR, "Syntax error, version mismatch" },
+ { LDNS_STATUS_SYNTAX_ALG_ERR, "Syntax error, algorithm unknown or non parseable" },
+ { LDNS_STATUS_SYNTAX_KEYWORD_ERR, "Syntax error, unknown keyword in input" },
+ { LDNS_STATUS_SYNTAX_ERR, "Syntax error, could not parse the RR" },
+ { LDNS_STATUS_SYNTAX_EMPTY, "Empty line was returned" },
+ { LDNS_STATUS_SYNTAX_TTL, "$TTL directive was seen in the zone" },
+ { LDNS_STATUS_SYNTAX_ORIGIN, "$ORIGIN directive was seen in the zone" },
+ { LDNS_STATUS_SYNTAX_INCLUDE, "$INCLUDE directive was seen in the zone" },
+ { LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW, "Iterations count for NSEC3 record higher than maximum" },
+ { LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR, "Syntax error, value expected" },
+ { LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer value too large" },
+ { LDNS_STATUS_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" },
+ { LDNS_STATUS_SOCKET_ERROR, "Error creating socket" },
+ { LDNS_STATUS_DNSSEC_EXISTENCE_DENIED, "Existence denied by NSEC" },
+ { LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED, "RR not covered by the given NSEC RRs" },
+ { LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED, "wildcard not covered by the given NSEC RRs" },
+ { LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND, "original of NSEC3 hashed name could not be found" },
+ { LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG, "The RRSIG has to few rdata fields" },
+ { LDNS_STATUS_MISSING_RDATA_FIELDS_KEY, "The DNSKEY has to few rdata fields" },
+ { 0, NULL }
+};
+
+const char *
+ldns_get_errorstr_by_id(ldns_status err)
+{
+ ldns_lookup_table *lt;
+
+ lt = ldns_lookup_by_id(ldns_error_str, err);
+
+ if (lt) {
+ return lt->name;
+ }
+ return NULL;
+}
diff --git a/3rdParty/Ldns/src/src/higher.c b/3rdParty/Ldns/src/src/higher.c
new file mode 100644
index 0000000..c9eb173
--- /dev/null
+++ b/3rdParty/Ldns/src/src/higher.c
@@ -0,0 +1,359 @@
+/*
+ * higher.c
+ *
+ * Specify some higher level functions that would
+ * be usefull to would be developers
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/sha.h>
+#endif /* HAVE_SSL */
+
+ldns_rr_list *
+ldns_get_rr_list_addr_by_name(ldns_resolver *res, ldns_rdf *name, ldns_rr_class c,
+ uint16_t flags)
+{
+ ldns_pkt *pkt;
+ ldns_rr_list *aaaa;
+ ldns_rr_list *a;
+ ldns_rr_list *result = NULL;
+ ldns_rr_list *hostsfilenames;
+ size_t i;
+ uint8_t ip6;
+
+ a = NULL;
+ aaaa = NULL;
+ result = NULL;
+
+ if (!res) {
+ return NULL;
+ }
+ if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+
+ ip6 = ldns_resolver_ip6(res); /* we use INET_ANY here, save
+ what was there */
+
+ ldns_resolver_set_ip6(res, LDNS_RESOLV_INETANY);
+
+ hostsfilenames = ldns_get_rr_list_hosts_frm_file(NULL);
+ for (i = 0; i < ldns_rr_list_rr_count(hostsfilenames); i++) {
+ if (ldns_rdf_compare(name,
+ ldns_rr_owner(ldns_rr_list_rr(hostsfilenames,
+ i))) == 0) {
+ if (!result) {
+ result = ldns_rr_list_new();
+ }
+ ldns_rr_list_push_rr(result,
+ ldns_rr_clone(ldns_rr_list_rr(hostsfilenames, i)));
+ }
+ }
+ ldns_rr_list_deep_free(hostsfilenames);
+
+ if (result) {
+ return result;
+ }
+
+ /* add the RD flags, because we want an answer */
+ pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_AAAA, c, flags | LDNS_RD);
+ if (pkt) {
+ /* extract the data we need */
+ aaaa = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_AAAA,
+ LDNS_SECTION_ANSWER);
+ ldns_pkt_free(pkt);
+ }
+
+ pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_A, c, flags | LDNS_RD);
+ if (pkt) {
+ /* extract the data we need */
+ a = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_A, LDNS_SECTION_ANSWER);
+ ldns_pkt_free(pkt);
+ }
+ ldns_resolver_set_ip6(res, ip6);
+
+ if (aaaa && a) {
+ result = ldns_rr_list_cat_clone(aaaa, a);
+ ldns_rr_list_deep_free(aaaa);
+ ldns_rr_list_deep_free(a);
+ return result;
+ }
+
+ if (aaaa) {
+ result = ldns_rr_list_clone(aaaa);
+ }
+
+ if (a) {
+ result = ldns_rr_list_clone(a);
+ }
+
+ ldns_rr_list_deep_free(aaaa);
+ ldns_rr_list_deep_free(a);
+ return result;
+}
+
+ldns_rr_list *
+ldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class c,
+ uint16_t flags)
+{
+ ldns_pkt *pkt;
+ ldns_rr_list *names;
+ ldns_rdf *name;
+
+ names = NULL;
+
+ if (!res || !addr) {
+ return NULL;
+ }
+
+ if (ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_A &&
+ ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_AAAA) {
+ return NULL;
+ }
+
+ name = ldns_rdf_address_reverse(addr);
+
+ /* add the RD flags, because we want an answer */
+ pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_PTR, c, flags | LDNS_RD);
+ if (pkt) {
+ /* extract the data we need */
+ names = ldns_pkt_rr_list_by_type(pkt,
+ LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER);
+ }
+ return names;
+}
+
+/* read a line, put it in a buffer, parse the buffer */
+ldns_rr_list *
+ldns_get_rr_list_hosts_frm_fp(FILE *fp)
+{
+ return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL);
+}
+
+ldns_rr_list *
+ldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr)
+{
+ ssize_t i, j;
+ size_t cnt;
+ char *line;
+ char *word;
+ char *addr;
+ char *rr_str;
+ ldns_buffer *linebuf;
+ ldns_rr *rr;
+ ldns_rr_list *list;
+ ldns_rdf *tmp;
+ bool ip6;
+ ldns_status parse_result;
+
+ line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
+ word = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
+ addr = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
+ rr_str = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
+ ip6 = false;
+ list = ldns_rr_list_new();
+ rr = NULL;
+ if(!line || !word || !addr || !rr_str || !list) {
+ LDNS_FREE(line);
+ LDNS_FREE(word);
+ LDNS_FREE(addr);
+ LDNS_FREE(rr_str);
+ ldns_rr_list_free(list);
+ return NULL;
+ }
+
+ for(i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr);
+ i > 0; i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr)) {
+ /* # is comment */
+ if (line[0] == '#') {
+ continue;
+ }
+ /* put it in a buffer for further processing */
+ linebuf = LDNS_MALLOC(ldns_buffer);
+ if(!linebuf) {
+ LDNS_FREE(line);
+ LDNS_FREE(word);
+ LDNS_FREE(addr);
+ LDNS_FREE(rr_str);
+ ldns_rr_list_deep_free(list);
+ return NULL;
+ }
+
+ ldns_buffer_new_frm_data(linebuf, line, (size_t) i);
+ for(cnt = 0, j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN);
+ j > 0;
+ j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN), cnt++) {
+ if (cnt == 0) {
+ /* the address */
+ if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA,
+ word))) {
+ /* ip6 */
+ ldns_rdf_deep_free(tmp);
+ ip6 = true;
+ } else {
+ if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
+ word))) {
+ /* ip4 */
+ ldns_rdf_deep_free(tmp);
+ ip6 = false;
+ } else {
+ /* kaput */
+ break;
+ }
+ }
+ (void)strlcpy(addr, word, LDNS_MAX_LINELEN+1);
+ } else {
+ /* la al la la */
+ if (ip6) {
+ snprintf(rr_str, LDNS_MAX_LINELEN,
+ "%s IN AAAA %s", word, addr);
+ } else {
+ snprintf(rr_str, LDNS_MAX_LINELEN,
+ "%s IN A %s", word, addr);
+ }
+ parse_result = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL);
+ if (parse_result == LDNS_STATUS_OK && ldns_rr_owner(rr) && ldns_rr_rd_count(rr) > 0) {
+ ldns_rr_list_push_rr(list, ldns_rr_clone(rr));
+ }
+ ldns_rr_free(rr);
+ }
+ }
+ ldns_buffer_free(linebuf);
+ }
+ LDNS_FREE(line);
+ LDNS_FREE(word);
+ LDNS_FREE(addr);
+ LDNS_FREE(rr_str);
+ return list;
+}
+
+ldns_rr_list *
+ldns_get_rr_list_hosts_frm_file(char *filename)
+{
+ ldns_rr_list *names;
+ FILE *fp;
+
+ if (!filename) {
+ fp = fopen(LDNS_RESOLV_HOSTS, "r");
+
+ } else {
+ fp = fopen(filename, "r");
+ }
+ if (!fp) {
+ return NULL;
+ }
+
+ names = ldns_get_rr_list_hosts_frm_fp(fp);
+ fclose(fp);
+ return names;
+}
+
+uint16_t
+ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c,
+ ldns_rr_list **ret)
+{
+ ldns_rdf_type t;
+ uint16_t names_found;
+ ldns_resolver *r;
+ ldns_status s;
+
+ t = ldns_rdf_get_type(node);
+ names_found = 0;
+ r = res;
+
+ if (res == NULL) {
+ /* prepare a new resolver, using /etc/resolv.conf as a guide */
+ s = ldns_resolver_new_frm_file(&r, NULL);
+ if (s != LDNS_STATUS_OK) {
+ return 0;
+ }
+ }
+
+ if (t == LDNS_RDF_TYPE_DNAME) {
+ /* we're asked to query for a name */
+ *ret = ldns_get_rr_list_addr_by_name(r, node, c, 0);
+ names_found = ldns_rr_list_rr_count(*ret);
+ }
+
+ if (t == LDNS_RDF_TYPE_A || t == LDNS_RDF_TYPE_AAAA) {
+ /* an address */
+ *ret = ldns_get_rr_list_name_by_addr(r, node, c, 0);
+ names_found = ldns_rr_list_rr_count(*ret);
+ }
+
+ if (res == NULL) {
+ ldns_resolver_deep_free(r);
+ }
+
+ return names_found;
+}
+
+bool
+ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t)
+{
+ /* does the nsec cover the t given? */
+ /* copied from host2str.c line 465: ldns_rdf2buffer_str_nsec */
+ uint8_t window_block_nr;
+ uint8_t bitmap_length;
+ uint16_t type;
+ uint16_t pos = 0;
+ uint16_t bit_pos;
+ ldns_rdf *nsec_type_list = ldns_rr_rdf(nsec, 1);
+ uint8_t *data;
+
+ if (nsec_type_list == NULL) {
+ return false;
+ }
+ data = ldns_rdf_data(nsec_type_list);
+
+ while(pos < ldns_rdf_size(nsec_type_list)) {
+ window_block_nr = data[pos];
+ bitmap_length = data[pos + 1];
+ pos += 2;
+
+ for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
+ if (ldns_get_bit(&data[pos], bit_pos)) {
+ type = 256 * (uint16_t) window_block_nr + bit_pos;
+
+ if ((ldns_rr_type)type == t) {
+ /* we have a winner */
+ return true;
+ }
+ }
+ }
+ pos += (uint16_t) bitmap_length;
+ }
+ return false;
+}
+
+void
+ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...)
+{
+ int16_t rdf;
+ ldns_rdf *rd;
+ va_list va_rdf;
+ va_start(va_rdf, rdfnum);
+
+ for (rdf = (int16_t)rdfnum; rdf != -1; rdf = (int16_t)va_arg(va_rdf, int))
+ {
+ rd = ldns_rr_rdf(r, rdf);
+ if (!rd) {
+ continue;
+ } else {
+ ldns_rdf_print(fp, rd);
+ fprintf(fp, " "); /* not sure if we want to do this */
+ }
+ }
+ va_end(va_rdf);
+}
diff --git a/3rdParty/Ldns/src/src/host2str.c b/3rdParty/Ldns/src/src/host2str.c
new file mode 100644
index 0000000..eff1216
--- /dev/null
+++ b/3rdParty/Ldns/src/src/host2str.c
@@ -0,0 +1,2311 @@
+/*
+ * host2str.c
+ *
+ * conversion routines from the host format
+ * to the presentation format (strings)
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <limits.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <time.h>
+#include <sys/time.h>
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+
+/* lookup tables for standard DNS stuff */
+
+/* Taken from RFC 2535, section 7. */
+ldns_lookup_table ldns_algorithms[] = {
+ { LDNS_RSAMD5, "RSAMD5" },
+ { LDNS_DH, "DH" },
+ { LDNS_DSA, "DSA" },
+ { LDNS_ECC, "ECC" },
+ { LDNS_RSASHA1, "RSASHA1" },
+ { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" },
+ { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
+#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
+ { LDNS_INDIRECT, "INDIRECT" },
+ { LDNS_PRIVATEDNS, "PRIVATEDNS" },
+ { LDNS_PRIVATEOID, "PRIVATEOID" },
+ { 0, NULL }
+};
+
+/* Taken from RFC 4398 */
+ldns_lookup_table ldns_cert_algorithms[] = {
+ { LDNS_CERT_PKIX, "PKIX" },
+ { LDNS_CERT_SPKI, "SPKI" },
+ { LDNS_CERT_PGP, "PGP" },
+ { LDNS_CERT_IPKIX, "IPKIX" },
+ { LDNS_CERT_ISPKI, "ISPKI" },
+ { LDNS_CERT_IPGP, "IPGP" },
+ { LDNS_CERT_ACPKIX, "ACPKIX" },
+ { LDNS_CERT_IACPKIX, "IACPKIX" },
+ { LDNS_CERT_URI, "URI" },
+ { LDNS_CERT_OID, "OID" },
+ { 0, NULL }
+};
+
+/* classes */
+ldns_lookup_table ldns_rr_classes[] = {
+ { LDNS_RR_CLASS_IN, "IN" },
+ { LDNS_RR_CLASS_CH, "CH" },
+ { LDNS_RR_CLASS_HS, "HS" },
+ { LDNS_RR_CLASS_NONE, "NONE" },
+ { LDNS_RR_CLASS_ANY, "ANY" },
+ { 0, NULL }
+};
+
+/* if these are used elsewhere */
+ldns_lookup_table ldns_rcodes[] = {
+ { LDNS_RCODE_NOERROR, "NOERROR" },
+ { LDNS_RCODE_FORMERR, "FORMERR" },
+ { LDNS_RCODE_SERVFAIL, "SERVFAIL" },
+ { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" },
+ { LDNS_RCODE_NOTIMPL, "NOTIMPL" },
+ { LDNS_RCODE_REFUSED, "REFUSED" },
+ { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" },
+ { LDNS_RCODE_YXRRSET, "YXRRSET" },
+ { LDNS_RCODE_NXRRSET, "NXRRSET" },
+ { LDNS_RCODE_NOTAUTH, "NOTAUTH" },
+ { LDNS_RCODE_NOTZONE, "NOTZONE" },
+ { 0, NULL }
+};
+
+ldns_lookup_table ldns_opcodes[] = {
+ { LDNS_PACKET_QUERY, "QUERY" },
+ { LDNS_PACKET_IQUERY, "IQUERY" },
+ { LDNS_PACKET_STATUS, "STATUS" },
+ { LDNS_PACKET_NOTIFY, "NOTIFY" },
+ { LDNS_PACKET_UPDATE, "UPDATE" },
+ { 0, NULL }
+};
+
+const ldns_output_format ldns_output_format_nocomments_record = { 0, NULL };
+const ldns_output_format *ldns_output_format_nocomments
+ = &ldns_output_format_nocomments_record;
+const ldns_output_format ldns_output_format_onlykeyids_record = {
+ LDNS_COMMENT_KEY, NULL
+};
+const ldns_output_format *ldns_output_format_onlykeyids
+ = &ldns_output_format_onlykeyids_record;
+const ldns_output_format *ldns_output_format_default
+ = &ldns_output_format_onlykeyids_record;
+const ldns_output_format ldns_output_format_bubblebabble_record = {
+ LDNS_COMMENT_KEY | LDNS_COMMENT_BUBBLEBABBLE | LDNS_COMMENT_FLAGS, NULL
+};
+const ldns_output_format *ldns_output_format_bubblebabble
+ = &ldns_output_format_bubblebabble_record;
+
+ldns_status
+ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode)
+{
+ ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
+ if (lt && lt->name) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "OPCODE%u", opcode);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_pkt_rcode2buffer_str(ldns_buffer *output, ldns_pkt_rcode rcode)
+{
+ ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
+ if (lt && lt->name) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "RCODE%u", rcode);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_algorithm2buffer_str(ldns_buffer *output,
+ ldns_algorithm algorithm)
+{
+ ldns_lookup_table *lt = ldns_lookup_by_id(ldns_algorithms,
+ algorithm);
+ if (lt && lt->name) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "ALG%u", algorithm);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_cert_algorithm2buffer_str(ldns_buffer *output,
+ ldns_cert_algorithm cert_algorithm)
+{
+ ldns_lookup_table *lt = ldns_lookup_by_id(ldns_cert_algorithms,
+ cert_algorithm);
+ if (lt && lt->name) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "CERT_ALG%u",
+ cert_algorithm);
+ }
+ return ldns_buffer_status(output);
+}
+
+char *
+ldns_pkt_opcode2str(ldns_pkt_opcode opcode)
+{
+ char *str;
+ ldns_buffer *buf;
+
+ buf = ldns_buffer_new(12);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_pkt_opcode2buffer_str(buf, opcode) == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+
+ ldns_buffer_free(buf);
+ return str;
+}
+
+char *
+ldns_pkt_rcode2str(ldns_pkt_rcode rcode)
+{
+ char *str;
+ ldns_buffer *buf;
+
+ buf = ldns_buffer_new(10);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_pkt_rcode2buffer_str(buf, rcode) == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+
+ ldns_buffer_free(buf);
+ return str;
+}
+
+char *
+ldns_pkt_algorithm2str(ldns_algorithm algorithm)
+{
+ char *str;
+ ldns_buffer *buf;
+
+ buf = ldns_buffer_new(10);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_algorithm2buffer_str(buf, algorithm)
+ == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+
+ ldns_buffer_free(buf);
+ return str;
+}
+
+char *
+ldns_pkt_cert_algorithm2str(ldns_cert_algorithm cert_algorithm)
+{
+ char *str;
+ ldns_buffer *buf;
+
+ buf = ldns_buffer_new(10);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_cert_algorithm2buffer_str(buf, cert_algorithm)
+ == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+
+ ldns_buffer_free(buf);
+ return str;
+}
+
+
+/* do NOT pass compressed data here :p */
+ldns_status
+ldns_rdf2buffer_str_dname(ldns_buffer *output, const ldns_rdf *dname)
+{
+ /* can we do with 1 pos var? or without at all? */
+ uint8_t src_pos = 0;
+ uint8_t len;
+ uint8_t *data;
+ uint8_t i;
+ unsigned char c;
+
+ data = (uint8_t*)ldns_rdf_data(dname);
+ len = data[src_pos];
+
+ if (ldns_rdf_size(dname) > LDNS_MAX_DOMAINLEN) {
+ /* too large, return */
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+
+ /* special case: root label */
+ if (1 == ldns_rdf_size(dname)) {
+ ldns_buffer_printf(output, ".");
+ } else {
+ while ((len > 0) && src_pos < ldns_rdf_size(dname)) {
+ src_pos++;
+ for(i = 0; i < len; i++) {
+ /* paranoia check for various 'strange'
+ characters in dnames
+ */
+ c = (unsigned char) data[src_pos];
+ if(c == '.' || c == ';' ||
+ c == '(' || c == ')' ||
+ c == '\\') {
+ ldns_buffer_printf(output, "\\%c",
+ data[src_pos]);
+ } else if (!(isascii(c) && isgraph(c))) {
+ ldns_buffer_printf(output, "\\%03u",
+ data[src_pos]);
+ } else {
+ ldns_buffer_printf(output, "%c", data[src_pos]);
+ }
+ src_pos++;
+ }
+
+ if (src_pos < ldns_rdf_size(dname)) {
+ ldns_buffer_printf(output, ".");
+ }
+ len = data[src_pos];
+ }
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_int8(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint8_t data = ldns_rdf_data(rdf)[0];
+ ldns_buffer_printf(output, "%lu", (unsigned long) data);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_int16(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf));
+ ldns_buffer_printf(output, "%lu", (unsigned long) data);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_int32(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint32_t data = ldns_read_uint32(ldns_rdf_data(rdf));
+ ldns_buffer_printf(output, "%lu", (unsigned long) data);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_time(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* create a YYYYMMDDHHMMSS string if possible */
+ struct tm tm;
+ char date_buf[16];
+
+ memset(&tm, 0, sizeof(tm));
+ if (ldns_serial_arithmitics_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);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_a(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ char str[INET_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET, ldns_rdf_data(rdf), str, INET_ADDRSTRLEN)) {
+ ldns_buffer_printf(output, "%s", str);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_aaaa(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ char str[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, ldns_rdf_data(rdf), str, INET6_ADDRSTRLEN)) {
+ ldns_buffer_printf(output, "%s", str);
+ }
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_str(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ const uint8_t *data = ldns_rdf_data(rdf);
+ uint8_t length = data[0];
+ size_t i;
+
+ ldns_buffer_printf(output, "\"");
+ for (i = 1; i <= length; ++i) {
+ char ch = (char) data[i];
+ if (isprint((int)ch) || ch=='\t') {
+ if (ch=='\"'||ch=='\\')
+ ldns_buffer_printf(output, "\\%c", ch);
+ else
+ ldns_buffer_printf(output, "%c", ch);
+ } else {
+ ldns_buffer_printf(output, "\\%03u",
+ (unsigned)(uint8_t) ch);
+ }
+ }
+ ldns_buffer_printf(output, "\"");
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_b64(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ size_t size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf));
+ char *b64 = LDNS_XMALLOC(char, size);
+ if(!b64) return LDNS_STATUS_MEM_ERR;
+ if (ldns_b64_ntop(ldns_rdf_data(rdf), ldns_rdf_size(rdf), b64, size)) {
+ ldns_buffer_printf(output, "%s", b64);
+ }
+ LDNS_FREE(b64);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_b32_ext(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ size_t size;
+ char *b32;
+ if(ldns_rdf_size(rdf) == 0)
+ return LDNS_STATUS_OK;
+ /* remove -1 for the b32-hash-len octet */
+ size = ldns_b32_ntop_calculate_size(ldns_rdf_size(rdf) - 1);
+ /* add one for the end nul for the string */
+ b32 = LDNS_XMALLOC(char, size + 1);
+ if(!b32) return LDNS_STATUS_MEM_ERR;
+ size = (size_t) ldns_b32_ntop_extended_hex(ldns_rdf_data(rdf) + 1,
+ ldns_rdf_size(rdf) - 1, b32, size+1);
+ if (size > 0) {
+ ldns_buffer_printf(output, "%s", b32);
+ }
+ LDNS_FREE(b32);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ size_t i;
+ for (i = 0; i < ldns_rdf_size(rdf); i++) {
+ ldns_buffer_printf(output, "%02x", ldns_rdf_data(rdf)[i]);
+ }
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf));
+ const ldns_rr_descriptor *descriptor;
+
+ descriptor = ldns_rr_descript(data);
+ if (descriptor && descriptor->_name) {
+ ldns_buffer_printf(output, "%s", descriptor->_name);
+ } else {
+ ldns_buffer_printf(output, "TYPE%u", data);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_class(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf));
+ ldns_lookup_table *lt;
+
+ lt = ldns_lookup_by_id(ldns_rr_classes, (int) data);
+ if (lt) {
+ ldns_buffer_printf(output, "\t%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "\tCLASS%d", data);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_cert_alg(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf));
+ ldns_lookup_table *lt;
+ lt = ldns_lookup_by_id(ldns_cert_algorithms, (int) data);
+ if (lt) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "%d", data);
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_alg(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* don't use algorithm mnemonics in the presentation format
+ this kind of got sneaked into the rfc's */
+ uint8_t data = ldns_rdf_data(rdf)[0];
+ ldns_buffer_printf(output, "%d", data);
+ return ldns_buffer_status(output);
+}
+
+static void
+loc_cm_print(ldns_buffer *output, uint8_t mantissa, uint8_t exponent)
+{
+ uint8_t i;
+ /* is it 0.<two digits> ? */
+ if(exponent < 2) {
+ if(exponent == 1)
+ mantissa *= 10;
+ ldns_buffer_printf(output, "0.%02ld", (long)mantissa);
+ return;
+ }
+ /* always <digit><string of zeros> */
+ ldns_buffer_printf(output, "%d", (int)mantissa);
+ for(i=0; i<exponent-2; i++)
+ ldns_buffer_printf(output, "0");
+}
+
+ldns_status
+ldns_rr_type2buffer_str(ldns_buffer *output, const ldns_rr_type type)
+{
+ const ldns_rr_descriptor *descriptor;
+
+ descriptor = ldns_rr_descript(type);
+
+ if (descriptor && descriptor->_name) {
+ ldns_buffer_printf(output, "%s", descriptor->_name);
+ } else {
+ /* exceptions for pseudotypes */
+ switch (type) {
+ case LDNS_RR_TYPE_IXFR:
+ ldns_buffer_printf(output, "IXFR");
+ break;
+ case LDNS_RR_TYPE_AXFR:
+ ldns_buffer_printf(output, "AXFR");
+ break;
+ case LDNS_RR_TYPE_MAILA:
+ ldns_buffer_printf(output, "MAILA");
+ break;
+ case LDNS_RR_TYPE_MAILB:
+ ldns_buffer_printf(output, "MAILB");
+ break;
+ case LDNS_RR_TYPE_ANY:
+ ldns_buffer_printf(output, "ANY");
+ break;
+ default:
+ ldns_buffer_printf(output, "TYPE%u", type);
+ }
+ }
+ return ldns_buffer_status(output);
+}
+
+char *
+ldns_rr_type2str(const ldns_rr_type type)
+{
+ char *str;
+ ldns_buffer *buf;
+
+ buf = ldns_buffer_new(10);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_rr_type2buffer_str(buf, type) == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+
+ ldns_buffer_free(buf);
+ return str;
+}
+
+
+ldns_status
+ldns_rr_class2buffer_str(ldns_buffer *output,
+ const ldns_rr_class klass)
+{
+ ldns_lookup_table *lt;
+
+ lt = ldns_lookup_by_id(ldns_rr_classes, klass);
+ if (lt) {
+ ldns_buffer_printf(output, "%s", lt->name);
+ } else {
+ ldns_buffer_printf(output, "CLASS%d", klass);
+ }
+ return ldns_buffer_status(output);
+}
+
+char *
+ldns_rr_class2str(const ldns_rr_class klass)
+{
+ ldns_buffer *buf;
+ char *str;
+
+ buf = ldns_buffer_new(10);
+ if (!buf) {
+ return NULL;
+ }
+
+ str = NULL;
+ if (ldns_rr_class2buffer_str(buf, klass) == LDNS_STATUS_OK) {
+ str = ldns_buffer2str(buf);
+ }
+ ldns_buffer_free(buf);
+ return str;
+}
+
+ldns_status
+ldns_rdf2buffer_str_loc(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* we could do checking (ie degrees < 90 etc)? */
+ uint8_t version = ldns_rdf_data(rdf)[0];
+ uint8_t size;
+ uint8_t horizontal_precision;
+ uint8_t vertical_precision;
+ uint32_t longitude;
+ uint32_t latitude;
+ uint32_t altitude;
+ char northerness;
+ char easterness;
+ uint32_t h;
+ uint32_t m;
+ double s;
+
+ uint32_t equator = (uint32_t) ldns_power(2, 31);
+
+ if (version == 0) {
+ size = ldns_rdf_data(rdf)[1];
+ horizontal_precision = ldns_rdf_data(rdf)[2];
+ vertical_precision = ldns_rdf_data(rdf)[3];
+
+ latitude = ldns_read_uint32(&ldns_rdf_data(rdf)[4]);
+ longitude = ldns_read_uint32(&ldns_rdf_data(rdf)[8]);
+ altitude = ldns_read_uint32(&ldns_rdf_data(rdf)[12]);
+
+ if (latitude > equator) {
+ northerness = 'N';
+ latitude = latitude - equator;
+ } else {
+ northerness = 'S';
+ latitude = equator - latitude;
+ }
+ h = latitude / (1000 * 60 * 60);
+ latitude = latitude % (1000 * 60 * 60);
+ m = latitude / (1000 * 60);
+ latitude = latitude % (1000 * 60);
+ s = (double) latitude / 1000.0;
+ ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
+ h, m, s, northerness);
+
+ if (longitude > equator) {
+ easterness = 'E';
+ longitude = longitude - equator;
+ } else {
+ easterness = 'W';
+ longitude = equator - longitude;
+ }
+ h = longitude / (1000 * 60 * 60);
+ longitude = longitude % (1000 * 60 * 60);
+ m = longitude / (1000 * 60);
+ longitude = longitude % (1000 * 60);
+ s = (double) longitude / (1000.0);
+ ldns_buffer_printf(output, "%02u %02u %0.3f %c ",
+ h, m, s, easterness);
+
+
+ s = ((double) altitude) / 100;
+ s -= 100000;
+
+ if(altitude%100 != 0)
+ ldns_buffer_printf(output, "%.2f", s);
+ else
+ ldns_buffer_printf(output, "%.0f", s);
+
+ ldns_buffer_printf(output, "m ");
+
+ loc_cm_print(output, (size & 0xf0) >> 4, size & 0x0f);
+ ldns_buffer_printf(output, "m ");
+
+ loc_cm_print(output, (horizontal_precision & 0xf0) >> 4,
+ horizontal_precision & 0x0f);
+ ldns_buffer_printf(output, "m ");
+
+ loc_cm_print(output, (vertical_precision & 0xf0) >> 4,
+ vertical_precision & 0x0f);
+ ldns_buffer_printf(output, "m");
+
+ return ldns_buffer_status(output);
+ } else {
+ return ldns_rdf2buffer_str_hex(output, rdf);
+ }
+}
+
+ldns_status
+ldns_rdf2buffer_str_unknown(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ ldns_buffer_printf(output, "\\# %u ", ldns_rdf_size(rdf));
+ return ldns_rdf2buffer_str_hex(output, rdf);
+}
+
+ldns_status
+ldns_rdf2buffer_str_nsap(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ ldns_buffer_printf(output, "0x");
+ return ldns_rdf2buffer_str_hex(output, rdf);
+}
+
+ldns_status
+ldns_rdf2buffer_str_atma(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ return ldns_rdf2buffer_str_hex(output, rdf);
+}
+
+ldns_status
+ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* protocol, followed by bitmap of services */
+ struct protoent *protocol;
+ char *proto_name = NULL;
+ uint8_t protocol_nr;
+ struct servent *service;
+ uint16_t current_service;
+
+ protocol_nr = ldns_rdf_data(rdf)[0];
+ protocol = getprotobynumber((int) protocol_nr);
+ if (protocol && (protocol->p_name != NULL)) {
+ proto_name = protocol->p_name;
+ ldns_buffer_printf(output, "%s ", protocol->p_name);
+ } else {
+ ldns_buffer_printf(output, "%u ", protocol_nr);
+ }
+
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+
+ for (current_service = 0;
+ current_service < ldns_rdf_size(rdf) * 7; current_service++) {
+ if (ldns_get_bit(&(ldns_rdf_data(rdf)[1]), current_service)) {
+ service = getservbyport((int) htons(current_service),
+ proto_name);
+ if (service && service->s_name) {
+ ldns_buffer_printf(output, "%s ", service->s_name);
+ } else {
+ ldns_buffer_printf(output, "%u ", current_service);
+ }
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+ }
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* Note: this code is duplicated in higher.c in
+ * ldns_nsec_type_check() function
+ */
+ uint8_t window_block_nr;
+ uint8_t bitmap_length;
+ uint16_t type;
+ uint16_t pos = 0;
+ uint16_t bit_pos;
+ uint8_t *data = ldns_rdf_data(rdf);
+ const ldns_rr_descriptor *descriptor;
+
+ while(pos < ldns_rdf_size(rdf)) {
+ window_block_nr = data[pos];
+ bitmap_length = data[pos + 1];
+ pos += 2;
+
+ for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
+ if (ldns_get_bit(&data[pos], bit_pos)) {
+ type = 256 * (uint16_t) window_block_nr + bit_pos;
+ descriptor = ldns_rr_descript(type);
+
+ if (descriptor && descriptor->_name) {
+ ldns_buffer_printf(output, "%s ",
+ descriptor->_name);
+ } else {
+ ldns_buffer_printf(output, "TYPE%u ", type);
+ }
+ }
+ }
+
+ pos += (uint16_t) bitmap_length;
+ }
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint8_t salt_length;
+ uint8_t salt_pos;
+
+ uint8_t *data = ldns_rdf_data(rdf);
+
+ if(ldns_rdf_size(rdf) == 0) {
+ output->_status = LDNS_STATUS_ERR;
+ return ldns_buffer_status(output);
+ }
+ salt_length = data[0];
+ /* from now there are variable length entries so remember pos */
+ if (salt_length == 0 || ((size_t)salt_length)+1 > ldns_rdf_size(rdf)) {
+ ldns_buffer_printf(output, "- ");
+ } else {
+ for (salt_pos = 0; salt_pos < salt_length; salt_pos++) {
+ ldns_buffer_printf(output, "%02x", data[1 + salt_pos]);
+ }
+ ldns_buffer_printf(output, " ");
+ }
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* period is the number of seconds */
+ uint32_t p = ldns_read_uint32(ldns_rdf_data(rdf));
+ ldns_buffer_printf(output, "%u", p);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_tsigtime(ldns_buffer *output,const ldns_rdf *rdf)
+{
+ /* tsigtime is 48 bits network order unsigned integer */
+ uint64_t tsigtime = 0;
+ uint8_t *data = ldns_rdf_data(rdf);
+
+ if (ldns_rdf_size(rdf) != 6) {
+ return LDNS_STATUS_ERR;
+ }
+
+ tsigtime = ldns_read_uint16(data);
+ tsigtime *= 65536;
+ tsigtime += ldns_read_uint16(data+2);
+ tsigtime *= 65536;
+
+ ldns_buffer_printf(output, "%llu ", tsigtime);
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_apl(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ uint8_t *data = ldns_rdf_data(rdf);
+ uint16_t address_family;
+ uint8_t prefix;
+ bool negation;
+ uint8_t adf_length;
+ size_t i;
+ size_t pos = 0;
+
+ while (pos < (unsigned int) ldns_rdf_size(rdf)) {
+ if(pos + 3 >= (unsigned)ldns_rdf_size(rdf))
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ address_family = ldns_read_uint16(&data[pos]);
+ prefix = data[pos + 2];
+ negation = data[pos + 3] & LDNS_APL_NEGATION;
+ adf_length = data[pos + 3] & LDNS_APL_MASK;
+ if (address_family == LDNS_APL_IP4) {
+ /* check if prefix < 32? */
+ if (negation) {
+ ldns_buffer_printf(output, "!");
+ }
+ ldns_buffer_printf(output, "%u:", address_family);
+ /* address is variable length 0 - 4 */
+ for (i = 0; i < 4; i++) {
+ if (i > 0) {
+ ldns_buffer_printf(output, ".");
+ }
+ if (i < (unsigned short) adf_length) {
+ if(pos+i+4 >= ldns_rdf_size(rdf))
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ ldns_buffer_printf(output, "%d",
+ data[pos + i + 4]);
+ } else {
+ ldns_buffer_printf(output, "0");
+ }
+ }
+ ldns_buffer_printf(output, "/%u ", prefix);
+ } else if (address_family == LDNS_APL_IP6) {
+ /* check if prefix < 128? */
+ if (negation) {
+ ldns_buffer_printf(output, "!");
+ }
+ ldns_buffer_printf(output, "%u:", address_family);
+ /* address is variable length 0 - 16 */
+ for (i = 0; i < 16; i++) {
+ if (i % 2 == 0 && i > 0) {
+ ldns_buffer_printf(output, ":");
+ }
+ if (i < (unsigned short) adf_length) {
+ if(pos+i+4 >= ldns_rdf_size(rdf))
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ ldns_buffer_printf(output, "%02x",
+ data[pos + i + 4]);
+ } else {
+ ldns_buffer_printf(output, "00");
+ }
+ }
+ ldns_buffer_printf(output, "/%u ", prefix);
+
+ } else {
+ /* unknown address family */
+ ldns_buffer_printf(output, "Unknown address family: %u data: ",
+ address_family);
+ for (i = 1; i < (unsigned short) (4 + adf_length); i++) {
+ if(pos+i >= ldns_rdf_size(rdf))
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ ldns_buffer_printf(output, "%02x", data[i]);
+ }
+ }
+ pos += 4 + adf_length;
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_int16_data(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* Subtract the size (2) of the number that specifies the length */
+ size_t size = ldns_b64_ntop_calculate_size(ldns_rdf_size(rdf) - 2);
+ char *b64 = LDNS_XMALLOC(char, size);
+ if(!b64)
+ return LDNS_STATUS_MEM_ERR;
+
+ ldns_buffer_printf(output, "%u ", ldns_rdf_size(rdf) - 2);
+
+ if (ldns_rdf_size(rdf) > 2 &&
+ ldns_b64_ntop(ldns_rdf_data(rdf) + 2,
+ ldns_rdf_size(rdf) - 2,
+ b64, size)) {
+ ldns_buffer_printf(output, "%s", b64);
+ }
+ LDNS_FREE(b64);
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_ipseckey(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* wire format from
+ http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt
+ */
+ uint8_t *data = ldns_rdf_data(rdf);
+ uint8_t precedence;
+ uint8_t gateway_type;
+ uint8_t algorithm;
+
+ ldns_rdf *gateway = NULL;
+ uint8_t *gateway_data;
+
+ size_t public_key_size;
+ uint8_t *public_key_data;
+ ldns_rdf *public_key;
+
+ size_t offset = 0;
+ ldns_status status;
+
+ precedence = data[0];
+ gateway_type = data[1];
+ algorithm = data[2];
+ offset = 3;
+
+ switch (gateway_type) {
+ case 0:
+ /* no gateway */
+ break;
+ case 1:
+ gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP4ADDRLEN);
+ if(!gateway_data)
+ return LDNS_STATUS_MEM_ERR;
+ memcpy(gateway_data, &data[offset], LDNS_IP4ADDRLEN);
+ gateway = ldns_rdf_new(LDNS_RDF_TYPE_A, LDNS_IP4ADDRLEN , gateway_data);
+ offset += LDNS_IP4ADDRLEN;
+ if(!gateway) {
+ LDNS_FREE(gateway_data);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ break;
+ case 2:
+ gateway_data = LDNS_XMALLOC(uint8_t, LDNS_IP6ADDRLEN);
+ if(!gateway_data)
+ return LDNS_STATUS_MEM_ERR;
+ memcpy(gateway_data, &data[offset], LDNS_IP6ADDRLEN);
+ offset += LDNS_IP6ADDRLEN;
+ gateway =
+ ldns_rdf_new(LDNS_RDF_TYPE_AAAA, LDNS_IP6ADDRLEN, gateway_data);
+ if(!gateway) {
+ LDNS_FREE(gateway_data);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ break;
+ case 3:
+ status = ldns_wire2dname(&gateway, data, ldns_rdf_size(rdf), &offset);
+ if(status != LDNS_STATUS_OK)
+ return status;
+ break;
+ default:
+ /* error? */
+ break;
+ }
+
+ public_key_size = ldns_rdf_size(rdf) - offset;
+ public_key_data = LDNS_XMALLOC(uint8_t, public_key_size);
+ if(!public_key_data) {
+ ldns_rdf_free(gateway);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ memcpy(public_key_data, &data[offset], public_key_size);
+ public_key = ldns_rdf_new(LDNS_RDF_TYPE_B64, public_key_size, public_key_data);
+ if(!public_key) {
+ LDNS_FREE(public_key_data);
+ ldns_rdf_free(gateway);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ ldns_buffer_printf(output, "%u %u %u ", precedence, gateway_type, algorithm);
+ if (gateway)
+ (void) ldns_rdf2buffer_str(output, gateway);
+ else
+ ldns_buffer_printf(output, ".");
+ ldns_buffer_printf(output, " ");
+ (void) ldns_rdf2buffer_str(output, public_key);
+
+ ldns_rdf_free(gateway);
+ ldns_rdf_free(public_key);
+
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rdf2buffer_str_tsig(ldns_buffer *output, const ldns_rdf *rdf)
+{
+ /* TSIG RRs have no presentation format, make them #size <data> */
+ return ldns_rdf2buffer_str_unknown(output, rdf);
+}
+
+
+ldns_status
+ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf)
+{
+ ldns_status res = LDNS_STATUS_OK;
+
+ /*ldns_buffer_printf(buffer, "%u:", ldns_rdf_get_type(rdf));*/
+ if (rdf) {
+ switch(ldns_rdf_get_type(rdf)) {
+ case LDNS_RDF_TYPE_NONE:
+ break;
+ case LDNS_RDF_TYPE_DNAME:
+ res = ldns_rdf2buffer_str_dname(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_INT8:
+ res = ldns_rdf2buffer_str_int8(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_INT16:
+ res = ldns_rdf2buffer_str_int16(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_INT32:
+ res = ldns_rdf2buffer_str_int32(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_PERIOD:
+ res = ldns_rdf2buffer_str_period(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_TSIGTIME:
+ res = ldns_rdf2buffer_str_tsigtime(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_A:
+ res = ldns_rdf2buffer_str_a(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_AAAA:
+ res = ldns_rdf2buffer_str_aaaa(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_STR:
+ res = ldns_rdf2buffer_str_str(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_APL:
+ res = ldns_rdf2buffer_str_apl(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_B32_EXT:
+ res = ldns_rdf2buffer_str_b32_ext(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_B64:
+ res = ldns_rdf2buffer_str_b64(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_HEX:
+ res = ldns_rdf2buffer_str_hex(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_NSEC:
+ res = ldns_rdf2buffer_str_nsec(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_NSEC3_SALT:
+ res = ldns_rdf2buffer_str_nsec3_salt(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_TYPE:
+ res = ldns_rdf2buffer_str_type(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_CLASS:
+ res = ldns_rdf2buffer_str_class(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_CERT_ALG:
+ res = ldns_rdf2buffer_str_cert_alg(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_ALG:
+ res = ldns_rdf2buffer_str_alg(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_UNKNOWN:
+ res = ldns_rdf2buffer_str_unknown(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_TIME:
+ res = ldns_rdf2buffer_str_time(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_LOC:
+ res = ldns_rdf2buffer_str_loc(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_WKS:
+ case LDNS_RDF_TYPE_SERVICE:
+ res = ldns_rdf2buffer_str_wks(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_NSAP:
+ res = ldns_rdf2buffer_str_nsap(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_ATMA:
+ res = ldns_rdf2buffer_str_atma(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_IPSECKEY:
+ res = ldns_rdf2buffer_str_ipseckey(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_TSIG:
+ res = ldns_rdf2buffer_str_tsig(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_INT16_DATA:
+ res = ldns_rdf2buffer_str_int16_data(buffer, rdf);
+ break;
+ case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+ res = ldns_rdf2buffer_str_b32_ext(buffer, rdf);
+ break;
+ }
+ } else {
+ ldns_buffer_printf(buffer, "(null) ");
+ res = ldns_buffer_status(buffer);
+ }
+ return res;
+}
+
+ldns_rdf *
+ldns_b32_ext2dname(const ldns_rdf *rdf)
+{
+ size_t size;
+ char *b32;
+ ldns_rdf *out;
+ if(ldns_rdf_size(rdf) == 0)
+ return NULL;
+ /* remove -1 for the b32-hash-len octet */
+ size = ldns_b32_ntop_calculate_size(ldns_rdf_size(rdf) - 1);
+ /* add one for the end nul for the string */
+ b32 = LDNS_XMALLOC(char, size + 2);
+ if (b32) {
+ if (ldns_b32_ntop_extended_hex(ldns_rdf_data(rdf) + 1,
+ ldns_rdf_size(rdf) - 1, b32, size+1) > 0) {
+ b32[size] = '.';
+ b32[size+1] = '\0';
+ if (ldns_str2rdf_dname(&out, b32) == LDNS_STATUS_OK) {
+ LDNS_FREE(b32);
+ return out;
+ }
+ }
+ LDNS_FREE(b32);
+ }
+ return NULL;
+}
+
+ldns_status
+ldns_rr2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_rr *rr)
+{
+ uint16_t i, flags;
+ ldns_status status = LDNS_STATUS_OK;
+
+ if (fmt == NULL) {
+ fmt = ldns_output_format_default;
+ }
+ if (!rr) {
+ if (LDNS_COMMENT_NULLS & fmt->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;
+ }
+
+ /* 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));
+ }
+
+ 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");
+
+ 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");
+ }
+
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ /* ldns_rdf2buffer_str handles NULL input fine! */
+ status = ldns_rdf2buffer_str(output, ldns_rr_rdf(rr, i));
+ if(status != LDNS_STATUS_OK)
+ return status;
+ if (i < ldns_rr_rd_count(rr) - 1) {
+ ldns_buffer_printf(output, " ");
+ }
+ }
+ /* per RR special comments - handy for DNSSEC types */
+ /* check to prevent question sec. rr from
+ * getting here */
+ if (ldns_rr_rd_count(rr) > 0) {
+ switch (ldns_rr_get_type(rr)) {
+ case LDNS_RR_TYPE_DNSKEY:
+ /* if ldns_rr_rd_count(rr) > 0
+ then ldns_rr_rdf(rr, 0) exists! */
+ if (! (fmt->flags & LDNS_COMMENT_KEY)) {
+ break;
+ }
+ flags = ldns_rdf2native_int16(
+ ldns_rr_rdf(rr, 0));
+ ldns_buffer_printf(output, " ;{");
+ if (fmt->flags & LDNS_COMMENT_KEY_ID) {
+ ldns_buffer_printf(output, "id = %u",
+ (unsigned int)
+ ldns_calc_keytag(rr));
+ }
+ if ((fmt->flags & LDNS_COMMENT_KEY_TYPE)
+ && (flags & LDNS_KEY_ZONE_KEY)){
+ if (flags & LDNS_KEY_SEP_KEY) {
+ ldns_buffer_printf(
+ output, " (ksk)");
+ }
+ else {
+ ldns_buffer_printf(
+ output, " (zsk)");
+ }
+ if (fmt->flags & LDNS_COMMENT_KEY_SIZE){
+ ldns_buffer_printf(
+ output, ", ");
+ }
+ } else if (fmt->flags
+ & (LDNS_COMMENT_KEY_ID
+ |LDNS_COMMENT_KEY_SIZE)) {
+ ldns_buffer_printf( output, ", ");
+ }
+ if (fmt->flags & LDNS_COMMENT_KEY_SIZE) {
+ ldns_buffer_printf(output, "size = %db",
+ ldns_rr_dnskey_key_size(rr));
+ }
+ ldns_buffer_printf(output, "}");
+ break;
+ case LDNS_RR_TYPE_RRSIG:
+ if ((fmt->flags & LDNS_COMMENT_KEY)
+ && (fmt->flags
+ & LDNS_COMMENT_RRSIGS)
+ && ldns_rr_rdf(rr, 6) != NULL) {
+ ldns_buffer_printf(output
+ , " ;{id = %d}"
+ , ldns_rdf2native_int16(
+ ldns_rr_rdf(rr, 6)));
+ }
+ break;
+ case LDNS_RR_TYPE_DS:
+ if ((fmt->flags & LDNS_COMMENT_BUBBLEBABBLE)
+ && ldns_rr_rdf(rr, 3) != NULL) {
+ uint8_t *data = ldns_rdf_data(
+ ldns_rr_rdf(rr, 3));
+ size_t len = ldns_rdf_size(
+ ldns_rr_rdf(rr, 3));
+ char *babble = ldns_bubblebabble(
+ data, len);
+ if(babble) {
+ ldns_buffer_printf(output
+ , " ;{%s}", babble);
+ }
+ LDNS_FREE(babble);
+ }
+ break;
+ case LDNS_RR_TYPE_NSEC3:
+ if (! (fmt->flags & LDNS_COMMENT_FLAGS) &&
+ ! (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN)) {
+ break;
+ }
+ ldns_buffer_printf(output, " ;{");
+ if ((fmt->flags & LDNS_COMMENT_FLAGS)) {
+ if (ldns_nsec3_optout(rr)) {
+ ldns_buffer_printf(output,
+ " flags: optout");
+ } else {
+ ldns_buffer_printf(output,
+ " flags: -");
+ }
+ if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN
+ && fmt->data != NULL) {
+ ldns_buffer_printf(output, ", ");
+ }
+ }
+ if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN
+ && fmt->data != NULL) {
+ ldns_rbnode_t *node;
+ ldns_rdf *key = ldns_dname_label(
+ ldns_rr_owner(rr), 0);
+ if (key) {
+ node = ldns_rbtree_search(
+ (ldns_rbtree_t *)
+ fmt->data,
+ (void *) key);
+ if (node->data) {
+ ldns_buffer_printf(
+ output,
+ "from: ");
+ (void)
+ ldns_rdf2buffer_str(
+ output,
+ (ldns_rdf *)
+ node->data);
+ }
+ ldns_rdf_free(key);
+ }
+ key = ldns_b32_ext2dname(
+ ldns_nsec3_next_owner(rr));
+ if (key) {
+ node = ldns_rbtree_search(
+ (ldns_rbtree_t *)
+ fmt->data,
+ (void *) key);
+ if (node->data) {
+ ldns_buffer_printf(
+ output,
+ " to: ");
+ (void)
+ ldns_rdf2buffer_str(
+ output,
+ (ldns_rdf *)
+ node->data);
+ }
+ ldns_rdf_free(key);
+ }
+ }
+ ldns_buffer_printf(output, "}");
+ break;
+ default:
+ break;
+
+ }
+ }
+ /* last */
+ ldns_buffer_printf(output, "\n");
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rr2buffer_str(ldns_buffer *output, const ldns_rr *rr)
+{
+ return ldns_rr2buffer_str_fmt(output, ldns_output_format_default, rr);
+}
+
+ldns_status
+ldns_rr_list2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_rr_list *list)
+{
+ uint16_t i;
+
+ for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
+ (void) ldns_rr2buffer_str_fmt(output, fmt,
+ ldns_rr_list_rr(list, i));
+ }
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_rr_list2buffer_str(ldns_buffer *output, const ldns_rr_list *list)
+{
+ return ldns_rr_list2buffer_str_fmt(
+ output, ldns_output_format_default, list);
+}
+
+ldns_status
+ldns_pktheader2buffer_str(ldns_buffer *output, const ldns_pkt *pkt)
+{
+ ldns_lookup_table *opcode = ldns_lookup_by_id(ldns_opcodes,
+ (int) ldns_pkt_get_opcode(pkt));
+ ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes,
+ (int) ldns_pkt_get_rcode(pkt));
+
+ ldns_buffer_printf(output, ";; ->>HEADER<<- ");
+ if (opcode) {
+ ldns_buffer_printf(output, "opcode: %s, ", opcode->name);
+ } else {
+ ldns_buffer_printf(output, "opcode: ?? (%u), ",
+ ldns_pkt_get_opcode(pkt));
+ }
+ if (rcode) {
+ ldns_buffer_printf(output, "rcode: %s, ", rcode->name);
+ } else {
+ ldns_buffer_printf(output, "rcode: ?? (%u), ", ldns_pkt_get_rcode(pkt));
+ }
+ ldns_buffer_printf(output, "id: %d\n", ldns_pkt_id(pkt));
+ ldns_buffer_printf(output, ";; flags: ");
+
+ if (ldns_pkt_qr(pkt)) {
+ ldns_buffer_printf(output, "qr ");
+ }
+ if (ldns_pkt_aa(pkt)) {
+ ldns_buffer_printf(output, "aa ");
+ }
+ if (ldns_pkt_tc(pkt)) {
+ ldns_buffer_printf(output, "tc ");
+ }
+ if (ldns_pkt_rd(pkt)) {
+ ldns_buffer_printf(output, "rd ");
+ }
+ if (ldns_pkt_cd(pkt)) {
+ ldns_buffer_printf(output, "cd ");
+ }
+ if (ldns_pkt_ra(pkt)) {
+ ldns_buffer_printf(output, "ra ");
+ }
+ if (ldns_pkt_ad(pkt)) {
+ ldns_buffer_printf(output, "ad ");
+ }
+ ldns_buffer_printf(output, "; ");
+ ldns_buffer_printf(output, "QUERY: %u, ", ldns_pkt_qdcount(pkt));
+ ldns_buffer_printf(output, "ANSWER: %u, ", ldns_pkt_ancount(pkt));
+ ldns_buffer_printf(output, "AUTHORITY: %u, ", ldns_pkt_nscount(pkt));
+ ldns_buffer_printf(output, "ADDITIONAL: %u ", ldns_pkt_arcount(pkt));
+ return ldns_buffer_status(output);
+}
+
+ldns_status
+ldns_pkt2buffer_str_fmt(ldns_buffer *output,
+ const ldns_output_format *fmt, const ldns_pkt *pkt)
+{
+ uint16_t i;
+ ldns_status status = LDNS_STATUS_OK;
+ char *tmp;
+ struct timeval time;
+ time_t time_tt;
+
+ if (!pkt) {
+ ldns_buffer_printf(output, "null");
+ return LDNS_STATUS_OK;
+ }
+
+ if (ldns_buffer_status_ok(output)) {
+ status = ldns_pktheader2buffer_str(output, pkt);
+ if (status != LDNS_STATUS_OK) {
+ return status;
+ }
+
+ ldns_buffer_printf(output, "\n");
+
+ ldns_buffer_printf(output, ";; QUESTION SECTION:\n;; ");
+
+
+ for (i = 0; i < ldns_pkt_qdcount(pkt); i++) {
+ status = ldns_rr2buffer_str_fmt(output, fmt,
+ ldns_rr_list_rr(
+ ldns_pkt_question(pkt), i));
+ if (status != LDNS_STATUS_OK) {
+ return status;
+ }
+ }
+ 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;
+ }
+
+ }
+ ldns_buffer_printf(output, "\n");
+
+ ldns_buffer_printf(output, ";; AUTHORITY SECTION:\n");
+
+ for (i = 0; i < ldns_pkt_nscount(pkt); i++) {
+ status = ldns_rr2buffer_str_fmt(output, fmt,
+ ldns_rr_list_rr(
+ ldns_pkt_authority(pkt), i));
+ if (status != LDNS_STATUS_OK) {
+ return status;
+ }
+ }
+ ldns_buffer_printf(output, "\n");
+
+ ldns_buffer_printf(output, ";; ADDITIONAL SECTION:\n");
+ for (i = 0; i < ldns_pkt_arcount(pkt); i++) {
+ status = ldns_rr2buffer_str_fmt(output, fmt,
+ ldns_rr_list_rr(
+ ldns_pkt_additional(pkt), i));
+ if (status != LDNS_STATUS_OK) {
+ return status;
+ }
+
+ }
+ ldns_buffer_printf(output, "\n");
+ /* add some futher fields */
+ ldns_buffer_printf(output, ";; Query time: %d msec\n",
+ ldns_pkt_querytime(pkt));
+ if (ldns_pkt_edns(pkt)) {
+ ldns_buffer_printf(output,
+ ";; EDNS: version %u; flags:",
+ ldns_pkt_edns_version(pkt));
+ if (ldns_pkt_edns_do(pkt)) {
+ ldns_buffer_printf(output, " do");
+ }
+ /* the extended rcode is the value set, shifted four bits,
+ * and or'd with the original rcode */
+ if (ldns_pkt_edns_extended_rcode(pkt)) {
+ ldns_buffer_printf(output, " ; ext-rcode: %d",
+ (ldns_pkt_edns_extended_rcode(pkt) << 4 | ldns_pkt_get_rcode(pkt)));
+ }
+ 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 (ldns_pkt_tsig(pkt)) {
+ ldns_buffer_printf(output, ";; TSIG:\n;; ");
+ (void) ldns_rr2buffer_str_fmt(
+ output, fmt, ldns_pkt_tsig(pkt));
+ ldns_buffer_printf(output, "\n");
+ }
+ if (ldns_pkt_answerfrom(pkt)) {
+ tmp = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
+ ldns_buffer_printf(output, ";; SERVER: %s\n", tmp);
+ LDNS_FREE(tmp);
+ }
+ time = ldns_pkt_timestamp(pkt);
+ time_tt = (time_t)time.tv_sec;
+ ldns_buffer_printf(output, ";; WHEN: %s",
+ (char*)ctime(&time_tt));
+
+ ldns_buffer_printf(output, ";; MSG SIZE rcvd: %d\n",
+ (int)ldns_pkt_size(pkt));
+ } else {
+ return ldns_buffer_status(output);
+ }
+ return status;
+}
+
+ldns_status
+ldns_pkt2buffer_str(ldns_buffer *output, const ldns_pkt *pkt)
+{
+ return ldns_pkt2buffer_str_fmt(output, ldns_output_format_default, pkt);
+}
+
+
+#ifdef HAVE_SSL
+static ldns_status
+ldns_hmac_key2buffer_str(ldns_buffer *output, const ldns_key *k)
+{
+ ldns_status status;
+ size_t i;
+ ldns_rdf *b64_bignum;
+
+ ldns_buffer_printf(output, "Key: ");
+
+ i = ldns_key_hmac_size(k);
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, ldns_key_hmac_key(k));
+ status = ldns_rdf2buffer_str(output, b64_bignum);
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ return status;
+}
+#endif
+
+#if defined(HAVE_SSL) && defined(USE_GOST)
+static ldns_status
+ldns_gost_key2buffer_str(ldns_buffer *output, EVP_PKEY *p)
+{
+ unsigned char* pp = NULL;
+ int ret;
+ ldns_rdf *b64_bignum;
+ ldns_status status;
+
+ ldns_buffer_printf(output, "GostAsn1: ");
+
+ ret = i2d_PrivateKey(p, &pp);
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, (size_t)ret, pp);
+ status = ldns_rdf2buffer_str(output, b64_bignum);
+
+ ldns_rdf_deep_free(b64_bignum);
+ OPENSSL_free(pp);
+ ldns_buffer_printf(output, "\n");
+ return status;
+}
+#endif
+
+ldns_status
+ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
+{
+ ldns_status status = LDNS_STATUS_OK;
+ unsigned char *bignum;
+#ifndef S_SPLINT_S
+ uint16_t i;
+#endif
+
+#ifdef HAVE_SSL
+ /* not used when ssl is not defined */
+ ldns_rdf *b64_bignum = NULL;
+
+ RSA *rsa;
+ DSA *dsa;
+#endif /* HAVE_SSL */
+
+ if (!k) {
+ return LDNS_STATUS_ERR;
+ }
+
+ bignum = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN);
+ if (!bignum) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_buffer_status_ok(output)) {
+#ifdef HAVE_SSL
+ switch(ldns_key_algorithm(k)) {
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+ case LDNS_SIGN_RSAMD5:
+ /* copied by looking at dnssec-keygen output */
+ /* header */
+ rsa = ldns_key_rsa_key(k);
+
+ ldns_buffer_printf(output,"Private-key-format: v1.2\n");
+ switch(ldns_key_algorithm(k)) {
+ case LDNS_SIGN_RSAMD5:
+ ldns_buffer_printf(output,
+ "Algorithm: %u (RSA)\n",
+ LDNS_RSAMD5);
+ break;
+ case LDNS_SIGN_RSASHA1:
+ ldns_buffer_printf(output,
+ "Algorithm: %u (RSASHA1)\n",
+ LDNS_RSASHA1);
+ break;
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ ldns_buffer_printf(output,
+ "Algorithm: %u (RSASHA1_NSEC3)\n",
+ LDNS_RSASHA1_NSEC3);
+ break;
+#ifdef USE_SHA2
+ case LDNS_SIGN_RSASHA256:
+ ldns_buffer_printf(output,
+ "Algorithm: %u (RSASHA256)\n",
+ LDNS_RSASHA256);
+ break;
+ case LDNS_SIGN_RSASHA512:
+ ldns_buffer_printf(output,
+ "Algorithm: %u (RSASHA512)\n",
+ LDNS_RSASHA512);
+ break;
+#endif
+ default:
+ fprintf(stderr, "Warning: unknown signature ");
+ fprintf(stderr,
+ "algorithm type %u\n",
+ ldns_key_algorithm(k));
+ ldns_buffer_printf(output,
+ "Algorithm: %u (Unknown)\n",
+ ldns_key_algorithm(k));
+ break;
+ }
+
+ /* print to buf, convert to bin, convert to b64,
+ * print to buf */
+ ldns_buffer_printf(output, "Modulus: ");
+#ifndef S_SPLINT_S
+ i = (uint16_t)BN_bn2bin(rsa->n, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ ldns_buffer_printf(output, "PublicExponent: ");
+ i = (uint16_t)BN_bn2bin(rsa->e, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+
+ ldns_buffer_printf(output, "PrivateExponent: ");
+ if (rsa->d) {
+ i = (uint16_t)BN_bn2bin(rsa->d, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Prime1: ");
+ if (rsa->p) {
+ i = (uint16_t)BN_bn2bin(rsa->p, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Prime2: ");
+ if (rsa->q) {
+ i = (uint16_t)BN_bn2bin(rsa->q, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Exponent1: ");
+ if (rsa->dmp1) {
+ i = (uint16_t)BN_bn2bin(rsa->dmp1, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Exponent2: ");
+ if (rsa->dmq1) {
+ i = (uint16_t)BN_bn2bin(rsa->dmq1, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Coefficient: ");
+ if (rsa->iqmp) {
+ i = (uint16_t)BN_bn2bin(rsa->iqmp, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ ldns_buffer_printf(output, "(Not available)\n");
+ }
+#endif /* splint */
+
+ RSA_free(rsa);
+ break;
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+ dsa = ldns_key_dsa_key(k);
+
+ ldns_buffer_printf(output,"Private-key-format: v1.2\n");
+ if (ldns_key_algorithm(k) == LDNS_SIGN_DSA) {
+ ldns_buffer_printf(output,"Algorithm: 3 (DSA)\n");
+ } else if (ldns_key_algorithm(k) == LDNS_SIGN_DSA_NSEC3) {
+ ldns_buffer_printf(output,"Algorithm: 6 (DSA_NSEC3)\n");
+ }
+
+ /* print to buf, convert to bin, convert to b64,
+ * print to buf */
+ ldns_buffer_printf(output, "Prime(p): ");
+#ifndef S_SPLINT_S
+ if (dsa->p) {
+ i = (uint16_t)BN_bn2bin(dsa->p, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ printf("(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Subprime(q): ");
+ if (dsa->q) {
+ i = (uint16_t)BN_bn2bin(dsa->q, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ printf("(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Base(g): ");
+ if (dsa->g) {
+ i = (uint16_t)BN_bn2bin(dsa->g, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ printf("(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Private_value(x): ");
+ if (dsa->priv_key) {
+ i = (uint16_t)BN_bn2bin(dsa->priv_key, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ printf("(Not available)\n");
+ }
+
+ ldns_buffer_printf(output, "Public_value(y): ");
+ if (dsa->pub_key) {
+ i = (uint16_t)BN_bn2bin(dsa->pub_key, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ } else {
+ printf("(Not available)\n");
+ }
+#endif /* splint */
+ break;
+ case LDNS_SIGN_ECC_GOST:
+ /* no format defined, use blob */
+#if defined(HAVE_SSL) && defined(USE_GOST)
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: %d (ECC-GOST)\n", LDNS_SIGN_ECC_GOST);
+ status = ldns_gost_key2buffer_str(output,
+#ifndef S_SPLINT_S
+ k->_key.key
+#else
+ NULL
+#endif
+ );
+
+#endif
+ break;
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ case LDNS_SIGN_ECDSAP384SHA384:
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: %d (", ldns_key_algorithm(k));
+ status=ldns_algorithm2buffer_str(output, (ldns_algorithm)ldns_key_algorithm(k));
+#ifndef S_SPLINT_S
+ ldns_buffer_printf(output, ")\n");
+ if(k->_key.key) {
+ EC_KEY* ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+ const BIGNUM* b = EC_KEY_get0_private_key(ec);
+ ldns_buffer_printf(output, "PrivateKey: ");
+ i = (uint16_t)BN_bn2bin(b, bignum);
+ if (i > LDNS_MAX_KEYLEN) {
+ goto error;
+ }
+ b64_bignum = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, i, bignum);
+ if (ldns_rdf2buffer_str(output, b64_bignum) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ ldns_rdf_deep_free(b64_bignum);
+ ldns_buffer_printf(output, "\n");
+ /* down reference count in EC_KEY
+ * its still assigned to the PKEY */
+ EC_KEY_free(ec);
+ }
+#endif /* splint */
+ break;
+#endif
+ case LDNS_SIGN_HMACMD5:
+ /* there's not much of a format defined for TSIG */
+ /* It's just a binary blob, Same for all algorithms */
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: 157 (HMAC_MD5)\n");
+ status = ldns_hmac_key2buffer_str(output, k);
+ break;
+ case LDNS_SIGN_HMACSHA1:
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: 158 (HMAC_SHA1)\n");
+ status = ldns_hmac_key2buffer_str(output, k);
+ break;
+ case LDNS_SIGN_HMACSHA256:
+ ldns_buffer_printf(output, "Private-key-format: v1.2\n");
+ ldns_buffer_printf(output, "Algorithm: 159 (HMAC_SHA256)\n");
+ status = ldns_hmac_key2buffer_str(output, k);
+ break;
+ }
+#endif /* HAVE_SSL */
+ } else {
+#ifdef HAVE_SSL
+ LDNS_FREE(b64_bignum);
+#endif
+ LDNS_FREE(bignum);
+ return ldns_buffer_status(output);
+ }
+ LDNS_FREE(bignum);
+ return status;
+
+#ifdef HAVE_SSL
+ /* compiles warn the label isn't used */
+error:
+ LDNS_FREE(bignum);
+ return LDNS_STATUS_ERR;
+#endif /* HAVE_SSL */
+
+}
+
+/*
+ * Zero terminate the buffer and fix it to the size of the string.
+ */
+char *
+ldns_buffer2str(ldns_buffer *buffer)
+{
+ char *tmp_str;
+ char *str;
+
+ /* check if buffer ends with \0, if not, and
+ if there is space, add it */
+ if (*(ldns_buffer_at(buffer, ldns_buffer_position(buffer))) != 0) {
+ if (!ldns_buffer_reserve(buffer, 1)) {
+ return NULL;
+ }
+ ldns_buffer_write_u8(buffer, (uint8_t) '\0');
+ if (!ldns_buffer_set_capacity(buffer, ldns_buffer_position(buffer))) {
+ return NULL;
+ }
+ }
+
+ tmp_str = ldns_buffer_export(buffer);
+ str = LDNS_XMALLOC(char, strlen(tmp_str) + 1);
+ if(!str) {
+ return NULL;
+ }
+ memcpy(str, tmp_str, strlen(tmp_str) + 1);
+
+ return str;
+}
+
+char *
+ldns_rdf2str(const ldns_rdf *rdf)
+{
+ char *result = NULL;
+ ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ if (!tmp_buffer) {
+ return NULL;
+ }
+ if (ldns_rdf2buffer_str(tmp_buffer, rdf) == LDNS_STATUS_OK) {
+ /* export and return string, destroy rest */
+ result = ldns_buffer2str(tmp_buffer);
+ }
+ ldns_buffer_free(tmp_buffer);
+ return result;
+}
+
+char *
+ldns_rr2str_fmt(const ldns_output_format *fmt, const ldns_rr *rr)
+{
+ char *result = NULL;
+ ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ if (!tmp_buffer) {
+ return NULL;
+ }
+ if (ldns_rr2buffer_str_fmt(tmp_buffer, fmt, rr)
+ == LDNS_STATUS_OK) {
+ /* export and return string, destroy rest */
+ result = ldns_buffer2str(tmp_buffer);
+ }
+ ldns_buffer_free(tmp_buffer);
+ return result;
+}
+
+char *
+ldns_rr2str(const ldns_rr *rr)
+{
+ return ldns_rr2str_fmt(ldns_output_format_default, rr);
+}
+
+char *
+ldns_pkt2str_fmt(const ldns_output_format *fmt, const ldns_pkt *pkt)
+{
+ char *result = NULL;
+ ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ if (!tmp_buffer) {
+ return NULL;
+ }
+ if (ldns_pkt2buffer_str_fmt(tmp_buffer, fmt, pkt)
+ == LDNS_STATUS_OK) {
+ /* export and return string, destroy rest */
+ result = ldns_buffer2str(tmp_buffer);
+ }
+
+ ldns_buffer_free(tmp_buffer);
+ return result;
+}
+
+char *
+ldns_pkt2str(const ldns_pkt *pkt)
+{
+ return ldns_pkt2str_fmt(ldns_output_format_default, pkt);
+}
+
+char *
+ldns_key2str(const ldns_key *k)
+{
+ char *result = NULL;
+ ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ if (!tmp_buffer) {
+ return NULL;
+ }
+ if (ldns_key2buffer_str(tmp_buffer, k) == LDNS_STATUS_OK) {
+ /* export and return string, destroy rest */
+ result = ldns_buffer2str(tmp_buffer);
+ }
+ ldns_buffer_free(tmp_buffer);
+ return result;
+}
+
+char *
+ldns_rr_list2str_fmt(const ldns_output_format *fmt, const ldns_rr_list *list)
+{
+ char *result = NULL;
+ ldns_buffer *tmp_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+
+ if (!tmp_buffer) {
+ return NULL;
+ }
+ if (list) {
+ if (ldns_rr_list2buffer_str_fmt(
+ tmp_buffer, fmt, list)
+ == LDNS_STATUS_OK) {
+ }
+ } else {
+ if (fmt == NULL) {
+ fmt = ldns_output_format_default;
+ }
+ if (fmt->flags & LDNS_COMMENT_NULLS) {
+ ldns_buffer_printf(tmp_buffer, "; (null)\n");
+ }
+ }
+
+ /* export and return string, destroy rest */
+ result = ldns_buffer2str(tmp_buffer);
+ ldns_buffer_free(tmp_buffer);
+ return result;
+}
+
+char *
+ldns_rr_list2str(const ldns_rr_list *list)
+{
+ return ldns_rr_list2str_fmt(ldns_output_format_default, list);
+}
+
+void
+ldns_rdf_print(FILE *output, const ldns_rdf *rdf)
+{
+ char *str = ldns_rdf2str(rdf);
+ if (str) {
+ fprintf(output, "%s", str);
+ } else {
+ fprintf(output, "Unable to convert rdf to string\n");
+ }
+ LDNS_FREE(str);
+}
+
+void
+ldns_rr_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_rr *rr)
+{
+ char *str = ldns_rr2str_fmt(fmt, rr);
+ if (str) {
+ fprintf(output, "%s", str);
+ } else {
+ fprintf(output, "Unable to convert rr to string\n");
+ }
+ LDNS_FREE(str);
+}
+
+void
+ldns_rr_print(FILE *output, const ldns_rr *rr)
+{
+ ldns_rr_print_fmt(output, ldns_output_format_default, rr);
+}
+
+void
+ldns_pkt_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_pkt *pkt)
+{
+ char *str = ldns_pkt2str_fmt(fmt, pkt);
+ if (str) {
+ fprintf(output, "%s", str);
+ } else {
+ fprintf(output, "Unable to convert packet to string\n");
+ }
+ LDNS_FREE(str);
+}
+
+void
+ldns_pkt_print(FILE *output, const ldns_pkt *pkt)
+{
+ ldns_pkt_print_fmt(output, ldns_output_format_default, pkt);
+}
+
+void
+ldns_rr_list_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_rr_list *lst)
+{
+ size_t i;
+ for (i = 0; i < ldns_rr_list_rr_count(lst); i++) {
+ ldns_rr_print_fmt(output, fmt, ldns_rr_list_rr(lst, i));
+ }
+}
+
+void
+ldns_rr_list_print(FILE *output, const ldns_rr_list *lst)
+{
+ ldns_rr_list_print_fmt(output, ldns_output_format_default, lst);
+}
+
+void
+ldns_resolver_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_resolver *r)
+{
+ uint16_t i;
+ ldns_rdf **n;
+ ldns_rdf **s;
+ size_t *rtt;
+ if (!r) {
+ return;
+ }
+ n = ldns_resolver_nameservers(r);
+ s = ldns_resolver_searchlist(r);
+ rtt = ldns_resolver_rtt(r);
+
+ fprintf(output, "port: %d\n", (int)ldns_resolver_port(r));
+ fprintf(output, "edns0 size: %d\n", (int)ldns_resolver_edns_udp_size(r));
+ fprintf(output, "use ip6: %d\n", (int)ldns_resolver_ip6(r));
+
+ fprintf(output, "recursive: %d\n", ldns_resolver_recursive(r));
+ fprintf(output, "usevc: %d\n", ldns_resolver_usevc(r));
+ fprintf(output, "igntc: %d\n", ldns_resolver_igntc(r));
+ fprintf(output, "fail: %d\n", ldns_resolver_fail(r));
+ fprintf(output, "retry: %d\n", (int)ldns_resolver_retry(r));
+ fprintf(output, "retrans: %d\n", (int)ldns_resolver_retrans(r));
+ fprintf(output, "fallback: %d\n", ldns_resolver_fallback(r));
+ fprintf(output, "random: %d\n", ldns_resolver_random(r));
+ fprintf(output, "timeout: %d\n", (int)ldns_resolver_timeout(r).tv_sec);
+ fprintf(output, "dnssec: %d\n", ldns_resolver_dnssec(r));
+ fprintf(output, "dnssec cd: %d\n", ldns_resolver_dnssec_cd(r));
+ fprintf(output, "trust anchors (%d listed):\n",
+ (int)ldns_rr_list_rr_count(ldns_resolver_dnssec_anchors(r)));
+ ldns_rr_list_print_fmt(output, fmt, ldns_resolver_dnssec_anchors(r));
+ fprintf(output, "tsig: %s %s\n",
+ ldns_resolver_tsig_keyname(r)?ldns_resolver_tsig_keyname(r):"-",
+ ldns_resolver_tsig_algorithm(r)?ldns_resolver_tsig_algorithm(r):"-");
+ fprintf(output, "debug: %d\n", ldns_resolver_debug(r));
+
+ fprintf(output, "default domain: ");
+ ldns_rdf_print(output, ldns_resolver_domain(r));
+ fprintf(output, "\n");
+ fprintf(output, "apply default domain: %d\n", ldns_resolver_defnames(r));
+
+ fprintf(output, "searchlist (%d listed):\n", (int)ldns_resolver_searchlist_count(r));
+ for (i = 0; i < ldns_resolver_searchlist_count(r); i++) {
+ fprintf(output, "\t");
+ ldns_rdf_print(output, s[i]);
+ fprintf(output, "\n");
+ }
+ fprintf(output, "apply search list: %d\n", ldns_resolver_dnsrch(r));
+
+ fprintf(output, "nameservers (%d listed):\n", (int)ldns_resolver_nameserver_count(r));
+ for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
+ fprintf(output, "\t");
+ ldns_rdf_print(output, n[i]);
+
+ switch ((int)rtt[i]) {
+ case LDNS_RESOLV_RTT_MIN:
+ fprintf(output, " - reachable\n");
+ break;
+ case LDNS_RESOLV_RTT_INF:
+ fprintf(output, " - unreachable\n");
+ break;
+ }
+ }
+}
+
+void
+ldns_resolver_print(FILE *output, const ldns_resolver *r)
+{
+ ldns_resolver_print_fmt(output, ldns_output_format_default, r);
+}
+
+void
+ldns_zone_print_fmt(FILE *output,
+ const ldns_output_format *fmt, const ldns_zone *z)
+{
+ if(ldns_zone_soa(z))
+ ldns_rr_print_fmt(output, fmt, ldns_zone_soa(z));
+ ldns_rr_list_print_fmt(output, fmt, ldns_zone_rrs(z));
+}
+void
+ldns_zone_print(FILE *output, const ldns_zone *z)
+{
+ ldns_zone_print_fmt(output, ldns_output_format_default, z);
+}
diff --git a/3rdParty/Ldns/src/src/host2wire.c b/3rdParty/Ldns/src/src/host2wire.c
new file mode 100644
index 0000000..ca28dba
--- /dev/null
+++ b/3rdParty/Ldns/src/src/host2wire.c
@@ -0,0 +1,433 @@
+/*
+ * host2wire.c
+ *
+ * conversion routines from the host to the wire format.
+ * This will usually just a re-ordering of the
+ * data (as we store it in network format)
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+/* TODO Jelte
+ add a pointer to a 'possiblecompression' structure
+ to all the needed functions?
+ something like an array of name, pointer values?
+ every dname part could be added to it
+*/
+
+ldns_status
+ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
+{
+ if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) {
+ ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
+ }
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
+{
+ if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
+ ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
+ }
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
+{
+ size_t i;
+ uint8_t *rdf_data;
+
+ if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
+ if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
+ rdf_data = ldns_rdf_data(rdf);
+ for (i = 0; i < ldns_rdf_size(rdf); i++) {
+ ldns_buffer_write_u8(buffer,
+ (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
+ }
+ }
+ } else {
+ /* direct copy for all other types */
+ if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
+ ldns_buffer_write(buffer,
+ ldns_rdf_data(rdf),
+ ldns_rdf_size(rdf));
+ }
+ }
+ return ldns_buffer_status(buffer);
+}
+
+/* convert a rr list to wireformat */
+ldns_status
+ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
+{
+ uint16_t rr_count;
+ uint16_t i;
+
+ rr_count = ldns_rr_list_rr_count(rr_list);
+ for(i = 0; i < rr_count; i++) {
+ (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
+ LDNS_SECTION_ANY);
+ }
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
+ const ldns_rr *rr,
+ int section)
+{
+ uint16_t i;
+ uint16_t rdl_pos = 0;
+ bool pre_rfc3597 = false;
+ switch (ldns_rr_get_type(rr)) {
+ case LDNS_RR_TYPE_NS:
+ case LDNS_RR_TYPE_MD:
+ case LDNS_RR_TYPE_MF:
+ case LDNS_RR_TYPE_CNAME:
+ case LDNS_RR_TYPE_SOA:
+ case LDNS_RR_TYPE_MB:
+ case LDNS_RR_TYPE_MG:
+ case LDNS_RR_TYPE_MR:
+ case LDNS_RR_TYPE_PTR:
+ case LDNS_RR_TYPE_HINFO:
+ case LDNS_RR_TYPE_MINFO:
+ case LDNS_RR_TYPE_MX:
+ case LDNS_RR_TYPE_RP:
+ case LDNS_RR_TYPE_AFSDB:
+ case LDNS_RR_TYPE_RT:
+ case LDNS_RR_TYPE_SIG:
+ case LDNS_RR_TYPE_PX:
+ case LDNS_RR_TYPE_NXT:
+ case LDNS_RR_TYPE_NAPTR:
+ case LDNS_RR_TYPE_KX:
+ case LDNS_RR_TYPE_SRV:
+ case LDNS_RR_TYPE_DNAME:
+ case LDNS_RR_TYPE_A6:
+ pre_rfc3597 = true;
+ break;
+ default:
+ break;
+ }
+
+ if (ldns_rr_owner(rr)) {
+ (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
+ }
+
+ if (ldns_buffer_reserve(buffer, 4)) {
+ (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
+ (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
+ }
+
+ if (section != LDNS_SECTION_QUESTION) {
+ if (ldns_buffer_reserve(buffer, 6)) {
+ ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
+ /* remember pos for later */
+ rdl_pos = ldns_buffer_position(buffer);
+ ldns_buffer_write_u16(buffer, 0);
+ }
+
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ if (pre_rfc3597) {
+ (void) ldns_rdf2buffer_wire_canonical(
+ buffer, ldns_rr_rdf(rr, i));
+ } else {
+ (void) ldns_rdf2buffer_wire(
+ buffer, ldns_rr_rdf(rr, i));
+ }
+ }
+
+ if (rdl_pos != 0) {
+ ldns_buffer_write_u16_at(buffer, rdl_pos,
+ ldns_buffer_position(buffer)
+ - rdl_pos - 2);
+ }
+ }
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
+{
+ uint16_t i;
+ uint16_t rdl_pos = 0;
+
+ if (ldns_rr_owner(rr)) {
+ (void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
+ }
+
+ if (ldns_buffer_reserve(buffer, 4)) {
+ (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
+ (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
+ }
+
+ if (section != LDNS_SECTION_QUESTION) {
+ if (ldns_buffer_reserve(buffer, 6)) {
+ ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
+ /* remember pos for later */
+ rdl_pos = ldns_buffer_position(buffer);
+ ldns_buffer_write_u16(buffer, 0);
+ }
+
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ (void) ldns_rdf2buffer_wire(
+ buffer, ldns_rr_rdf(rr, i));
+ }
+
+ if (rdl_pos != 0) {
+ ldns_buffer_write_u16_at(buffer, rdl_pos,
+ ldns_buffer_position(buffer)
+ - rdl_pos - 2);
+ }
+ }
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
+{
+ uint16_t i;
+
+ /* it must be a sig RR */
+ if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* Convert all the rdfs, except the actual signature data
+ * rdf number 8 - the last, hence: -1 */
+ for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
+ (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
+ }
+
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
+{
+ uint16_t i;
+ /* convert all the rdf's */
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
+ }
+
+ return ldns_buffer_status(buffer);
+}
+
+/*
+ * Copies the packet header data to the buffer in wire format
+ */
+static ldns_status
+ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
+{
+ uint8_t flags;
+ uint16_t arcount;
+
+ if (ldns_buffer_reserve(buffer, 12)) {
+ ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
+
+ flags = ldns_pkt_qr(packet) << 7
+ | ldns_pkt_get_opcode(packet) << 3
+ | ldns_pkt_aa(packet) << 2
+ | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
+ ldns_buffer_write_u8(buffer, flags);
+
+ flags = ldns_pkt_ra(packet) << 7
+ /*| ldns_pkt_z(packet) << 6*/
+ | ldns_pkt_ad(packet) << 5
+ | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet);
+ ldns_buffer_write_u8(buffer, flags);
+
+ ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
+ ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
+ ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
+ /* add EDNS0 and TSIG to additional if they are there */
+ arcount = ldns_pkt_arcount(packet);
+ if (ldns_pkt_tsig(packet)) {
+ arcount++;
+ }
+ if (ldns_pkt_edns(packet)) {
+ arcount++;
+ }
+ ldns_buffer_write_u16(buffer, arcount);
+ }
+
+ return ldns_buffer_status(buffer);
+}
+
+ldns_status
+ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
+{
+ ldns_rr_list *rr_list;
+ uint16_t i;
+
+ /* edns tmp vars */
+ ldns_rr *edns_rr;
+ uint8_t edata[4];
+
+ (void) ldns_hdr2buffer_wire(buffer, packet);
+
+ rr_list = ldns_pkt_question(packet);
+ if (rr_list) {
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ (void) ldns_rr2buffer_wire(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
+ }
+ }
+ rr_list = ldns_pkt_answer(packet);
+ if (rr_list) {
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ (void) ldns_rr2buffer_wire(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
+ }
+ }
+ rr_list = ldns_pkt_authority(packet);
+ if (rr_list) {
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ (void) ldns_rr2buffer_wire(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
+ }
+ }
+ rr_list = ldns_pkt_additional(packet);
+ if (rr_list) {
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ (void) ldns_rr2buffer_wire(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
+ }
+ }
+
+ /* add EDNS to additional if it is needed */
+ if (ldns_pkt_edns(packet)) {
+ edns_rr = ldns_rr_new();
+ if(!edns_rr) return LDNS_STATUS_MEM_ERR;
+ ldns_rr_set_owner(edns_rr,
+ ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
+ ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
+ ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
+ edata[0] = ldns_pkt_edns_extended_rcode(packet);
+ edata[1] = ldns_pkt_edns_version(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);
+ (void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
+ /* take the edns rdata back out of the rr before we free rr */
+ if (packet->_edns_data)
+ (void)ldns_rr_pop_rdf (edns_rr);
+ ldns_rr_free(edns_rr);
+ }
+
+ /* add TSIG to additional if it is there */
+ if (ldns_pkt_tsig(packet)) {
+ (void) ldns_rr2buffer_wire(buffer,
+ ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
+ }
+
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
+{
+ ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ uint8_t *result = NULL;
+ ldns_status status;
+ *result_size = 0;
+ *dest = NULL;
+ if(!buffer) return LDNS_STATUS_MEM_ERR;
+
+ status = ldns_rdf2buffer_wire(buffer, rdf);
+ if (status == LDNS_STATUS_OK) {
+ *result_size = ldns_buffer_position(buffer);
+ result = (uint8_t *) ldns_buffer_export(buffer);
+ } else {
+ ldns_buffer_free(buffer);
+ return status;
+ }
+
+ if (result) {
+ *dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
+ if(!*dest) {
+ ldns_buffer_free(buffer);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ memcpy(*dest, result, ldns_buffer_position(buffer));
+ }
+
+ ldns_buffer_free(buffer);
+ return status;
+}
+
+ldns_status
+ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
+{
+ ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ uint8_t *result = NULL;
+ ldns_status status;
+ *result_size = 0;
+ *dest = NULL;
+ if(!buffer) return LDNS_STATUS_MEM_ERR;
+
+ status = ldns_rr2buffer_wire(buffer, rr, section);
+ if (status == LDNS_STATUS_OK) {
+ *result_size = ldns_buffer_position(buffer);
+ result = (uint8_t *) ldns_buffer_export(buffer);
+ } else {
+ ldns_buffer_free(buffer);
+ return status;
+ }
+
+ if (result) {
+ *dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
+ if(!*dest) {
+ ldns_buffer_free(buffer);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ memcpy(*dest, result, ldns_buffer_position(buffer));
+ }
+
+ ldns_buffer_free(buffer);
+ return status;
+}
+
+ldns_status
+ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
+{
+ ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ uint8_t *result = NULL;
+ ldns_status status;
+ *result_size = 0;
+ *dest = NULL;
+ if(!buffer) return LDNS_STATUS_MEM_ERR;
+
+ status = ldns_pkt2buffer_wire(buffer, packet);
+ if (status == LDNS_STATUS_OK) {
+ *result_size = ldns_buffer_position(buffer);
+ result = (uint8_t *) ldns_buffer_export(buffer);
+ } else {
+ ldns_buffer_free(buffer);
+ return status;
+ }
+
+ if (result) {
+ *dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
+ if(!*dest) {
+ ldns_buffer_free(buffer);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ memcpy(*dest, result, ldns_buffer_position(buffer));
+ }
+
+ ldns_buffer_free(buffer);
+ return status;
+}
diff --git a/3rdParty/Ldns/src/src/keys.c b/3rdParty/Ldns/src/src/keys.c
new file mode 100644
index 0000000..3772122
--- /dev/null
+++ b/3rdParty/Ldns/src/src/keys.c
@@ -0,0 +1,1672 @@
+/*
+ * keys.c handle private keys for use in DNSSEC
+ *
+ * This module should hide some of the openSSL complexities
+ * and give a general interface for private keys and hmac
+ * handling
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+#endif /* HAVE_SSL */
+
+ldns_lookup_table ldns_signing_algorithms[] = {
+ { LDNS_SIGN_RSAMD5, "RSAMD5" },
+ { LDNS_SIGN_RSASHA1, "RSASHA1" },
+ { LDNS_SIGN_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
+#ifdef USE_SHA2
+ { LDNS_SIGN_RSASHA256, "RSASHA256" },
+ { LDNS_SIGN_RSASHA512, "RSASHA512" },
+#endif
+#ifdef USE_GOST
+ { LDNS_SIGN_ECC_GOST, "ECC-GOST" },
+#endif
+#ifdef USE_ECDSA
+ { LDNS_SIGN_ECDSAP256SHA256, "ECDSAP256SHA256" },
+ { LDNS_SIGN_ECDSAP384SHA384, "ECDSAP384SHA384" },
+#endif
+ { LDNS_SIGN_DSA, "DSA" },
+ { LDNS_SIGN_DSA_NSEC3, "DSA-NSEC3-SHA1" },
+ { LDNS_SIGN_HMACMD5, "hmac-md5.sig-alg.reg.int" },
+ { LDNS_SIGN_HMACSHA1, "hmac-sha1" },
+ { LDNS_SIGN_HMACSHA256, "hmac-sha256" },
+ { 0, NULL }
+};
+
+ldns_key_list *
+ldns_key_list_new()
+{
+ ldns_key_list *key_list = LDNS_MALLOC(ldns_key_list);
+ if (!key_list) {
+ return NULL;
+ } else {
+ key_list->_key_count = 0;
+ key_list->_keys = NULL;
+ return key_list;
+ }
+}
+
+ldns_key *
+ldns_key_new()
+{
+ ldns_key *newkey;
+
+ newkey = LDNS_MALLOC(ldns_key);
+ if (!newkey) {
+ return NULL;
+ } else {
+ /* some defaults - not sure wether to do this */
+ ldns_key_set_use(newkey, true);
+ ldns_key_set_flags(newkey, LDNS_KEY_ZONE_KEY);
+ ldns_key_set_origttl(newkey, 0);
+ ldns_key_set_keytag(newkey, 0);
+ ldns_key_set_inception(newkey, 0);
+ ldns_key_set_expiration(newkey, 0);
+ ldns_key_set_pubkey_owner(newkey, NULL);
+#ifdef HAVE_SSL
+ ldns_key_set_evp_key(newkey, NULL);
+#endif /* HAVE_SSL */
+ ldns_key_set_hmac_key(newkey, NULL);
+ ldns_key_set_external_key(newkey, NULL);
+ return newkey;
+ }
+}
+
+ldns_status
+ldns_key_new_frm_fp(ldns_key **k, FILE *fp)
+{
+ return ldns_key_new_frm_fp_l(k, fp, NULL);
+}
+
+#ifdef HAVE_SSL
+ldns_status
+ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm alg)
+{
+ ldns_key *k;
+
+ k = ldns_key_new();
+ if(!k) return LDNS_STATUS_MEM_ERR;
+#ifndef S_SPLINT_S
+ k->_key.key = ENGINE_load_private_key(e, key_id, UI_OpenSSL(), NULL);
+ if(!k->_key.key) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_key_set_algorithm(k, (ldns_signing_algorithm) alg);
+ if (!k->_key.key) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ENGINE_KEY_NOT_LOADED;
+ }
+#endif /* splint */
+ *key = k;
+ return LDNS_STATUS_OK;
+}
+#endif
+
+#ifdef USE_GOST
+/** store GOST engine reference loaded into OpenSSL library */
+ENGINE* ldns_gost_engine = NULL;
+
+int
+ldns_key_EVP_load_gost_id(void)
+{
+ static int gost_id = 0;
+ const EVP_PKEY_ASN1_METHOD* meth;
+ ENGINE* e;
+
+ if(gost_id) return gost_id;
+
+ /* see if configuration loaded gost implementation from other engine*/
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
+ if(meth) {
+ EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+ return gost_id;
+ }
+
+ /* see if engine can be loaded already */
+ e = ENGINE_by_id("gost");
+ if(!e) {
+ /* load it ourself, in case statically linked */
+ ENGINE_load_builtin_engines();
+ ENGINE_load_dynamic();
+ e = ENGINE_by_id("gost");
+ }
+ if(!e) {
+ /* no gost engine in openssl */
+ return 0;
+ }
+ if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
+ ENGINE_finish(e);
+ ENGINE_free(e);
+ return 0;
+ }
+
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
+ if(!meth) {
+ /* algo not found */
+ ENGINE_finish(e);
+ ENGINE_free(e);
+ return 0;
+ }
+ /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
+ * on some platforms this frees up the meth and unloads gost stuff */
+ ldns_gost_engine = e;
+
+ EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
+ return gost_id;
+}
+
+void ldns_key_EVP_unload_gost(void)
+{
+ if(ldns_gost_engine) {
+ ENGINE_finish(ldns_gost_engine);
+ ENGINE_free(ldns_gost_engine);
+ ldns_gost_engine = NULL;
+ }
+}
+
+/** read GOST private key */
+static EVP_PKEY*
+ldns_key_new_frm_fp_gost_l(FILE* fp, int* line_nr)
+{
+ char token[16384];
+ const unsigned char* pp;
+ int gost_id;
+ EVP_PKEY* pkey;
+ ldns_rdf* b64rdf = NULL;
+
+ gost_id = ldns_key_EVP_load_gost_id();
+ if(!gost_id)
+ return NULL;
+
+ if (ldns_fget_keyword_data_l(fp, "GostAsn1", ": ", token, "\n",
+ sizeof(token), line_nr) == -1)
+ return NULL;
+ while(strlen(token) < 96) {
+ /* read more b64 from the file, b64 split on multiple lines */
+ if(ldns_fget_token_l(fp, token+strlen(token), "\n",
+ sizeof(token)-strlen(token), line_nr) == -1)
+ return NULL;
+ }
+ if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
+ return NULL;
+ pp = (unsigned char*)ldns_rdf_data(b64rdf);
+ pkey = d2i_PrivateKey(gost_id, NULL, &pp, (int)ldns_rdf_size(b64rdf));
+ ldns_rdf_deep_free(b64rdf);
+ return pkey;
+}
+#endif
+
+#ifdef USE_ECDSA
+/** calculate public key from private key */
+static int
+ldns_EC_KEY_calc_public(EC_KEY* ec)
+{
+ EC_POINT* pub_key;
+ const EC_GROUP* group;
+ group = EC_KEY_get0_group(ec);
+ pub_key = EC_POINT_new(group);
+ if(!pub_key) return 0;
+ if(!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) {
+ EC_POINT_free(pub_key);
+ return 0;
+ }
+ if(!EC_POINT_mul(group, pub_key, EC_KEY_get0_private_key(ec),
+ NULL, NULL, NULL)) {
+ EC_POINT_free(pub_key);
+ return 0;
+ }
+ if(EC_KEY_set_public_key(ec, pub_key) == 0) {
+ EC_POINT_free(pub_key);
+ return 0;
+ }
+ EC_POINT_free(pub_key);
+ return 1;
+}
+
+/** read ECDSA private key */
+static EVP_PKEY*
+ldns_key_new_frm_fp_ecdsa_l(FILE* fp, ldns_algorithm alg, int* line_nr)
+{
+ char token[16384];
+ ldns_rdf* b64rdf = NULL;
+ unsigned char* pp;
+ BIGNUM* bn;
+ EVP_PKEY* evp_key;
+ EC_KEY* ec;
+ if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n",
+ sizeof(token), line_nr) == -1)
+ return NULL;
+ if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
+ return NULL;
+ pp = (unsigned char*)ldns_rdf_data(b64rdf);
+
+ if(alg == LDNS_ECDSAP256SHA256)
+ ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ else if(alg == LDNS_ECDSAP384SHA384)
+ ec = EC_KEY_new_by_curve_name(NID_secp384r1);
+ else ec = NULL;
+ if(!ec) {
+ ldns_rdf_deep_free(b64rdf);
+ return NULL;
+ }
+ bn = BN_bin2bn(pp, (int)ldns_rdf_size(b64rdf), NULL);
+ ldns_rdf_deep_free(b64rdf);
+ if(!bn) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ EC_KEY_set_private_key(ec, bn);
+ BN_free(bn);
+ if(!ldns_EC_KEY_calc_public(ec)) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+
+ evp_key = EVP_PKEY_new();
+ if(!evp_key) {
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
+ EVP_PKEY_free(evp_key);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ return evp_key;
+}
+#endif
+
+ldns_status
+ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
+{
+ ldns_key *k;
+ char *d;
+ ldns_signing_algorithm alg;
+ ldns_rr *key_rr;
+#ifdef HAVE_SSL
+ RSA *rsa;
+ DSA *dsa;
+ unsigned char *hmac;
+ size_t hmac_size;
+#endif /* HAVE_SSL */
+
+ k = ldns_key_new();
+
+ d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN);
+ if (!k || !d) {
+ ldns_key_free(k);
+ LDNS_FREE(d);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ alg = 0;
+
+ /* the file is highly structured. Do this in sequence */
+ /* RSA:
+ * Private-key-format: v1.x.
+ * Algorithm: 1 (RSA)
+
+ */
+ /* get the key format version number */
+ if (ldns_fget_keyword_data_l(fp, "Private-key-format", ": ", d, "\n",
+ LDNS_MAX_LINELEN, line_nr) == -1) {
+ /* no version information */
+ ldns_key_free(k);
+ LDNS_FREE(d);
+ return LDNS_STATUS_SYNTAX_ERR;
+ }
+ if (strncmp(d, "v1.", 3) != 0) {
+ ldns_key_free(k);
+ LDNS_FREE(d);
+ return LDNS_STATUS_SYNTAX_VERSION_ERR;
+ }
+
+ /* get the algorithm type, our file function strip ( ) so there are
+ * not in the return string! */
+ if (ldns_fget_keyword_data_l(fp, "Algorithm", ": ", d, "\n",
+ LDNS_MAX_LINELEN, line_nr) == -1) {
+ /* no alg information */
+ ldns_key_free(k);
+ LDNS_FREE(d);
+ return LDNS_STATUS_SYNTAX_ALG_ERR;
+ }
+
+ if (strncmp(d, "1 RSA", 2) == 0) {
+ alg = LDNS_SIGN_RSAMD5;
+ }
+ if (strncmp(d, "2 DH", 2) == 0) {
+ alg = (ldns_signing_algorithm)LDNS_DH;
+ }
+ if (strncmp(d, "3 DSA", 2) == 0) {
+ alg = LDNS_SIGN_DSA;
+ }
+ if (strncmp(d, "4 ECC", 2) == 0) {
+ alg = (ldns_signing_algorithm)LDNS_ECC;
+ }
+ if (strncmp(d, "5 RSASHA1", 2) == 0) {
+ alg = LDNS_SIGN_RSASHA1;
+ }
+ if (strncmp(d, "6 DSA", 2) == 0) {
+ alg = LDNS_SIGN_DSA_NSEC3;
+ }
+ if (strncmp(d, "7 RSASHA1", 2) == 0) {
+ alg = LDNS_SIGN_RSASHA1_NSEC3;
+ }
+
+ if (strncmp(d, "8 RSASHA256", 2) == 0) {
+#ifdef USE_SHA2
+ alg = LDNS_SIGN_RSASHA256;
+#else
+ fprintf(stderr, "Warning: SHA256 not compiled into this ");
+ fprintf(stderr, "version of ldns\n");
+#endif
+ }
+ if (strncmp(d, "10 RSASHA512", 3) == 0) {
+#ifdef USE_SHA2
+ alg = LDNS_SIGN_RSASHA512;
+#else
+ fprintf(stderr, "Warning: SHA512 not compiled into this ");
+ fprintf(stderr, "version of ldns\n");
+#endif
+ }
+ if (strncmp(d, "12 ECC-GOST", 3) == 0) {
+#ifdef USE_GOST
+ alg = LDNS_SIGN_ECC_GOST;
+#else
+ fprintf(stderr, "Warning: ECC-GOST not compiled into this ");
+ fprintf(stderr, "version of ldns, use --enable-gost\n");
+#endif
+ }
+#ifdef USE_ECDSA
+ if (strncmp(d, "13 ECDSAP256SHA256", 3) == 0) {
+ alg = LDNS_SIGN_ECDSAP256SHA256;
+ }
+ if (strncmp(d, "14 ECDSAP384SHA384", 3) == 0) {
+ alg = LDNS_SIGN_ECDSAP384SHA384;
+ }
+#endif
+ if (strncmp(d, "157 HMAC-MD5", 4) == 0) {
+ alg = LDNS_SIGN_HMACMD5;
+ }
+ if (strncmp(d, "158 HMAC-SHA1", 4) == 0) {
+ alg = LDNS_SIGN_HMACSHA1;
+ }
+ if (strncmp(d, "159 HMAC-SHA256", 4) == 0) {
+ alg = LDNS_SIGN_HMACSHA256;
+ }
+
+ LDNS_FREE(d);
+
+ switch(alg) {
+ case LDNS_SIGN_RSAMD5:
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+#ifdef USE_SHA2
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+#endif
+ ldns_key_set_algorithm(k, alg);
+#ifdef HAVE_SSL
+ rsa = ldns_key_new_frm_fp_rsa_l(fp, line_nr);
+ if (!rsa) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_key_set_rsa_key(k, rsa);
+ RSA_free(rsa);
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+ ldns_key_set_algorithm(k, alg);
+#ifdef HAVE_SSL
+ dsa = ldns_key_new_frm_fp_dsa_l(fp, line_nr);
+ if (!dsa) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_key_set_dsa_key(k, dsa);
+ DSA_free(dsa);
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_HMACMD5:
+ case LDNS_SIGN_HMACSHA1:
+ case LDNS_SIGN_HMACSHA256:
+ ldns_key_set_algorithm(k, alg);
+#ifdef HAVE_SSL
+ hmac = ldns_key_new_frm_fp_hmac_l(fp, line_nr, &hmac_size);
+ if (!hmac) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_key_set_hmac_size(k, hmac_size);
+ ldns_key_set_hmac_key(k, hmac);
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_ECC_GOST:
+ ldns_key_set_algorithm(k, alg);
+#if defined(HAVE_SSL) && defined(USE_GOST)
+ if(!ldns_key_EVP_load_gost_id()) {
+ ldns_key_free(k);
+ return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL;
+ }
+ ldns_key_set_evp_key(k,
+ ldns_key_new_frm_fp_gost_l(fp, line_nr));
+#ifndef S_SPLINT_S
+ if(!k->_key.key) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+#endif /* splint */
+#endif
+ break;
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ case LDNS_SIGN_ECDSAP384SHA384:
+ ldns_key_set_algorithm(k, alg);
+ ldns_key_set_evp_key(k,
+ ldns_key_new_frm_fp_ecdsa_l(fp, (ldns_algorithm)alg, line_nr));
+#ifndef S_SPLINT_S
+ if(!k->_key.key) {
+ ldns_key_free(k);
+ return LDNS_STATUS_ERR;
+ }
+#endif /* splint */
+ break;
+#endif
+ default:
+ ldns_key_free(k);
+ return LDNS_STATUS_SYNTAX_ALG_ERR;
+ }
+ key_rr = ldns_key2rr(k);
+ ldns_key_set_keytag(k, ldns_calc_keytag(key_rr));
+ ldns_rr_free(key_rr);
+
+ if (key) {
+ *key = k;
+ return LDNS_STATUS_OK;
+ }
+ return LDNS_STATUS_ERR;
+}
+
+#ifdef HAVE_SSL
+RSA *
+ldns_key_new_frm_fp_rsa(FILE *f)
+{
+ return ldns_key_new_frm_fp_rsa_l(f, NULL);
+}
+
+RSA *
+ldns_key_new_frm_fp_rsa_l(FILE *f, int *line_nr)
+{
+ /* we parse
+ * Modulus:
+ * PublicExponent:
+ * PrivateExponent:
+ * Prime1:
+ * Prime2:
+ * Exponent1:
+ * Exponent2:
+ * Coefficient:
+ *
+ * man 3 RSA:
+ *
+ * struct
+ * {
+ * BIGNUM *n; // public modulus
+ * BIGNUM *e; // public exponent
+ * BIGNUM *d; // private exponent
+ * BIGNUM *p; // secret prime factor
+ * BIGNUM *q; // secret prime factor
+ * BIGNUM *dmp1; // d mod (p-1)
+ * BIGNUM *dmq1; // d mod (q-1)
+ * BIGNUM *iqmp; // q^-1 mod p
+ * // ...
+ *
+ */
+ char *d;
+ RSA *rsa;
+ uint8_t *buf;
+ int i;
+
+ d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN);
+ buf = LDNS_XMALLOC(uint8_t, LDNS_MAX_LINELEN);
+ rsa = RSA_new();
+ if (!d || !rsa || !buf) {
+ goto error;
+ }
+
+ /* I could use functions again, but that seems an overkill,
+ * allthough this also looks tedious
+ */
+
+ /* Modules, rsa->n */
+ if (ldns_fget_keyword_data_l(f, "Modulus", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+#ifndef S_SPLINT_S
+ rsa->n = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->n) {
+ goto error;
+ }
+
+ /* PublicExponent, rsa->e */
+ if (ldns_fget_keyword_data_l(f, "PublicExponent", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->e = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->e) {
+ goto error;
+ }
+
+ /* PrivateExponent, rsa->d */
+ if (ldns_fget_keyword_data_l(f, "PrivateExponent", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->d = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->d) {
+ goto error;
+ }
+
+ /* Prime1, rsa->p */
+ if (ldns_fget_keyword_data_l(f, "Prime1", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->p = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->p) {
+ goto error;
+ }
+
+ /* Prime2, rsa->q */
+ if (ldns_fget_keyword_data_l(f, "Prime2", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->q = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->q) {
+ goto error;
+ }
+
+ /* Exponent1, rsa->dmp1 */
+ if (ldns_fget_keyword_data_l(f, "Exponent1", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->dmp1 = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->dmp1) {
+ goto error;
+ }
+
+ /* Exponent2, rsa->dmq1 */
+ if (ldns_fget_keyword_data_l(f, "Exponent2", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->dmq1 = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->dmq1) {
+ goto error;
+ }
+
+ /* Coefficient, rsa->iqmp */
+ if (ldns_fget_keyword_data_l(f, "Coefficient", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ rsa->iqmp = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!rsa->iqmp) {
+ goto error;
+ }
+#endif /* splint */
+
+ LDNS_FREE(buf);
+ LDNS_FREE(d);
+ return rsa;
+
+error:
+ RSA_free(rsa);
+ LDNS_FREE(d);
+ LDNS_FREE(buf);
+ return NULL;
+}
+
+DSA *
+ldns_key_new_frm_fp_dsa(FILE *f)
+{
+ return ldns_key_new_frm_fp_dsa_l(f, NULL);
+}
+
+DSA *
+ldns_key_new_frm_fp_dsa_l(FILE *f, int *line_nr)
+{
+ int i;
+ char *d;
+ DSA *dsa;
+ uint8_t *buf;
+
+ line_nr = line_nr;
+
+ d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN);
+ buf = LDNS_XMALLOC(uint8_t, LDNS_MAX_LINELEN);
+ dsa = DSA_new();
+ if (!d || !dsa || !buf) {
+ goto error;
+ }
+
+ /* the line parser removes the () from the input... */
+
+ /* Prime, dsa->p */
+ if (ldns_fget_keyword_data_l(f, "Primep", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+#ifndef S_SPLINT_S
+ dsa->p = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!dsa->p) {
+ goto error;
+ }
+
+ /* Subprime, dsa->q */
+ if (ldns_fget_keyword_data_l(f, "Subprimeq", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ dsa->q = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!dsa->q) {
+ goto error;
+ }
+
+ /* Base, dsa->g */
+ if (ldns_fget_keyword_data_l(f, "Baseg", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ dsa->g = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!dsa->g) {
+ goto error;
+ }
+
+ /* Private key, dsa->priv_key */
+ if (ldns_fget_keyword_data_l(f, "Private_valuex", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ dsa->priv_key = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!dsa->priv_key) {
+ goto error;
+ }
+
+ /* Public key, dsa->priv_key */
+ if (ldns_fget_keyword_data_l(f, "Public_valuey", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = ldns_b64_pton((const char*)d, buf, ldns_b64_ntop_calculate_size(strlen(d)));
+ dsa->pub_key = BN_bin2bn((const char unsigned*)buf, i, NULL);
+ if (!dsa->pub_key) {
+ goto error;
+ }
+#endif /* splint */
+
+ LDNS_FREE(buf);
+ LDNS_FREE(d);
+
+ return dsa;
+
+error:
+ LDNS_FREE(d);
+ LDNS_FREE(buf);
+ DSA_free(dsa);
+ return NULL;
+}
+
+unsigned char *
+ldns_key_new_frm_fp_hmac(FILE *f, size_t *hmac_size)
+{
+ return ldns_key_new_frm_fp_hmac_l(f, NULL, hmac_size);
+}
+
+unsigned char *
+ldns_key_new_frm_fp_hmac_l(FILE *f, int *line_nr, size_t *hmac_size)
+{
+ size_t i;
+ char *d;
+ unsigned char *buf;
+
+ line_nr = line_nr;
+
+ d = LDNS_XMALLOC(char, LDNS_MAX_LINELEN);
+ buf = LDNS_XMALLOC(unsigned char, LDNS_MAX_LINELEN);
+ if(!d || !buf) {
+ goto error;
+ }
+
+ if (ldns_fget_keyword_data_l(f, "Key", ": ", d, "\n", LDNS_MAX_LINELEN, line_nr) == -1) {
+ goto error;
+ }
+ i = (size_t) ldns_b64_pton((const char*)d,
+ buf,
+ ldns_b64_ntop_calculate_size(strlen(d)));
+
+ *hmac_size = i;
+ return buf;
+
+ error:
+ LDNS_FREE(d);
+ LDNS_FREE(buf);
+ *hmac_size = 0;
+ return NULL;
+}
+#endif /* HAVE_SSL */
+
+#ifdef USE_GOST
+static EVP_PKEY*
+ldns_gen_gost_key(void)
+{
+ EVP_PKEY_CTX* ctx;
+ EVP_PKEY* p = NULL;
+ int gost_id = ldns_key_EVP_load_gost_id();
+ if(!gost_id)
+ return NULL;
+ ctx = EVP_PKEY_CTX_new_id(gost_id, NULL);
+ if(!ctx) {
+ /* the id should be available now */
+ return NULL;
+ }
+ if(EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0) {
+ /* cannot set paramset */
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+ }
+
+ if(EVP_PKEY_keygen_init(ctx) <= 0) {
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+ }
+ if(EVP_PKEY_keygen(ctx, &p) <= 0) {
+ EVP_PKEY_free(p);
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+ }
+ EVP_PKEY_CTX_free(ctx);
+ return p;
+}
+#endif
+
+ldns_key *
+ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
+{
+ ldns_key *k;
+#ifdef HAVE_SSL
+ DSA *d;
+ RSA *r;
+# ifdef USE_ECDSA
+ EC_KEY *ec = NULL;
+# endif
+#else
+ int i;
+ uint16_t offset = 0;
+#endif
+ unsigned char *hmac;
+
+ k = ldns_key_new();
+ if (!k) {
+ return NULL;
+ }
+ switch(alg) {
+ case LDNS_SIGN_RSAMD5:
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+#ifdef HAVE_SSL
+ r = RSA_generate_key((int)size, RSA_F4, NULL, NULL);
+ if(!r) {
+ ldns_key_free(k);
+ return NULL;
+ }
+ if (RSA_check_key(r) != 1) {
+ ldns_key_free(k);
+ return NULL;
+ }
+ ldns_key_set_rsa_key(k, r);
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+#ifdef HAVE_SSL
+ d = DSA_generate_parameters((int)size, NULL, 0, NULL, NULL, NULL, NULL);
+ if (!d) {
+ ldns_key_free(k);
+ return NULL;
+ }
+ if (DSA_generate_key(d) != 1) {
+ ldns_key_free(k);
+ return NULL;
+ }
+ ldns_key_set_dsa_key(k, d);
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_HMACMD5:
+ case LDNS_SIGN_HMACSHA1:
+ case LDNS_SIGN_HMACSHA256:
+#ifdef HAVE_SSL
+#ifndef S_SPLINT_S
+ k->_key.key = NULL;
+#endif /* splint */
+#endif /* HAVE_SSL */
+ size = size / 8;
+ ldns_key_set_hmac_size(k, size);
+
+ hmac = LDNS_XMALLOC(unsigned char, size);
+ if(!hmac) {
+ ldns_key_free(k);
+ return NULL;
+ }
+#ifdef HAVE_SSL
+ if (RAND_bytes(hmac, (int) size) != 1) {
+ LDNS_FREE(hmac);
+ ldns_key_free(k);
+ return NULL;
+ }
+#else
+ while (offset + sizeof(i) < size) {
+ i = random();
+ memcpy(&hmac[offset], &i, sizeof(i));
+ offset += sizeof(i);
+ }
+ if (offset < size) {
+ i = random();
+ memcpy(&hmac[offset], &i, size - offset);
+ }
+#endif /* HAVE_SSL */
+ ldns_key_set_hmac_key(k, hmac);
+
+ ldns_key_set_flags(k, 0);
+ break;
+ case LDNS_SIGN_ECC_GOST:
+#if defined(HAVE_SSL) && defined(USE_GOST)
+ ldns_key_set_evp_key(k, ldns_gen_gost_key());
+#ifndef S_SPLINT_S
+ if(!k->_key.key) {
+ ldns_key_free(k);
+ return NULL;
+ }
+#endif /* splint */
+#endif /* HAVE_SSL and USE_GOST */
+ break;
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ case LDNS_SIGN_ECDSAP384SHA384:
+ if(alg == LDNS_SIGN_ECDSAP256SHA256)
+ ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ else if(alg == LDNS_SIGN_ECDSAP384SHA384)
+ ec = EC_KEY_new_by_curve_name(NID_secp384r1);
+ if(!ec) {
+ ldns_key_free(k);
+ return NULL;
+ }
+ if(!EC_KEY_generate_key(ec)) {
+ ldns_key_free(k);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ k->_key.key = EVP_PKEY_new();
+ if(!k->_key.key) {
+ ldns_key_free(k);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+ if (!EVP_PKEY_assign_EC_KEY(k->_key.key, ec)) {
+ ldns_key_free(k);
+ EC_KEY_free(ec);
+ return NULL;
+ }
+#endif /* splint */
+ break;
+#endif
+ }
+ ldns_key_set_algorithm(k, alg);
+ return k;
+}
+
+void
+ldns_key_print(FILE *output, const ldns_key *k)
+{
+ char *str = ldns_key2str(k);
+ if (str) {
+ fprintf(output, "%s", str);
+ } else {
+ fprintf(output, "Unable to convert private key to string\n");
+ }
+ LDNS_FREE(str);
+}
+
+
+void
+ldns_key_set_algorithm(ldns_key *k, ldns_signing_algorithm l)
+{
+ k->_alg = l;
+}
+
+void
+ldns_key_set_flags(ldns_key *k, uint16_t f)
+{
+ k->_extra.dnssec.flags = f;
+}
+
+#ifdef HAVE_SSL
+#ifndef S_SPLINT_S
+void
+ldns_key_set_evp_key(ldns_key *k, EVP_PKEY *e)
+{
+ k->_key.key = e;
+}
+
+void
+ldns_key_set_rsa_key(ldns_key *k, RSA *r)
+{
+ EVP_PKEY *key = EVP_PKEY_new();
+ EVP_PKEY_set1_RSA(key, r);
+ k->_key.key = key;
+}
+
+void
+ldns_key_set_dsa_key(ldns_key *k, DSA *d)
+{
+ EVP_PKEY *key = EVP_PKEY_new();
+ EVP_PKEY_set1_DSA(key, d);
+ k->_key.key = key;
+}
+#endif /* splint */
+#endif /* HAVE_SSL */
+
+void
+ldns_key_set_hmac_key(ldns_key *k, unsigned char *hmac)
+{
+ k->_key.hmac.key = hmac;
+}
+
+void
+ldns_key_set_hmac_size(ldns_key *k, size_t hmac_size)
+{
+ k->_key.hmac.size = hmac_size;
+}
+
+void
+ldns_key_set_external_key(ldns_key *k, void *external_key)
+{
+ k->_key.external_key = external_key;
+}
+
+void
+ldns_key_set_origttl(ldns_key *k, uint32_t t)
+{
+ k->_extra.dnssec.orig_ttl = t;
+}
+
+void
+ldns_key_set_inception(ldns_key *k, uint32_t i)
+{
+ k->_extra.dnssec.inception = i;
+}
+
+void
+ldns_key_set_expiration(ldns_key *k, uint32_t e)
+{
+ k->_extra.dnssec.expiration = e;
+}
+
+void
+ldns_key_set_pubkey_owner(ldns_key *k, ldns_rdf *r)
+{
+ k->_pubkey_owner = r;
+}
+
+void
+ldns_key_set_keytag(ldns_key *k, uint16_t tag)
+{
+ k->_extra.dnssec.keytag = tag;
+}
+
+/* read */
+size_t
+ldns_key_list_key_count(const ldns_key_list *key_list)
+{
+ return key_list->_key_count;
+}
+
+ldns_key *
+ldns_key_list_key(const ldns_key_list *key, size_t nr)
+{
+ if (nr < ldns_key_list_key_count(key)) {
+ return key->_keys[nr];
+ } else {
+ return NULL;
+ }
+}
+
+ldns_signing_algorithm
+ldns_key_algorithm(const ldns_key *k)
+{
+ return k->_alg;
+}
+
+void
+ldns_key_set_use(ldns_key *k, bool v)
+{
+ if (k) {
+ k->_use = v;
+ }
+}
+
+bool
+ldns_key_use(const ldns_key *k)
+{
+ if (k) {
+ return k->_use;
+ }
+ return false;
+}
+
+#ifdef HAVE_SSL
+#ifndef S_SPLINT_S
+EVP_PKEY *
+ldns_key_evp_key(const ldns_key *k)
+{
+ return k->_key.key;
+}
+
+RSA *
+ldns_key_rsa_key(const ldns_key *k)
+{
+ if (k->_key.key) {
+ return EVP_PKEY_get1_RSA(k->_key.key);
+ } else {
+ return NULL;
+ }
+}
+
+DSA *
+ldns_key_dsa_key(const ldns_key *k)
+{
+ if (k->_key.key) {
+ return EVP_PKEY_get1_DSA(k->_key.key);
+ } else {
+ return NULL;
+ }
+}
+#endif /* splint */
+#endif /* HAVE_SSL */
+
+unsigned char *
+ldns_key_hmac_key(const ldns_key *k)
+{
+ if (k->_key.hmac.key) {
+ return k->_key.hmac.key;
+ } else {
+ return NULL;
+ }
+}
+
+size_t
+ldns_key_hmac_size(const ldns_key *k)
+{
+ if (k->_key.hmac.size) {
+ return k->_key.hmac.size;
+ } else {
+ return 0;
+ }
+}
+
+void *
+ldns_key_external_key(const ldns_key *k)
+{
+ return k->_key.external_key;
+}
+
+uint32_t
+ldns_key_origttl(const ldns_key *k)
+{
+ return k->_extra.dnssec.orig_ttl;
+}
+
+uint16_t
+ldns_key_flags(const ldns_key *k)
+{
+ return k->_extra.dnssec.flags;
+}
+
+uint32_t
+ldns_key_inception(const ldns_key *k)
+{
+ return k->_extra.dnssec.inception;
+}
+
+uint32_t
+ldns_key_expiration(const ldns_key *k)
+{
+ return k->_extra.dnssec.expiration;
+}
+
+uint16_t
+ldns_key_keytag(const ldns_key *k)
+{
+ return k->_extra.dnssec.keytag;
+}
+
+ldns_rdf *
+ldns_key_pubkey_owner(const ldns_key *k)
+{
+ return k->_pubkey_owner;
+}
+
+/* write */
+void
+ldns_key_list_set_use(ldns_key_list *keys, bool v)
+{
+ size_t i;
+
+ for (i = 0; i < ldns_key_list_key_count(keys); i++) {
+ ldns_key_set_use(ldns_key_list_key(keys, i), v);
+ }
+}
+
+void
+ldns_key_list_set_key_count(ldns_key_list *key, size_t count)
+{
+ key->_key_count = count;
+}
+
+bool
+ldns_key_list_push_key(ldns_key_list *key_list, ldns_key *key)
+{
+ size_t key_count;
+ ldns_key **keys;
+
+ key_count = ldns_key_list_key_count(key_list);
+
+ /* grow the array */
+ keys = LDNS_XREALLOC(
+ key_list->_keys, ldns_key *, key_count + 1);
+ if (!keys) {
+ return false;
+ }
+
+ /* add the new member */
+ key_list->_keys = keys;
+ key_list->_keys[key_count] = key;
+
+ ldns_key_list_set_key_count(key_list, key_count + 1);
+ return true;
+}
+
+ldns_key *
+ldns_key_list_pop_key(ldns_key_list *key_list)
+{
+ size_t key_count;
+ ldns_key** a;
+ ldns_key *pop;
+
+ if (!key_list) {
+ return NULL;
+ }
+
+ key_count = ldns_key_list_key_count(key_list);
+ if (key_count == 0) {
+ return NULL;
+ }
+
+ pop = ldns_key_list_key(key_list, key_count);
+
+ /* shrink the array */
+ a = LDNS_XREALLOC(key_list->_keys, ldns_key *, key_count - 1);
+ if(a) {
+ key_list->_keys = a;
+ }
+
+ ldns_key_list_set_key_count(key_list, key_count - 1);
+
+ return pop;
+}
+
+#ifdef HAVE_SSL
+#ifndef S_SPLINT_S
+/* data pointer must be large enough (LDNS_MAX_KEYLEN) */
+static bool
+ldns_key_rsa2bin(unsigned char *data, RSA *k, uint16_t *size)
+{
+ int i,j;
+
+ if (!k) {
+ return false;
+ }
+
+ if (BN_num_bytes(k->e) <= 256) {
+ /* normally only this path is executed (small factors are
+ * more common
+ */
+ data[0] = (unsigned char) BN_num_bytes(k->e);
+ i = BN_bn2bin(k->e, data + 1);
+ j = BN_bn2bin(k->n, data + i + 1);
+ *size = (uint16_t) i + j;
+ } else if (BN_num_bytes(k->e) <= 65536) {
+ data[0] = 0;
+ /* BN_bn2bin does bigendian, _uint16 also */
+ ldns_write_uint16(data + 1, (uint16_t) BN_num_bytes(k->e));
+
+ BN_bn2bin(k->e, data + 3);
+ BN_bn2bin(k->n, data + 4 + BN_num_bytes(k->e));
+ *size = (uint16_t) BN_num_bytes(k->n) + 6;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+/* data pointer must be large enough (LDNS_MAX_KEYLEN) */
+static bool
+ldns_key_dsa2bin(unsigned char *data, DSA *k, uint16_t *size)
+{
+ uint8_t T;
+
+ if (!k) {
+ return false;
+ }
+
+ /* See RFC2536 */
+ *size = (uint16_t)BN_num_bytes(k->g);
+ T = (*size - 64) / 8;
+ memcpy(data, &T, 1);
+
+ if (T > 8) {
+ fprintf(stderr, "DSA key with T > 8 (ie. > 1024 bits)");
+ fprintf(stderr, " not implemented\n");
+ return false;
+ }
+
+ /* size = 64 + (T * 8); */
+ data[0] = (unsigned char)T;
+ BN_bn2bin(k->q, data + 1 ); /* 20 octects */
+ BN_bn2bin(k->p, data + 21 ); /* offset octects */
+ BN_bn2bin(k->g, data + 21 + *size); /* offset octets */
+ BN_bn2bin(k->pub_key, data + 21 + *size + *size); /* offset octets */
+ *size = 21 + (*size * 3);
+ return true;
+}
+
+#ifdef USE_GOST
+static bool
+ldns_key_gost2bin(unsigned char* data, EVP_PKEY* k, uint16_t* size)
+{
+ int i;
+ unsigned char* pp = NULL;
+ if(i2d_PUBKEY(k, &pp) != 37 + 64) {
+ /* expect 37 byte(ASN header) and 64 byte(X and Y) */
+ CRYPTO_free(pp);
+ return false;
+ }
+ /* omit ASN header */
+ for(i=0; i<64; i++)
+ data[i] = pp[i+37];
+ CRYPTO_free(pp);
+ *size = 64;
+ return true;
+}
+#endif /* USE_GOST */
+#endif /* splint */
+#endif /* HAVE_SSL */
+
+ldns_rr *
+ldns_key2rr(const ldns_key *k)
+{
+ /* this function will convert a the keydata contained in
+ * rsa/dsa pointers to a DNSKEY rr. It will fill in as
+ * much as it can, but it does not know about key-flags
+ * for instance
+ */
+ ldns_rr *pubkey;
+ ldns_rdf *keybin;
+ unsigned char *bin = NULL;
+ uint16_t size = 0;
+#ifdef HAVE_SSL
+ RSA *rsa = NULL;
+ DSA *dsa = NULL;
+#endif /* HAVE_SSL */
+#ifdef USE_ECDSA
+ EC_KEY* ec;
+#endif
+ int internal_data = 0;
+
+ pubkey = ldns_rr_new();
+ if (!k) {
+ return NULL;
+ }
+
+ switch (ldns_key_algorithm(k)) {
+ case LDNS_SIGN_HMACMD5:
+ case LDNS_SIGN_HMACSHA1:
+ case LDNS_SIGN_HMACSHA256:
+ ldns_rr_set_type(pubkey, LDNS_RR_TYPE_KEY);
+ break;
+ default:
+ ldns_rr_set_type(pubkey, LDNS_RR_TYPE_DNSKEY);
+ break;
+ }
+ /* zero-th rdf - flags */
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
+ ldns_key_flags(k)));
+ /* first - proto */
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, LDNS_DNSSEC_KEYPROTO));
+
+ if (ldns_key_pubkey_owner(k)) {
+ ldns_rr_set_owner(pubkey, ldns_rdf_clone(ldns_key_pubkey_owner(k)));
+ }
+
+ /* third - da algorithm */
+ switch(ldns_key_algorithm(k)) {
+ case LDNS_SIGN_RSAMD5:
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k)));
+#ifdef HAVE_SSL
+ rsa = ldns_key_rsa_key(k);
+ if (rsa) {
+ bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN);
+ if (!bin) {
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ if (!ldns_key_rsa2bin(bin, rsa, &size)) {
+ LDNS_FREE(bin);
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ RSA_free(rsa);
+ internal_data = 1;
+ }
+#endif
+ size++;
+ break;
+ case LDNS_SIGN_DSA:
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA));
+#ifdef HAVE_SSL
+ dsa = ldns_key_dsa_key(k);
+ if (dsa) {
+ bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN);
+ if (!bin) {
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ if (!ldns_key_dsa2bin(bin, dsa, &size)) {
+ LDNS_FREE(bin);
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ DSA_free(dsa);
+ internal_data = 1;
+ }
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_DSA_NSEC3:
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA_NSEC3));
+#ifdef HAVE_SSL
+ dsa = ldns_key_dsa_key(k);
+ if (dsa) {
+ bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN);
+ if (!bin) {
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ if (!ldns_key_dsa2bin(bin, dsa, &size)) {
+ LDNS_FREE(bin);
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ DSA_free(dsa);
+ internal_data = 1;
+ }
+#endif /* HAVE_SSL */
+ break;
+ case LDNS_SIGN_ECC_GOST:
+ ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(
+ LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k)));
+#if defined(HAVE_SSL) && defined(USE_GOST)
+ bin = LDNS_XMALLOC(unsigned char, LDNS_MAX_KEYLEN);
+ if (!bin) {
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ if (!ldns_key_gost2bin(bin, k->_key.key, &size)) {
+ LDNS_FREE(bin);
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+#endif /* splint */
+ internal_data = 1;
+#endif /* HAVE_SSL and USE_GOST */
+ break;
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ case LDNS_SIGN_ECDSAP384SHA384:
+ ldns_rr_push_rdf(pubkey, ldns_native2rdf_int8(
+ LDNS_RDF_TYPE_ALG, ldns_key_algorithm(k)));
+ bin = NULL;
+#ifndef S_SPLINT_S
+ ec = EVP_PKEY_get1_EC_KEY(k->_key.key);
+#endif
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+ size = (uint16_t)i2o_ECPublicKey(ec, NULL);
+ if(!i2o_ECPublicKey(ec, &bin)) {
+ EC_KEY_free(ec);
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ if(size > 1) {
+ /* move back one byte to shave off the 0x02
+ * 'uncompressed' indicator that openssl made
+ * Actually its 0x04 (from implementation).
+ */
+ assert(bin[0] == POINT_CONVERSION_UNCOMPRESSED);
+ size -= 1;
+ memmove(bin, bin+1, size);
+ }
+ /* down the reference count for ec, its still assigned
+ * to the pkey */
+ EC_KEY_free(ec);
+ internal_data = 1;
+ break;
+#endif
+ case LDNS_SIGN_HMACMD5:
+ case LDNS_SIGN_HMACSHA1:
+ case LDNS_SIGN_HMACSHA256:
+ bin = LDNS_XMALLOC(unsigned char, ldns_key_hmac_size(k));
+ if (!bin) {
+ ldns_rr_free(pubkey);
+ return NULL;
+ }
+ ldns_rr_push_rdf(pubkey,
+ ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG,
+ ldns_key_algorithm(k)));
+ size = ldns_key_hmac_size(k);
+ memcpy(bin, ldns_key_hmac_key(k), size);
+ internal_data = 1;
+ break;
+ }
+ /* fourth the key bin material */
+ if (internal_data) {
+ keybin = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, size, bin);
+ LDNS_FREE(bin);
+ ldns_rr_push_rdf(pubkey, keybin);
+ }
+ return pubkey;
+}
+
+void
+ldns_key_free(ldns_key *key)
+{
+ LDNS_FREE(key);
+}
+
+void
+ldns_key_deep_free(ldns_key *key)
+{
+ if (ldns_key_pubkey_owner(key)) {
+ ldns_rdf_deep_free(ldns_key_pubkey_owner(key));
+ }
+#ifdef HAVE_SSL
+ if (ldns_key_evp_key(key)) {
+ EVP_PKEY_free(ldns_key_evp_key(key));
+ }
+#endif /* HAVE_SSL */
+ if (ldns_key_hmac_key(key)) {
+ free(ldns_key_hmac_key(key));
+ }
+ LDNS_FREE(key);
+}
+
+void
+ldns_key_list_free(ldns_key_list *key_list)
+{
+ size_t i;
+ for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
+ ldns_key_deep_free(ldns_key_list_key(key_list, i));
+ }
+ LDNS_FREE(key_list->_keys);
+ LDNS_FREE(key_list);
+}
+
+ldns_rr *
+ldns_read_anchor_file(const char *filename)
+{
+ FILE *fp;
+ /*char line[LDNS_MAX_PACKETLEN];*/
+ char *line = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN);
+ int c;
+ size_t i = 0;
+ ldns_rr *r;
+ ldns_status status;
+ if(!line) {
+ return NULL;
+ }
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
+ LDNS_FREE(line);
+ return NULL;
+ }
+
+ while ((c = fgetc(fp)) && i+1 < LDNS_MAX_PACKETLEN && c != EOF) {
+ line[i] = c;
+ i++;
+ }
+ line[i] = '\0';
+
+ fclose(fp);
+
+ if (i <= 0) {
+ fprintf(stderr, "nothing read from %s", filename);
+ LDNS_FREE(line);
+ return NULL;
+ } else {
+ status = ldns_rr_new_frm_str(&r, line, 0, NULL, NULL);
+ if (status == LDNS_STATUS_OK && (ldns_rr_get_type(r) == LDNS_RR_TYPE_DNSKEY || ldns_rr_get_type(r) == LDNS_RR_TYPE_DS)) {
+ LDNS_FREE(line);
+ return r;
+ } else {
+ fprintf(stderr, "Error creating DNSKEY or DS rr from %s: %s\n", filename, ldns_get_errorstr_by_id(status));
+ LDNS_FREE(line);
+ return NULL;
+ }
+ }
+}
+
+char *
+ldns_key_get_file_base_name(ldns_key *key)
+{
+ ldns_buffer *buffer;
+ char *file_base_name;
+
+ buffer = ldns_buffer_new(255);
+ ldns_buffer_printf(buffer, "K");
+ (void)ldns_rdf2buffer_str_dname(buffer, ldns_key_pubkey_owner(key));
+ ldns_buffer_printf(buffer,
+ "+%03u+%05u",
+ ldns_key_algorithm(key),
+ ldns_key_keytag(key));
+ file_base_name = strdup(ldns_buffer_export(buffer));
+ ldns_buffer_free(buffer);
+ return file_base_name;
+}
+
+int ldns_key_algo_supported(int algo)
+{
+ ldns_lookup_table *lt = ldns_signing_algorithms;
+ while(lt->name) {
+ if(lt->id == algo)
+ return 1;
+ lt++;
+ }
+ return 0;
+}
+
+ldns_signing_algorithm ldns_get_signing_algorithm_by_name(const char* name)
+{
+ /* list of (signing algorithm id, alias_name) */
+ ldns_lookup_table aliases[] = {
+ /* from bind dnssec-keygen */
+ {LDNS_SIGN_HMACMD5, "HMAC-MD5"},
+ {LDNS_SIGN_DSA_NSEC3, "NSEC3DSA"},
+ {LDNS_SIGN_RSASHA1_NSEC3, "NSEC3RSASHA1"},
+ /* old ldns usage, now RFC names */
+ {LDNS_SIGN_DSA_NSEC3, "DSA_NSEC3" },
+ {LDNS_SIGN_RSASHA1_NSEC3, "RSASHA1_NSEC3" },
+#ifdef USE_GOST
+ {LDNS_SIGN_ECC_GOST, "GOST"},
+#endif
+ /* compat with possible output */
+ {LDNS_DH, "DH"},
+ {LDNS_ECC, "ECC"},
+ {LDNS_INDIRECT, "INDIRECT"},
+ {LDNS_PRIVATEDNS, "PRIVATEDNS"},
+ {LDNS_PRIVATEOID, "PRIVATEOID"},
+ {0, NULL}};
+ ldns_lookup_table* lt = ldns_signing_algorithms;
+ while(lt->name) {
+ if(strcasecmp(lt->name, name) == 0)
+ return lt->id;
+ lt++;
+ }
+ lt = aliases;
+ while(lt->name) {
+ if(strcasecmp(lt->name, name) == 0)
+ return lt->id;
+ lt++;
+ }
+ if(atoi(name) != 0)
+ return atoi(name);
+ return 0;
+}
diff --git a/3rdParty/Ldns/src/src/linktest.c b/3rdParty/Ldns/src/src/linktest.c
new file mode 100644
index 0000000..c21753a
--- /dev/null
+++ b/3rdParty/Ldns/src/src/linktest.c
@@ -0,0 +1,13 @@
+
+#include "ldns/config.h"
+#include <ldns/ldns.h>
+
+int
+main(void)
+{
+ ldns_rr *rr = ldns_rr_new();
+
+ ldns_rr_free(rr);
+ return 0;
+}
+
diff --git a/3rdParty/Ldns/src/src/net.c b/3rdParty/Ldns/src/src/net.c
new file mode 100644
index 0000000..870511a
--- /dev/null
+++ b/3rdParty/Ldns/src/src/net.c
@@ -0,0 +1,907 @@
+/*
+ * net.c
+ *
+ * Network implementation
+ * All network related functions are grouped here
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+ldns_status
+ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
+{
+ ldns_buffer *qb;
+ ldns_status result;
+ ldns_rdf *tsig_mac = NULL;
+
+ qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
+
+ if (query_pkt && ldns_pkt_tsig(query_pkt)) {
+ tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
+ }
+
+ if (!query_pkt ||
+ ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
+ result = LDNS_STATUS_ERR;
+ } else {
+ result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
+ }
+
+ ldns_buffer_free(qb);
+
+ return result;
+}
+
+ldns_status
+ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
+{
+ uint8_t i;
+
+ struct sockaddr_storage *ns;
+ size_t ns_len;
+ struct timeval tv_s;
+ struct timeval tv_e;
+
+ ldns_rdf **ns_array;
+ size_t *rtt;
+ ldns_pkt *reply;
+ bool all_servers_rtt_inf;
+ uint8_t retries;
+
+ uint8_t *reply_bytes = NULL;
+ size_t reply_size = 0;
+ ldns_status status, send_status;
+
+ assert(r != NULL);
+
+ status = LDNS_STATUS_OK;
+ rtt = ldns_resolver_rtt(r);
+ ns_array = ldns_resolver_nameservers(r);
+ reply = NULL;
+ ns_len = 0;
+
+ all_servers_rtt_inf = true;
+
+ if (ldns_resolver_random(r)) {
+ ldns_resolver_nameservers_randomize(r);
+ }
+
+ /* loop through all defined nameservers */
+ for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
+ if (rtt[i] == LDNS_RESOLV_RTT_INF) {
+ /* not reachable nameserver! */
+ continue;
+ }
+
+ /* maybe verbosity setting?
+ printf("Sending to ");
+ ldns_rdf_print(stdout, ns_array[i]);
+ printf("\n");
+ */
+ ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
+ ldns_resolver_port(r), &ns_len);
+
+
+#ifndef S_SPLINT_S
+ if ((ns->ss_family == AF_INET) &&
+ (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
+ /* not reachable */
+ continue;
+ }
+
+ if ((ns->ss_family == AF_INET6) &&
+ (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
+ /* not reachable */
+ continue;
+ }
+#endif
+
+ all_servers_rtt_inf = false;
+
+ gettimeofday(&tv_s, NULL);
+
+ send_status = LDNS_STATUS_ERR;
+
+ /* reply_bytes implicitly handles our error */
+ if (1 == ldns_resolver_usevc(r)) {
+ for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
+ send_status =
+ ldns_tcp_send(&reply_bytes, qb, ns,
+ (socklen_t)ns_len, ldns_resolver_timeout(r),
+ &reply_size);
+ if (send_status == LDNS_STATUS_OK) {
+ break;
+ }
+ }
+ } else {
+ for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
+ /* ldns_rdf_print(stdout, ns_array[i]); */
+ send_status =
+ ldns_udp_send(&reply_bytes, qb, ns,
+ (socklen_t)ns_len, ldns_resolver_timeout(r),
+ &reply_size);
+
+ if (send_status == LDNS_STATUS_OK) {
+ break;
+ }
+ }
+ }
+
+ if (send_status != LDNS_STATUS_OK) {
+ ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
+ status = send_status;
+ }
+
+ /* obey the fail directive */
+ if (!reply_bytes) {
+ /* the current nameserver seems to have a problem, blacklist it */
+ if (ldns_resolver_fail(r)) {
+ LDNS_FREE(ns);
+ return LDNS_STATUS_ERR;
+ } else {
+ LDNS_FREE(ns);
+ continue;
+ }
+ }
+
+ status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
+ if (status != LDNS_STATUS_OK) {
+ LDNS_FREE(reply_bytes);
+ LDNS_FREE(ns);
+ return status;
+ }
+
+ LDNS_FREE(ns);
+ gettimeofday(&tv_e, NULL);
+
+ if (reply) {
+ ldns_pkt_set_querytime(reply, (uint32_t)
+ ((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
+ (tv_e.tv_usec - tv_s.tv_usec) / 1000);
+ ldns_pkt_set_answerfrom(reply, ns_array[i]);
+ ldns_pkt_set_timestamp(reply, tv_s);
+ ldns_pkt_set_size(reply, reply_size);
+ break;
+ } else {
+ if (ldns_resolver_fail(r)) {
+ /* if fail is set bail out, after the first
+ * one */
+ break;
+ }
+ }
+
+ /* wait retrans seconds... */
+ sleep((unsigned int) ldns_resolver_retrans(r));
+ }
+
+ if (all_servers_rtt_inf) {
+ LDNS_FREE(reply_bytes);
+ return LDNS_STATUS_RES_NO_NS;
+ }
+#ifdef HAVE_SSL
+ if (tsig_mac && reply_bytes) {
+ if (!ldns_pkt_tsig_verify(reply,
+ reply_bytes,
+ reply_size,
+ ldns_resolver_tsig_keyname(r),
+ ldns_resolver_tsig_keydata(r), tsig_mac)) {
+ status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
+ }
+ }
+#else
+ (void)tsig_mac;
+#endif /* HAVE_SSL */
+
+ LDNS_FREE(reply_bytes);
+ if (result) {
+ *result = reply;
+ }
+
+ return status;
+}
+
+/** best effort to set nonblocking */
+static void
+ldns_sock_nonblock(int sockfd)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(sockfd, F_GETFL)) != -1) {
+ flag |= O_NONBLOCK;
+ if(fcntl(sockfd, F_SETFL, flag) == -1) {
+ /* ignore error, continue blockingly */
+ }
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long on = 1;
+ if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
+ /* ignore error, continue blockingly */
+ }
+#endif
+}
+
+/** best effort to set blocking */
+static void
+ldns_sock_block(int sockfd)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(sockfd, F_GETFL)) != -1) {
+ flag &= ~O_NONBLOCK;
+ if(fcntl(sockfd, F_SETFL, flag) == -1) {
+ /* ignore error, continue */
+ }
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long off = 0;
+ if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
+ /* ignore error, continue */
+ }
+#endif
+}
+
+/** wait for a socket to become ready */
+static int
+ldns_sock_wait(int sockfd, struct timeval timeout, int write)
+{
+ int ret;
+#ifndef S_SPLINT_S
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(FD_SET_T sockfd, &fds);
+ if(write)
+ ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
+ else
+ ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
+#endif
+ if(ret == 0)
+ /* timeout expired */
+ return 0;
+ else if(ret == -1)
+ /* error */
+ return 0;
+ return 1;
+}
+
+ldns_status
+ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to,
+ socklen_t tolen, struct timeval timeout, size_t *answer_size)
+{
+ int sockfd;
+ uint8_t *answer;
+
+ sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout);
+
+ if (sockfd == 0) {
+ return LDNS_STATUS_SOCKET_ERROR;
+ }
+
+ /* wait for an response*/
+ if(!ldns_sock_wait(sockfd, timeout, 0)) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ /* set to nonblocking, so if the checksum is bad, it becomes
+ * an EGAIN error and the ldns_udp_send function does not block,
+ * but returns a 'NETWORK_ERROR' much like a timeout. */
+ ldns_sock_nonblock(sockfd);
+
+ answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+
+ if (*answer_size == 0) {
+ /* oops */
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ *result = answer;
+ return LDNS_STATUS_OK;
+}
+
+int
+ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout)
+{
+ int sockfd;
+
+ sockfd = ldns_udp_connect(to, timeout);
+
+ if (sockfd == 0) {
+ return 0;
+ }
+
+ if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+ return sockfd;
+}
+
+int
+ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
+{
+ int sockfd;
+
+#ifndef S_SPLINT_S
+ if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
+ IPPROTO_UDP))
+ == -1) {
+ return 0;
+ }
+#endif
+ return sockfd;
+}
+
+int
+ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout)
+{
+ int sockfd;
+
+#ifndef S_SPLINT_S
+ if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
+ IPPROTO_TCP)) == -1) {
+ return 0;
+ }
+#endif
+
+ /* perform nonblocking connect, to be able to wait with select() */
+ ldns_sock_nonblock(sockfd);
+ if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
+#ifndef USE_WINSOCK
+#ifdef EINPROGRESS
+ if(errno != EINPROGRESS) {
+#else
+ if(1) {
+#endif
+ close(sockfd);
+ return 0;
+ }
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() != WSAEINPROGRESS &&
+ WSAGetLastError() != WSAEWOULDBLOCK) {
+ closesocket(sockfd);
+ return 0;
+ }
+#endif
+ /* error was only telling us that it would block */
+ }
+
+ /* wait(write) until connected or error */
+ while(1) {
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+
+ if(!ldns_sock_wait(sockfd, timeout, 1)) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+
+ /* check if there is a pending error for nonblocking connect */
+ if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &len) < 0) {
+#ifndef USE_WINSOCK
+ error = errno; /* on solaris errno is error */
+#else
+ error = WSAGetLastError();
+#endif
+ }
+#ifndef USE_WINSOCK
+#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
+ if(error == EINPROGRESS || error == EWOULDBLOCK)
+ continue; /* try again */
+#endif
+ else if(error != 0) {
+ close(sockfd);
+ /* error in errno for our user */
+ errno = error;
+ return 0;
+ }
+#else /* USE_WINSOCK */
+ if(error == WSAEINPROGRESS)
+ continue;
+ else if(error == WSAEWOULDBLOCK)
+ continue;
+ else if(error != 0) {
+ closesocket(sockfd);
+ errno = error;
+ return 0;
+ }
+#endif /* USE_WINSOCK */
+ /* connected */
+ break;
+ }
+
+ /* set the socket blocking again */
+ ldns_sock_block(sockfd);
+
+ return sockfd;
+}
+
+ssize_t
+ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
+ const struct sockaddr_storage *to, socklen_t tolen)
+{
+ uint8_t *sendbuf;
+ ssize_t bytes;
+
+ /* add length of packet */
+ sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
+ if(!sendbuf) return 0;
+ ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
+ memcpy(sendbuf + 2, ldns_buffer_export(qbin), ldns_buffer_position(qbin));
+
+ bytes = sendto(sockfd, (void*)sendbuf,
+ ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
+
+ LDNS_FREE(sendbuf);
+
+ if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
+ return 0;
+ }
+ return bytes;
+}
+
+/* don't wait for an answer */
+ssize_t
+ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
+ socklen_t tolen)
+{
+ ssize_t bytes;
+
+ bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
+ ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
+
+ if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
+ return 0;
+ }
+ if ((size_t) bytes != ldns_buffer_position(qbin)) {
+ return 0;
+ }
+ return bytes;
+}
+
+uint8_t *
+ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
+ socklen_t *fromlen)
+{
+ uint8_t *wire, *wireout;
+ ssize_t wire_size;
+
+ wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
+ if (!wire) {
+ *size = 0;
+ return NULL;
+ }
+
+ wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
+ (struct sockaddr *)from, fromlen);
+
+ /* recvfrom can also return 0 */
+ if (wire_size == -1 || wire_size == 0) {
+ *size = 0;
+ LDNS_FREE(wire);
+ return NULL;
+ }
+
+ *size = (size_t)wire_size;
+ wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
+ if(!wireout) LDNS_FREE(wire);
+
+ return wireout;
+}
+
+uint8_t *
+ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
+{
+ uint8_t *wire;
+ uint16_t wire_size;
+ ssize_t bytes = 0, rc = 0;
+
+ wire = LDNS_XMALLOC(uint8_t, 2);
+ if (!wire) {
+ *size = 0;
+ return NULL;
+ }
+
+ while (bytes < 2) {
+ if(!ldns_sock_wait(sockfd, timeout, 0)) {
+ *size = 0;
+ LDNS_FREE(wire);
+ return NULL;
+ }
+ rc = recv(sockfd, (void*) (wire + bytes),
+ (size_t) (2 - bytes), 0);
+ if (rc == -1 || rc == 0) {
+ *size = 0;
+ LDNS_FREE(wire);
+ return NULL;
+ }
+ bytes += rc;
+ }
+
+ wire_size = ldns_read_uint16(wire);
+
+ LDNS_FREE(wire);
+ wire = LDNS_XMALLOC(uint8_t, wire_size);
+ if (!wire) {
+ *size = 0;
+ return NULL;
+ }
+ bytes = 0;
+
+ while (bytes < (ssize_t) wire_size) {
+ if(!ldns_sock_wait(sockfd, timeout, 0)) {
+ *size = 0;
+ LDNS_FREE(wire);
+ return NULL;
+ }
+ rc = recv(sockfd, (void*) (wire + bytes),
+ (size_t) (wire_size - bytes), 0);
+ if (rc == -1 || rc == 0) {
+ LDNS_FREE(wire);
+ *size = 0;
+ return NULL;
+ }
+ bytes += rc;
+ }
+
+ *size = (size_t) bytes;
+ return wire;
+}
+
+uint8_t *
+ldns_tcp_read_wire(int sockfd, size_t *size)
+{
+ uint8_t *wire;
+ uint16_t wire_size;
+ ssize_t bytes = 0, rc = 0;
+
+ wire = LDNS_XMALLOC(uint8_t, 2);
+ if (!wire) {
+ *size = 0;
+ return NULL;
+ }
+
+ while (bytes < 2) {
+ rc = recv(sockfd, (void*) (wire + bytes),
+ (size_t) (2 - bytes), 0);
+ if (rc == -1 || rc == 0) {
+ *size = 0;
+ LDNS_FREE(wire);
+ return NULL;
+ }
+ bytes += rc;
+ }
+
+ wire_size = ldns_read_uint16(wire);
+
+ LDNS_FREE(wire);
+ wire = LDNS_XMALLOC(uint8_t, wire_size);
+ if (!wire) {
+ *size = 0;
+ return NULL;
+ }
+ bytes = 0;
+
+ while (bytes < (ssize_t) wire_size) {
+ rc = recv(sockfd, (void*) (wire + bytes),
+ (size_t) (wire_size - bytes), 0);
+ if (rc == -1 || rc == 0) {
+ LDNS_FREE(wire);
+ *size = 0;
+ return NULL;
+ }
+ bytes += rc;
+ }
+
+ *size = (size_t) bytes;
+ return wire;
+}
+
+/* keep in mind that in DNS tcp messages the first 2 bytes signal the
+ * amount data to expect
+ */
+ldns_status
+ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to,
+ socklen_t tolen, struct timeval timeout, size_t *answer_size)
+{
+ int sockfd;
+ uint8_t *answer;
+
+ sockfd = ldns_tcp_bgsend(qbin, to, tolen, timeout);
+
+ if (sockfd == 0) {
+ return LDNS_STATUS_ERR;
+ }
+
+ answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+
+ if (*answer_size == 0) {
+ /* oops */
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ /* resize accordingly */
+ *result = (uint8_t*)LDNS_XREALLOC(answer, uint8_t *, (size_t)*answer_size);
+ if(!*result) {
+ LDNS_FREE(answer);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ return LDNS_STATUS_OK;
+}
+
+int
+ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout)
+{
+ int sockfd;
+
+ sockfd = ldns_tcp_connect(to, tolen, timeout);
+
+ if (sockfd == 0) {
+ return 0;
+ }
+
+ if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+
+ return sockfd;
+}
+
+/* code from rdata.c */
+struct sockaddr_storage *
+ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size)
+{
+ struct sockaddr_storage *data;
+ struct sockaddr_in *data_in;
+ struct sockaddr_in6 *data_in6;
+
+ data = LDNS_MALLOC(struct sockaddr_storage);
+ if (!data) {
+ return NULL;
+ }
+ /* zero the structure for portability */
+ memset(data, 0, sizeof(struct sockaddr_storage));
+ if (port == 0) {
+ port = LDNS_PORT;
+ }
+
+ switch(ldns_rdf_get_type(rd)) {
+ case LDNS_RDF_TYPE_A:
+#ifndef S_SPLINT_S
+ data->ss_family = AF_INET;
+#endif
+ data_in = (struct sockaddr_in*) data;
+ data_in->sin_port = (in_port_t)htons(port);
+ memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
+ *size = sizeof(struct sockaddr_in);
+ return data;
+ case LDNS_RDF_TYPE_AAAA:
+#ifndef S_SPLINT_S
+ data->ss_family = AF_INET6;
+#endif
+ data_in6 = (struct sockaddr_in6*) data;
+ data_in6->sin6_port = (in_port_t)htons(port);
+ memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
+ *size = sizeof(struct sockaddr_in6);
+ return data;
+ default:
+ LDNS_FREE(data);
+ return NULL;
+ }
+}
+
+#ifndef S_SPLINT_S
+ldns_rdf *
+ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port)
+{
+ ldns_rdf *addr;
+ struct sockaddr_in *data_in;
+ struct sockaddr_in6 *data_in6;
+
+ switch(sock->ss_family) {
+ case AF_INET:
+ data_in = (struct sockaddr_in*)sock;
+ if (port) {
+ *port = ntohs((uint16_t)data_in->sin_port);
+ }
+ addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
+ LDNS_IP4ADDRLEN, &data_in->sin_addr);
+ break;
+ case AF_INET6:
+ data_in6 = (struct sockaddr_in6*)sock;
+ if (port) {
+ *port = ntohs((uint16_t)data_in6->sin6_port);
+ }
+ addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
+ LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
+ break;
+ default:
+ if (port) {
+ *port = 0;
+ }
+ return NULL;
+ }
+ return addr;
+}
+#endif
+
+/* code from resolver.c */
+ldns_status
+ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
+{
+ ldns_pkt *query;
+ ldns_buffer *query_wire;
+
+ struct sockaddr_storage *ns = NULL;
+ size_t ns_len = 0;
+ size_t ns_i;
+ ldns_status status;
+
+ if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
+ return LDNS_STATUS_ERR;
+ }
+
+ query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
+
+ if (!query) {
+ return LDNS_STATUS_ADDRESS_ERR;
+ }
+ /* For AXFR, we have to make the connection ourselves */
+ /* try all nameservers (which usually would mean v4 fallback if
+ * @hostname is used */
+ for (ns_i = 0;
+ ns_i < ldns_resolver_nameserver_count(resolver) &&
+ resolver->_socket == 0;
+ ns_i++) {
+ ns = ldns_rdf2native_sockaddr_storage(
+ resolver->_nameservers[ns_i],
+ ldns_resolver_port(resolver), &ns_len);
+
+ resolver->_socket = ldns_tcp_connect(ns, (socklen_t)ns_len,
+ ldns_resolver_timeout(resolver));
+ }
+
+ if (resolver->_socket == 0) {
+ ldns_pkt_free(query);
+ LDNS_FREE(ns);
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+#ifdef HAVE_SSL
+ if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
+ status = ldns_pkt_tsig_sign(query,
+ ldns_resolver_tsig_keyname(resolver),
+ ldns_resolver_tsig_keydata(resolver),
+ 300, ldns_resolver_tsig_algorithm(resolver), NULL);
+ if (status != LDNS_STATUS_OK) {
+ /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+ we have to close the socket here! */
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return LDNS_STATUS_CRYPTO_TSIG_ERR;
+ }
+ }
+#endif /* HAVE_SSL */
+
+ /* Convert the query to a buffer
+ * Is this necessary?
+ */
+ query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if(!query_wire) {
+ ldns_pkt_free(query);
+ LDNS_FREE(ns);
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return LDNS_STATUS_MEM_ERR;
+ }
+ status = ldns_pkt2buffer_wire(query_wire, query);
+ if (status != LDNS_STATUS_OK) {
+ ldns_pkt_free(query);
+ ldns_buffer_free(query_wire);
+ LDNS_FREE(ns);
+
+ /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+ we have to close the socket here! */
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return status;
+ }
+ /* Send the query */
+ if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
+ (socklen_t)ns_len) == 0) {
+ ldns_pkt_free(query);
+ ldns_buffer_free(query_wire);
+ LDNS_FREE(ns);
+
+ /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
+ we have to close the socket here! */
+
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ ldns_pkt_free(query);
+ ldns_buffer_free(query_wire);
+ LDNS_FREE(ns);
+
+ /*
+ * The AXFR is done once the second SOA record is sent
+ */
+ resolver->_axfr_soa_count = 0;
+ return LDNS_STATUS_OK;
+}
diff --git a/3rdParty/Ldns/src/src/packet.c b/3rdParty/Ldns/src/src/packet.c
new file mode 100644
index 0000000..0ac5ca8
--- /dev/null
+++ b/3rdParty/Ldns/src/src/packet.c
@@ -0,0 +1,1007 @@
+/*
+ * packet.c
+ *
+ * dns packet implementation
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+#include <limits.h>
+
+#ifdef HAVE_SSL
+#include <openssl/rand.h>
+#endif
+
+/* Access functions
+ * do this as functions to get type checking
+ */
+
+#define LDNS_EDNS_MASK_DO_BIT 0x8000
+
+/* TODO defines for 3600 */
+/* convert to and from numerical flag values */
+ldns_lookup_table ldns_edns_flags[] = {
+ { 3600, "do"},
+ { 0, NULL}
+};
+
+/* read */
+uint16_t
+ldns_pkt_id(const ldns_pkt *packet)
+{
+ return packet->_header->_id;
+}
+
+bool
+ldns_pkt_qr(const ldns_pkt *packet)
+{
+ return packet->_header->_qr;
+}
+
+bool
+ldns_pkt_aa(const ldns_pkt *packet)
+{
+ return packet->_header->_aa;
+}
+
+bool
+ldns_pkt_tc(const ldns_pkt *packet)
+{
+ return packet->_header->_tc;
+}
+
+bool
+ldns_pkt_rd(const ldns_pkt *packet)
+{
+ return packet->_header->_rd;
+}
+
+bool
+ldns_pkt_cd(const ldns_pkt *packet)
+{
+ return packet->_header->_cd;
+}
+
+bool
+ldns_pkt_ra(const ldns_pkt *packet)
+{
+ return packet->_header->_ra;
+}
+
+bool
+ldns_pkt_ad(const ldns_pkt *packet)
+{
+ return packet->_header->_ad;
+}
+
+ldns_pkt_opcode
+ldns_pkt_get_opcode(const ldns_pkt *packet)
+{
+ return packet->_header->_opcode;
+}
+
+ldns_pkt_rcode
+ldns_pkt_get_rcode(const ldns_pkt *packet)
+{
+ return packet->_header->_rcode;
+}
+
+uint16_t
+ldns_pkt_qdcount(const ldns_pkt *packet)
+{
+ return packet->_header->_qdcount;
+}
+
+uint16_t
+ldns_pkt_ancount(const ldns_pkt *packet)
+{
+ return packet->_header->_ancount;
+}
+
+uint16_t
+ldns_pkt_nscount(const ldns_pkt *packet)
+{
+ return packet->_header->_nscount;
+}
+
+uint16_t
+ldns_pkt_arcount(const ldns_pkt *packet)
+{
+ return packet->_header->_arcount;
+}
+
+ldns_rr_list *
+ldns_pkt_question(const ldns_pkt *packet)
+{
+ return packet->_question;
+}
+
+ldns_rr_list *
+ldns_pkt_answer(const ldns_pkt *packet)
+{
+ return packet->_answer;
+}
+
+ldns_rr_list *
+ldns_pkt_authority(const ldns_pkt *packet)
+{
+ return packet->_authority;
+}
+
+ldns_rr_list *
+ldns_pkt_additional(const ldns_pkt *packet)
+{
+ return packet->_additional;
+}
+
+/* return ALL section concatenated */
+ldns_rr_list *
+ldns_pkt_all(const ldns_pkt *packet)
+{
+ ldns_rr_list *all, *prev_all;
+
+ all = ldns_rr_list_cat_clone(
+ ldns_pkt_question(packet),
+ ldns_pkt_answer(packet));
+ prev_all = all;
+ all = ldns_rr_list_cat_clone(all,
+ ldns_pkt_authority(packet));
+ ldns_rr_list_deep_free(prev_all);
+ prev_all = all;
+ all = ldns_rr_list_cat_clone(all,
+ ldns_pkt_additional(packet));
+ ldns_rr_list_deep_free(prev_all);
+ return all;
+}
+
+ldns_rr_list *
+ldns_pkt_all_noquestion(const ldns_pkt *packet)
+{
+ ldns_rr_list *all, *all2;
+
+ all = ldns_rr_list_cat_clone(
+ ldns_pkt_answer(packet),
+ ldns_pkt_authority(packet));
+ all2 = ldns_rr_list_cat_clone(all,
+ ldns_pkt_additional(packet));
+
+ ldns_rr_list_deep_free(all);
+ return all2;
+}
+
+size_t
+ldns_pkt_size(const ldns_pkt *packet)
+{
+ return packet->_size;
+}
+
+uint32_t
+ldns_pkt_querytime(const ldns_pkt *packet)
+{
+ return packet->_querytime;
+}
+
+ldns_rdf *
+ldns_pkt_answerfrom(const ldns_pkt *packet)
+{
+ return packet->_answerfrom;
+}
+
+struct timeval
+ldns_pkt_timestamp(const ldns_pkt *packet)
+{
+ return packet->timestamp;
+}
+
+uint16_t
+ldns_pkt_edns_udp_size(const ldns_pkt *packet)
+{
+ return packet->_edns_udp_size;
+}
+
+uint8_t
+ldns_pkt_edns_extended_rcode(const ldns_pkt *packet)
+{
+ return packet->_edns_extended_rcode;
+}
+
+uint8_t
+ldns_pkt_edns_version(const ldns_pkt *packet)
+{
+ return packet->_edns_version;
+}
+
+uint16_t
+ldns_pkt_edns_z(const ldns_pkt *packet)
+{
+ return packet->_edns_z;
+}
+
+bool
+ldns_pkt_edns_do(const ldns_pkt *packet)
+{
+ return (packet->_edns_z & LDNS_EDNS_MASK_DO_BIT);
+}
+
+void
+ldns_pkt_set_edns_do(ldns_pkt *packet, bool value)
+{
+ if (value) {
+ packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT;
+ } else {
+ packet->_edns_z = packet->_edns_z & ~LDNS_EDNS_MASK_DO_BIT;
+ }
+}
+
+ldns_rdf *
+ldns_pkt_edns_data(const ldns_pkt *packet)
+{
+ return packet->_edns_data;
+}
+
+/* return only those rr that share the ownername */
+ldns_rr_list *
+ldns_pkt_rr_list_by_name(ldns_pkt *packet,
+ ldns_rdf *ownername,
+ ldns_pkt_section sec)
+{
+ ldns_rr_list *rrs;
+ ldns_rr_list *new;
+ ldns_rr_list *ret;
+ uint16_t i;
+
+ if (!packet) {
+ return NULL;
+ }
+
+ rrs = ldns_pkt_get_section_clone(packet, sec);
+ new = ldns_rr_list_new();
+ ret = NULL;
+
+ for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ if (ldns_rdf_compare(ldns_rr_owner(
+ ldns_rr_list_rr(rrs, i)),
+ ownername) == 0) {
+ /* owner names match */
+ ldns_rr_list_push_rr(new, ldns_rr_list_rr(rrs, i));
+ ret = new;
+ }
+ }
+ return ret;
+}
+
+/* return only those rr that share a type */
+ldns_rr_list *
+ldns_pkt_rr_list_by_type(const ldns_pkt *packet,
+ ldns_rr_type type,
+ ldns_pkt_section sec)
+{
+ ldns_rr_list *rrs;
+ ldns_rr_list *new;
+ uint16_t i;
+
+ if(!packet) {
+ return NULL;
+ }
+
+ rrs = ldns_pkt_get_section_clone(packet, sec);
+ new = ldns_rr_list_new();
+
+ for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i))) {
+ /* types match */
+ ldns_rr_list_push_rr(new,
+ ldns_rr_clone(
+ ldns_rr_list_rr(rrs, i))
+ );
+ }
+ }
+ ldns_rr_list_deep_free(rrs);
+
+ if (ldns_rr_list_rr_count(new) == 0) {
+ ldns_rr_list_free(new);
+ return NULL;
+ } else {
+ return new;
+ }
+}
+
+/* return only those rrs that share name and type */
+ldns_rr_list *
+ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet,
+ const ldns_rdf *ownername,
+ ldns_rr_type type,
+ ldns_pkt_section sec)
+{
+ ldns_rr_list *rrs;
+ ldns_rr_list *new;
+ ldns_rr_list *ret;
+ uint16_t i;
+
+ if(!packet) {
+ return NULL;
+ }
+
+ rrs = ldns_pkt_get_section_clone(packet, sec);
+ new = ldns_rr_list_new();
+ ret = NULL;
+
+ for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) &&
+ ldns_rdf_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)),
+ ownername
+ ) == 0
+ ) {
+ /* types match */
+ ldns_rr_list_push_rr(new, ldns_rr_clone(ldns_rr_list_rr(rrs, i)));
+ ret = new;
+ }
+ }
+ ldns_rr_list_deep_free(rrs);
+ if (!ret) {
+ ldns_rr_list_free(new);
+ }
+ return ret;
+}
+
+bool
+ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr)
+{
+ bool result = false;
+
+ switch (sec) {
+ case LDNS_SECTION_QUESTION:
+ return ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr);
+ case LDNS_SECTION_ANSWER:
+ return ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr);
+ case LDNS_SECTION_AUTHORITY:
+ return ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr);
+ case LDNS_SECTION_ADDITIONAL:
+ return ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr);
+ case LDNS_SECTION_ANY:
+ result = ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr);
+ case LDNS_SECTION_ANY_NOQUESTION:
+ result = result
+ || ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr)
+ || ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr)
+ || ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr);
+ }
+
+ return result;
+}
+
+uint16_t
+ldns_pkt_section_count(const ldns_pkt *packet, ldns_pkt_section s)
+{
+ switch(s) {
+ case LDNS_SECTION_QUESTION:
+ return ldns_pkt_qdcount(packet);
+ case LDNS_SECTION_ANSWER:
+ return ldns_pkt_ancount(packet);
+ case LDNS_SECTION_AUTHORITY:
+ return ldns_pkt_nscount(packet);
+ case LDNS_SECTION_ADDITIONAL:
+ return ldns_pkt_arcount(packet);
+ case LDNS_SECTION_ANY:
+ return ldns_pkt_qdcount(packet) +
+ ldns_pkt_ancount(packet) +
+ ldns_pkt_nscount(packet) +
+ ldns_pkt_arcount(packet);
+ case LDNS_SECTION_ANY_NOQUESTION:
+ return ldns_pkt_ancount(packet) +
+ ldns_pkt_nscount(packet) +
+ ldns_pkt_arcount(packet);
+ default:
+ return 0;
+ }
+}
+
+bool
+ldns_pkt_empty(ldns_pkt *p)
+{
+ if (!p) {
+ return true; /* NULL is empty? */
+ }
+ if (ldns_pkt_section_count(p, LDNS_SECTION_ANY) > 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+ldns_rr_list *
+ldns_pkt_get_section_clone(const ldns_pkt *packet, ldns_pkt_section s)
+{
+ switch(s) {
+ case LDNS_SECTION_QUESTION:
+ return ldns_rr_list_clone(ldns_pkt_question(packet));
+ case LDNS_SECTION_ANSWER:
+ return ldns_rr_list_clone(ldns_pkt_answer(packet));
+ case LDNS_SECTION_AUTHORITY:
+ return ldns_rr_list_clone(ldns_pkt_authority(packet));
+ case LDNS_SECTION_ADDITIONAL:
+ return ldns_rr_list_clone(ldns_pkt_additional(packet));
+ case LDNS_SECTION_ANY:
+ /* these are already clones */
+ return ldns_pkt_all(packet);
+ case LDNS_SECTION_ANY_NOQUESTION:
+ return ldns_pkt_all_noquestion(packet);
+ default:
+ return NULL;
+ }
+}
+
+ldns_rr *ldns_pkt_tsig(const ldns_pkt *pkt) {
+ return pkt->_tsig_rr;
+}
+
+/* write */
+void
+ldns_pkt_set_id(ldns_pkt *packet, uint16_t id)
+{
+ packet->_header->_id = id;
+}
+
+void
+ldns_pkt_set_random_id(ldns_pkt *packet)
+{
+ uint16_t rid = ldns_get_random();
+ ldns_pkt_set_id(packet, rid);
+}
+
+
+void
+ldns_pkt_set_qr(ldns_pkt *packet, bool qr)
+{
+ packet->_header->_qr = qr;
+}
+
+void
+ldns_pkt_set_aa(ldns_pkt *packet, bool aa)
+{
+ packet->_header->_aa = aa;
+}
+
+void
+ldns_pkt_set_tc(ldns_pkt *packet, bool tc)
+{
+ packet->_header->_tc = tc;
+}
+
+void
+ldns_pkt_set_rd(ldns_pkt *packet, bool rd)
+{
+ packet->_header->_rd = rd;
+}
+
+void
+ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr)
+{
+ p->_additional = rr;
+}
+
+void
+ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr)
+{
+ p->_question = rr;
+}
+
+void
+ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr)
+{
+ p->_answer = rr;
+}
+
+void
+ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr)
+{
+ p->_authority = rr;
+}
+
+void
+ldns_pkt_set_cd(ldns_pkt *packet, bool cd)
+{
+ packet->_header->_cd = cd;
+}
+
+void
+ldns_pkt_set_ra(ldns_pkt *packet, bool ra)
+{
+ packet->_header->_ra = ra;
+}
+
+void
+ldns_pkt_set_ad(ldns_pkt *packet, bool ad)
+{
+ packet->_header->_ad = ad;
+}
+
+void
+ldns_pkt_set_opcode(ldns_pkt *packet, ldns_pkt_opcode opcode)
+{
+ packet->_header->_opcode = opcode;
+}
+
+void
+ldns_pkt_set_rcode(ldns_pkt *packet, uint8_t rcode)
+{
+ packet->_header->_rcode = rcode;
+}
+
+void
+ldns_pkt_set_qdcount(ldns_pkt *packet, uint16_t qdcount)
+{
+ packet->_header->_qdcount = qdcount;
+}
+
+void
+ldns_pkt_set_ancount(ldns_pkt *packet, uint16_t ancount)
+{
+ packet->_header->_ancount = ancount;
+}
+
+void
+ldns_pkt_set_nscount(ldns_pkt *packet, uint16_t nscount)
+{
+ packet->_header->_nscount = nscount;
+}
+
+void
+ldns_pkt_set_arcount(ldns_pkt *packet, uint16_t arcount)
+{
+ packet->_header->_arcount = arcount;
+}
+
+void
+ldns_pkt_set_querytime(ldns_pkt *packet, uint32_t time)
+{
+ packet->_querytime = time;
+}
+
+void
+ldns_pkt_set_answerfrom(ldns_pkt *packet, ldns_rdf *answerfrom)
+{
+ packet->_answerfrom = answerfrom;
+}
+
+void
+ldns_pkt_set_timestamp(ldns_pkt *packet, struct timeval timeval)
+{
+ packet->timestamp.tv_sec = timeval.tv_sec;
+ packet->timestamp.tv_usec = timeval.tv_usec;
+}
+
+void
+ldns_pkt_set_size(ldns_pkt *packet, size_t s)
+{
+ packet->_size = s;
+}
+
+void
+ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s)
+{
+ packet->_edns_udp_size = s;
+}
+
+void
+ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c)
+{
+ packet->_edns_extended_rcode = c;
+}
+
+void
+ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v)
+{
+ packet->_edns_version = v;
+}
+
+void
+ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z)
+{
+ packet->_edns_z = z;
+}
+
+void
+ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data)
+{
+ packet->_edns_data = data;
+}
+
+void
+ldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count)
+{
+ switch(s) {
+ case LDNS_SECTION_QUESTION:
+ ldns_pkt_set_qdcount(packet, count);
+ break;
+ case LDNS_SECTION_ANSWER:
+ ldns_pkt_set_ancount(packet, count);
+ break;
+ case LDNS_SECTION_AUTHORITY:
+ ldns_pkt_set_nscount(packet, count);
+ break;
+ case LDNS_SECTION_ADDITIONAL:
+ ldns_pkt_set_arcount(packet, count);
+ break;
+ case LDNS_SECTION_ANY:
+ case LDNS_SECTION_ANY_NOQUESTION:
+ break;
+ }
+}
+
+void ldns_pkt_set_tsig(ldns_pkt *pkt, ldns_rr *rr)
+{
+ pkt->_tsig_rr = rr;
+}
+
+bool
+ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr)
+{
+ switch(section) {
+ case LDNS_SECTION_QUESTION:
+ ldns_rr_list_push_rr(ldns_pkt_question(packet), rr);
+ ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1);
+ break;
+ case LDNS_SECTION_ANSWER:
+ ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr);
+ ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1);
+ break;
+ case LDNS_SECTION_AUTHORITY:
+ ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr);
+ ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1);
+ break;
+ case LDNS_SECTION_ADDITIONAL:
+ ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr);
+ ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1);
+ break;
+ case LDNS_SECTION_ANY:
+ case LDNS_SECTION_ANY_NOQUESTION:
+ /* shouldn't this error? */
+ break;
+ }
+ return true;
+}
+
+bool
+ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr)
+{
+
+ /* check to see if its there */
+ if (ldns_pkt_rr(pkt, sec, rr)) {
+ /* already there */
+ return false;
+ }
+ return ldns_pkt_push_rr(pkt, sec, rr);
+}
+
+bool
+ldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
+{
+ size_t i;
+ for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
+ if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
+{
+ size_t i;
+ for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
+ if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+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)
+ );
+}
+
+
+/* Create/destroy/convert functions
+ */
+ldns_pkt *
+ldns_pkt_new()
+{
+ ldns_pkt *packet;
+ packet = LDNS_MALLOC(ldns_pkt);
+ if (!packet) {
+ return NULL;
+ }
+
+ packet->_header = LDNS_MALLOC(ldns_hdr);
+ if (!packet->_header) {
+ LDNS_FREE(packet);
+ return NULL;
+ }
+
+ packet->_question = ldns_rr_list_new();
+ packet->_answer = ldns_rr_list_new();
+ packet->_authority = ldns_rr_list_new();
+ packet->_additional = ldns_rr_list_new();
+
+ /* default everything to false */
+ ldns_pkt_set_qr(packet, false);
+ ldns_pkt_set_aa(packet, false);
+ ldns_pkt_set_tc(packet, false);
+ ldns_pkt_set_rd(packet, false);
+ ldns_pkt_set_ra(packet, false);
+ ldns_pkt_set_ad(packet, false);
+ ldns_pkt_set_cd(packet, false);
+
+ ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY);
+ ldns_pkt_set_rcode(packet, 0);
+ ldns_pkt_set_id(packet, 0);
+ ldns_pkt_set_size(packet, 0);
+ ldns_pkt_set_querytime(packet, 0);
+ memset(&packet->timestamp, 0, sizeof(packet->timestamp));
+ ldns_pkt_set_answerfrom(packet, NULL);
+ ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0);
+ ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0);
+ ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0);
+ ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0);
+
+ ldns_pkt_set_edns_udp_size(packet, 0);
+ ldns_pkt_set_edns_extended_rcode(packet, 0);
+ ldns_pkt_set_edns_version(packet, 0);
+ ldns_pkt_set_edns_z(packet, 0);
+ ldns_pkt_set_edns_data(packet, NULL);
+
+ ldns_pkt_set_tsig(packet, NULL);
+
+ return packet;
+}
+
+void
+ldns_pkt_free(ldns_pkt *packet)
+{
+ if (packet) {
+ LDNS_FREE(packet->_header);
+ ldns_rr_list_deep_free(packet->_question);
+ ldns_rr_list_deep_free(packet->_answer);
+ ldns_rr_list_deep_free(packet->_authority);
+ ldns_rr_list_deep_free(packet->_additional);
+ ldns_rr_free(packet->_tsig_rr);
+ ldns_rdf_deep_free(packet->_edns_data);
+ LDNS_FREE(packet);
+ }
+}
+
+bool
+ldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags)
+{
+ if (!packet) {
+ return false;
+ }
+ if ((flags & LDNS_QR) == LDNS_QR) {
+ ldns_pkt_set_qr(packet, true);
+ }
+ if ((flags & LDNS_AA) == LDNS_AA) {
+ ldns_pkt_set_aa(packet, true);
+ }
+ if ((flags & LDNS_RD) == LDNS_RD) {
+ ldns_pkt_set_rd(packet, true);
+ }
+ if ((flags & LDNS_TC) == LDNS_TC) {
+ ldns_pkt_set_tc(packet, true);
+ }
+ if ((flags & LDNS_CD) == LDNS_CD) {
+ ldns_pkt_set_cd(packet, true);
+ }
+ if ((flags & LDNS_RA) == LDNS_RA) {
+ ldns_pkt_set_ra(packet, true);
+ }
+ if ((flags & LDNS_AD) == LDNS_AD) {
+ ldns_pkt_set_ad(packet, true);
+ }
+ return true;
+}
+
+ldns_status
+ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type,
+ ldns_rr_class rr_class, uint16_t flags)
+{
+ ldns_pkt *packet;
+ ldns_rr *question_rr;
+ ldns_rdf *name_rdf;
+
+ packet = ldns_pkt_new();
+ if (!packet) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ if (!ldns_pkt_set_flags(packet, flags)) {
+ return LDNS_STATUS_ERR;
+ }
+
+ question_rr = ldns_rr_new();
+ if (!question_rr) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ if (rr_type == 0) {
+ rr_type = LDNS_RR_TYPE_A;
+ }
+ if (rr_class == 0) {
+ rr_class = LDNS_RR_CLASS_IN;
+ }
+
+ if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) {
+ ldns_rr_set_owner(question_rr, name_rdf);
+ ldns_rr_set_type(question_rr, rr_type);
+ ldns_rr_set_class(question_rr, rr_class);
+ ldns_rr_set_question(question_rr, true);
+
+ ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
+ } else {
+ ldns_rr_free(question_rr);
+ ldns_pkt_free(packet);
+ return LDNS_STATUS_ERR;
+ }
+
+ packet->_tsig_rr = NULL;
+
+ ldns_pkt_set_answerfrom(packet, NULL);
+ if (p) {
+ *p = packet;
+ return LDNS_STATUS_OK;
+ } else {
+ return LDNS_STATUS_NULL;
+ }
+}
+
+ldns_pkt *
+ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class,
+ uint16_t flags)
+{
+ ldns_pkt *packet;
+ ldns_rr *question_rr;
+
+ packet = ldns_pkt_new();
+ if (!packet) {
+ return NULL;
+ }
+
+ if (!ldns_pkt_set_flags(packet, flags)) {
+ return NULL;
+ }
+
+ question_rr = ldns_rr_new();
+ if (!question_rr) {
+ return NULL;
+ }
+
+ if (rr_type == 0) {
+ rr_type = LDNS_RR_TYPE_A;
+ }
+ if (rr_class == 0) {
+ rr_class = LDNS_RR_CLASS_IN;
+ }
+
+ ldns_rr_set_owner(question_rr, rr_name);
+ ldns_rr_set_type(question_rr, rr_type);
+ ldns_rr_set_class(question_rr, rr_class);
+ ldns_rr_set_question(question_rr, true);
+
+ packet->_tsig_rr = NULL;
+
+ ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
+
+ return packet;
+}
+
+ldns_pkt_type
+ldns_pkt_reply_type(ldns_pkt *p)
+{
+ ldns_rr_list *tmp;
+
+ if (!p) {
+ return LDNS_PACKET_UNKNOWN;
+ }
+
+ if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) {
+ return LDNS_PACKET_NXDOMAIN;
+ }
+
+ if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0
+ && ldns_pkt_nscount(p) == 1) {
+
+ /* check for SOA */
+ tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA,
+ LDNS_SECTION_AUTHORITY);
+ if (tmp) {
+ ldns_rr_list_deep_free(tmp);
+ return LDNS_PACKET_NODATA;
+ } else {
+ /* I have no idea ... */
+ }
+ }
+
+ if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) {
+ tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS,
+ LDNS_SECTION_AUTHORITY);
+ if (tmp) {
+ /* there are nameservers here */
+ ldns_rr_list_deep_free(tmp);
+ return LDNS_PACKET_REFERRAL;
+ } else {
+ /* I have no idea */
+ }
+ ldns_rr_list_deep_free(tmp);
+ }
+
+ /* if we cannot determine the packet type, we say it's an
+ * answer...
+ */
+ return LDNS_PACKET_ANSWER;
+}
+
+ldns_pkt *
+ldns_pkt_clone(ldns_pkt *pkt)
+{
+ ldns_pkt *new_pkt;
+
+ if (!pkt) {
+ return NULL;
+ }
+ new_pkt = ldns_pkt_new();
+
+ ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt));
+ ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt));
+ ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt));
+ ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt));
+ ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt));
+ ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt));
+ ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt));
+ ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt));
+ ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt));
+ ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt));
+ ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt));
+ ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt));
+ ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt));
+ ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt));
+ ldns_pkt_set_answerfrom(new_pkt, ldns_pkt_answerfrom(pkt));
+ ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt));
+ ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt));
+ ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt)));
+
+ ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt));
+ ldns_pkt_set_edns_extended_rcode(new_pkt,
+ ldns_pkt_edns_extended_rcode(pkt));
+ ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt));
+ ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt));
+ if(ldns_pkt_edns_data(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));
+
+ ldns_rr_list_deep_free(new_pkt->_question);
+ ldns_rr_list_deep_free(new_pkt->_answer);
+ ldns_rr_list_deep_free(new_pkt->_authority);
+ ldns_rr_list_deep_free(new_pkt->_additional);
+ new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt));
+ new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt));
+ new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt));
+ new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt));
+ return new_pkt;
+}
diff --git a/3rdParty/Ldns/src/src/parse.c b/3rdParty/Ldns/src/src/parse.c
new file mode 100644
index 0000000..15cc300
--- /dev/null
+++ b/3rdParty/Ldns/src/src/parse.c
@@ -0,0 +1,450 @@
+/*
+ * a generic (simple) parser. Use to parse rr's, private key
+ * information and /etc/resolv.conf files
+ *
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+#include <ldns/config.h>
+#include <ldns/ldns.h>
+
+#include <limits.h>
+#include <strings.h>
+
+ldns_lookup_table ldns_directive_types[] = {
+ { LDNS_DIR_TTL, "$TTL" },
+ { LDNS_DIR_ORIGIN, "$ORIGIN" },
+ { LDNS_DIR_INCLUDE, "$INCLUDE" },
+ { 0, NULL }
+};
+
+/* add max_limit here? */
+ssize_t
+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)
+{
+ int c, prev_c;
+ int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
+ int com, quoted;
+ char *t;
+ size_t i;
+ const char *d;
+ const char *del;
+
+ /* standard delimeters */
+ if (!delim) {
+ /* from isspace(3) */
+ del = LDNS_PARSE_NORMAL;
+ } else {
+ del = delim;
+ }
+
+ p = 0;
+ i = 0;
+ com = 0;
+ quoted = 0;
+ prev_c = 0;
+ t = token;
+ if (del[0] == '"') {
+ quoted = 1;
+ }
+ while ((c = getc(f)) != EOF) {
+ if (c == '\r') /* carriage return */
+ c = ' ';
+ if (c == '(' && prev_c != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p++;
+ }
+ prev_c = c;
+ continue;
+ }
+
+ if (c == ')' && prev_c != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p--;
+ }
+ prev_c = c;
+ continue;
+ }
+
+ if (p < 0) {
+ /* more ) then ( - close off the string */
+ *t = '\0';
+ return 0;
+ }
+
+ /* do something with comments ; */
+ if (c == ';' && quoted == 0) {
+ if (prev_c != '\\') {
+ com = 1;
+ }
+ }
+ if (c == '\"' && com == 0 && prev_c != '\\') {
+ quoted = 1 - quoted;
+ }
+
+ if (c == '\n' && com != 0) {
+ /* comments */
+ com = 0;
+ *t = ' ';
+ if (line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ if (p == 0 && i > 0) {
+ goto tokenread;
+ } else {
+ prev_c = c;
+ continue;
+ }
+ }
+
+ if (com == 1) {
+ *t = ' ';
+ prev_c = c;
+ continue;
+ }
+
+ if (c == '\n' && p != 0 && t > token) {
+ /* in parentheses */
+ if (line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ *t++ = ' ';
+ prev_c = c;
+ continue;
+ }
+
+ /* check if we hit the delim */
+ for (d = del; *d; d++) {
+ if (c == *d && i > 0 && prev_c != '\\' && p == 0) {
+ if (c == '\n' && line_nr) {
+ *line_nr = *line_nr + 1;
+ }
+ goto tokenread;
+ }
+ }
+ if (c != '\0' && c != '\n') {
+ i++;
+ }
+ if (limit > 0 && i >= limit) {
+ *t = '\0';
+ return -1;
+ }
+ if (c != '\0' && c != '\n') {
+ *t++ = c;
+ }
+ if (c == '\\' && prev_c == '\\')
+ prev_c = 0;
+ else prev_c = c;
+ }
+ *t = '\0';
+ if (c == EOF) {
+ return (ssize_t)i;
+ }
+
+ if (i == 0) {
+ /* nothing read */
+ return -1;
+ }
+ if (p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+
+tokenread:
+ ldns_fskipcs_l(f, delim, line_nr);
+ *t = '\0';
+ if (p != 0) {
+ return -1;
+ }
+
+ return (ssize_t)i;
+}
+
+ssize_t
+ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
+ const char *d_del, size_t data_limit)
+{
+ return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
+ data_limit, NULL);
+}
+
+ssize_t
+ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
+ const char *d_del, size_t data_limit, int *line_nr)
+{
+ /* we assume: keyword|sep|data */
+ char *fkeyword;
+ ssize_t i;
+
+ if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+ return -1;
+ fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN);
+ if(!fkeyword)
+ return -1;
+
+ i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
+ if(i==0 || i==-1) {
+ LDNS_FREE(fkeyword);
+ return -1;
+ }
+
+ /* case??? i instead of strlen? */
+ if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
+ /* whee! */
+ /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
+ i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr);
+ LDNS_FREE(fkeyword);
+ return i;
+ } else {
+ /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
+ LDNS_FREE(fkeyword);
+ return -1;
+ }
+}
+
+
+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 com, quoted;
+ char *t;
+ size_t i;
+ const char *d;
+ const char *del;
+
+ /* standard delimiters */
+ if (!delim) {
+ /* from isspace(3) */
+ del = LDNS_PARSE_NORMAL;
+ } else {
+ del = delim;
+ }
+
+ p = 0;
+ i = 0;
+ com = 0;
+ quoted = 0;
+ t = token;
+ lc = 0;
+ if (del[0] == '"') {
+ quoted = 1;
+ }
+
+ while ((c = ldns_bgetc(b)) != EOF) {
+ if (c == '\r') /* carriage return */
+ c = ' ';
+ if (c == '(' && lc != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p++;
+ }
+ lc = c;
+ continue;
+ }
+
+ if (c == ')' && lc != '\\' && !quoted) {
+ /* this only counts for non-comments */
+ if (com == 0) {
+ p--;
+ }
+ lc = c;
+ continue;
+ }
+
+ if (p < 0) {
+ /* more ) then ( */
+ *t = '\0';
+ return 0;
+ }
+
+ /* do something with comments ; */
+ if (c == ';' && quoted == 0) {
+ if (lc != '\\') {
+ com = 1;
+ }
+ }
+ if (c == '"' && com == 0 && lc != '\\') {
+ quoted = 1 - quoted;
+ }
+
+ if (c == '\n' && com != 0) {
+ /* comments */
+ com = 0;
+ *t = ' ';
+ lc = c;
+ continue;
+ }
+
+ if (com == 1) {
+ *t = ' ';
+ lc = c;
+ continue;
+ }
+
+ if (c == '\n' && p != 0) {
+ /* in parentheses */
+ *t++ = ' ';
+ lc = c;
+ continue;
+ }
+
+ /* check if we hit the delim */
+ for (d = del; *d; d++) {
+ if (c == *d && lc != '\\' && p == 0) {
+ goto tokenread;
+ }
+ }
+
+ i++;
+ if (limit > 0 && i >= limit) {
+ *t = '\0';
+ return -1;
+ }
+ *t++ = c;
+
+ if (c == '\\' && lc == '\\') {
+ lc = 0;
+ } else {
+ lc = c;
+ }
+ }
+ *t = '\0';
+ if (i == 0) {
+ /* nothing read */
+ return -1;
+ }
+ if (p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+
+tokenread:
+ ldns_bskipcs(b, delim);
+ *t = '\0';
+
+ if (p != 0) {
+ return -1;
+ }
+ return (ssize_t)i;
+}
+
+void
+ldns_bskipc(ldns_buffer *buffer, char c)
+{
+ while (c == (char) ldns_buffer_read_u8_at(buffer, ldns_buffer_position(buffer))) {
+ if (ldns_buffer_available_at(buffer,
+ buffer->_position + sizeof(char), sizeof(char))) {
+ buffer->_position += sizeof(char);
+ } else {
+ return;
+ }
+ }
+}
+
+void
+ldns_bskipcs(ldns_buffer *buffer, const char *s)
+{
+ bool found;
+ char c;
+ const char *d;
+
+ while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) {
+ c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position);
+ found = false;
+ for (d = s; *d; d++) {
+ if (*d == c) {
+ found = true;
+ }
+ }
+ if (found && buffer->_limit > buffer->_position) {
+ buffer->_position += sizeof(char);
+ } else {
+ return;
+ }
+ }
+}
+
+void
+ldns_fskipc(FILE *fp, char c)
+{
+ fp = fp;
+ c = c;
+}
+
+
+void
+ldns_fskipcs(FILE *fp, const char *s)
+{
+ ldns_fskipcs_l(fp, s, NULL);
+}
+
+void
+ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr)
+{
+ bool found;
+ int c;
+ const char *d;
+
+ while ((c = fgetc(fp)) != EOF) {
+ if (line_nr && c == '\n') {
+ *line_nr = *line_nr + 1;
+ }
+ found = false;
+ for (d = s; *d; d++) {
+ if (*d == c) {
+ found = true;
+ }
+ }
+ if (!found) {
+ /* with getc, we've read too far */
+ ungetc(c, fp);
+ return;
+ }
+ }
+}
+
+ssize_t
+ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char
+*data, const char *d_del, size_t data_limit)
+{
+ /* we assume: keyword|sep|data */
+ char *fkeyword;
+ ssize_t i;
+
+ if(strlen(keyword) >= LDNS_MAX_KEYWORDLEN)
+ return -1;
+ fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN);
+ if(!fkeyword)
+ return -1; /* out of memory */
+
+ i = ldns_bget_token(b, fkeyword, k_del, data_limit);
+ if(i==0 || i==-1) {
+ LDNS_FREE(fkeyword);
+ return -1; /* nothing read */
+ }
+
+ /* case??? */
+ if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) {
+ LDNS_FREE(fkeyword);
+ /* whee, the match! */
+ /* retrieve it's data */
+ i = ldns_bget_token(b, data, d_del, 0);
+ return i;
+ } else {
+ LDNS_FREE(fkeyword);
+ return -1;
+ }
+}
+
diff --git a/3rdParty/Ldns/src/src/rbtree.c b/3rdParty/Ldns/src/src/rbtree.c
new file mode 100644
index 0000000..217e61d
--- /dev/null
+++ b/3rdParty/Ldns/src/src/rbtree.c
@@ -0,0 +1,669 @@
+/*
+ * rbtree.c -- generic red black tree
+ *
+ * Taken from Unbound, modified for ldns
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * \file
+ * Implementation of a redblack tree.
+ */
+
+#include <ldns/config.h>
+#include <ldns/rbtree.h>
+#include <stdlib.h>
+
+/** Node colour black */
+#define BLACK 0
+/** Node colour red */
+#define RED 1
+
+/** the NULL node, global alloc */
+ldns_rbnode_t ldns_rbtree_null_node = {
+ LDNS_RBTREE_NULL, /* Parent. */
+ LDNS_RBTREE_NULL, /* Left. */
+ LDNS_RBTREE_NULL, /* Right. */
+ NULL, /* Key. */
+ NULL, /* Data. */
+ BLACK /* Color. */
+};
+
+/** rotate subtree left (to preserve redblack property) */
+static void ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
+/** rotate subtree right (to preserve redblack property) */
+static void ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
+/** Fixup node colours when insert happened */
+static void ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node);
+/** Fixup node colours when delete happened */
+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.
+ *
+ * Return NULL on failure.
+ *
+ */
+ldns_rbtree_t *
+ldns_rbtree_create (int (*cmpf)(const void *, const void *))
+{
+ ldns_rbtree_t *rbtree;
+
+ /* Allocate memory for it */
+ rbtree = (ldns_rbtree_t *) malloc(sizeof(ldns_rbtree_t));
+ if (!rbtree) {
+ return NULL;
+ }
+
+ /* Initialize it */
+ ldns_rbtree_init(rbtree, cmpf);
+
+ return rbtree;
+}
+
+void
+ldns_rbtree_init(ldns_rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
+{
+ /* Initialize it */
+ rbtree->root = LDNS_RBTREE_NULL;
+ rbtree->count = 0;
+ rbtree->cmp = cmpf;
+}
+
+void
+ldns_rbtree_free(ldns_rbtree_t *rbtree)
+{
+ free(rbtree);
+}
+
+/*
+ * Rotates the node to the left.
+ *
+ */
+static void
+ldns_rbtree_rotate_left(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *right = node->right;
+ node->right = right->left;
+ if (right->left != LDNS_RBTREE_NULL)
+ right->left->parent = node;
+
+ right->parent = node->parent;
+
+ if (node->parent != LDNS_RBTREE_NULL) {
+ if (node == node->parent->left) {
+ node->parent->left = right;
+ } else {
+ node->parent->right = right;
+ }
+ } else {
+ rbtree->root = right;
+ }
+ right->left = node;
+ node->parent = right;
+}
+
+/*
+ * Rotates the node to the right.
+ *
+ */
+static void
+ldns_rbtree_rotate_right(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *left = node->left;
+ node->left = left->right;
+ if (left->right != LDNS_RBTREE_NULL)
+ left->right->parent = node;
+
+ left->parent = node->parent;
+
+ if (node->parent != LDNS_RBTREE_NULL) {
+ if (node == node->parent->right) {
+ node->parent->right = left;
+ } else {
+ node->parent->left = left;
+ }
+ } else {
+ rbtree->root = left;
+ }
+ left->right = node;
+ node->parent = left;
+}
+
+static void
+ldns_rbtree_insert_fixup(ldns_rbtree_t *rbtree, ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *uncle;
+
+ /* While not at the root and need fixing... */
+ while (node != rbtree->root && node->parent->color == RED) {
+ /* If our parent is left child of our grandparent... */
+ if (node->parent == node->parent->parent->left) {
+ uncle = node->parent->parent->right;
+
+ /* If our uncle is red... */
+ if (uncle->color == RED) {
+ /* Paint the parent and the uncle black... */
+ node->parent->color = BLACK;
+ uncle->color = BLACK;
+
+ /* And the grandparent red... */
+ node->parent->parent->color = RED;
+
+ /* And continue fixing the grandparent */
+ node = node->parent->parent;
+ } else { /* Our uncle is black... */
+ /* Are we the right child? */
+ if (node == node->parent->right) {
+ node = node->parent;
+ ldns_rbtree_rotate_left(rbtree, node);
+ }
+ /* Now we're the left child, repaint and rotate... */
+ node->parent->color = BLACK;
+ node->parent->parent->color = RED;
+ ldns_rbtree_rotate_right(rbtree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->left;
+
+ /* If our uncle is red... */
+ if (uncle->color == RED) {
+ /* Paint the parent and the uncle black... */
+ node->parent->color = BLACK;
+ uncle->color = BLACK;
+
+ /* And the grandparent red... */
+ node->parent->parent->color = RED;
+
+ /* And continue fixing the grandparent */
+ node = node->parent->parent;
+ } else { /* Our uncle is black... */
+ /* Are we the right child? */
+ if (node == node->parent->left) {
+ node = node->parent;
+ ldns_rbtree_rotate_right(rbtree, node);
+ }
+ /* Now we're the right child, repaint and rotate... */
+ node->parent->color = BLACK;
+ node->parent->parent->color = RED;
+ ldns_rbtree_rotate_left(rbtree, node->parent->parent);
+ }
+ }
+ }
+ rbtree->root->color = BLACK;
+}
+
+void
+ldns_rbtree_insert_vref(ldns_rbnode_t *data, void *rbtree)
+{
+ (void) ldns_rbtree_insert((ldns_rbtree_t *) rbtree,
+ data);
+}
+
+/*
+ * Inserts a node into a red black tree.
+ *
+ * Returns NULL on failure or the pointer to the newly added node
+ * otherwise.
+ */
+ldns_rbnode_t *
+ldns_rbtree_insert (ldns_rbtree_t *rbtree, ldns_rbnode_t *data)
+{
+ /* XXX Not necessary, but keeps compiler quiet... */
+ int r = 0;
+
+ /* We start at the root of the tree */
+ ldns_rbnode_t *node = rbtree->root;
+ ldns_rbnode_t *parent = LDNS_RBTREE_NULL;
+
+ /* Lets find the new parent... */
+ while (node != LDNS_RBTREE_NULL) {
+ /* Compare two keys, do we have a duplicate? */
+ if ((r = rbtree->cmp(data->key, node->key)) == 0) {
+ return NULL;
+ }
+ parent = node;
+
+ if (r < 0) {
+ node = node->left;
+ } else {
+ node = node->right;
+ }
+ }
+
+ /* Initialize the new node */
+ data->parent = parent;
+ data->left = data->right = LDNS_RBTREE_NULL;
+ data->color = RED;
+ rbtree->count++;
+
+ /* Insert it into the tree... */
+ if (parent != LDNS_RBTREE_NULL) {
+ if (r < 0) {
+ parent->left = data;
+ } else {
+ parent->right = data;
+ }
+ } else {
+ rbtree->root = data;
+ }
+
+ /* Fix up the red-black properties... */
+ ldns_rbtree_insert_fixup(rbtree, data);
+
+ return data;
+}
+
+/*
+ * Searches the red black tree, returns the data if key is found or NULL otherwise.
+ *
+ */
+ldns_rbnode_t *
+ldns_rbtree_search (ldns_rbtree_t *rbtree, const void *key)
+{
+ ldns_rbnode_t *node;
+
+ if (ldns_rbtree_find_less_equal(rbtree, key, &node)) {
+ return node;
+ } else {
+ return NULL;
+ }
+}
+
+/** helpers for delete: swap node colours */
+static void swap_int8(uint8_t* x, uint8_t* y)
+{
+ uint8_t t = *x; *x = *y; *y = t;
+}
+
+/** helpers for delete: swap node pointers */
+static void swap_np(ldns_rbnode_t** x, ldns_rbnode_t** y)
+{
+ ldns_rbnode_t* t = *x; *x = *y; *y = t;
+}
+
+/** Update parent pointers of child trees of 'parent' */
+static void change_parent_ptr(ldns_rbtree_t* rbtree, ldns_rbnode_t* parent, ldns_rbnode_t* old, ldns_rbnode_t* new)
+{
+ if(parent == LDNS_RBTREE_NULL)
+ {
+ if(rbtree->root == old) rbtree->root = new;
+ return;
+ }
+ if(parent->left == old) parent->left = new;
+ if(parent->right == old) parent->right = new;
+}
+/** Update parent pointer of a node 'child' */
+static void change_child_ptr(ldns_rbnode_t* child, ldns_rbnode_t* old, ldns_rbnode_t* new)
+{
+ if(child == LDNS_RBTREE_NULL) return;
+ if(child->parent == old) child->parent = new;
+}
+
+ldns_rbnode_t*
+ldns_rbtree_delete(ldns_rbtree_t *rbtree, const void *key)
+{
+ ldns_rbnode_t *to_delete;
+ ldns_rbnode_t *child;
+ if((to_delete = ldns_rbtree_search(rbtree, key)) == 0) return 0;
+ rbtree->count--;
+
+ /* make sure we have at most one non-leaf child */
+ if(to_delete->left != LDNS_RBTREE_NULL &&
+ to_delete->right != LDNS_RBTREE_NULL)
+ {
+ /* swap with smallest from right subtree (or largest from left) */
+ ldns_rbnode_t *smright = to_delete->right;
+ while(smright->left != LDNS_RBTREE_NULL)
+ smright = smright->left;
+ /* swap the smright and to_delete elements in the tree,
+ * but the ldns_rbnode_t is first part of user data struct
+ * so cannot just swap the keys and data pointers. Instead
+ * readjust the pointers left,right,parent */
+
+ /* swap colors - colors are tied to the position in the tree */
+ swap_int8(&to_delete->color, &smright->color);
+
+ /* swap child pointers in parents of smright/to_delete */
+ change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
+ if(to_delete->right != smright)
+ change_parent_ptr(rbtree, smright->parent, smright, to_delete);
+
+ /* swap parent pointers in children of smright/to_delete */
+ change_child_ptr(smright->left, smright, to_delete);
+ change_child_ptr(smright->left, smright, to_delete);
+ change_child_ptr(smright->right, smright, to_delete);
+ change_child_ptr(smright->right, smright, to_delete);
+ change_child_ptr(to_delete->left, to_delete, smright);
+ if(to_delete->right != smright)
+ change_child_ptr(to_delete->right, to_delete, smright);
+ if(to_delete->right == smright)
+ {
+ /* set up so after swap they work */
+ to_delete->right = to_delete;
+ smright->parent = smright;
+ }
+
+ /* swap pointers in to_delete/smright nodes */
+ swap_np(&to_delete->parent, &smright->parent);
+ swap_np(&to_delete->left, &smright->left);
+ swap_np(&to_delete->right, &smright->right);
+
+ /* now delete to_delete (which is at the location where the smright previously was) */
+ }
+
+ if(to_delete->left != LDNS_RBTREE_NULL) child = to_delete->left;
+ else child = to_delete->right;
+
+ /* unlink to_delete from the tree, replace to_delete with child */
+ change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
+ change_child_ptr(child, to_delete, to_delete->parent);
+
+ if(to_delete->color == RED)
+ {
+ /* if node is red then the child (black) can be swapped in */
+ }
+ else if(child->color == RED)
+ {
+ /* change child to BLACK, removing a RED node is no problem */
+ if(child!=LDNS_RBTREE_NULL) child->color = BLACK;
+ }
+ else ldns_rbtree_delete_fixup(rbtree, child, to_delete->parent);
+
+ /* unlink completely */
+ to_delete->parent = LDNS_RBTREE_NULL;
+ to_delete->left = LDNS_RBTREE_NULL;
+ to_delete->right = LDNS_RBTREE_NULL;
+ to_delete->color = BLACK;
+ return to_delete;
+}
+
+static void ldns_rbtree_delete_fixup(ldns_rbtree_t* rbtree, ldns_rbnode_t* child, ldns_rbnode_t* child_parent)
+{
+ ldns_rbnode_t* sibling;
+ int go_up = 1;
+
+ /* determine sibling to the node that is one-black short */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+
+ while(go_up)
+ {
+ if(child_parent == LDNS_RBTREE_NULL)
+ {
+ /* removed parent==black from root, every path, so ok */
+ return;
+ }
+
+ if(sibling->color == RED)
+ { /* rotate to get a black sibling */
+ child_parent->color = RED;
+ sibling->color = BLACK;
+ if(child_parent->right == child)
+ ldns_rbtree_rotate_right(rbtree, child_parent);
+ else ldns_rbtree_rotate_left(rbtree, child_parent);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+
+ if(child_parent->color == BLACK
+ && sibling->color == BLACK
+ && sibling->left->color == BLACK
+ && sibling->right->color == BLACK)
+ { /* fixup local with recolor of sibling */
+ if(sibling != LDNS_RBTREE_NULL)
+ sibling->color = RED;
+
+ child = child_parent;
+ child_parent = child_parent->parent;
+ /* prepare to go up, new sibling */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+ else go_up = 0;
+ }
+
+ if(child_parent->color == RED
+ && sibling->color == BLACK
+ && sibling->left->color == BLACK
+ && sibling->right->color == BLACK)
+ {
+ /* move red to sibling to rebalance */
+ if(sibling != LDNS_RBTREE_NULL)
+ sibling->color = RED;
+ child_parent->color = BLACK;
+ return;
+ }
+
+ /* get a new sibling, by rotating at sibling. See which child
+ of sibling is red */
+ if(child_parent->right == child
+ && sibling->color == BLACK
+ && sibling->right->color == RED
+ && sibling->left->color == BLACK)
+ {
+ sibling->color = RED;
+ sibling->right->color = BLACK;
+ ldns_rbtree_rotate_left(rbtree, sibling);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+ else if(child_parent->left == child
+ && sibling->color == BLACK
+ && sibling->left->color == RED
+ && sibling->right->color == BLACK)
+ {
+ sibling->color = RED;
+ sibling->left->color = BLACK;
+ ldns_rbtree_rotate_right(rbtree, sibling);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+
+ /* now we have a black sibling with a red child. rotate and exchange colors. */
+ sibling->color = child_parent->color;
+ child_parent->color = BLACK;
+ if(child_parent->right == child)
+ {
+ sibling->left->color = BLACK;
+ ldns_rbtree_rotate_right(rbtree, child_parent);
+ }
+ else
+ {
+ sibling->right->color = BLACK;
+ ldns_rbtree_rotate_left(rbtree, child_parent);
+ }
+}
+
+int
+ldns_rbtree_find_less_equal(ldns_rbtree_t *rbtree, const void *key, ldns_rbnode_t **result)
+{
+ int r;
+ ldns_rbnode_t *node;
+
+ /* We start at root... */
+ node = rbtree->root;
+
+ *result = NULL;
+
+ /* While there are children... */
+ while (node != LDNS_RBTREE_NULL) {
+ r = rbtree->cmp(key, node->key);
+ if (r == 0) {
+ /* Exact match */
+ *result = node;
+ return 1;
+ }
+ if (r < 0) {
+ node = node->left;
+ } else {
+ /* Temporary match */
+ *result = node;
+ node = node->right;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Finds the first element in the red black tree
+ *
+ */
+ldns_rbnode_t *
+ldns_rbtree_first (ldns_rbtree_t *rbtree)
+{
+ ldns_rbnode_t *node = rbtree->root;
+
+ if (rbtree->root != LDNS_RBTREE_NULL) {
+ for (node = rbtree->root; node->left != LDNS_RBTREE_NULL; node = node->left);
+ }
+ return node;
+}
+
+ldns_rbnode_t *
+ldns_rbtree_last (ldns_rbtree_t *rbtree)
+{
+ ldns_rbnode_t *node = rbtree->root;
+
+ if (rbtree->root != LDNS_RBTREE_NULL) {
+ for (node = rbtree->root; node->right != LDNS_RBTREE_NULL; node = node->right);
+ }
+ return node;
+}
+
+/*
+ * Returns the next node...
+ *
+ */
+ldns_rbnode_t *
+ldns_rbtree_next (ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *parent;
+
+ if (node->right != LDNS_RBTREE_NULL) {
+ /* One right, then keep on going left... */
+ for (node = node->right;
+ node->left != LDNS_RBTREE_NULL;
+ node = node->left);
+ } else {
+ parent = node->parent;
+ while (parent != LDNS_RBTREE_NULL && node == parent->right) {
+ node = parent;
+ parent = parent->parent;
+ }
+ node = parent;
+ }
+ return node;
+}
+
+ldns_rbnode_t *
+ldns_rbtree_previous(ldns_rbnode_t *node)
+{
+ ldns_rbnode_t *parent;
+
+ if (node->left != LDNS_RBTREE_NULL) {
+ /* One left, then keep on going right... */
+ for (node = node->left;
+ node->right != LDNS_RBTREE_NULL;
+ node = node->right);
+ } else {
+ parent = node->parent;
+ while (parent != LDNS_RBTREE_NULL && node == parent->left) {
+ node = parent;
+ parent = parent->parent;
+ }
+ node = parent;
+ }
+ return node;
+}
+
+/**
+ * split off elements number of elements from the start
+ * of the name tree and return a new tree
+ */
+ldns_rbtree_t *
+ldns_rbtree_split(ldns_rbtree_t *tree,
+ size_t elements)
+{
+ ldns_rbtree_t *new_tree;
+ ldns_rbnode_t *cur_node;
+ ldns_rbnode_t *move_node;
+ size_t count = 0;
+
+ new_tree = ldns_rbtree_create(tree->cmp);
+
+ cur_node = ldns_rbtree_first(tree);
+ while (count < elements && cur_node != LDNS_RBTREE_NULL) {
+ move_node = ldns_rbtree_delete(tree, cur_node->key);
+ (void)ldns_rbtree_insert(new_tree, move_node);
+ cur_node = ldns_rbtree_first(tree);
+ count++;
+ }
+
+ return new_tree;
+}
+
+/*
+ * add all node from the second tree to the first (removing them from the
+ * second), and fix up nsec(3)s if present
+ */
+void
+ldns_rbtree_join(ldns_rbtree_t *tree1, ldns_rbtree_t *tree2)
+{
+ ldns_traverse_postorder(tree2, ldns_rbtree_insert_vref, tree1);
+}
+
+/** recursive descent traverse */
+static void
+traverse_post(void (*func)(ldns_rbnode_t*, void*), void* arg,
+ ldns_rbnode_t* node)
+{
+ if(!node || node == LDNS_RBTREE_NULL)
+ return;
+ /* recurse */
+ traverse_post(func, arg, node->left);
+ traverse_post(func, arg, node->right);
+ /* call user func */
+ (*func)(node, arg);
+}
+
+void
+ldns_traverse_postorder(ldns_rbtree_t* tree,
+ void (*func)(ldns_rbnode_t*, void*), void* arg)
+{
+ traverse_post(func, arg, tree->root);
+}
diff --git a/3rdParty/Ldns/src/src/rdata.c b/3rdParty/Ldns/src/src/rdata.c
new file mode 100644
index 0000000..8af16a1
--- /dev/null
+++ b/3rdParty/Ldns/src/src/rdata.c
@@ -0,0 +1,675 @@
+/*
+ * rdata.c
+ *
+ * rdata implementation
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+/*
+ * Access functions
+ * do this as functions to get type checking
+ */
+
+/* read */
+size_t
+ldns_rdf_size(const ldns_rdf *rd)
+{
+ assert(rd != NULL);
+ return rd->_size;
+}
+
+ldns_rdf_type
+ldns_rdf_get_type(const ldns_rdf *rd)
+{
+ assert(rd != NULL);
+ return rd->_type;
+}
+
+uint8_t *
+ldns_rdf_data(const ldns_rdf *rd)
+{
+ assert(rd != NULL);
+ return rd->_data;
+}
+
+/* write */
+void
+ldns_rdf_set_size(ldns_rdf *rd, size_t size)
+{
+ assert(rd != NULL);
+ rd->_size = size;
+}
+
+void
+ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type)
+{
+ assert(rd != NULL);
+ rd->_type = type;
+}
+
+void
+ldns_rdf_set_data(ldns_rdf *rd, void *data)
+{
+ /* only copy the pointer */
+ assert(rd != NULL);
+ rd->_data = data;
+}
+
+/* for types that allow it, return
+ * the native/host order type */
+uint8_t
+ldns_rdf2native_int8(const ldns_rdf *rd)
+{
+ uint8_t data;
+
+ /* only allow 8 bit rdfs */
+ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) {
+ return 0;
+ }
+
+ memcpy(&data, ldns_rdf_data(rd), sizeof(data));
+ return data;
+}
+
+uint16_t
+ldns_rdf2native_int16(const ldns_rdf *rd)
+{
+ uint16_t data;
+
+ /* only allow 16 bit rdfs */
+ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) {
+ return 0;
+ }
+
+ memcpy(&data, ldns_rdf_data(rd), sizeof(data));
+ return ntohs(data);
+}
+
+uint32_t
+ldns_rdf2native_int32(const ldns_rdf *rd)
+{
+ uint32_t data;
+
+ /* only allow 32 bit rdfs */
+ if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) {
+ return 0;
+ }
+
+ memcpy(&data, ldns_rdf_data(rd), sizeof(data));
+ return ntohl(data);
+}
+
+time_t
+ldns_rdf2native_time_t(const ldns_rdf *rd)
+{
+ uint32_t data;
+
+ switch(ldns_rdf_get_type(rd)) {
+ case LDNS_RDF_TYPE_TIME:
+ memcpy(&data, ldns_rdf_data(rd), sizeof(data));
+ return (time_t)ntohl(data);
+ default:
+ return 0;
+ }
+}
+
+ldns_rdf *
+ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value)
+{
+ return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value);
+}
+
+ldns_rdf *
+ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value)
+{
+ uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1);
+ ldns_rdf* rdf;
+ if (!rdf_data) {
+ return NULL;
+ }
+ ldns_write_uint16(rdf_data, value);
+ rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data);
+ if(!rdf)
+ LDNS_FREE(rdf_data);
+ return rdf;
+}
+
+ldns_rdf *
+ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value)
+{
+ uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1);
+ ldns_rdf* rdf;
+ if (!rdf_data) {
+ return NULL;
+ }
+ ldns_write_uint32(rdf_data, value);
+ rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data);
+ if(!rdf)
+ LDNS_FREE(rdf_data);
+ return rdf;
+}
+
+ldns_rdf *
+ldns_native2rdf_int16_data(size_t size, uint8_t *data)
+{
+ uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2);
+ ldns_rdf* rdf;
+ if (!rdf_data) {
+ return NULL;
+ }
+ ldns_write_uint16(rdf_data, size);
+ memcpy(rdf_data + 2, data, size);
+ rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data);
+ if(!rdf)
+ LDNS_FREE(rdf_data);
+ return rdf;
+}
+
+/* note: data must be allocated memory */
+ldns_rdf *
+ldns_rdf_new(ldns_rdf_type type, size_t size, void *data)
+{
+ ldns_rdf *rd;
+ rd = LDNS_MALLOC(ldns_rdf);
+ if (!rd) {
+ return NULL;
+ }
+ ldns_rdf_set_size(rd, size);
+ ldns_rdf_set_type(rd, type);
+ ldns_rdf_set_data(rd, data);
+ return rd;
+}
+
+ldns_rdf *
+ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
+{
+ ldns_rdf *rdf;
+
+ /* if the size is too big, fail */
+ if (size > LDNS_MAX_RDFLEN) {
+ return NULL;
+ }
+
+ /* allocate space */
+ rdf = LDNS_MALLOC(ldns_rdf);
+ if (!rdf) {
+ return NULL;
+ }
+ rdf->_data = LDNS_XMALLOC(uint8_t, size);
+ if (!rdf->_data) {
+ LDNS_FREE(rdf);
+ return NULL;
+ }
+
+ /* set the values */
+ ldns_rdf_set_type(rdf, type);
+ ldns_rdf_set_size(rdf, size);
+ memcpy(rdf->_data, data, size);
+
+ return rdf;
+}
+
+ldns_rdf *
+ldns_rdf_clone(const ldns_rdf *rd)
+{
+ assert(rd != NULL);
+ return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd),
+ ldns_rdf_size(rd), ldns_rdf_data(rd)));
+}
+
+void
+ldns_rdf_deep_free(ldns_rdf *rd)
+{
+ if (rd) {
+ if (rd->_data) {
+ LDNS_FREE(rd->_data);
+ }
+ LDNS_FREE(rd);
+ }
+}
+
+void
+ldns_rdf_free(ldns_rdf *rd)
+{
+ if (rd) {
+ LDNS_FREE(rd);
+ }
+}
+
+ldns_rdf *
+ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
+{
+ ldns_rdf *rdf = NULL;
+ ldns_status status;
+
+ switch (type) {
+ case LDNS_RDF_TYPE_DNAME:
+ status = ldns_str2rdf_dname(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_INT8:
+ status = ldns_str2rdf_int8(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_INT16:
+ status = ldns_str2rdf_int16(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_INT32:
+ status = ldns_str2rdf_int32(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_A:
+ status = ldns_str2rdf_a(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_AAAA:
+ status = ldns_str2rdf_aaaa(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_STR:
+ status = ldns_str2rdf_str(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_APL:
+ status = ldns_str2rdf_apl(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_B64:
+ status = ldns_str2rdf_b64(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_B32_EXT:
+ status = ldns_str2rdf_b32_ext(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_HEX:
+ status = ldns_str2rdf_hex(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_NSEC:
+ status = ldns_str2rdf_nsec(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_TYPE:
+ status = ldns_str2rdf_type(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_CLASS:
+ status = ldns_str2rdf_class(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_CERT_ALG:
+ status = ldns_str2rdf_cert_alg(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_ALG:
+ status = ldns_str2rdf_alg(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_UNKNOWN:
+ status = ldns_str2rdf_unknown(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_TIME:
+ status = ldns_str2rdf_time(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_PERIOD:
+ status = ldns_str2rdf_period(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_TSIG:
+ status = ldns_str2rdf_tsig(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_SERVICE:
+ status = ldns_str2rdf_service(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_LOC:
+ status = ldns_str2rdf_loc(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_WKS:
+ status = ldns_str2rdf_wks(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_NSAP:
+ status = ldns_str2rdf_nsap(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_ATMA:
+ status = ldns_str2rdf_atma(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_IPSECKEY:
+ status = ldns_str2rdf_ipseckey(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_NSEC3_SALT:
+ status = ldns_str2rdf_nsec3_salt(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+ status = ldns_str2rdf_b32_ext(&rdf, str);
+ break;
+ case LDNS_RDF_TYPE_NONE:
+ default:
+ /* default default ??? */
+ status = LDNS_STATUS_ERR;
+ break;
+ }
+ if (LDNS_STATUS_OK == status) {
+ ldns_rdf_set_type(rdf, type);
+ return rdf;
+ }
+ if (rdf) {
+ LDNS_FREE(rdf);
+ }
+ return NULL;
+}
+
+ldns_status
+ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp)
+{
+ return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL);
+}
+
+ldns_status
+ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr)
+{
+ char *line;
+ ldns_rdf *r;
+ ssize_t t;
+
+ line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
+ if (!line) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ /* read an entire line in from the file */
+ if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) {
+ LDNS_FREE(line);
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ }
+ r = ldns_rdf_new_frm_str(type, (const char*) line);
+ LDNS_FREE(line);
+ if (rdf) {
+ *rdf = r;
+ return LDNS_STATUS_OK;
+ } else {
+ return LDNS_STATUS_NULL;
+ }
+}
+
+ldns_rdf *
+ldns_rdf_address_reverse(ldns_rdf *rd)
+{
+ uint8_t buf_4[LDNS_IP4ADDRLEN];
+ uint8_t buf_6[LDNS_IP6ADDRLEN * 2];
+ ldns_rdf *rev;
+ ldns_rdf *in_addr;
+ ldns_rdf *ret_dname;
+ uint8_t octet;
+ uint8_t nnibble;
+ uint8_t nibble;
+ uint8_t i, j;
+
+ char *char_dname;
+ int nbit;
+
+ if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A &&
+ ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) {
+ return NULL;
+ }
+
+ in_addr = NULL;
+ ret_dname = NULL;
+
+ switch(ldns_rdf_get_type(rd)) {
+ case LDNS_RDF_TYPE_A:
+ /* the length of the buffer is 4 */
+ buf_4[3] = ldns_rdf_data(rd)[0];
+ buf_4[2] = ldns_rdf_data(rd)[1];
+ buf_4[1] = ldns_rdf_data(rd)[2];
+ buf_4[0] = ldns_rdf_data(rd)[3];
+ in_addr = ldns_dname_new_frm_str("in-addr.arpa.");
+ if (!in_addr) {
+ return NULL;
+ }
+ /* make a new rdf and convert that back */
+ rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A,
+ LDNS_IP4ADDRLEN, (void*)&buf_4);
+ if (!rev) {
+ LDNS_FREE(in_addr);
+ return NULL;
+ }
+
+ /* convert rev to a string */
+ char_dname = ldns_rdf2str(rev);
+ if (!char_dname) {
+ LDNS_FREE(in_addr);
+ ldns_rdf_deep_free(rev);
+ return NULL;
+ }
+ /* transform back to rdf with type dname */
+ ret_dname = ldns_dname_new_frm_str(char_dname);
+ if (!ret_dname) {
+ LDNS_FREE(in_addr);
+ ldns_rdf_deep_free(rev);
+ LDNS_FREE(char_dname);
+ return NULL;
+ }
+ /* not needed anymore */
+ ldns_rdf_deep_free(rev);
+ LDNS_FREE(char_dname);
+ break;
+ case LDNS_RDF_TYPE_AAAA:
+ /* some foo magic to reverse the nibbles ... */
+
+ for (nbit = 127; nbit >= 0; nbit = nbit - 4) {
+ /* calculate octett (8 bit) */
+ octet = ( ((unsigned int) nbit) & 0x78) >> 3;
+ /* calculate nibble */
+ nnibble = ( ((unsigned int) nbit) & 0x04) >> 2;
+ /* extract nibble */
+ nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 -
+ nnibble)) ) ) >> ( 4 * (1 -
+ nnibble));
+
+ buf_6[(LDNS_IP6ADDRLEN * 2 - 1) -
+ (octet * 2 + nnibble)] =
+ (uint8_t)ldns_int_to_hexdigit((int)nibble);
+ }
+
+ char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4));
+ if (!char_dname) {
+ return NULL;
+ }
+ char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */
+
+ /* walk the string and add . 's */
+ for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) {
+ char_dname[j] = (char)buf_6[i];
+ if (i != LDNS_IP6ADDRLEN * 2 - 1) {
+ char_dname[j + 1] = '.';
+ }
+ }
+ in_addr = ldns_dname_new_frm_str("ip6.arpa.");
+ if (!in_addr) {
+ LDNS_FREE(char_dname);
+ return NULL;
+ }
+
+ /* convert rev to a string */
+ ret_dname = ldns_dname_new_frm_str(char_dname);
+ LDNS_FREE(char_dname);
+ if (!ret_dname) {
+ ldns_rdf_deep_free(in_addr);
+ return NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ /* add the suffix */
+ rev = ldns_dname_cat_clone(ret_dname, in_addr);
+
+ ldns_rdf_deep_free(ret_dname);
+ ldns_rdf_deep_free(in_addr);
+ return rev;
+}
+
+ldns_status
+ldns_octet(char *word, size_t *length)
+{
+ char *s;
+ char *p;
+ *length = 0;
+
+ for (s = p = word; *s != '\0'; s++,p++) {
+ switch (*s) {
+ case '.':
+ if (s[1] == '.') {
+ return LDNS_STATUS_EMPTY_LABEL;
+ }
+ *p = *s;
+ (*length)++;
+ break;
+ case '\\':
+ if ('0' <= s[1] && s[1] <= '9' &&
+ '0' <= s[2] && s[2] <= '9' &&
+ '0' <= s[3] && s[3] <= '9') {
+ /* \DDD seen */
+ int val = ((s[1] - '0') * 100 +
+ (s[2] - '0') * 10 + (s[3] - '0'));
+
+ if (0 <= val && val <= 255) {
+ /* this also handles \0 */
+ s += 3;
+ *p = val;
+ (*length)++;
+ } else {
+ return LDNS_STATUS_DDD_OVERFLOW;
+ }
+ } else {
+ /* an espaced character, like \<space> ?
+ * remove the '\' keep the rest */
+ *p = *++s;
+ (*length)++;
+ }
+ break;
+ case '\"':
+ /* non quoted " Is either first or the last character in
+ * the string */
+
+ *p = *++s; /* skip it */
+ (*length)++;
+ /* I'm not sure if this is needed in libdns... MG */
+ if ( *s == '\0' ) {
+ /* ok, it was the last one */
+ *p = '\0';
+ return LDNS_STATUS_OK;
+ }
+ break;
+ default:
+ *p = *s;
+ (*length)++;
+ break;
+ }
+ }
+ *p = '\0';
+ return LDNS_STATUS_OK;
+}
+
+int
+ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2)
+{
+ uint16_t i1, i2, i;
+ uint8_t *d1, *d2;
+
+ /* only when both are not NULL we can say anything about them */
+ if (!rd1 && !rd2) {
+ return 0;
+ }
+ if (!rd1 || !rd2) {
+ return -1;
+ }
+ i1 = ldns_rdf_size(rd1);
+ i2 = ldns_rdf_size(rd2);
+
+ if (i1 < i2) {
+ return -1;
+ } else if (i1 > i2) {
+ return +1;
+ } else {
+ d1 = (uint8_t*)ldns_rdf_data(rd1);
+ d2 = (uint8_t*)ldns_rdf_data(rd2);
+ for(i = 0; i < i1; i++) {
+ if (d1[i] < d2[i]) {
+ return -1;
+ } else if (d1[i] > d2[i]) {
+ return +1;
+ }
+ }
+ }
+ return 0;
+}
+
+uint32_t
+ldns_str2period(const char *nptr, const char **endptr)
+{
+ int sign = 0;
+ uint32_t i = 0;
+ uint32_t seconds = 0;
+
+ for(*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case '-':
+ if(sign == 0) {
+ sign = -1;
+ } else {
+ return seconds;
+ }
+ break;
+ case '+':
+ if(sign == 0) {
+ sign = 1;
+ } else {
+ return seconds;
+ }
+ break;
+ case 's':
+ case 'S':
+ seconds += i;
+ i = 0;
+ break;
+ case 'm':
+ case 'M':
+ seconds += i * 60;
+ i = 0;
+ break;
+ case 'h':
+ case 'H':
+ seconds += i * 60 * 60;
+ i = 0;
+ break;
+ case 'd':
+ case 'D':
+ seconds += i * 60 * 60 * 24;
+ i = 0;
+ break;
+ case 'w':
+ case 'W':
+ seconds += i * 60 * 60 * 24 * 7;
+ i = 0;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ seconds += i;
+ /* disregard signedness */
+ return seconds;
+ }
+ }
+ seconds += i;
+ /* disregard signedness */
+ return seconds;
+}
diff --git a/3rdParty/Ldns/src/src/resolver.c b/3rdParty/Ldns/src/src/resolver.c
new file mode 100644
index 0000000..732f2a8
--- /dev/null
+++ b/3rdParty/Ldns/src/src/resolver.c
@@ -0,0 +1,1350 @@
+/*
+ * resolver.c
+ *
+ * resolver implementation
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+#include <strings.h>
+
+/* Access function for reading
+ * and setting the different Resolver
+ * options */
+
+/* read */
+uint16_t
+ldns_resolver_port(const ldns_resolver *r)
+{
+ return r->_port;
+}
+
+uint16_t
+ldns_resolver_edns_udp_size(const ldns_resolver *r)
+{
+ return r->_edns_udp_size;
+}
+
+uint8_t
+ldns_resolver_retry(const ldns_resolver *r)
+{
+ return r->_retry;
+}
+
+uint8_t
+ldns_resolver_retrans(const ldns_resolver *r)
+{
+ return r->_retrans;
+}
+
+bool
+ldns_resolver_fallback(const ldns_resolver *r)
+{
+ return r->_fallback;
+}
+
+uint8_t
+ldns_resolver_ip6(const ldns_resolver *r)
+{
+ return r->_ip6;
+}
+
+bool
+ldns_resolver_recursive(const ldns_resolver *r)
+{
+ return r->_recursive;
+}
+
+bool
+ldns_resolver_debug(const ldns_resolver *r)
+{
+ return r->_debug;
+}
+
+bool
+ldns_resolver_dnsrch(const ldns_resolver *r)
+{
+ return r->_dnsrch;
+}
+
+bool
+ldns_resolver_fail(const ldns_resolver *r)
+{
+ return r->_fail;
+}
+
+bool
+ldns_resolver_defnames(const ldns_resolver *r)
+{
+ return r->_defnames;
+}
+
+ldns_rdf *
+ldns_resolver_domain(const ldns_resolver *r)
+{
+ return r->_domain;
+}
+
+ldns_rdf **
+ldns_resolver_searchlist(const ldns_resolver *r)
+{
+ return r->_searchlist;
+}
+
+ldns_rdf **
+ldns_resolver_nameservers(const ldns_resolver *r)
+{
+ return r->_nameservers;
+}
+
+size_t
+ldns_resolver_nameserver_count(const ldns_resolver *r)
+{
+ return r->_nameserver_count;
+}
+
+bool
+ldns_resolver_dnssec(const ldns_resolver *r)
+{
+ return r->_dnssec;
+}
+
+bool
+ldns_resolver_dnssec_cd(const ldns_resolver *r)
+{
+ return r->_dnssec_cd;
+}
+
+ldns_rr_list *
+ldns_resolver_dnssec_anchors(const ldns_resolver *r)
+{
+ return r->_dnssec_anchors;
+}
+
+bool
+ldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys)
+{
+ size_t i;
+ bool result = false;
+
+ ldns_rr_list * trust_anchors;
+ ldns_rr * cur_rr;
+
+ if (!r || !keys) { return false; }
+
+ trust_anchors = ldns_resolver_dnssec_anchors(r);
+
+ if (!trust_anchors) { return false; }
+
+ for (i = 0; i < ldns_rr_list_rr_count(keys); i++) {
+
+ cur_rr = ldns_rr_list_rr(keys, i);
+ if (ldns_rr_list_contains_rr(trust_anchors, cur_rr)) {
+ if (trusted_keys) { ldns_rr_list_push_rr(trusted_keys, cur_rr); }
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+bool
+ldns_resolver_igntc(const ldns_resolver *r)
+{
+ return r->_igntc;
+}
+
+bool
+ldns_resolver_usevc(const ldns_resolver *r)
+{
+ return r->_usevc;
+}
+
+size_t *
+ldns_resolver_rtt(const ldns_resolver *r)
+{
+ return r->_rtt;
+}
+
+size_t
+ldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos)
+{
+ size_t *rtt;
+
+ assert(r != NULL);
+
+ rtt = ldns_resolver_rtt(r);
+
+ if (pos >= ldns_resolver_nameserver_count(r)) {
+ /* error ?*/
+ return 0;
+ } else {
+ return rtt[pos];
+ }
+
+}
+
+struct timeval
+ldns_resolver_timeout(const ldns_resolver *r)
+{
+ return r->_timeout;
+}
+
+char *
+ldns_resolver_tsig_keyname(const ldns_resolver *r)
+{
+ return r->_tsig_keyname;
+}
+
+char *
+ldns_resolver_tsig_algorithm(const ldns_resolver *r)
+{
+ return r->_tsig_algorithm;
+}
+
+char *
+ldns_resolver_tsig_keydata(const ldns_resolver *r)
+{
+ return r->_tsig_keydata;
+}
+
+bool
+ldns_resolver_random(const ldns_resolver *r)
+{
+ return r->_random;
+}
+
+size_t
+ldns_resolver_searchlist_count(const ldns_resolver *r)
+{
+ return r->_searchlist_count;
+}
+
+/* write */
+void
+ldns_resolver_set_port(ldns_resolver *r, uint16_t p)
+{
+ r->_port = p;
+}
+
+ldns_rdf *
+ldns_resolver_pop_nameserver(ldns_resolver *r)
+{
+ ldns_rdf **nameservers;
+ ldns_rdf *pop;
+ size_t ns_count;
+ size_t *rtt;
+
+ assert(r != NULL);
+
+ ns_count = ldns_resolver_nameserver_count(r);
+ nameservers = ldns_resolver_nameservers(r);
+ rtt = ldns_resolver_rtt(r);
+ if (ns_count == 0 || !nameservers) {
+ return NULL;
+ }
+
+ pop = nameservers[ns_count - 1];
+
+ nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count - 1));
+ rtt = LDNS_XREALLOC(rtt, size_t, (ns_count - 1));
+
+ if(nameservers)
+ ldns_resolver_set_nameservers(r, nameservers);
+ if(rtt)
+ ldns_resolver_set_rtt(r, rtt);
+ /* decr the count */
+ ldns_resolver_dec_nameserver_count(r);
+ return pop;
+}
+
+ldns_status
+ldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n)
+{
+ ldns_rdf **nameservers;
+ size_t ns_count;
+ size_t *rtt;
+
+ if (ldns_rdf_get_type(n) != LDNS_RDF_TYPE_A &&
+ ldns_rdf_get_type(n) != LDNS_RDF_TYPE_AAAA) {
+ return LDNS_STATUS_ERR;
+ }
+
+ ns_count = ldns_resolver_nameserver_count(r);
+ nameservers = ldns_resolver_nameservers(r);
+ rtt = ldns_resolver_rtt(r);
+
+ /* make room for the next one */
+ if (ns_count == 0) {
+ nameservers = LDNS_XMALLOC(ldns_rdf *, 1);
+ } else {
+ nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count + 1));
+ }
+ if(!nameservers)
+ return LDNS_STATUS_MEM_ERR;
+
+ /* set the new value in the resolver */
+ ldns_resolver_set_nameservers(r, nameservers);
+
+ /* don't forget the rtt */
+ if (ns_count == 0) {
+ rtt = LDNS_XMALLOC(size_t, 1);
+ } else {
+ rtt = LDNS_XREALLOC(rtt, size_t, (ns_count + 1));
+ }
+ if(!rtt)
+ return LDNS_STATUS_MEM_ERR;
+
+ /* slide n in its slot. */
+ /* we clone it here, because then we can free the original
+ * rr's where it stood */
+ nameservers[ns_count] = ldns_rdf_clone(n);
+ rtt[ns_count] = LDNS_RESOLV_RTT_MIN;
+ ldns_resolver_incr_nameserver_count(r);
+ ldns_resolver_set_rtt(r, rtt);
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr)
+{
+ ldns_rdf *address;
+ if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_A &&
+ ldns_rr_get_type(rr) != LDNS_RR_TYPE_AAAA)) {
+ return LDNS_STATUS_ERR;
+ }
+ address = ldns_rr_rdf(rr, 0); /* extract the ip number */
+ if (address) {
+ return ldns_resolver_push_nameserver(r, address);
+ } else {
+ return LDNS_STATUS_ERR;
+ }
+}
+
+ldns_status
+ldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist)
+{
+ ldns_rr *rr;
+ ldns_status stat;
+ size_t i;
+
+ stat = LDNS_STATUS_OK;
+ if (rrlist) {
+ for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
+ rr = ldns_rr_list_rr(rrlist, i);
+ if (ldns_resolver_push_nameserver_rr(r, rr) != LDNS_STATUS_OK) {
+ stat = LDNS_STATUS_ERR;
+ break;
+ }
+ }
+ return stat;
+ } else {
+ return LDNS_STATUS_ERR;
+ }
+}
+
+void
+ldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s)
+{
+ r->_edns_udp_size = s;
+}
+
+void
+ldns_resolver_set_recursive(ldns_resolver *r, bool re)
+{
+ r->_recursive = re;
+}
+
+void
+ldns_resolver_set_dnssec(ldns_resolver *r, bool d)
+{
+ r->_dnssec = d;
+}
+
+void
+ldns_resolver_set_dnssec_cd(ldns_resolver *r, bool d)
+{
+ r->_dnssec_cd = d;
+}
+
+void
+ldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l)
+{
+ r->_dnssec_anchors = l;
+}
+
+ldns_status
+ldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr)
+{
+ ldns_rr_list * trust_anchors;
+
+ if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (!(trust_anchors = ldns_resolver_dnssec_anchors(r))) { /* Initialize */
+ trust_anchors = ldns_rr_list_new();
+ ldns_resolver_set_dnssec_anchors(r, trust_anchors);
+ }
+
+ return (ldns_rr_list_push_rr(trust_anchors, ldns_rr_clone(rr))) ? LDNS_STATUS_OK : LDNS_STATUS_ERR;
+}
+
+void
+ldns_resolver_set_igntc(ldns_resolver *r, bool i)
+{
+ r->_igntc = i;
+}
+
+void
+ldns_resolver_set_usevc(ldns_resolver *r, bool vc)
+{
+ r->_usevc = vc;
+}
+
+void
+ldns_resolver_set_debug(ldns_resolver *r, bool d)
+{
+ r->_debug = d;
+}
+
+void
+ldns_resolver_set_ip6(ldns_resolver *r, uint8_t ip6)
+{
+ r->_ip6 = ip6;
+}
+
+void
+ldns_resolver_set_fail(ldns_resolver *r, bool f)
+{
+ r->_fail =f;
+}
+
+void
+ldns_resolver_set_searchlist_count(ldns_resolver *r, size_t c)
+{
+ r->_searchlist_count = c;
+}
+
+void
+ldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c)
+{
+ r->_nameserver_count = c;
+}
+
+void
+ldns_resolver_set_dnsrch(ldns_resolver *r, bool d)
+{
+ r->_dnsrch = d;
+}
+
+void
+ldns_resolver_set_retry(ldns_resolver *r, uint8_t retry)
+{
+ r->_retry = retry;
+}
+
+void
+ldns_resolver_set_retrans(ldns_resolver *r, uint8_t retrans)
+{
+ r->_retrans = retrans;
+}
+
+void
+ldns_resolver_set_fallback(ldns_resolver *r, bool fallback)
+{
+ r->_fallback = fallback;
+}
+
+void
+ldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **n)
+{
+ r->_nameservers = n;
+}
+
+void
+ldns_resolver_set_defnames(ldns_resolver *r, bool d)
+{
+ r->_defnames = d;
+}
+
+void
+ldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt)
+{
+ r->_rtt = rtt;
+}
+
+void
+ldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value)
+{
+ size_t *rtt;
+
+ assert(r != NULL);
+
+ rtt = ldns_resolver_rtt(r);
+
+ if (pos >= ldns_resolver_nameserver_count(r)) {
+ /* error ?*/
+ } else {
+ rtt[pos] = value;
+ }
+
+}
+
+void
+ldns_resolver_incr_nameserver_count(ldns_resolver *r)
+{
+ size_t c;
+
+ c = ldns_resolver_nameserver_count(r);
+ ldns_resolver_set_nameserver_count(r, ++c);
+}
+
+void
+ldns_resolver_dec_nameserver_count(ldns_resolver *r)
+{
+ size_t c;
+
+ c = ldns_resolver_nameserver_count(r);
+ if (c == 0) {
+ return;
+ } else {
+ ldns_resolver_set_nameserver_count(r, --c);
+ }
+}
+
+void
+ldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *d)
+{
+ r->_domain = d;
+}
+
+void
+ldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout)
+{
+ r->_timeout.tv_sec = timeout.tv_sec;
+ r->_timeout.tv_usec = timeout.tv_usec;
+}
+
+void
+ldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *d)
+{
+ ldns_rdf **searchlist;
+ size_t list_count;
+
+ if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
+ return;
+ }
+
+ list_count = ldns_resolver_searchlist_count(r);
+ searchlist = ldns_resolver_searchlist(r);
+
+ searchlist = LDNS_XREALLOC(searchlist, ldns_rdf *, (list_count + 1));
+ if (searchlist) {
+ r->_searchlist = searchlist;
+
+ searchlist[list_count] = ldns_rdf_clone(d);
+ ldns_resolver_set_searchlist_count(r, list_count + 1);
+ } /* no way to report mem err */
+}
+
+void
+ldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname)
+{
+ LDNS_FREE(r->_tsig_keyname);
+ r->_tsig_keyname = strdup(tsig_keyname);
+}
+
+void
+ldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm)
+{
+ LDNS_FREE(r->_tsig_algorithm);
+ r->_tsig_algorithm = strdup(tsig_algorithm);
+}
+
+void
+ldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata)
+{
+ LDNS_FREE(r->_tsig_keydata);
+ r->_tsig_keydata = strdup(tsig_keydata);
+}
+
+void
+ldns_resolver_set_random(ldns_resolver *r, bool b)
+{
+ r->_random = b;
+}
+
+/* more sophisticated functions */
+ldns_resolver *
+ldns_resolver_new(void)
+{
+ ldns_resolver *r;
+
+ r = LDNS_MALLOC(ldns_resolver);
+ if (!r) {
+ return NULL;
+ }
+
+ r->_searchlist = NULL;
+ r->_nameservers = NULL;
+ r->_rtt = NULL;
+
+ /* defaults are filled out */
+ ldns_resolver_set_searchlist_count(r, 0);
+ ldns_resolver_set_nameserver_count(r, 0);
+ ldns_resolver_set_usevc(r, 0);
+ ldns_resolver_set_port(r, LDNS_PORT);
+ ldns_resolver_set_domain(r, NULL);
+ ldns_resolver_set_defnames(r, false);
+ ldns_resolver_set_retry(r, 3);
+ ldns_resolver_set_retrans(r, 2);
+ ldns_resolver_set_fallback(r, true);
+ ldns_resolver_set_fail(r, false);
+ ldns_resolver_set_edns_udp_size(r, 0);
+ ldns_resolver_set_dnssec(r, false);
+ ldns_resolver_set_dnssec_cd(r, false);
+ ldns_resolver_set_dnssec_anchors(r, NULL);
+ ldns_resolver_set_ip6(r, LDNS_RESOLV_INETANY);
+ ldns_resolver_set_igntc(r, false);
+ ldns_resolver_set_recursive(r, false);
+ ldns_resolver_set_dnsrch(r, true);
+
+ /* randomize the nameserver to be queried
+ * when there are multiple
+ */
+ ldns_resolver_set_random(r, true);
+
+ ldns_resolver_set_debug(r, 0);
+
+ r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC;
+ r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC;
+
+ /* TODO: fd=0 is actually a valid socket (stdin),
+ replace with -1 */
+ r->_socket = 0;
+ r->_axfr_soa_count = 0;
+ r->_axfr_i = 0;
+ r->_cur_axfr_pkt = NULL;
+
+ r->_tsig_keyname = NULL;
+ r->_tsig_keydata = NULL;
+ r->_tsig_algorithm = NULL;
+ return r;
+}
+
+ldns_status
+ldns_resolver_new_frm_fp(ldns_resolver **res, FILE *fp)
+{
+ return ldns_resolver_new_frm_fp_l(res, fp, NULL);
+}
+
+ldns_status
+ldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
+{
+ ldns_resolver *r;
+ const char *keyword[LDNS_RESOLV_KEYWORDS];
+ char word[LDNS_MAX_LINELEN + 1];
+ int8_t expect;
+ uint8_t i;
+ ldns_rdf *tmp;
+#ifdef HAVE_SSL
+ ldns_rr *tmp_rr;
+#endif
+ ssize_t gtr, bgtr;
+ ldns_buffer *b;
+ int lnr = 0, oldline;
+ if(!line_nr) line_nr = &lnr;
+
+ /* do this better
+ * expect =
+ * 0: keyword
+ * 1: default domain dname
+ * 2: NS aaaa or a record
+ */
+
+ /* recognized keywords */
+ keyword[LDNS_RESOLV_NAMESERVER] = "nameserver";
+ keyword[LDNS_RESOLV_DEFDOMAIN] = "domain";
+ keyword[LDNS_RESOLV_SEARCH] = "search";
+ /* these two are read but not used atm TODO */
+ keyword[LDNS_RESOLV_SORTLIST] = "sortlist";
+ keyword[LDNS_RESOLV_OPTIONS] = "options";
+ keyword[LDNS_RESOLV_ANCHOR] = "anchor";
+ expect = LDNS_RESOLV_KEYWORD;
+
+ r = ldns_resolver_new();
+ if (!r) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ gtr = 1;
+ word[0] = 0;
+ oldline = *line_nr;
+ expect = LDNS_RESOLV_KEYWORD;
+ while (gtr > 0) {
+ /* check comments */
+ if (word[0] == '#') {
+ word[0]='x';
+ if(oldline == *line_nr) {
+ /* skip until end of line */
+ int c;
+ do {
+ c = fgetc(fp);
+ } while(c != EOF && c != '\n');
+ if(c=='\n' && line_nr) (*line_nr)++;
+ }
+ /* and read next to prepare for further parsing */
+ oldline = *line_nr;
+ continue;
+ }
+ oldline = *line_nr;
+ switch(expect) {
+ case LDNS_RESOLV_KEYWORD:
+ /* keyword */
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+ if (gtr != 0) {
+ if(word[0] == '#') continue;
+ for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) {
+ if (strcasecmp(keyword[i], word) == 0) {
+ /* chosen the keyword and
+ * expect values carefully
+ */
+ expect = i;
+ break;
+ }
+ }
+ /* no keyword recognized */
+ if (expect == LDNS_RESOLV_KEYWORD) {
+ /* skip line */
+ /*
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_SYNTAX_KEYWORD_ERR;
+ */
+ }
+ }
+ break;
+ case LDNS_RESOLV_DEFDOMAIN:
+ /* default domain dname */
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+ if (gtr == 0) {
+ return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
+ }
+ if(word[0] == '#') {
+ expect = LDNS_RESOLV_KEYWORD;
+ continue;
+ }
+ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
+ if (!tmp) {
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_SYNTAX_DNAME_ERR;
+ }
+
+ /* DOn't free, because we copy the pointer */
+ ldns_resolver_set_domain(r, tmp);
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ case LDNS_RESOLV_NAMESERVER:
+ /* NS aaaa or a record */
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+ if (gtr == 0) {
+ return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
+ }
+ if(word[0] == '#') {
+ expect = LDNS_RESOLV_KEYWORD;
+ continue;
+ }
+ if(strchr(word, '%')) {
+ /* snip off interface labels,
+ * fe80::222:19ff:fe31:4222%eth0 */
+ strchr(word, '%')[0]=0;
+ }
+ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word);
+ if (!tmp) {
+ /* try ip4 */
+ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, word);
+ }
+ /* could not parse it, exit */
+ if (!tmp) {
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_SYNTAX_ERR;
+ }
+ (void)ldns_resolver_push_nameserver(r, tmp);
+ ldns_rdf_deep_free(tmp);
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ case LDNS_RESOLV_SEARCH:
+ /* search list domain dname */
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+ b = LDNS_MALLOC(ldns_buffer);
+ if(!b) {
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ ldns_buffer_new_frm_data(b, word, (size_t) gtr);
+ if(ldns_buffer_status(b) != LDNS_STATUS_OK) {
+ LDNS_FREE(b);
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1);
+ while (bgtr > 0) {
+ gtr -= bgtr;
+ if(word[0] == '#') {
+ expect = LDNS_RESOLV_KEYWORD;
+ ldns_buffer_free(b);
+ continue;
+ }
+ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
+ if (!tmp) {
+ ldns_resolver_deep_free(r);
+ ldns_buffer_free(b);
+ return LDNS_STATUS_SYNTAX_DNAME_ERR;
+ }
+
+ ldns_resolver_push_searchlist(r, tmp);
+
+ ldns_rdf_deep_free(tmp);
+ bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL,
+ (size_t) gtr + 1);
+ }
+ ldns_buffer_free(b);
+ gtr = 1;
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ case LDNS_RESOLV_SORTLIST:
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+ /* sortlist not implemented atm */
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ case LDNS_RESOLV_OPTIONS:
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
+ /* options not implemented atm */
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ case LDNS_RESOLV_ANCHOR:
+ /* a file containing a DNSSEC trust anchor */
+ gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
+ if (gtr == 0) {
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
+ }
+ if(word[0] == '#') {
+ expect = LDNS_RESOLV_KEYWORD;
+ continue;
+ }
+
+#ifdef HAVE_SSL
+ tmp_rr = ldns_read_anchor_file(word);
+ (void) ldns_resolver_push_dnssec_anchor(r, tmp_rr);
+ ldns_rr_free(tmp_rr);
+#endif
+ expect = LDNS_RESOLV_KEYWORD;
+ break;
+ }
+ }
+
+ if (res) {
+ *res = r;
+ return LDNS_STATUS_OK;
+ } else {
+ ldns_resolver_deep_free(r);
+ return LDNS_STATUS_NULL;
+ }
+}
+
+ldns_status
+ldns_resolver_new_frm_file(ldns_resolver **res, const char *filename)
+{
+ ldns_resolver *r;
+ FILE *fp;
+ ldns_status s;
+
+ if (!filename) {
+ fp = fopen(LDNS_RESOLV_CONF, "r");
+
+ } else {
+ fp = fopen(filename, "r");
+ }
+ if (!fp) {
+ return LDNS_STATUS_FILE_ERR;
+ }
+
+ s = ldns_resolver_new_frm_fp(&r, fp);
+ fclose(fp);
+ if (s == LDNS_STATUS_OK) {
+ if (res) {
+ *res = r;
+ return LDNS_STATUS_OK;
+ } else {
+ return LDNS_STATUS_NULL;
+ }
+ }
+ return s;
+}
+
+void
+ldns_resolver_free(ldns_resolver *res)
+{
+ LDNS_FREE(res);
+}
+
+void
+ldns_resolver_deep_free(ldns_resolver *res)
+{
+ size_t i;
+
+ if (res) {
+ if (res->_searchlist) {
+ for (i = 0; i < ldns_resolver_searchlist_count(res); i++) {
+ ldns_rdf_deep_free(res->_searchlist[i]);
+ }
+ LDNS_FREE(res->_searchlist);
+ }
+ if (res->_nameservers) {
+ for (i = 0; i < res->_nameserver_count; i++) {
+ ldns_rdf_deep_free(res->_nameservers[i]);
+ }
+ LDNS_FREE(res->_nameservers);
+ }
+ if (ldns_resolver_domain(res)) {
+ ldns_rdf_deep_free(ldns_resolver_domain(res));
+ }
+ if (res->_tsig_keyname) {
+ LDNS_FREE(res->_tsig_keyname);
+ }
+ if (res->_tsig_keydata) {
+ LDNS_FREE(res->_tsig_keydata);
+ }
+ if (res->_tsig_algorithm) {
+ LDNS_FREE(res->_tsig_algorithm);
+ }
+
+ if (res->_cur_axfr_pkt) {
+ ldns_pkt_free(res->_cur_axfr_pkt);
+ }
+
+ if (res->_rtt) {
+ LDNS_FREE(res->_rtt);
+ }
+ if (res->_dnssec_anchors) {
+ ldns_rr_list_deep_free(res->_dnssec_anchors);
+ }
+ LDNS_FREE(res);
+ }
+}
+
+ldns_pkt *
+ldns_resolver_search(const ldns_resolver *r,const ldns_rdf *name,
+ ldns_rr_type t, ldns_rr_class c, uint16_t flags)
+{
+
+ char *str_dname;
+ ldns_rdf *new_name;
+ ldns_rdf **search_list;
+ size_t i;
+ ldns_pkt *p;
+
+ str_dname = ldns_rdf2str(name);
+
+ if (ldns_dname_str_absolute(str_dname)) {
+ /* query as-is */
+ return ldns_resolver_query(r, name, t, c, flags);
+ } else if (ldns_resolver_dnsrch(r)) {
+ search_list = ldns_resolver_searchlist(r);
+ for (i = 0; i < ldns_resolver_searchlist_count(r); i++) {
+ new_name = ldns_dname_cat_clone(name, search_list[i]);
+
+ p = ldns_resolver_query(r, new_name, t, c, flags);
+ ldns_rdf_free(new_name);
+ if (p) {
+ if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NOERROR) {
+ return p;
+ } else {
+ ldns_pkt_free(p);
+ p = NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+ldns_pkt *
+ldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name,
+ ldns_rr_type t, ldns_rr_class c, uint16_t flags)
+{
+ ldns_rdf *newname;
+ ldns_pkt *pkt;
+ ldns_status status;
+
+ pkt = NULL;
+
+ if (!ldns_resolver_defnames(r)) {
+ status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name,
+ t, c, flags);
+ if (status == LDNS_STATUS_OK) {
+ return pkt;
+ } else {
+ if (pkt) {
+ ldns_pkt_free(pkt);
+ }
+ return NULL;
+ }
+ }
+
+ if (!ldns_resolver_domain(r)) {
+ /* _defnames is set, but the domain is not....?? */
+ status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name,
+ t, c, flags);
+ if (status == LDNS_STATUS_OK) {
+ return pkt;
+ } else {
+ if (pkt) {
+ ldns_pkt_free(pkt);
+ }
+ return NULL;
+ }
+ }
+
+ newname = ldns_dname_cat_clone((const ldns_rdf*)name, ldns_resolver_domain(r));
+ if (!newname) {
+ if (pkt) {
+ ldns_pkt_free(pkt);
+ }
+ return NULL;
+ }
+
+ (void)ldns_resolver_send(&pkt, (ldns_resolver *)r, newname, t, c,
+ flags);
+
+ ldns_rdf_free(newname);
+
+ return pkt;
+}
+
+static size_t *
+ldns_resolver_backup_rtt(ldns_resolver *r)
+{
+ size_t *new_rtt;
+ size_t *old_rtt = ldns_resolver_rtt(r);
+
+ if (old_rtt && ldns_resolver_nameserver_count(r)) {
+ new_rtt = LDNS_XMALLOC(size_t
+ , ldns_resolver_nameserver_count(r));
+ memcpy(new_rtt, old_rtt, sizeof(size_t)
+ * ldns_resolver_nameserver_count(r));
+ ldns_resolver_set_rtt(r, new_rtt);
+ return old_rtt;
+ }
+ return NULL;
+}
+
+static void
+ldns_resolver_restore_rtt(ldns_resolver *r, size_t *old_rtt)
+{
+ size_t *cur_rtt = ldns_resolver_rtt(r);
+
+ if (cur_rtt) {
+ LDNS_FREE(cur_rtt);
+ }
+ ldns_resolver_set_rtt(r, old_rtt);
+}
+
+ldns_status
+ldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r,
+ ldns_pkt *query_pkt)
+{
+ ldns_pkt *answer_pkt = NULL;
+ ldns_status stat = LDNS_STATUS_OK;
+ size_t *rtt;
+
+ stat = ldns_send(&answer_pkt, (ldns_resolver *)r, query_pkt);
+ if (stat != LDNS_STATUS_OK) {
+ if(answer_pkt) {
+ ldns_pkt_free(answer_pkt);
+ answer_pkt = NULL;
+ }
+ } else {
+ /* if tc=1 fall back to EDNS and/or TCP */
+ /* check for tcp first (otherwise we don't care about tc=1) */
+ if (!ldns_resolver_usevc(r) && ldns_resolver_fallback(r)) {
+ if (ldns_pkt_tc(answer_pkt)) {
+ /* was EDNS0 set? */
+ if (ldns_pkt_edns_udp_size(query_pkt) == 0) {
+ ldns_pkt_set_edns_udp_size(query_pkt
+ , 4096);
+ ldns_pkt_free(answer_pkt);
+ /* Nameservers should not become
+ * unreachable because fragments are
+ * dropped (network error). We might
+ * still have success with TCP.
+ * Therefore maintain reachability
+ * statuses of the nameservers by
+ * backup and restore the rtt list.
+ */
+ rtt = ldns_resolver_backup_rtt(r);
+ stat = ldns_send(&answer_pkt, r
+ , query_pkt);
+ ldns_resolver_restore_rtt(r, rtt);
+ }
+ /* either way, if it is still truncated, use TCP */
+ if (stat != LDNS_STATUS_OK ||
+ ldns_pkt_tc(answer_pkt)) {
+ ldns_resolver_set_usevc(r, true);
+ ldns_pkt_free(answer_pkt);
+ stat = ldns_send(&answer_pkt, r, query_pkt);
+ ldns_resolver_set_usevc(r, false);
+ }
+ }
+ }
+ }
+
+ if (answer) {
+ *answer = answer_pkt;
+ }
+
+ return stat;
+}
+
+ldns_status
+ldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r,
+ const ldns_rdf *name, ldns_rr_type t,
+ ldns_rr_class c, uint16_t flags)
+{
+ struct timeval now;
+
+ /* prepare a question pkt from the parameters
+ * and then send this */
+ *query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags);
+ if (!*query_pkt) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* set DO bit if necessary */
+ if (ldns_resolver_dnssec(r)) {
+ if (ldns_resolver_edns_udp_size(r) == 0) {
+ ldns_resolver_set_edns_udp_size(r, 4096);
+ }
+ ldns_pkt_set_edns_do(*query_pkt, true);
+ if (ldns_resolver_dnssec_cd(r) || (flags & LDNS_CD)) {
+ ldns_pkt_set_cd(*query_pkt, true);
+ }
+ }
+
+ /* transfer the udp_edns_size from the resolver to the packet */
+ if (ldns_resolver_edns_udp_size(r) != 0) {
+ ldns_pkt_set_edns_udp_size(*query_pkt, ldns_resolver_edns_udp_size(r));
+ }
+
+ /* set the timestamp */
+ now.tv_sec = time(NULL);
+ now.tv_usec = 0;
+ ldns_pkt_set_timestamp(*query_pkt, now);
+
+
+ if (ldns_resolver_debug(r)) {
+ ldns_pkt_print(stdout, *query_pkt);
+ }
+
+ /* only set the id if it is not set yet */
+ if (ldns_pkt_id(*query_pkt) == 0) {
+ ldns_pkt_set_random_id(*query_pkt);
+ }
+
+ return LDNS_STATUS_OK;
+}
+
+
+ldns_status
+ldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name,
+ ldns_rr_type t, ldns_rr_class c, uint16_t flags)
+{
+ ldns_pkt *query_pkt;
+ ldns_pkt *answer_pkt;
+ ldns_status status;
+
+ assert(r != NULL);
+ assert(name != NULL);
+
+ answer_pkt = NULL;
+
+ /* do all the preprocessing here, then fire of an query to
+ * the network */
+
+ if (0 == t) {
+ t= LDNS_RR_TYPE_A;
+ }
+ if (0 == c) {
+ c= LDNS_RR_CLASS_IN;
+ }
+ if (0 == ldns_resolver_nameserver_count(r)) {
+ return LDNS_STATUS_RES_NO_NS;
+ }
+ if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
+ return LDNS_STATUS_RES_QUERY;
+ }
+
+ status = ldns_resolver_prepare_query_pkt(&query_pkt, r, name,
+ t, c, flags);
+ if (status != LDNS_STATUS_OK) {
+ return status;
+ }
+
+ /* if tsig values are set, tsign it */
+ /* TODO: make last 3 arguments optional too? maybe make complete
+ rr instead of seperate values in resolver (and packet)
+ Jelte
+ should this go in pkt_prepare?
+ */
+ if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) {
+#ifdef HAVE_SSL
+ status = ldns_pkt_tsig_sign(query_pkt,
+ ldns_resolver_tsig_keyname(r),
+ ldns_resolver_tsig_keydata(r),
+ 300, ldns_resolver_tsig_algorithm(r), NULL);
+ if (status != LDNS_STATUS_OK) {
+ return LDNS_STATUS_CRYPTO_TSIG_ERR;
+ }
+#else
+ return LDNS_STATUS_CRYPTO_TSIG_ERR;
+#endif /* HAVE_SSL */
+ }
+
+ status = ldns_resolver_send_pkt(&answer_pkt, r, query_pkt);
+ ldns_pkt_free(query_pkt);
+
+ /* allows answer to be NULL when not interested in return value */
+ if (answer) {
+ *answer = answer_pkt;
+ }
+ return status;
+}
+
+ldns_rr *
+ldns_axfr_next(ldns_resolver *resolver)
+{
+ ldns_rr *cur_rr;
+ uint8_t *packet_wire;
+ size_t packet_wire_size;
+ ldns_lookup_table *rcode;
+ ldns_status status;
+
+ /* check if start() has been called */
+ if (!resolver || resolver->_socket == 0) {
+ return NULL;
+ }
+
+ if (resolver->_cur_axfr_pkt) {
+ if (resolver->_axfr_i == ldns_pkt_ancount(resolver->_cur_axfr_pkt)) {
+ ldns_pkt_free(resolver->_cur_axfr_pkt);
+ resolver->_cur_axfr_pkt = NULL;
+ return ldns_axfr_next(resolver);
+ }
+ cur_rr = ldns_rr_clone(ldns_rr_list_rr(
+ ldns_pkt_answer(resolver->_cur_axfr_pkt),
+ resolver->_axfr_i));
+ resolver->_axfr_i++;
+ if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) {
+ resolver->_axfr_soa_count++;
+ if (resolver->_axfr_soa_count >= 2) {
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+ ldns_pkt_free(resolver->_cur_axfr_pkt);
+ resolver->_cur_axfr_pkt = NULL;
+ }
+ }
+ return cur_rr;
+ } else {
+ packet_wire = ldns_tcp_read_wire(resolver->_socket, &packet_wire_size);
+ if(!packet_wire)
+ return NULL;
+
+ status = ldns_wire2pkt(&resolver->_cur_axfr_pkt, packet_wire,
+ packet_wire_size);
+ free(packet_wire);
+
+ resolver->_axfr_i = 0;
+ if (status != LDNS_STATUS_OK) {
+ /* TODO: make status return type of this function (...api change) */
+ fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status));
+
+ /* RoRi: we must now also close the socket, otherwise subsequent uses of the
+ same resolver structure will fail because the link is still open or
+ in an undefined state */
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return NULL;
+ } else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) {
+ rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(resolver->_cur_axfr_pkt));
+ fprintf(stderr, "Error in AXFR: %s\n", rcode->name);
+
+ /* RoRi: we must now also close the socket, otherwise subsequent uses of the
+ same resolver structure will fail because the link is still open or
+ in an undefined state */
+#ifndef USE_WINSOCK
+ close(resolver->_socket);
+#else
+ closesocket(resolver->_socket);
+#endif
+ resolver->_socket = 0;
+
+ return NULL;
+ } else {
+ return ldns_axfr_next(resolver);
+ }
+
+ }
+
+}
+
+bool
+ldns_axfr_complete(const ldns_resolver *res)
+{
+ /* complete when soa count is 2? */
+ return res->_axfr_soa_count == 2;
+}
+
+ldns_pkt *
+ldns_axfr_last_pkt(const ldns_resolver *res)
+{
+ return res->_cur_axfr_pkt;
+}
+
+/* random isn't really that good */
+void
+ldns_resolver_nameservers_randomize(ldns_resolver *r)
+{
+ uint16_t i, j;
+ ldns_rdf **ns, *tmp;
+
+ /* should I check for ldns_resolver_random?? */
+ assert(r != NULL);
+
+ ns = ldns_resolver_nameservers(r);
+ for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
+ j = ldns_get_random() % ldns_resolver_nameserver_count(r);
+ tmp = ns[i];
+ ns[i] = ns[j];
+ ns[j] = tmp;
+ }
+ ldns_resolver_set_nameservers(r, ns);
+}
+
diff --git a/3rdParty/Ldns/src/src/rr.c b/3rdParty/Ldns/src/src/rr.c
new file mode 100644
index 0000000..b61e119
--- /dev/null
+++ b/3rdParty/Ldns/src/src/rr.c
@@ -0,0 +1,2421 @@
+/* rr.c
+ *
+ * access functions for ldns_rr -
+ * a Net::DNS like library for C
+ * LibDNS Team @ NLnet Labs
+ *
+ * (c) NLnet Labs, 2004-2006
+ * See the file LICENSE for the license
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+#include <limits.h>
+
+#include <errno.h>
+
+#define LDNS_SYNTAX_DATALEN 16
+#define LDNS_TTL_DATALEN 21
+#define LDNS_RRLIST_INIT 8
+
+ldns_rr *
+ldns_rr_new(void)
+{
+ ldns_rr *rr;
+ rr = LDNS_MALLOC(ldns_rr);
+ if (!rr) {
+ return NULL;
+ }
+
+ ldns_rr_set_owner(rr, NULL);
+ ldns_rr_set_question(rr, false);
+ ldns_rr_set_rd_count(rr, 0);
+ rr->_rdata_fields = NULL;
+ ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
+ ldns_rr_set_ttl(rr, LDNS_DEFAULT_TTL);
+ return rr;
+}
+
+ldns_rr *
+ldns_rr_new_frm_type(ldns_rr_type t)
+{
+ ldns_rr *rr;
+ const ldns_rr_descriptor *desc;
+ size_t i;
+
+ rr = LDNS_MALLOC(ldns_rr);
+ if (!rr) {
+ return NULL;
+ }
+
+ desc = ldns_rr_descript(t);
+
+ rr->_rdata_fields = LDNS_XMALLOC(ldns_rdf *, ldns_rr_descriptor_minimum(desc));
+ if(!rr->_rdata_fields) {
+ LDNS_FREE(rr);
+ return NULL;
+ }
+ for (i = 0; i < ldns_rr_descriptor_minimum(desc); i++) {
+ rr->_rdata_fields[i] = NULL;
+ }
+
+ ldns_rr_set_owner(rr, NULL);
+ ldns_rr_set_question(rr, false);
+ /* set the count to minimum */
+ ldns_rr_set_rd_count(rr, ldns_rr_descriptor_minimum(desc));
+ ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
+ ldns_rr_set_ttl(rr, LDNS_DEFAULT_TTL);
+ ldns_rr_set_type(rr, t);
+ return rr;
+}
+
+void
+ldns_rr_free(ldns_rr *rr)
+{
+ size_t i;
+ if (rr) {
+ if (ldns_rr_owner(rr)) {
+ ldns_rdf_deep_free(ldns_rr_owner(rr));
+ }
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ ldns_rdf_deep_free(ldns_rr_rdf(rr, i));
+ }
+ LDNS_FREE(rr->_rdata_fields);
+ LDNS_FREE(rr);
+ }
+}
+
+/*
+ * trailing spaces are allowed
+ * leading spaces are not allowed
+ * allow ttl to be optional
+ * class is optional too
+ * if ttl is missing, and default_ttl is 0, use DEF_TTL
+ * allow ttl to be written as 1d3h
+ * So the RR should look like. e.g.
+ * miek.nl. 3600 IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. 1h IN MX 10 elektron.atoom.net
+ * or
+ * miek.nl. IN MX 10 elektron.atoom.net
+ */
+static ldns_status
+ldns_rr_new_frm_str_internal(ldns_rr **newrr, const char *str,
+ uint32_t default_ttl, ldns_rdf *origin,
+ ldns_rdf **prev, bool question)
+{
+ ldns_rr *new;
+ const ldns_rr_descriptor *desc;
+ ldns_rr_type rr_type;
+ ldns_buffer *rr_buf = NULL;
+ ldns_buffer *rd_buf = NULL;
+ uint32_t ttl_val;
+ char *owner = NULL;
+ char *ttl = NULL;
+ ldns_rr_class clas_val;
+ char *clas = NULL;
+ char *type = NULL;
+ char *rdata = NULL;
+ char *rd = NULL;
+ char *b64 = NULL;
+ size_t rd_strlen;
+ const char *delimiters;
+ ssize_t c;
+ ldns_rdf *owner_dname;
+ const char* endptr;
+ int was_unknown_rr_format = 0;
+ ldns_status status = LDNS_STATUS_OK;
+
+ /* used for types with unknown number of rdatas */
+ bool done;
+ bool quoted;
+
+ ldns_rdf *r = NULL;
+ uint16_t r_cnt;
+ uint16_t r_min;
+ uint16_t r_max;
+ size_t pre_data_pos;
+
+ new = ldns_rr_new();
+
+ owner = LDNS_XMALLOC(char, LDNS_MAX_DOMAINLEN + 1);
+ ttl = LDNS_XMALLOC(char, LDNS_TTL_DATALEN);
+ clas = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN);
+ rdata = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN + 1);
+ rr_buf = LDNS_MALLOC(ldns_buffer);
+ rd_buf = LDNS_MALLOC(ldns_buffer);
+ rd = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
+ b64 = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
+ if (!new || !owner || !ttl || !clas || !rdata || !rr_buf || !rd_buf || !rd || !b64 ) {
+ status = LDNS_STATUS_MEM_ERR;
+ LDNS_FREE(rr_buf);
+ goto ldnserror;
+ }
+
+ ldns_buffer_new_frm_data(rr_buf, (char*)str, strlen(str));
+
+ /* split the rr in its parts -1 signals trouble */
+ if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1) {
+ status = LDNS_STATUS_SYNTAX_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+
+ if (ldns_bget_token(rr_buf, ttl, "\t\n ", LDNS_TTL_DATALEN) == -1) {
+ status = LDNS_STATUS_SYNTAX_TTL_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ ttl_val = (uint32_t) ldns_str2period(ttl, &endptr);
+
+ if (strlen(ttl) > 0 && !isdigit((int) ttl[0])) {
+ /* ah, it's not there or something */
+ if (default_ttl == 0) {
+ ttl_val = LDNS_DEFAULT_TTL;
+ } else {
+ ttl_val = default_ttl;
+ }
+ /* we not ASSUMING the TTL is missing and that
+ * the rest of the RR is still there. That is
+ * CLASS TYPE RDATA
+ * so ttl value we read is actually the class
+ */
+ clas_val = ldns_get_rr_class_by_name(ttl);
+ /* class can be left out too, assume IN, current
+ * token must be type
+ */
+ if (clas_val == 0) {
+ clas_val = LDNS_RR_CLASS_IN;
+ type = LDNS_XMALLOC(char, strlen(ttl) + 1);
+ if(!type) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ strncpy(type, ttl, strlen(ttl) + 1);
+ }
+ } else {
+ if (ldns_bget_token(rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
+ status = LDNS_STATUS_SYNTAX_CLASS_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ clas_val = ldns_get_rr_class_by_name(clas);
+ /* class can be left out too, assume IN, current
+ * token must be type
+ */
+ if (clas_val == 0) {
+ clas_val = LDNS_RR_CLASS_IN;
+ type = LDNS_XMALLOC(char, strlen(clas) + 1);
+ if(!type) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ strncpy(type, clas, strlen(clas) + 1);
+ }
+ }
+ /* the rest should still be waiting for us */
+
+ if (!type) {
+ type = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN);
+ if(!type) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ if (ldns_bget_token(rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
+ status = LDNS_STATUS_SYNTAX_TYPE_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ }
+
+ if (ldns_bget_token(rr_buf, rdata, "\0", LDNS_MAX_PACKETLEN) == -1) {
+ /* apparently we are done, and it's only a question RR
+ * so do not set status and go to ldnserror here
+ */
+ }
+
+ ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata));
+
+ if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) {
+ if (origin) {
+ ldns_rr_set_owner(new, ldns_rdf_clone(origin));
+ } else if (prev && *prev) {
+ ldns_rr_set_owner(new, ldns_rdf_clone(*prev));
+ } else {
+ /* default to root */
+ ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
+ }
+
+ /* @ also overrides prev */
+ if (prev) {
+ ldns_rdf_deep_free(*prev);
+ *prev = ldns_rdf_clone(ldns_rr_owner(new));
+ if (!*prev) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ }
+ } else {
+ if (strlen(owner) == 0) {
+ /* no ownername was given, try prev, if that fails
+ * origin, else default to root */
+ if (prev && *prev) {
+ ldns_rr_set_owner(new, ldns_rdf_clone(*prev));
+ } else if (origin) {
+ ldns_rr_set_owner(new, ldns_rdf_clone(origin));
+ } else {
+ ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
+ }
+ if(!ldns_rr_owner(new)) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ } else {
+ owner_dname = ldns_dname_new_frm_str(owner);
+ if (!owner_dname) {
+ status = LDNS_STATUS_SYNTAX_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+
+ ldns_rr_set_owner(new, owner_dname);
+ if (!ldns_dname_str_absolute(owner) && origin) {
+ if(ldns_dname_cat(ldns_rr_owner(new),
+ origin) != LDNS_STATUS_OK) {
+ status = LDNS_STATUS_SYNTAX_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ }
+ if (prev) {
+ ldns_rdf_deep_free(*prev);
+ *prev = ldns_rdf_clone(ldns_rr_owner(new));
+ if(!*prev) {
+ status = LDNS_STATUS_MEM_ERR;
+ ldns_buffer_free(rr_buf);
+ goto ldnserror;
+ }
+ }
+ }
+ }
+ LDNS_FREE(owner);
+ owner = NULL;
+
+ ldns_rr_set_question(new, question);
+
+ ldns_rr_set_ttl(new, ttl_val);
+ LDNS_FREE(ttl);
+ ttl = NULL;
+
+ ldns_rr_set_class(new, clas_val);
+ LDNS_FREE(clas);
+ clas = NULL;
+
+ rr_type = ldns_get_rr_type_by_name(type);
+ LDNS_FREE(type);
+ type = NULL;
+
+ desc = ldns_rr_descript((uint16_t)rr_type);
+ ldns_rr_set_type(new, rr_type);
+ if (desc) {
+ /* only the rdata remains */
+ r_max = ldns_rr_descriptor_maximum(desc);
+ r_min = ldns_rr_descriptor_minimum(desc);
+ } else {
+ r_min = 0;
+ r_max = 1;
+ }
+
+ /* depending on the rr_type we need to extract
+ * the rdata differently, e.g. NSEC/NSEC3 */
+ switch(rr_type) {
+ default:
+ done = false;
+
+ for (r_cnt = 0; !done && r_cnt < r_max; r_cnt++) {
+ quoted = false;
+ /* if type = B64, the field may contain spaces */
+ if (ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_B64 ||
+ ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_HEX ||
+ ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_LOC ||
+ ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_WKS ||
+ ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_IPSECKEY ||
+ ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_NSEC) {
+ delimiters = "\n\t";
+ } else {
+ delimiters = "\n\t ";
+ }
+
+ if (ldns_rr_descriptor_field_type(desc,
+ r_cnt) == LDNS_RDF_TYPE_STR &&
+ ldns_buffer_remaining(rd_buf) > 0) {
+ /* skip spaces */
+ while (*(ldns_buffer_current(rd_buf)) == ' ') {
+ ldns_buffer_skip(rd_buf, 1);
+ }
+
+ if (*(ldns_buffer_current(rd_buf)) == '\"') {
+ delimiters = "\"\0";
+ ldns_buffer_skip(rd_buf, 1);
+ quoted = true;
+ }
+ }
+
+ /* because number of fields can be variable, we can't
+ rely on _maximum() only */
+ /* skip spaces */
+ while (ldns_buffer_position(rd_buf) < ldns_buffer_limit(rd_buf) &&
+ *(ldns_buffer_current(rd_buf)) == ' ' && !quoted
+ ) {
+ ldns_buffer_skip(rd_buf, 1);
+ }
+
+ pre_data_pos = ldns_buffer_position(rd_buf);
+ if ((c = ldns_bget_token(rd_buf, rd, delimiters,
+ LDNS_MAX_RDFLEN)) != -1) {
+ /* hmmz, rfc3597 specifies that any type can be represented with
+ * \# method, which can contain spaces...
+ * it does specify size though...
+ */
+ rd_strlen = strlen(rd);
+
+ /* unknown RR data */
+ if (strncmp(rd, "\\#", 2) == 0 && !quoted && (rd_strlen == 2 || rd[2]==' ')) {
+ uint16_t hex_data_size;
+ char *hex_data_str;
+ uint16_t cur_hex_data_size;
+
+ was_unknown_rr_format = 1;
+ /* go back to before \# and skip it while setting delimiters better */
+ ldns_buffer_set_position(rd_buf, pre_data_pos);
+ delimiters = "\n\t ";
+ (void)ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
+ /* read rdata octet length */
+ c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
+ if (c == -1) {
+ /* something goes very wrong here */
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ }
+ hex_data_size = (uint16_t) atoi(rd);
+ /* copy the hex chars into hex str (which is 2 chars per byte) */
+ hex_data_str = LDNS_XMALLOC(char, 2 * hex_data_size + 1);
+ if (!hex_data_str) {
+ /* malloc error */
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ }
+ cur_hex_data_size = 0;
+ while(cur_hex_data_size < 2 * hex_data_size) {
+ c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
+ if (c != -1) {
+ rd_strlen = strlen(rd);
+ }
+ if (c == -1 || (size_t)cur_hex_data_size + rd_strlen > 2 * (size_t)hex_data_size) {
+ LDNS_FREE(hex_data_str);
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ }
+ strncpy(hex_data_str + cur_hex_data_size, rd, rd_strlen);
+ cur_hex_data_size += rd_strlen;
+ }
+ hex_data_str[cur_hex_data_size] = '\0';
+
+ /* correct the rdf type */
+ /* if *we* know the type, interpret it as wireformat */
+ if (desc) {
+ size_t hex_pos = 0;
+ uint8_t *hex_data = LDNS_XMALLOC(uint8_t, hex_data_size + 2);
+ ldns_status s;
+ if(!hex_data) {
+ LDNS_FREE(hex_data_str);
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ ldns_write_uint16(hex_data, hex_data_size);
+ ldns_hexstring_to_data(hex_data + 2, hex_data_str);
+ s = ldns_wire2rdf(new, hex_data,
+ hex_data_size+2, &hex_pos);
+ if(s != LDNS_STATUS_OK) {
+ LDNS_FREE(hex_data_str);
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return s;
+ }
+ LDNS_FREE(hex_data);
+ } else {
+ r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str);
+ if(!r) {
+ LDNS_FREE(hex_data_str);
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN);
+ if(!ldns_rr_push_rdf(new, r)) {
+ LDNS_FREE(hex_data_str);
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ }
+ LDNS_FREE(hex_data_str);
+ } else {
+ /* Normal RR */
+ switch(ldns_rr_descriptor_field_type(desc, r_cnt)) {
+ case LDNS_RDF_TYPE_HEX:
+ case LDNS_RDF_TYPE_B64:
+ /* can have spaces, and will always be the last
+ * record of the rrdata. Read in the rest */
+ if ((c = ldns_bget_token(rd_buf,
+ b64,
+ "\n",
+ LDNS_MAX_RDFLEN))
+ != -1) {
+ rd = strncat(rd,
+ b64,
+ LDNS_MAX_RDFLEN
+ - strlen(rd) - 1);
+ }
+ r = ldns_rdf_new_frm_str(
+ ldns_rr_descriptor_field_type(desc, r_cnt),
+ rd);
+ break;
+ case LDNS_RDF_TYPE_DNAME:
+ r = ldns_rdf_new_frm_str(
+ ldns_rr_descriptor_field_type(desc, r_cnt),
+ rd);
+
+ /* check if the origin should be used or concatenated */
+ if (r && ldns_rdf_size(r) > 1 && ldns_rdf_data(r)[0] == 1
+ && ldns_rdf_data(r)[1] == '@') {
+ ldns_rdf_deep_free(r);
+ if (origin) {
+ r = ldns_rdf_clone(origin);
+ } else {
+ /* if this is the SOA, use its own owner name */
+ if (rr_type == LDNS_RR_TYPE_SOA) {
+ r = ldns_rdf_clone(ldns_rr_owner(new));
+ } else {
+ r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".");
+ }
+ }
+ } else if (r && rd_strlen >= 1 && !ldns_dname_str_absolute(rd) && origin) {
+ if (ldns_dname_cat(r, origin) != LDNS_STATUS_OK) {
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_ERR;
+ }
+ }
+ break;
+ default:
+ r = ldns_rdf_new_frm_str(
+ ldns_rr_descriptor_field_type(desc, r_cnt),
+ rd);
+ break;
+ }
+ if (r) {
+ ldns_rr_push_rdf(new, r);
+ } else {
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+ ldns_rr_free(new);
+ return LDNS_STATUS_SYNTAX_RDATA_ERR;
+ }
+ }
+ if (quoted) {
+ if (ldns_buffer_available(rd_buf, 1)) {
+ ldns_buffer_skip(rd_buf, 1);
+ } else {
+ done = true;
+ }
+ }
+ } else {
+ done = true;
+ }
+ }
+ }
+ LDNS_FREE(rd);
+ LDNS_FREE(b64);
+ ldns_buffer_free(rd_buf);
+ ldns_buffer_free(rr_buf);
+ LDNS_FREE(rdata);
+
+ if (!question && desc && !was_unknown_rr_format && ldns_rr_rd_count(new) < r_min) {
+ ldns_rr_free(new);
+ return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
+ }
+
+ if (newrr) {
+ *newrr = new;
+ }
+ return LDNS_STATUS_OK;
+
+ldnserror:
+ LDNS_FREE(type);
+ LDNS_FREE(owner);
+ LDNS_FREE(ttl);
+ LDNS_FREE(clas);
+ LDNS_FREE(rdata);
+ LDNS_FREE(rd);
+ LDNS_FREE(rd_buf);
+ LDNS_FREE(b64);
+ ldns_rr_free(new);
+ return status;
+}
+
+ldns_status
+ldns_rr_new_frm_str(ldns_rr **newrr, const char *str,
+ uint32_t default_ttl, ldns_rdf *origin,
+ ldns_rdf **prev)
+{
+ return ldns_rr_new_frm_str_internal(newrr,
+ str,
+ default_ttl,
+ origin,
+ prev,
+ false);
+}
+
+ldns_status
+ldns_rr_new_question_frm_str(ldns_rr **newrr, const char *str,
+ ldns_rdf *origin, ldns_rdf **prev)
+{
+ return ldns_rr_new_frm_str_internal(newrr,
+ str,
+ 0,
+ origin,
+ prev,
+ true);
+}
+
+ldns_status
+ldns_rr_new_frm_fp(ldns_rr **newrr, FILE *fp, uint32_t *ttl, ldns_rdf **origin, ldns_rdf **prev)
+{
+ return ldns_rr_new_frm_fp_l(newrr, fp, ttl, origin, prev, NULL);
+}
+
+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)
+{
+ char *line;
+ const char *endptr; /* unused */
+ ldns_rr *rr;
+ uint32_t ttl;
+ ldns_rdf *tmp;
+ ldns_status s;
+ ssize_t size;
+ int offset = 0;
+
+ 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) {
+ LDNS_FREE(line);
+ return LDNS_STATUS_SYNTAX_EMPTY;
+ }
+
+ if (strncmp(line, "$ORIGIN", 7) == 0 && isspace(line[7])) {
+ if (*origin) {
+ ldns_rdf_deep_free(*origin);
+ *origin = NULL;
+ }
+ offset = 8;
+ while (isspace(line[offset])) {
+ offset++;
+ }
+ tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, line + offset);
+ if (!tmp) {
+ /* could not parse what next to $ORIGIN */
+ LDNS_FREE(line);
+ return LDNS_STATUS_SYNTAX_DNAME_ERR;
+ }
+ *origin = tmp;
+ s = LDNS_STATUS_SYNTAX_ORIGIN;
+ } else if (strncmp(line, "$TTL", 4) == 0 && isspace(line[4])) {
+ offset = 5;
+ while (isspace(line[offset])) {
+ offset++;
+ }
+ if (default_ttl) {
+ *default_ttl = ldns_str2period(line + offset, &endptr);
+ }
+ s = LDNS_STATUS_SYNTAX_TTL;
+ } else if (strncmp(line, "$INCLUDE", 8) == 0) {
+ s = LDNS_STATUS_SYNTAX_INCLUDE;
+ } else {
+ if (origin && *origin) {
+ s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, *origin, prev);
+ } else {
+ s = ldns_rr_new_frm_str(&rr, (const char*) line, ttl, NULL, prev);
+ }
+ }
+ LDNS_FREE(line);
+ if (newrr && s == LDNS_STATUS_OK) {
+ *newrr = rr;
+ }
+ return s;
+}
+
+void
+ldns_rr_set_owner(ldns_rr *rr, ldns_rdf *owner)
+{
+ rr->_owner = owner;
+}
+
+void
+ldns_rr_set_question(ldns_rr *rr, bool question)
+{
+ rr->_rr_question = question;
+}
+
+void
+ldns_rr_set_ttl(ldns_rr *rr, uint32_t ttl)
+{
+ rr->_ttl = ttl;
+}
+
+void
+ldns_rr_set_rd_count(ldns_rr *rr, size_t count)
+{
+ rr->_rd_count = count;
+}
+
+void
+ldns_rr_set_type(ldns_rr *rr, ldns_rr_type rr_type)
+{
+ rr->_rr_type = rr_type;
+}
+
+void
+ldns_rr_set_class(ldns_rr *rr, ldns_rr_class rr_class)
+{
+ rr->_rr_class = rr_class;
+}
+
+ldns_rdf *
+ldns_rr_set_rdf(ldns_rr *rr, const ldns_rdf *f, size_t position)
+{
+ size_t rd_count;
+ ldns_rdf *pop;
+
+ rd_count = ldns_rr_rd_count(rr);
+ if (position < rd_count) {
+ /* dicard the old one */
+ pop = rr->_rdata_fields[position];
+ rr->_rdata_fields[position] = (ldns_rdf*)f;
+ return pop;
+ } else {
+ return NULL;
+ }
+}
+
+bool
+ldns_rr_push_rdf(ldns_rr *rr, const ldns_rdf *f)
+{
+ size_t rd_count;
+ ldns_rdf **rdata_fields;
+
+ rd_count = ldns_rr_rd_count(rr);
+
+ /* grow the array */
+ rdata_fields = LDNS_XREALLOC(
+ rr->_rdata_fields, ldns_rdf *, rd_count + 1);
+ if (!rdata_fields) {
+ return false;
+ }
+
+ /* add the new member */
+ rr->_rdata_fields = rdata_fields;
+ rr->_rdata_fields[rd_count] = (ldns_rdf*)f;
+
+ ldns_rr_set_rd_count(rr, rd_count + 1);
+ return true;
+}
+
+ldns_rdf *
+ldns_rr_pop_rdf(ldns_rr *rr)
+{
+ size_t rd_count;
+ ldns_rdf *pop;
+ ldns_rdf** newrd;
+
+ rd_count = ldns_rr_rd_count(rr);
+
+ if (rd_count == 0) {
+ return NULL;
+ }
+
+ pop = rr->_rdata_fields[rd_count - 1];
+
+ /* try to shrink the array */
+ if(rd_count > 1) {
+ newrd = LDNS_XREALLOC(
+ rr->_rdata_fields, ldns_rdf *, rd_count - 1);
+ if(newrd)
+ rr->_rdata_fields = newrd;
+ } else {
+ LDNS_FREE(rr->_rdata_fields);
+ }
+
+ ldns_rr_set_rd_count(rr, rd_count - 1);
+ return pop;
+}
+
+ldns_rdf *
+ldns_rr_rdf(const ldns_rr *rr, size_t nr)
+{
+ if (rr && nr < ldns_rr_rd_count(rr)) {
+ return rr->_rdata_fields[nr];
+ } else {
+ return NULL;
+ }
+}
+
+ldns_rdf *
+ldns_rr_owner(const ldns_rr *rr)
+{
+ return rr->_owner;
+}
+
+bool
+ldns_rr_is_question(const ldns_rr *rr)
+{
+ return rr->_rr_question;
+}
+
+uint32_t
+ldns_rr_ttl(const ldns_rr *rr)
+{
+ return rr->_ttl;
+}
+
+size_t
+ldns_rr_rd_count(const ldns_rr *rr)
+{
+ return rr->_rd_count;
+}
+
+ldns_rr_type
+ldns_rr_get_type(const ldns_rr *rr)
+{
+ return rr->_rr_type;
+}
+
+ldns_rr_class
+ldns_rr_get_class(const ldns_rr *rr)
+{
+ return rr->_rr_class;
+}
+
+/* rr_lists */
+
+size_t
+ldns_rr_list_rr_count(const ldns_rr_list *rr_list)
+{
+ if (rr_list) {
+ return rr_list->_rr_count;
+ } else {
+ return 0;
+ }
+}
+
+ldns_rr *
+ldns_rr_list_set_rr(ldns_rr_list *rr_list, const ldns_rr *r, size_t count)
+{
+ ldns_rr *old;
+
+ if (count > ldns_rr_list_rr_count(rr_list)) {
+ return NULL;
+ }
+
+ old = ldns_rr_list_rr(rr_list, count);
+
+ /* overwrite old's pointer */
+ rr_list->_rrs[count] = (ldns_rr*)r;
+ return old;
+}
+
+void
+ldns_rr_list_set_rr_count(ldns_rr_list *rr_list, size_t count)
+{
+ assert(count <= rr_list->_rr_capacity);
+ rr_list->_rr_count = count;
+}
+
+ldns_rr *
+ldns_rr_list_rr(const ldns_rr_list *rr_list, size_t nr)
+{
+ if (nr < ldns_rr_list_rr_count(rr_list)) {
+ return rr_list->_rrs[nr];
+ } else {
+ return NULL;
+ }
+}
+
+ldns_rr_list *
+ldns_rr_list_new()
+{
+ ldns_rr_list *rr_list = LDNS_MALLOC(ldns_rr_list);
+ if(!rr_list) return NULL;
+ rr_list->_rr_count = 0;
+ rr_list->_rr_capacity = 0;
+ rr_list->_rrs = NULL;
+ return rr_list;
+}
+
+void
+ldns_rr_list_free(ldns_rr_list *rr_list)
+{
+ if (rr_list) {
+ LDNS_FREE(rr_list->_rrs);
+ LDNS_FREE(rr_list);
+ }
+}
+
+void
+ldns_rr_list_deep_free(ldns_rr_list *rr_list)
+{
+ size_t i;
+
+ if (rr_list) {
+ for (i=0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ ldns_rr_free(ldns_rr_list_rr(rr_list, i));
+ }
+ LDNS_FREE(rr_list->_rrs);
+ LDNS_FREE(rr_list);
+ }
+}
+
+
+/* add right to left. So we modify *left! */
+bool
+ldns_rr_list_cat(ldns_rr_list *left, ldns_rr_list *right)
+{
+ size_t r_rr_count;
+ size_t i;
+
+ if (!left) {
+ return false;
+ }
+
+ if (right) {
+ r_rr_count = ldns_rr_list_rr_count(right);
+ } else {
+ r_rr_count = 0;
+ }
+
+ /* push right to left */
+ for(i = 0; i < r_rr_count; i++) {
+ ldns_rr_list_push_rr(left, ldns_rr_list_rr(right, i));
+ }
+ return true;
+}
+
+ldns_rr_list *
+ldns_rr_list_cat_clone(ldns_rr_list *left, ldns_rr_list *right)
+{
+ size_t l_rr_count;
+ size_t r_rr_count;
+ size_t i;
+ ldns_rr_list *cat;
+
+ if (left) {
+ l_rr_count = ldns_rr_list_rr_count(left);
+ } else {
+ return ldns_rr_list_clone(right);
+ }
+
+ if (right) {
+ r_rr_count = ldns_rr_list_rr_count(right);
+ } else {
+ r_rr_count = 0;
+ }
+
+ cat = ldns_rr_list_new();
+
+ if (!cat) {
+ return NULL;
+ }
+
+ /* left */
+ for(i = 0; i < l_rr_count; i++) {
+ ldns_rr_list_push_rr(cat,
+ ldns_rr_clone(ldns_rr_list_rr(left, i)));
+ }
+ /* right */
+ for(i = 0; i < r_rr_count; i++) {
+ ldns_rr_list_push_rr(cat,
+ ldns_rr_clone(ldns_rr_list_rr(right, i)));
+ }
+ return cat;
+}
+
+ldns_rr_list *
+ldns_rr_list_subtype_by_rdf(ldns_rr_list *l, ldns_rdf *r, size_t pos)
+{
+ size_t i;
+ ldns_rr_list *subtyped;
+ ldns_rdf *list_rdf;
+
+ subtyped = ldns_rr_list_new();
+
+ for(i = 0; i < ldns_rr_list_rr_count(l); i++) {
+ list_rdf = ldns_rr_rdf(
+ ldns_rr_list_rr(l, i),
+ pos);
+ if (!list_rdf) {
+ /* pos is too large or any other error */
+ ldns_rr_list_deep_free(subtyped);
+ return NULL;
+ }
+
+ if (ldns_rdf_compare(list_rdf, r) == 0) {
+ /* a match */
+ ldns_rr_list_push_rr(subtyped,
+ ldns_rr_clone(ldns_rr_list_rr(l, i)));
+ }
+ }
+
+ if (ldns_rr_list_rr_count(subtyped) > 0) {
+ return subtyped;
+ } else {
+ ldns_rr_list_free(subtyped);
+ return NULL;
+ }
+}
+
+bool
+ldns_rr_list_push_rr(ldns_rr_list *rr_list, const ldns_rr *rr)
+{
+ size_t rr_count;
+ size_t cap;
+
+ rr_count = ldns_rr_list_rr_count(rr_list);
+ cap = rr_list->_rr_capacity;
+
+ /* grow the array */
+ if(rr_count+1 > cap) {
+ ldns_rr **rrs;
+
+ if(cap == 0)
+ cap = LDNS_RRLIST_INIT; /* initial list size */
+ else cap *= 2;
+ rrs = LDNS_XREALLOC(rr_list->_rrs, ldns_rr *, cap);
+ if (!rrs) {
+ return false;
+ }
+ rr_list->_rrs = rrs;
+ rr_list->_rr_capacity = cap;
+ }
+
+ /* add the new member */
+ rr_list->_rrs[rr_count] = (ldns_rr*)rr;
+
+ ldns_rr_list_set_rr_count(rr_list, rr_count + 1);
+ return true;
+}
+
+bool
+ldns_rr_list_push_rr_list(ldns_rr_list *rr_list, const ldns_rr_list *push_list)
+{
+ size_t i;
+
+ for(i = 0; i < ldns_rr_list_rr_count(push_list); i++) {
+ if (!ldns_rr_list_push_rr(rr_list,
+ ldns_rr_list_rr(push_list, i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+ldns_rr *
+ldns_rr_list_pop_rr(ldns_rr_list *rr_list)
+{
+ size_t rr_count;
+ size_t cap;
+ ldns_rr *pop;
+
+ rr_count = ldns_rr_list_rr_count(rr_list);
+
+ if (rr_count == 0) {
+ return NULL;
+ }
+
+ cap = rr_list->_rr_capacity;
+ pop = ldns_rr_list_rr(rr_list, rr_count - 1);
+
+ /* shrink the array */
+ if(cap > LDNS_RRLIST_INIT && rr_count-1 <= cap/2) {
+ ldns_rr** a;
+ cap /= 2;
+ a = LDNS_XREALLOC(rr_list->_rrs, ldns_rr *, cap);
+ if(a) {
+ rr_list->_rrs = a;
+ rr_list->_rr_capacity = cap;
+ }
+ }
+
+ ldns_rr_list_set_rr_count(rr_list, rr_count - 1);
+
+ return pop;
+}
+
+ldns_rr_list *
+ldns_rr_list_pop_rr_list(ldns_rr_list *rr_list, size_t howmany)
+{
+ /* pop a number of rr's and put them in a rr_list */
+ ldns_rr_list *popped;
+ ldns_rr *p;
+ size_t i = howmany;
+
+ popped = ldns_rr_list_new();
+
+ if (!popped) {
+ return NULL;
+ }
+
+
+ while(i > 0 &&
+ (p = ldns_rr_list_pop_rr(rr_list)) != NULL) {
+ ldns_rr_list_push_rr(popped, p);
+ i--;
+ }
+
+ if (i == howmany) {
+ return NULL;
+ } else {
+ return popped;
+ }
+}
+
+
+bool
+ldns_rr_list_contains_rr(const ldns_rr_list *rr_list, ldns_rr *rr)
+{
+ size_t i;
+
+ if (!rr_list || !rr || ldns_rr_list_rr_count(rr_list) == 0) {
+ return false;
+ }
+
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ if (rr == ldns_rr_list_rr(rr_list, i)) {
+ return true;
+ } else if (ldns_rr_compare(rr, ldns_rr_list_rr(rr_list, i)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ldns_is_rrset(ldns_rr_list *rr_list)
+{
+ ldns_rr_type t;
+ ldns_rr_class c;
+ ldns_rdf *o;
+ ldns_rr *tmp;
+ size_t i;
+
+ if (!rr_list || ldns_rr_list_rr_count(rr_list) == 0) {
+ return false;
+ }
+
+ tmp = ldns_rr_list_rr(rr_list, 0);
+
+ t = ldns_rr_get_type(tmp);
+ c = ldns_rr_get_class(tmp);
+ o = ldns_rr_owner(tmp);
+
+ /* compare these with the rest of the rr_list, start with 1 */
+ for (i = 1; i < ldns_rr_list_rr_count(rr_list); i++) {
+ tmp = ldns_rr_list_rr(rr_list, i);
+ if (t != ldns_rr_get_type(tmp)) {
+ return false;
+ }
+ if (c != ldns_rr_get_class(tmp)) {
+ return false;
+ }
+ if (ldns_rdf_compare(o, ldns_rr_owner(tmp)) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ldns_rr_set_push_rr(ldns_rr_list *rr_list, ldns_rr *rr)
+{
+ size_t rr_count;
+ size_t i;
+ ldns_rr *last;
+
+ assert(rr != NULL);
+
+ rr_count = ldns_rr_list_rr_count(rr_list);
+
+ if (rr_count == 0) {
+ /* nothing there, so checking it is
+ * not needed */
+ return ldns_rr_list_push_rr(rr_list, rr);
+ } else {
+ /* check with the final rr in the rr_list */
+ last = ldns_rr_list_rr(rr_list, rr_count - 1);
+
+ if (ldns_rr_get_class(last) != ldns_rr_get_class(rr)) {
+ return false;
+ }
+ if (ldns_rr_get_type(last) != ldns_rr_get_type(rr)) {
+ return false;
+ }
+ /* only check if not equal to RRSIG */
+ if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
+ if (ldns_rr_ttl(last) != ldns_rr_ttl(rr)) {
+ return false;
+ }
+ }
+ if (ldns_rdf_compare(ldns_rr_owner(last),
+ ldns_rr_owner(rr)) != 0) {
+ return false;
+ }
+ /* ok, still alive - check if the rr already
+ * exists - if so, dont' add it */
+ for(i = 0; i < rr_count; i++) {
+ if(ldns_rr_compare(
+ ldns_rr_list_rr(rr_list, i), rr) == 0) {
+ return false;
+ }
+ }
+ /* it's safe, push it */
+ return ldns_rr_list_push_rr(rr_list, rr);
+ }
+}
+
+ldns_rr *
+ldns_rr_set_pop_rr(ldns_rr_list *rr_list)
+{
+ return ldns_rr_list_pop_rr(rr_list);
+}
+
+ldns_rr_list *
+ldns_rr_list_pop_rrset(ldns_rr_list *rr_list)
+{
+ ldns_rr_list *rrset;
+ ldns_rr *last_rr = NULL;
+ ldns_rr *next_rr;
+
+ if (!rr_list) {
+ return NULL;
+ }
+
+ rrset = ldns_rr_list_new();
+ if (!last_rr) {
+ last_rr = ldns_rr_list_pop_rr(rr_list);
+ if (!last_rr) {
+ ldns_rr_list_free(rrset);
+ return NULL;
+ } else {
+ ldns_rr_list_push_rr(rrset, last_rr);
+ }
+ }
+
+ if (ldns_rr_list_rr_count(rr_list) > 0) {
+ next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1);
+ } else {
+ next_rr = NULL;
+ }
+
+ while (next_rr) {
+ if (
+ ldns_rdf_compare(ldns_rr_owner(next_rr),
+ ldns_rr_owner(last_rr)) == 0
+ &&
+ ldns_rr_get_type(next_rr) == ldns_rr_get_type(last_rr)
+ &&
+ ldns_rr_get_class(next_rr) == ldns_rr_get_class(last_rr)
+ ) {
+ ldns_rr_list_push_rr(rrset, ldns_rr_list_pop_rr(rr_list));
+ if (ldns_rr_list_rr_count(rr_list) > 0) {
+ last_rr = next_rr;
+ next_rr = ldns_rr_list_rr(rr_list, ldns_rr_list_rr_count(rr_list) - 1);
+ } else {
+ next_rr = NULL;
+ }
+ } else {
+ next_rr = NULL;
+ }
+ }
+
+ return rrset;
+}
+
+ldns_rr *
+ldns_rr_clone(const ldns_rr *rr)
+{
+ size_t i;
+ ldns_rr *new_rr;
+
+ if (!rr) {
+ return NULL;
+ }
+
+ new_rr = ldns_rr_new();
+ if (!new_rr) {
+ return NULL;
+ }
+ if (ldns_rr_owner(rr)) {
+ ldns_rr_set_owner(new_rr, ldns_rdf_clone(ldns_rr_owner(rr)));
+ }
+ ldns_rr_set_ttl(new_rr, ldns_rr_ttl(rr));
+ ldns_rr_set_type(new_rr, ldns_rr_get_type(rr));
+ ldns_rr_set_class(new_rr, ldns_rr_get_class(rr));
+ ldns_rr_set_question(new_rr, ldns_rr_is_question(rr));
+
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ if (ldns_rr_rdf(rr,i)) {
+ ldns_rr_push_rdf(new_rr, ldns_rdf_clone(ldns_rr_rdf(rr, i)));
+ }
+ }
+
+ return new_rr;
+}
+
+ldns_rr_list *
+ldns_rr_list_clone(const ldns_rr_list *rrlist)
+{
+ size_t i;
+ ldns_rr_list *new_list;
+ ldns_rr *r;
+
+ if (!rrlist) {
+ return NULL;
+ }
+
+ new_list = ldns_rr_list_new();
+ if (!new_list) {
+ return NULL;
+ }
+ for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
+ r = ldns_rr_clone(
+ ldns_rr_list_rr(rrlist, i)
+ );
+ if (!r) {
+ /* huh, failure in cloning */
+ ldns_rr_list_deep_free(new_list);
+ return NULL;
+ }
+ ldns_rr_list_push_rr(new_list, r);
+ }
+ return new_list;
+}
+
+
+int
+qsort_rr_compare(const void *a, const void *b)
+{
+ const ldns_rr *rr1 = * (const ldns_rr **) a;
+ const ldns_rr *rr2 = * (const ldns_rr **) b;
+
+ if (rr1 == NULL && rr2 == NULL) {
+ return 0;
+ }
+ if (rr1 == NULL) {
+ return -1;
+ }
+ if (rr2 == NULL) {
+ return 1;
+ }
+ return ldns_rr_compare(rr1, rr2);
+}
+
+int
+qsort_schwartz_rr_compare(const void *a, const void *b)
+{
+ int result = 0;
+ ldns_rr *rr1, *rr2;
+ ldns_buffer *rr1_buf, *rr2_buf;
+ struct ldns_schwartzian_compare_struct *sa = *(struct ldns_schwartzian_compare_struct **) a;
+ struct ldns_schwartzian_compare_struct *sb = *(struct ldns_schwartzian_compare_struct **) b;
+ /* if we are doing 2wire, we need to do lowercasing on the dname (and maybe on the rdata)
+ * this must be done for comparison only, so we need to have a temp var for both buffers,
+ * which is only used when the transformed object value isn't there yet
+ */
+ ldns_rr *canonical_a, *canonical_b;
+
+ rr1 = (ldns_rr *) sa->original_object;
+ rr2 = (ldns_rr *) sb->original_object;
+
+ result = ldns_rr_compare_no_rdata(rr1, rr2);
+
+ if (result == 0) {
+ if (!sa->transformed_object) {
+ canonical_a = ldns_rr_clone(sa->original_object);
+ ldns_rr2canonical(canonical_a);
+ sa->transformed_object = ldns_buffer_new(ldns_rr_uncompressed_size(canonical_a));
+ if (ldns_rr2buffer_wire(sa->transformed_object, canonical_a, LDNS_SECTION_ANY) != LDNS_STATUS_OK) {
+ ldns_buffer_free((ldns_buffer *)sa->transformed_object);
+ sa->transformed_object = NULL;
+ ldns_rr_free(canonical_a);
+ return 0;
+ }
+ ldns_rr_free(canonical_a);
+ }
+ if (!sb->transformed_object) {
+ canonical_b = ldns_rr_clone(sb->original_object);
+ ldns_rr2canonical(canonical_b);
+ sb->transformed_object = ldns_buffer_new(ldns_rr_uncompressed_size(canonical_b));
+ if (ldns_rr2buffer_wire(sb->transformed_object, canonical_b, LDNS_SECTION_ANY) != LDNS_STATUS_OK) {
+ ldns_buffer_free((ldns_buffer *)sa->transformed_object);
+ ldns_buffer_free((ldns_buffer *)sb->transformed_object);
+ sa->transformed_object = NULL;
+ sb->transformed_object = NULL;
+ ldns_rr_free(canonical_b);
+ return 0;
+ }
+ ldns_rr_free(canonical_b);
+ }
+ rr1_buf = (ldns_buffer *) sa->transformed_object;
+ rr2_buf = (ldns_buffer *) sb->transformed_object;
+
+ result = ldns_rr_compare_wire(rr1_buf, rr2_buf);
+ }
+
+ return result;
+}
+
+void
+ldns_rr_list_sort(ldns_rr_list *unsorted)
+{
+ struct ldns_schwartzian_compare_struct **sortables;
+ size_t item_count;
+ size_t i;
+
+ if (unsorted) {
+ item_count = ldns_rr_list_rr_count(unsorted);
+
+ sortables = LDNS_XMALLOC(struct ldns_schwartzian_compare_struct *,
+ item_count);
+ if(!sortables) return; /* no way to return error */
+ for (i = 0; i < item_count; i++) {
+ sortables[i] = LDNS_XMALLOC(struct ldns_schwartzian_compare_struct, 1);
+ if(!sortables[i]) {
+ /* free the allocated parts */
+ while(i>0) {
+ i--;
+ LDNS_FREE(sortables[i]);
+ }
+ /* no way to return error */
+ return;
+ }
+ sortables[i]->original_object = ldns_rr_list_rr(unsorted, i);
+ sortables[i]->transformed_object = NULL;
+ }
+ qsort(sortables,
+ item_count,
+ sizeof(struct ldns_schwartzian_compare_struct *),
+ qsort_schwartz_rr_compare);
+ for (i = 0; i < item_count; i++) {
+ unsorted->_rrs[i] = sortables[i]->original_object;
+ if (sortables[i]->transformed_object) {
+ ldns_buffer_free(sortables[i]->transformed_object);
+ }
+ LDNS_FREE(sortables[i]);
+ }
+ LDNS_FREE(sortables);
+ }
+}
+
+int
+ldns_rr_compare_no_rdata(const ldns_rr *rr1, const ldns_rr *rr2)
+{
+ size_t rr1_len;
+ size_t rr2_len;
+ size_t offset;
+
+ assert(rr1 != NULL);
+ assert(rr2 != NULL);
+
+ rr1_len = ldns_rr_uncompressed_size(rr1);
+ rr2_len = ldns_rr_uncompressed_size(rr2);
+
+ if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) < 0) {
+ return -1;
+ } else if (ldns_dname_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2)) > 0) {
+ return 1;
+ }
+
+ /* should return -1 if rr1 comes before rr2, so need to do rr1 - rr2, not rr2 - rr1 */
+ if (ldns_rr_get_class(rr1) != ldns_rr_get_class(rr2)) {
+ return ldns_rr_get_class(rr1) - ldns_rr_get_class(rr2);
+ }
+
+ /* should return -1 if rr1 comes before rr2, so need to do rr1 - rr2, not rr2 - rr1 */
+ if (ldns_rr_get_type(rr1) != ldns_rr_get_type(rr2)) {
+ return ldns_rr_get_type(rr1) - ldns_rr_get_type(rr2);
+ }
+
+ /* offset is the owername length + ttl + type + class + rdlen == start of wire format rdata */
+ offset = ldns_rdf_size(ldns_rr_owner(rr1)) + 4 + 2 + 2 + 2;
+ /* if either record doesn't have any RDATA... */
+ if (offset > rr1_len || offset > rr2_len) {
+ if (rr1_len == rr2_len) {
+ return 0;
+ }
+ return ((int) rr2_len - (int) rr1_len);
+ }
+
+ return 0;
+}
+
+int ldns_rr_compare_wire(ldns_buffer *rr1_buf, ldns_buffer *rr2_buf)
+{
+ size_t rr1_len, rr2_len, min_len, i, offset;
+
+ rr1_len = ldns_buffer_capacity(rr1_buf);
+ rr2_len = ldns_buffer_capacity(rr2_buf);
+
+ /* jump past dname (checked in earlier part)
+ * and especially past TTL */
+ offset = 0;
+ while (offset < rr1_len && *ldns_buffer_at(rr1_buf, offset) != 0) {
+ offset += *ldns_buffer_at(rr1_buf, offset) + 1;
+ }
+ /* jump to rdata section (PAST the rdata length field, otherwise
+ rrs with different lengths might be sorted erroneously */
+ offset += 11;
+ min_len = (rr1_len < rr2_len) ? rr1_len : rr2_len;
+ /* Compare RRs RDATA byte for byte. */
+ for(i = offset; i < min_len; i++) {
+ if (*ldns_buffer_at(rr1_buf,i) < *ldns_buffer_at(rr2_buf,i)) {
+ return -1;
+ } else if (*ldns_buffer_at(rr1_buf,i) > *ldns_buffer_at(rr2_buf,i)) {
+ return +1;
+ }
+ }
+
+ /* If both RDATAs are the same up to min_len, then the shorter one sorts first. */
+ if (rr1_len < rr2_len) {
+ return -1;
+ } else if (rr1_len > rr2_len) {
+ return +1;
+ }
+ /* The RDATAs are equal. */
+ return 0;
+
+}
+
+int
+ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2)
+{
+ int result;
+ size_t rr1_len, rr2_len;
+
+ ldns_buffer *rr1_buf;
+ ldns_buffer *rr2_buf;
+
+ result = ldns_rr_compare_no_rdata(rr1, rr2);
+ if (result == 0) {
+ rr1_len = ldns_rr_uncompressed_size(rr1);
+ rr2_len = ldns_rr_uncompressed_size(rr2);
+
+ rr1_buf = ldns_buffer_new(rr1_len);
+ rr2_buf = ldns_buffer_new(rr2_len);
+
+ if (ldns_rr2buffer_wire_canonical(rr1_buf,
+ rr1,
+ LDNS_SECTION_ANY)
+ != LDNS_STATUS_OK) {
+ ldns_buffer_free(rr1_buf);
+ ldns_buffer_free(rr2_buf);
+ return 0;
+ }
+ if (ldns_rr2buffer_wire_canonical(rr2_buf,
+ rr2,
+ LDNS_SECTION_ANY)
+ != LDNS_STATUS_OK) {
+ ldns_buffer_free(rr1_buf);
+ ldns_buffer_free(rr2_buf);
+ return 0;
+ }
+
+ result = ldns_rr_compare_wire(rr1_buf, rr2_buf);
+
+ ldns_buffer_free(rr1_buf);
+ ldns_buffer_free(rr2_buf);
+ }
+
+ return result;
+}
+
+/* convert dnskey to a ds with the given algorithm,
+ * then compare the result with the given ds */
+static int
+ldns_rr_compare_ds_dnskey(ldns_rr *ds,
+ ldns_rr *dnskey)
+{
+ ldns_rr *ds_gen;
+ bool result = false;
+ ldns_hash algo;
+
+ if (!dnskey || !ds ||
+ ldns_rr_get_type(ds) != LDNS_RR_TYPE_DS ||
+ ldns_rr_get_type(dnskey) != LDNS_RR_TYPE_DNSKEY) {
+ return false;
+ }
+
+ if (ldns_rr_rdf(ds, 2) == NULL) {
+ return false;
+ }
+ algo = ldns_rdf2native_int8(ldns_rr_rdf(ds, 2));
+
+ ds_gen = ldns_key_rr2ds(dnskey, algo);
+ if (ds_gen) {
+ result = ldns_rr_compare(ds, ds_gen) == 0;
+ ldns_rr_free(ds_gen);
+ }
+ return result;
+}
+
+bool
+ldns_rr_compare_ds(const ldns_rr *orr1, const ldns_rr *orr2)
+{
+ bool result;
+ ldns_rr *rr1 = ldns_rr_clone(orr1);
+ ldns_rr *rr2 = ldns_rr_clone(orr2);
+
+ /* set ttls to zero */
+ ldns_rr_set_ttl(rr1, 0);
+ ldns_rr_set_ttl(rr2, 0);
+
+ if (ldns_rr_get_type(rr1) == LDNS_RR_TYPE_DS &&
+ ldns_rr_get_type(rr2) == LDNS_RR_TYPE_DNSKEY) {
+ result = ldns_rr_compare_ds_dnskey(rr1, rr2);
+ } else if (ldns_rr_get_type(rr1) == LDNS_RR_TYPE_DNSKEY &&
+ ldns_rr_get_type(rr2) == LDNS_RR_TYPE_DS) {
+ result = ldns_rr_compare_ds_dnskey(rr2, rr1);
+ } else {
+ result = (ldns_rr_compare(rr1, rr2) == 0);
+ }
+
+ ldns_rr_free(rr1);
+ ldns_rr_free(rr2);
+
+ return result;
+}
+
+int
+ldns_rr_list_compare(const ldns_rr_list *rrl1, const ldns_rr_list *rrl2)
+{
+ size_t i = 0;
+ int rr_cmp;
+
+ assert(rrl1 != NULL);
+ assert(rrl2 != NULL);
+
+ for (i = 0; i < ldns_rr_list_rr_count(rrl1) && i < ldns_rr_list_rr_count(rrl2); i++) {
+ rr_cmp = ldns_rr_compare(ldns_rr_list_rr(rrl1, i), ldns_rr_list_rr(rrl2, i));
+ if (rr_cmp != 0) {
+ return rr_cmp;
+ }
+ }
+
+ if (i == ldns_rr_list_rr_count(rrl1) &&
+ i != ldns_rr_list_rr_count(rrl2)) {
+ return 1;
+ } else if (i == ldns_rr_list_rr_count(rrl2) &&
+ i != ldns_rr_list_rr_count(rrl1)) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+size_t
+ldns_rr_uncompressed_size(const ldns_rr *r)
+{
+ size_t rrsize;
+ size_t i;
+
+ rrsize = 0;
+ /* add all the rdf sizes */
+ for(i = 0; i < ldns_rr_rd_count(r); i++) {
+ rrsize += ldns_rdf_size(ldns_rr_rdf(r, i));
+ }
+ /* ownername */
+ rrsize += ldns_rdf_size(ldns_rr_owner(r));
+ rrsize += LDNS_RR_OVERHEAD;
+ return rrsize;
+}
+
+void
+ldns_rr2canonical(ldns_rr *rr)
+{
+ uint16_t i;
+
+ if (!rr) {
+ return;
+ }
+
+ ldns_dname2canonical(ldns_rr_owner(rr));
+
+ /*
+ * lowercase the rdata dnames if the rr type is one
+ * of the list in chapter 7 of RFC3597
+ */
+ switch(ldns_rr_get_type(rr)) {
+ case LDNS_RR_TYPE_NS:
+ case LDNS_RR_TYPE_MD:
+ case LDNS_RR_TYPE_MF:
+ case LDNS_RR_TYPE_CNAME:
+ case LDNS_RR_TYPE_SOA:
+ case LDNS_RR_TYPE_MB:
+ case LDNS_RR_TYPE_MG:
+ case LDNS_RR_TYPE_MR:
+ case LDNS_RR_TYPE_PTR:
+ case LDNS_RR_TYPE_MINFO:
+ case LDNS_RR_TYPE_MX:
+ case LDNS_RR_TYPE_RP:
+ case LDNS_RR_TYPE_AFSDB:
+ case LDNS_RR_TYPE_RT:
+ case LDNS_RR_TYPE_SIG:
+ case LDNS_RR_TYPE_PX:
+ case LDNS_RR_TYPE_NXT:
+ case LDNS_RR_TYPE_NAPTR:
+ case LDNS_RR_TYPE_KX:
+ case LDNS_RR_TYPE_SRV:
+ case LDNS_RR_TYPE_DNAME:
+ case LDNS_RR_TYPE_A6:
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ ldns_dname2canonical(ldns_rr_rdf(rr, i));
+ }
+ return;
+ default:
+ /* do nothing */
+ return;
+ }
+}
+
+void
+ldns_rr_list2canonical(ldns_rr_list *rr_list)
+{
+ size_t i;
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ ldns_rr2canonical(ldns_rr_list_rr(rr_list, i));
+ }
+}
+
+uint8_t
+ldns_rr_label_count(ldns_rr *rr)
+{
+ if (!rr) {
+ return 0;
+ }
+ return ldns_dname_label_count(
+ ldns_rr_owner(rr));
+}
+
+/** \cond */
+static const ldns_rdf_type type_0_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const ldns_rdf_type type_a_wireformat[] = { LDNS_RDF_TYPE_A };
+static const ldns_rdf_type type_ns_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_md_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_mf_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_cname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_soa_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD, LDNS_RDF_TYPE_PERIOD,
+ LDNS_RDF_TYPE_PERIOD
+};
+static const ldns_rdf_type type_mb_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_mg_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_mr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_wks_wireformat[] = {
+ LDNS_RDF_TYPE_A, LDNS_RDF_TYPE_WKS
+};
+static const ldns_rdf_type type_ptr_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_hinfo_wireformat[] = {
+ LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const ldns_rdf_type type_minfo_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_mx_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_rp_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_afsdb_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_x25_wireformat[] = { LDNS_RDF_TYPE_STR };
+static const ldns_rdf_type type_isdn_wireformat[] = {
+ LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR
+};
+static const ldns_rdf_type type_rt_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_nsap_wireformat[] = {
+ LDNS_RDF_TYPE_NSAP
+};
+static const ldns_rdf_type type_nsap_ptr_wireformat[] = {
+ LDNS_RDF_TYPE_STR
+};
+static const ldns_rdf_type type_sig_wireformat[] = {
+ LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_key_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_px_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_gpos_wireformat[] = {
+ LDNS_RDF_TYPE_STR,
+ LDNS_RDF_TYPE_STR,
+ LDNS_RDF_TYPE_STR
+};
+static const ldns_rdf_type type_aaaa_wireformat[] = { LDNS_RDF_TYPE_AAAA };
+static const ldns_rdf_type type_loc_wireformat[] = { LDNS_RDF_TYPE_LOC };
+static const ldns_rdf_type type_nxt_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_UNKNOWN
+};
+static const ldns_rdf_type type_eid_wireformat[] = {
+ LDNS_RDF_TYPE_HEX
+};
+static const ldns_rdf_type type_nimloc_wireformat[] = {
+ LDNS_RDF_TYPE_HEX
+};
+static const ldns_rdf_type type_srv_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_atma_wireformat[] = {
+ LDNS_RDF_TYPE_ATMA
+};
+static const ldns_rdf_type type_naptr_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_kx_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME
+};
+static const ldns_rdf_type type_cert_wireformat[] = {
+ LDNS_RDF_TYPE_CERT_ALG, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_a6_wireformat[] = { LDNS_RDF_TYPE_UNKNOWN };
+static const ldns_rdf_type type_dname_wireformat[] = { LDNS_RDF_TYPE_DNAME };
+static const ldns_rdf_type type_sink_wireformat[] = { LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_apl_wireformat[] = {
+ LDNS_RDF_TYPE_APL
+};
+static const ldns_rdf_type type_ds_wireformat[] = {
+ LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const ldns_rdf_type type_sshfp_wireformat[] = {
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX
+};
+static const ldns_rdf_type type_ipseckey_wireformat[] = {
+ LDNS_RDF_TYPE_IPSECKEY
+};
+static const ldns_rdf_type type_rrsig_wireformat[] = {
+ LDNS_RDF_TYPE_TYPE, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT32,
+ LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_TIME, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_nsec_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_NSEC
+};
+static const ldns_rdf_type type_dhcid_wireformat[] = {
+ LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_talink_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_DNAME
+};
+/* nsec3 is some vars, followed by same type of data of nsec */
+static const ldns_rdf_type type_nsec3_wireformat[] = {
+/* LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/
+ LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC
+};
+
+static const ldns_rdf_type type_nsec3param_wireformat[] = {
+/* LDNS_RDF_TYPE_NSEC3_PARAMS_VARS*/
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_NSEC3_SALT
+};
+
+static const ldns_rdf_type type_dnskey_wireformat[] = {
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT8,
+ LDNS_RDF_TYPE_ALG,
+ LDNS_RDF_TYPE_B64
+};
+static const ldns_rdf_type type_tsig_wireformat[] = {
+ LDNS_RDF_TYPE_DNAME,
+ LDNS_RDF_TYPE_TSIGTIME,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16_DATA,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16,
+ LDNS_RDF_TYPE_INT16_DATA
+};
+/** \endcond */
+
+/** \cond */
+/* All RR's defined in 1035 are well known and can thus
+ * be compressed. See RFC3597. These RR's are:
+ * CNAME HINFO MB MD MF MG MINFO MR MX NULL NS PTR SOA TXT
+ */
+static ldns_rr_descriptor rdata_field_descriptors[] = {
+ /* 0 */
+ { 0, NULL, 0, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 1 */
+ {LDNS_RR_TYPE_A, "A", 1, 1, type_a_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 2 */
+ {LDNS_RR_TYPE_NS, "NS", 1, 1, type_ns_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 3 */
+ {LDNS_RR_TYPE_MD, "MD", 1, 1, type_md_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 4 */
+ {LDNS_RR_TYPE_MF, "MF", 1, 1, type_mf_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 5 */
+ {LDNS_RR_TYPE_CNAME, "CNAME", 1, 1, type_cname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 6 */
+ {LDNS_RR_TYPE_SOA, "SOA", 7, 7, type_soa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+ /* 7 */
+ {LDNS_RR_TYPE_MB, "MB", 1, 1, type_mb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 8 */
+ {LDNS_RR_TYPE_MG, "MG", 1, 1, type_mg_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 9 */
+ {LDNS_RR_TYPE_MR, "MR", 1, 1, type_mr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 10 */
+ {LDNS_RR_TYPE_NULL, "NULL", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 11 */
+ {LDNS_RR_TYPE_WKS, "WKS", 2, 2, type_wks_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 12 */
+ {LDNS_RR_TYPE_PTR, "PTR", 1, 1, type_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 13 */
+ {LDNS_RR_TYPE_HINFO, "HINFO", 2, 2, type_hinfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 14 */
+ {LDNS_RR_TYPE_MINFO, "MINFO", 2, 2, type_minfo_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 2 },
+ /* 15 */
+ {LDNS_RR_TYPE_MX, "MX", 2, 2, type_mx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_COMPRESS, 1 },
+ /* 16 */
+ {LDNS_RR_TYPE_TXT, "TXT", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+ /* 17 */
+ {LDNS_RR_TYPE_RP, "RP", 2, 2, type_rp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+ /* 18 */
+ {LDNS_RR_TYPE_AFSDB, "AFSDB", 2, 2, type_afsdb_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 19 */
+ {LDNS_RR_TYPE_X25, "X25", 1, 1, type_x25_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 20 */
+ {LDNS_RR_TYPE_ISDN, "ISDN", 1, 2, type_isdn_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 21 */
+ {LDNS_RR_TYPE_RT, "RT", 2, 2, type_rt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 22 */
+ {LDNS_RR_TYPE_NSAP, "NSAP", 1, 1, type_nsap_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 23 */
+ {LDNS_RR_TYPE_NSAP_PTR, "NSAP-PTR", 1, 1, type_nsap_ptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 24 */
+ {LDNS_RR_TYPE_SIG, "SIG", 9, 9, type_sig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 25 */
+ {LDNS_RR_TYPE_KEY, "KEY", 4, 4, type_key_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 26 */
+ {LDNS_RR_TYPE_PX, "PX", 3, 3, type_px_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+ /* 27 */
+ {LDNS_RR_TYPE_GPOS, "GPOS", 1, 1, type_gpos_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 28 */
+ {LDNS_RR_TYPE_AAAA, "AAAA", 1, 1, type_aaaa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 29 */
+ {LDNS_RR_TYPE_LOC, "LOC", 1, 1, type_loc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 30 */
+ {LDNS_RR_TYPE_NXT, "NXT", 2, 2, type_nxt_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 31 */
+ {LDNS_RR_TYPE_EID, "EID", 1, 1, type_eid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 32 */
+ {LDNS_RR_TYPE_NIMLOC, "NIMLOC", 1, 1, type_nimloc_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 33 */
+ {LDNS_RR_TYPE_SRV, "SRV", 4, 4, type_srv_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 34 */
+ {LDNS_RR_TYPE_ATMA, "ATMA", 1, 1, type_atma_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 35 */
+ {LDNS_RR_TYPE_NAPTR, "NAPTR", 6, 6, type_naptr_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 36 */
+ {LDNS_RR_TYPE_KX, "KX", 2, 2, type_kx_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 37 */
+ {LDNS_RR_TYPE_CERT, "CERT", 4, 4, type_cert_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 38 */
+ {LDNS_RR_TYPE_A6, "A6", 1, 1, type_a6_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 39 */
+ {LDNS_RR_TYPE_DNAME, "DNAME", 1, 1, type_dname_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 40 */
+ {LDNS_RR_TYPE_SINK, "SINK", 1, 1, type_sink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 41 */
+ {LDNS_RR_TYPE_OPT, "OPT", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 42 */
+ {LDNS_RR_TYPE_APL, "APL", 0, 0, type_apl_wireformat, LDNS_RDF_TYPE_APL, LDNS_RR_NO_COMPRESS, 0 },
+ /* 43 */
+ {LDNS_RR_TYPE_DS, "DS", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 44 */
+ {LDNS_RR_TYPE_SSHFP, "SSHFP", 3, 3, type_sshfp_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 45 */
+ {LDNS_RR_TYPE_IPSECKEY, "IPSECKEY", 1, 1, type_ipseckey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 46 */
+ {LDNS_RR_TYPE_RRSIG, "RRSIG", 9, 9, type_rrsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 },
+ /* 47 */
+ {LDNS_RR_TYPE_NSEC, "NSEC", 1, 2, type_nsec_wireformat, LDNS_RDF_TYPE_NSEC, LDNS_RR_NO_COMPRESS, 1 },
+ /* 48 */
+ {LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 49 */
+{LDNS_RR_TYPE_DHCID, "DHCID", 1, 1, type_dhcid_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 50 */
+ {LDNS_RR_TYPE_NSEC3, "NSEC3", 5, 6, type_nsec3_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 51 */
+{LDNS_RR_TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, type_nsec3param_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+ /* 52 */
+{LDNS_RR_TYPE_NULL, "TYPE52", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE55", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE56", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE57", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_TALINK, "TALINK", 2, 2, type_talink_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 2 },
+{LDNS_RR_TYPE_NULL, "TYPE59", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE60", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE63", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE64", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE65", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE66", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE67", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE68", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE69", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE70", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE71", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE72", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE73", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE74", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE75", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE76", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE77", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE78", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE79", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE80", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE81", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE82", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE83", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE84", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE85", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE86", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE87", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE88", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE89", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE90", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE91", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE92", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE93", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE94", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE95", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE96", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE97", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE98", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_SPF, "SPF", 1, 0, NULL, LDNS_RDF_TYPE_STR, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE100", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE101", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE102", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE103", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE104", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE105", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE106", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE107", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE108", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE109", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE110", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE111", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE112", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE113", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE114", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE115", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE116", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE117", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE118", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE119", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE120", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE121", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE122", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE123", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE124", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE125", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE126", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE127", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE128", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE129", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE130", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE131", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE132", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE133", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE134", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE135", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE136", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE137", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE138", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE139", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE140", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE141", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE142", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE143", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE144", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE145", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE146", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE147", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE148", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE149", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE150", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE151", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE152", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE153", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE154", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE155", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE156", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE157", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE158", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE159", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE160", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE161", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE162", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE163", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE164", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE165", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE166", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE167", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE168", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE169", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE170", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE171", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE172", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE173", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE174", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE175", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE176", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE177", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE178", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE179", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE180", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE181", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE182", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE183", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE184", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE185", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE186", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE187", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE188", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE189", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE190", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE191", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE192", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE193", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE194", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE195", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE196", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE197", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE198", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE199", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE200", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE201", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE202", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE203", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE204", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE205", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE206", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE207", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE208", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE209", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE210", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE211", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE212", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE213", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE214", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE215", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE216", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE217", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE218", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE219", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE220", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE221", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE222", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE223", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE224", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE225", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE226", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE227", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE228", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE229", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE230", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE231", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE232", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE233", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE234", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE235", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE236", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE237", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE238", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE239", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE240", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE241", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE242", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE243", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE244", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE245", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE246", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NULL, "TYPE249", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+/* LDNS_RDF_TYPE_INT16_DATA essentially takes two fields (length and data) and
+ * makes them into one. So, while in rfc 2845 is specified that a TSIG may have
+ * 8 or 9 rdata fields, by this implementation, the min/max are 7 each.
+ */
+{LDNS_RR_TYPE_TSIG, "TSIG", 7, 7, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+/* split in array, no longer contiguous */
+{LDNS_RR_TYPE_DLV, "DLV", 4, 4, type_ds_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }
+};
+/** \endcond */
+
+/**
+ * \def LDNS_RDATA_FIELD_DESCRIPTORS_COUNT
+ * computes the number of rdata fields
+ */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \
+ (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0]))
+
+const ldns_rr_descriptor *
+ldns_rr_descript(uint16_t type)
+{
+ size_t i;
+ if (type <= LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) {
+ return &rdata_field_descriptors[type];
+ } else {
+ /* because not all array index equals type code */
+ for (i = LDNS_RDATA_FIELD_DESCRIPTORS_COMMON;
+ i < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT;
+ i++) {
+ if (rdata_field_descriptors[i]._type == type) {
+ return &rdata_field_descriptors[i];
+ }
+ }
+ return &rdata_field_descriptors[0];
+ }
+}
+
+size_t
+ldns_rr_descriptor_minimum(const ldns_rr_descriptor *descriptor)
+{
+ if (descriptor) {
+ return descriptor->_minimum;
+ } else {
+ return 0;
+ }
+}
+
+size_t
+ldns_rr_descriptor_maximum(const ldns_rr_descriptor *descriptor)
+{
+ if (descriptor) {
+ if (descriptor->_variable != LDNS_RDF_TYPE_NONE) {
+ /* Should really be SIZE_MAX... bad FreeBSD. */
+ return UINT_MAX;
+ } else {
+ return descriptor->_maximum;
+ }
+ } else {
+ return 0;
+ }
+}
+
+ldns_rdf_type
+ldns_rr_descriptor_field_type(const ldns_rr_descriptor *descriptor,
+ size_t index)
+{
+ assert(descriptor != NULL);
+ assert(index < descriptor->_maximum
+ || descriptor->_variable != LDNS_RDF_TYPE_NONE);
+ if (index < descriptor->_maximum) {
+ return descriptor->_wireformat[index];
+ } else {
+ return descriptor->_variable;
+ }
+}
+
+ldns_rr_type
+ldns_get_rr_type_by_name(const char *name)
+{
+ unsigned int i;
+ const char *desc_name;
+ const ldns_rr_descriptor *desc;
+
+ /* TYPEXX representation */
+ if (strlen(name) > 4 && strncasecmp(name, "TYPE", 4) == 0) {
+ return atoi(name + 4);
+ }
+
+ /* Normal types */
+ for (i = 0; i < (unsigned int) LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) {
+ desc = &rdata_field_descriptors[i];
+ desc_name = desc->_name;
+ if(desc_name &&
+ strlen(name) == strlen(desc_name) &&
+ strncasecmp(name, desc_name, strlen(desc_name)) == 0) {
+ /* because not all array index equals type code */
+ return desc->_type;
+ }
+ }
+
+ /* special cases for query types */
+ if (strlen(name) == 4 && strncasecmp(name, "IXFR", 4) == 0) {
+ return 251;
+ } else if (strlen(name) == 4 && strncasecmp(name, "AXFR", 4) == 0) {
+ return 252;
+ } else if (strlen(name) == 5 && strncasecmp(name, "MAILB", 5) == 0) {
+ return 253;
+ } else if (strlen(name) == 5 && strncasecmp(name, "MAILA", 5) == 0) {
+ return 254;
+ } else if (strlen(name) == 3 && strncasecmp(name, "ANY", 3) == 0) {
+ return 255;
+ }
+
+ return 0;
+}
+
+ldns_rr_class
+ldns_get_rr_class_by_name(const char *name)
+{
+ ldns_lookup_table *lt;
+
+ /* CLASSXX representation */
+ if (strlen(name) > 5 && strncasecmp(name, "CLASS", 5) == 0) {
+ return atoi(name + 5);
+ }
+
+ /* Normal types */
+ lt = ldns_lookup_by_name(ldns_rr_classes, name);
+
+ if (lt) {
+ return lt->id;
+ }
+ return 0;
+}
+
+
+ldns_rr_type
+ldns_rdf2rr_type(const ldns_rdf *rd)
+{
+ ldns_rr_type r;
+
+ if (!rd) {
+ return 0;
+ }
+
+ if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TYPE) {
+ return 0;
+ }
+
+ r = (ldns_rr_type) ldns_rdf2native_int16(rd);
+ return r;
+}
+
+ldns_rr_type
+ldns_rr_list_type(const ldns_rr_list *rr_list)
+{
+ if (rr_list && ldns_rr_list_rr_count(rr_list) > 0) {
+ return ldns_rr_get_type(ldns_rr_list_rr(rr_list, 0));
+ } else {
+ return 0;
+ }
+}
+
+ldns_rdf *
+ldns_rr_list_owner(const ldns_rr_list *rr_list)
+{
+ if (rr_list && ldns_rr_list_rr_count(rr_list) > 0) {
+ return ldns_rr_owner(ldns_rr_list_rr(rr_list, 0));
+ } else {
+ return NULL;
+ }
+}
diff --git a/3rdParty/Ldns/src/src/rr_functions.c b/3rdParty/Ldns/src/src/rr_functions.c
new file mode 100644
index 0000000..b4847d6
--- /dev/null
+++ b/3rdParty/Ldns/src/src/rr_functions.c
@@ -0,0 +1,419 @@
+/*
+ * rr_function.c
+ *
+ * function that operate on specific rr types
+ *
+ * (c) NLnet Labs, 2004-2006
+ * See the file LICENSE for the license
+ */
+
+/*
+ * These come strait from perldoc Net::DNS::RR::xxx
+ * first the read variant, then the write. This is
+ * not complete.
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <limits.h>
+#include <strings.h>
+
+/**
+ * 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
+ * \return the rdf sought
+ */
+static ldns_rdf *
+ldns_rr_function(ldns_rr_type type, const ldns_rr *rr, size_t pos)
+{
+ if (!rr || ldns_rr_get_type(rr) != type) {
+ return NULL;
+ }
+ return ldns_rr_rdf(rr, pos);
+}
+
+/**
+ * set a specific rdf
+ * \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
+ * \return true or false
+ */
+static bool
+ldns_rr_set_function(ldns_rr_type type, ldns_rr *rr, ldns_rdf *rdf, size_t pos)
+{
+ ldns_rdf *pop;
+ if (!rr || ldns_rr_get_type(rr) != type) {
+ return false;
+ }
+ pop = ldns_rr_set_rdf(rr, rdf, pos);
+ ldns_rdf_deep_free(pop);
+ return true;
+}
+
+/* A/AAAA records */
+ldns_rdf *
+ldns_rr_a_address(const ldns_rr *r)
+{
+ /* 2 types to check, cannot use the macro */
+ if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A &&
+ ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) {
+ return NULL;
+ }
+ return ldns_rr_rdf(r, 0);
+}
+
+bool
+ldns_rr_a_set_address(ldns_rr *r, ldns_rdf *f)
+{
+ /* 2 types to check, cannot use the macro... */
+ ldns_rdf *pop;
+ if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A &&
+ ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) {
+ return false;
+ }
+ pop = ldns_rr_set_rdf(r, f, 0);
+ if (pop) {
+ LDNS_FREE(pop);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* NS record */
+ldns_rdf *
+ldns_rr_ns_nsdname(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_NS, r, 0);
+}
+
+/* MX record */
+ldns_rdf *
+ldns_rr_mx_preference(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_MX, r, 0);
+}
+
+ldns_rdf *
+ldns_rr_mx_exchange(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_MX, r, 1);
+}
+
+/* RRSIG record */
+ldns_rdf *
+ldns_rr_rrsig_typecovered(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 0);
+}
+
+bool
+ldns_rr_rrsig_set_typecovered(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 0);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_algorithm(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 1);
+}
+
+bool
+ldns_rr_rrsig_set_algorithm(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 1);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_labels(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 2);
+}
+
+bool
+ldns_rr_rrsig_set_labels(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 2);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_origttl(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 3);
+}
+
+bool
+ldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 3);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_expiration(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 4);
+}
+
+bool
+ldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 4);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_inception(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 5);
+}
+
+bool
+ldns_rr_rrsig_set_inception(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 5);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_keytag(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 6);
+}
+
+bool
+ldns_rr_rrsig_set_keytag(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 6);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_signame(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 7);
+}
+
+bool
+ldns_rr_rrsig_set_signame(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 7);
+}
+
+ldns_rdf *
+ldns_rr_rrsig_sig(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 8);
+}
+
+bool
+ldns_rr_rrsig_set_sig(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 8);
+}
+
+/* DNSKEY record */
+ldns_rdf *
+ldns_rr_dnskey_flags(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 0);
+}
+
+bool
+ldns_rr_dnskey_set_flags(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 0);
+}
+
+ldns_rdf *
+ldns_rr_dnskey_protocol(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 1);
+}
+
+bool
+ldns_rr_dnskey_set_protocol(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 1);
+}
+
+ldns_rdf *
+ldns_rr_dnskey_algorithm(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 2);
+}
+
+bool
+ldns_rr_dnskey_set_algorithm(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 2);
+}
+
+ldns_rdf *
+ldns_rr_dnskey_key(const ldns_rr *r)
+{
+ return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 3);
+}
+
+bool
+ldns_rr_dnskey_set_key(ldns_rr *r, ldns_rdf *f)
+{
+ return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 3);
+}
+
+size_t
+ldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
+ const size_t len,
+ const ldns_algorithm alg)
+{
+ /* for DSA keys */
+ uint8_t t;
+
+ /* for RSA keys */
+ uint16_t exp;
+ uint16_t int16;
+
+ switch ((ldns_signing_algorithm)alg) {
+ case LDNS_SIGN_DSA:
+ case LDNS_SIGN_DSA_NSEC3:
+ if (len > 0) {
+ t = keydata[0];
+ return (64 + t*8)*8;
+ } else {
+ return 0;
+ }
+ break;
+ case LDNS_SIGN_RSAMD5:
+ case LDNS_SIGN_RSASHA1:
+ case LDNS_SIGN_RSASHA1_NSEC3:
+#ifdef USE_SHA2
+ case LDNS_SIGN_RSASHA256:
+ case LDNS_SIGN_RSASHA512:
+#endif
+ if (len > 0) {
+ if (keydata[0] == 0) {
+ /* big exponent */
+ if (len > 3) {
+ memmove(&int16, keydata + 1, 2);
+ exp = ntohs(int16);
+ return (len - exp - 3)*8;
+ } else {
+ return 0;
+ }
+ } else {
+ exp = keydata[0];
+ return (len-exp-1)*8;
+ }
+ } else {
+ return 0;
+ }
+ break;
+#ifdef USE_GOST
+ case LDNS_SIGN_ECC_GOST:
+ return 512;
+#endif
+#ifdef USE_ECDSA
+ case LDNS_SIGN_ECDSAP256SHA256:
+ return 256;
+ case LDNS_SIGN_ECDSAP384SHA384:
+ return 384;
+#endif
+ case LDNS_SIGN_HMACMD5:
+ return len;
+ default:
+ return 0;
+ }
+}
+
+size_t
+ldns_rr_dnskey_key_size(const ldns_rr *key)
+{
+ if (!key || !ldns_rr_dnskey_key(key)
+ || !ldns_rr_dnskey_algorithm(key)) {
+ return 0;
+ }
+ return ldns_rr_dnskey_key_size_raw((unsigned char*)ldns_rdf_data(ldns_rr_dnskey_key(key)),
+ ldns_rdf_size(ldns_rr_dnskey_key(key)),
+ ldns_rdf2native_int8(ldns_rr_dnskey_algorithm(key))
+ );
+}
+
+uint32_t ldns_soa_serial_identity(uint32_t ATTR_UNUSED(_), void *data)
+{
+ return (uint32_t) (intptr_t) data;
+}
+
+uint32_t ldns_soa_serial_increment(uint32_t s, void *ATTR_UNUSED(_))
+{
+ return ldns_soa_serial_increment_by(s, (void *)1);
+}
+
+uint32_t ldns_soa_serial_increment_by(uint32_t s, void *data)
+{
+ return s + (intptr_t) data;
+}
+
+uint32_t ldns_soa_serial_datecounter(uint32_t s, void *data)
+{
+ struct tm tm;
+ char s_str[11];
+ uint32_t new_s;
+ time_t t = data ? (time_t) (intptr_t) data : ldns_time(NULL);
+
+ (void) strftime(s_str, 11, "%Y%m%d00", localtime_r(&t, &tm));
+ new_s = (uint32_t) atoi(s_str);
+ return new_s > s ? new_s : s+1;
+}
+
+uint32_t ldns_soa_serial_unixtime(uint32_t s, void *data)
+{
+ uint32_t new_s = data ? (uint32_t) (intptr_t) data
+ : (uint32_t) ldns_time(NULL);
+ return new_s > s ? new_s : s+1;
+}
+
+void
+ldns_rr_soa_increment(ldns_rr *soa)
+{
+ ldns_rr_soa_increment_func_data(soa, ldns_soa_serial_increment, NULL);
+}
+
+void
+ldns_rr_soa_increment_func(ldns_rr *soa, ldns_soa_serial_increment_func_t f)
+{
+ ldns_rr_soa_increment_func_data(soa, f, NULL);
+}
+
+void
+ldns_rr_soa_increment_func_data(ldns_rr *soa,
+ ldns_soa_serial_increment_func_t f, void *data)
+{
+ ldns_rdf *prev_soa_serial_rdf;
+ if ( !soa || !f || ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA
+ || !ldns_rr_rdf(soa, 2)) {
+ return;
+ }
+ prev_soa_serial_rdf = ldns_rr_set_rdf(
+ soa
+ , ldns_native2rdf_int32(
+ LDNS_RDF_TYPE_INT32
+ , (*f)( ldns_rdf2native_int32(
+ ldns_rr_rdf(soa, 2))
+ , data
+ )
+ )
+ , 2
+ );
+ LDNS_FREE(prev_soa_serial_rdf);
+}
+
+void
+ldns_rr_soa_increment_func_int(ldns_rr *soa,
+ ldns_soa_serial_increment_func_t f, int data)
+{
+ ldns_rr_soa_increment_func_data(soa, f, (void *) (intptr_t) data);
+}
+
diff --git a/3rdParty/Ldns/src/src/sha1.c b/3rdParty/Ldns/src/src/sha1.c
new file mode 100644
index 0000000..5dec680
--- /dev/null
+++ b/3rdParty/Ldns/src/src/sha1.c
@@ -0,0 +1,177 @@
+/*
+ * modified for ldns by Jelte Jansen, original taken from OpenBSD:
+ *
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include <ldns/config.h>
+#include <ldns/ldns.h>
+#include <strings.h>
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void
+ldns_sha1_transform(uint32_t state[5], const unsigned char buffer[LDNS_SHA1_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d, e;
+ typedef union {
+ unsigned char c[64];
+ unsigned int l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+ unsigned char workspace[LDNS_SHA1_BLOCK_LENGTH];
+
+ block = (CHAR64LONG16 *)workspace;
+ memmove(block, buffer, LDNS_SHA1_BLOCK_LENGTH);
+#else
+ block = (CHAR64LONG16 *)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void
+ldns_sha1_init(ldns_sha1_ctx *context)
+{
+ /* SHA1 initialization constants */
+ context->count = 0;
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+}
+
+
+/* Run your data through this. */
+
+void
+ldns_sha1_update(ldns_sha1_ctx *context, const unsigned char *data, unsigned int len)
+{
+ unsigned int i;
+ unsigned int j;
+
+ j = (unsigned)(uint32_t)((context->count >> 3) & 63);
+ context->count += (len << 3);
+ if ((j + len) > 63) {
+ memmove(&context->buffer[j], data, (i = 64 - j));
+ ldns_sha1_transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ ldns_sha1_transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memmove(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void
+ldns_sha1_final(unsigned char digest[LDNS_SHA1_DIGEST_LENGTH], ldns_sha1_ctx *context)
+{
+ unsigned int i;
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count >>
+ ((7 - (i & 7)) * 8)) & 255); /* Endian independent */
+ }
+ ldns_sha1_update(context, (unsigned char *)"\200", 1);
+ while ((context->count & 504) != 448) {
+ ldns_sha1_update(context, (unsigned char *)"\0", 1);
+ }
+ ldns_sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+
+ if (digest != NULL)
+ for (i = 0; i < LDNS_SHA1_DIGEST_LENGTH; i++) {
+ digest[i] = (unsigned char)((context->state[i >> 2] >>
+ ((3 - (i & 3)) * 8)) & 255);
+ }
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
+ ldns_sha1_transform(context->state, context->buffer);
+#endif
+}
+
+unsigned char *
+ldns_sha1(unsigned char *data, unsigned int data_len, unsigned char *digest)
+{
+ ldns_sha1_ctx ctx;
+ ldns_sha1_init(&ctx);
+ ldns_sha1_update(&ctx, data, data_len);
+ ldns_sha1_final(digest, &ctx);
+ return digest;
+}
diff --git a/3rdParty/Ldns/src/src/sha2.c b/3rdParty/Ldns/src/src/sha2.c
new file mode 100644
index 0000000..6ba4ab5
--- /dev/null
+++ b/3rdParty/Ldns/src/src/sha2.c
@@ -0,0 +1,982 @@
+/*
+ * FILE: sha2.c
+ * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
+ *
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Modified by Jelte Jansen to fit in ldns, and not clash with any
+ * system-defined SHA code.
+ * Changes:
+ * - Renamed (external) functions and constants to fit ldns style
+ * - Removed _End and _Data functions
+ * - Added ldns_shaX(data, len, digest) convenience functions
+ * - Removed prototypes of _Transform functions and made those static
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
+ */
+
+#include <ldns/config.h>
+#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
+#include <assert.h> /* assert() */
+#include <ldns/sha2.h>
+
+/*
+ * ASSERT NOTE:
+ * Some sanity checking code is included using assert(). On my FreeBSD
+ * system, this additional code can be removed by compiling with NDEBUG
+ * defined. Check your own systems manpage on assert() to see how to
+ * compile WITHOUT the sanity checking code on your system.
+ *
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file). Either define on the command line, for example:
+ *
+ * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ * #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * 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.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ * #define LITTLE_ENDIAN 1234
+ * #define BIG_ENDIAN 4321
+ *
+ * And for little-endian machines, add:
+ *
+ * #define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ * #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+
+typedef uint8_t sha2_byte; /* Exactly 1 byte */
+typedef uint32_t sha2_word32; /* Exactly 4 bytes */
+#ifdef S_SPLINT_S
+typedef unsigned long long sha2_word64; /* lint 8 bytes */
+#else
+typedef uint64_t sha2_word64; /* Exactly 8 bytes */
+#endif
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define ldns_sha256_SHORT_BLOCK_LENGTH (LDNS_SHA256_BLOCK_LENGTH - 8)
+#define ldns_sha384_SHORT_BLOCK_LENGTH (LDNS_SHA384_BLOCK_LENGTH - 16)
+#define ldns_sha512_SHORT_BLOCK_LENGTH (LDNS_SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ sha2_word32 tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#ifndef S_SPLINT_S
+#define REVERSE64(w,x) { \
+ sha2_word64 tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#else /* splint */
+#define REVERSE64(w,x) /* splint */
+#endif /* splint */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (sha2_word64)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+#ifdef S_SPLINT_S
+#undef ADDINC128
+#define ADDINC128(w,n) /* splint */
+#endif
+
+/*
+ * Macros for copying blocks of memory and for zeroing out ranges
+ * of memory. Using these macros makes it easy to switch from
+ * using memset()/memcpy() and using bzero()/bcopy().
+ *
+ * Please define either SHA2_USE_MEMSET_MEMCPY or define
+ * SHA2_USE_BZERO_BCOPY depending on which function set you
+ * choose to use:
+ */
+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
+/* Default to memset()/memcpy() if no option is specified */
+#define SHA2_USE_MEMSET_MEMCPY 1
+#endif
+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
+/* Abort with an error if BOTH options are defined */
+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
+#endif
+
+#ifdef SHA2_USE_MEMSET_MEMCPY
+#define MEMSET_BZERO(p,l) memset((p), 0, (l))
+#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
+#endif
+#ifdef SHA2_USE_BZERO_BCOPY
+#define MEMSET_BZERO(p,l) bzero((p), (l))
+#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l))
+#endif
+
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and
+ * S is a ROTATION) because the SHA-256/384/512 description document
+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ * same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+static const sha2_word32 K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* initial hash value H for SHA-256: */
+static const sha2_word32 ldns_sha256_initial_hash_value[8] = {
+ 0x6a09e667UL,
+ 0xbb67ae85UL,
+ 0x3c6ef372UL,
+ 0xa54ff53aUL,
+ 0x510e527fUL,
+ 0x9b05688cUL,
+ 0x1f83d9abUL,
+ 0x5be0cd19UL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+static const sha2_word64 K512[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* initial hash value H for SHA-384 */
+static const sha2_word64 sha384_initial_hash_value[8] = {
+ 0xcbbb9d5dc1059ed8ULL,
+ 0x629a292a367cd507ULL,
+ 0x9159015a3070dd17ULL,
+ 0x152fecd8f70e5939ULL,
+ 0x67332667ffc00b31ULL,
+ 0x8eb44a8768581511ULL,
+ 0xdb0c2e0d64f98fa7ULL,
+ 0x47b5481dbefa4fa4ULL
+};
+
+/* initial hash value H for SHA-512 */
+static const sha2_word64 sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908ULL,
+ 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL,
+ 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL,
+ 0x5be0cd19137e2179ULL
+};
+
+/*** SHA-256: *********************************************************/
+void ldns_sha256_init(ldns_sha256_CTX* context) {
+ if (context == (ldns_sha256_CTX*)0) {
+ return;
+ }
+ MEMCPY_BCOPY(context->state, ldns_sha256_initial_hash_value, LDNS_SHA256_DIGEST_LENGTH);
+ MEMSET_BZERO(context->buffer, LDNS_SHA256_BLOCK_LENGTH);
+ context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+static void ldns_sha256_Transform(ldns_sha256_CTX* context,
+ const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+static void ldns_sha256_Transform(ldns_sha256_CTX* context,
+ const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, T2, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void ldns_sha256_update(ldns_sha256_CTX* context, const sha2_byte *data, size_t len) {
+ size_t freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (ldns_sha256_CTX*)0 && data != (sha2_byte*)0);
+
+ usedspace = (context->bitcount >> 3) % LDNS_SHA256_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = LDNS_SHA256_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
+ context->bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ ldns_sha256_Transform(context, (sha2_word32*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
+ context->bitcount += len << 3;
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= LDNS_SHA256_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ ldns_sha256_Transform(context, (sha2_word32*)data);
+ context->bitcount += LDNS_SHA256_BLOCK_LENGTH << 3;
+ len -= LDNS_SHA256_BLOCK_LENGTH;
+ data += LDNS_SHA256_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ MEMCPY_BCOPY(context->buffer, data, len);
+ context->bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void ldns_sha256_final(sha2_byte digest[], ldns_sha256_CTX* context) {
+ sha2_word32 *d = (sha2_word32*)digest;
+ size_t usedspace;
+
+ /* Sanity check: */
+ assert(context != (ldns_sha256_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ usedspace = (context->bitcount >> 3) % LDNS_SHA256_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount,context->bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ldns_sha256_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(&context->buffer[usedspace], ldns_sha256_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < LDNS_SHA256_BLOCK_LENGTH) {
+ MEMSET_BZERO(&context->buffer[usedspace], LDNS_SHA256_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ ldns_sha256_Transform(context, (sha2_word32*)context->buffer);
+
+ /* And set-up for the last transform: */
+ MEMSET_BZERO(context->buffer, ldns_sha256_SHORT_BLOCK_LENGTH);
+ }
+ } else {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(context->buffer, ldns_sha256_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Set the bit count: */
+ *(sha2_word64*)&context->buffer[ldns_sha256_SHORT_BLOCK_LENGTH] = context->bitcount;
+
+ /* final transform: */
+ ldns_sha256_Transform(context, (sha2_word32*)context->buffer);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE32(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->state, LDNS_SHA256_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Clean up state data: */
+ MEMSET_BZERO(context, sizeof(ldns_sha256_CTX));
+ usedspace = 0;
+}
+
+unsigned char *
+ldns_sha256(unsigned char *data, unsigned int data_len, unsigned char *digest)
+{
+ ldns_sha256_CTX ctx;
+ ldns_sha256_init(&ctx);
+ ldns_sha256_update(&ctx, data, data_len);
+ ldns_sha256_final(digest, &ctx);
+ return digest;
+}
+
+/*** SHA-512: *********************************************************/
+void ldns_sha512_init(ldns_sha512_CTX* context) {
+ if (context == (ldns_sha512_CTX*)0) {
+ return;
+ }
+ MEMCPY_BCOPY(context->state, sha512_initial_hash_value, LDNS_SHA512_DIGEST_LENGTH);
+ MEMSET_BZERO(context->buffer, LDNS_SHA512_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE64(*data++, W512[j]); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + W512[j]; \
+ (d) += T1, \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+ j++
+
+
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+ K512[j] + (W512[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ s0 = W512[(j+1)&0x0f]; \
+ s0 = sigma0_512(s0); \
+ s1 = W512[(j+14)&0x0f]; \
+ s1 = sigma1_512(s1); \
+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ j++
+
+static void ldns_sha512_Transform(ldns_sha512_CTX* context,
+ const sha2_word64* data) {
+ sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word64 T1, *W512 = (sha2_word64*)context->buffer;
+ int j;
+
+ /* initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds up to 79: */
+ do {
+ ROUND512(a,b,c,d,e,f,g,h);
+ ROUND512(h,a,b,c,d,e,f,g);
+ ROUND512(g,h,a,b,c,d,e,f);
+ ROUND512(f,g,h,a,b,c,d,e);
+ ROUND512(e,f,g,h,a,b,c,d);
+ ROUND512(d,e,f,g,h,a,b,c);
+ ROUND512(c,d,e,f,g,h,a,b);
+ ROUND512(b,c,d,e,f,g,h,a);
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+static void ldns_sha512_Transform(ldns_sha512_CTX* context,
+ const sha2_word64* data) {
+ sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer;
+ int j;
+
+ /* initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert TO host byte order */
+ REVERSE64(*data++, W512[j]);
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void ldns_sha512_update(ldns_sha512_CTX* context, const sha2_byte *data, size_t len) {
+ size_t freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ assert(context != (ldns_sha512_CTX*)0 && data != (sha2_byte*)0);
+
+ usedspace = (context->bitcount[0] >> 3) % LDNS_SHA512_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = LDNS_SHA512_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
+ ADDINC128(context->bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ ldns_sha512_Transform(context, (sha2_word64*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
+ ADDINC128(context->bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= LDNS_SHA512_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ ldns_sha512_Transform(context, (sha2_word64*)data);
+ ADDINC128(context->bitcount, LDNS_SHA512_BLOCK_LENGTH << 3);
+ len -= LDNS_SHA512_BLOCK_LENGTH;
+ data += LDNS_SHA512_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ MEMCPY_BCOPY(context->buffer, data, len);
+ ADDINC128(context->bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+static void ldns_sha512_Last(ldns_sha512_CTX* context) {
+ size_t usedspace;
+
+ usedspace = (context->bitcount[0] >> 3) % LDNS_SHA512_BLOCK_LENGTH;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount[0],context->bitcount[0]);
+ REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= ldns_sha512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ MEMSET_BZERO(&context->buffer[usedspace], ldns_sha512_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < LDNS_SHA512_BLOCK_LENGTH) {
+ MEMSET_BZERO(&context->buffer[usedspace], LDNS_SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ ldns_sha512_Transform(context, (sha2_word64*)context->buffer);
+
+ /* And set-up for the last transform: */
+ MEMSET_BZERO(context->buffer, LDNS_SHA512_BLOCK_LENGTH - 2);
+ }
+ } else {
+ /* Prepare for final transform: */
+ MEMSET_BZERO(context->buffer, ldns_sha512_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ *(sha2_word64*)&context->buffer[ldns_sha512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(sha2_word64*)&context->buffer[ldns_sha512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+ /* final transform: */
+ ldns_sha512_Transform(context, (sha2_word64*)context->buffer);
+}
+
+void ldns_sha512_final(sha2_byte digest[], ldns_sha512_CTX* context) {
+ sha2_word64 *d = (sha2_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (ldns_sha512_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ ldns_sha512_Last(context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->state, LDNS_SHA512_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ MEMSET_BZERO(context, sizeof(ldns_sha512_CTX));
+}
+
+unsigned char *
+ldns_sha512(unsigned char *data, unsigned int data_len, unsigned char *digest)
+{
+ ldns_sha512_CTX ctx;
+ ldns_sha512_init(&ctx);
+ ldns_sha512_update(&ctx, data, data_len);
+ ldns_sha512_final(digest, &ctx);
+ return digest;
+}
+
+/*** SHA-384: *********************************************************/
+void ldns_sha384_init(ldns_sha384_CTX* context) {
+ if (context == (ldns_sha384_CTX*)0) {
+ return;
+ }
+ MEMCPY_BCOPY(context->state, sha384_initial_hash_value, LDNS_SHA512_DIGEST_LENGTH);
+ MEMSET_BZERO(context->buffer, LDNS_SHA384_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void ldns_sha384_update(ldns_sha384_CTX* context, const sha2_byte* data, size_t len) {
+ ldns_sha512_update((ldns_sha512_CTX*)context, data, len);
+}
+
+void ldns_sha384_final(sha2_byte digest[], ldns_sha384_CTX* context) {
+ sha2_word64 *d = (sha2_word64*)digest;
+
+ /* Sanity check: */
+ assert(context != (ldns_sha384_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+ ldns_sha512_Last((ldns_sha512_CTX*)context);
+
+ /* Save the hash data for output: */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 6; j++) {
+ REVERSE64(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ MEMCPY_BCOPY(d, context->state, LDNS_SHA384_DIGEST_LENGTH);
+#endif
+ }
+
+ /* Zero out state data */
+ MEMSET_BZERO(context, sizeof(ldns_sha384_CTX));
+}
+
+unsigned char *
+ldns_sha384(unsigned char *data, unsigned int data_len, unsigned char *digest)
+{
+ ldns_sha384_CTX ctx;
+ ldns_sha384_init(&ctx);
+ ldns_sha384_update(&ctx, data, data_len);
+ ldns_sha384_final(digest, &ctx);
+ return digest;
+}
diff --git a/3rdParty/Ldns/src/src/str2host.c b/3rdParty/Ldns/src/src/str2host.c
new file mode 100644
index 0000000..4ec9d37
--- /dev/null
+++ b/3rdParty/Ldns/src/src/str2host.c
@@ -0,0 +1,1316 @@
+/*
+ * str2host.c
+ *
+ * conversion routines from the presentation format
+ * to the host format
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <time.h>
+
+#include <errno.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <limits.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+ldns_status
+ldns_str2rdf_int16(ldns_rdf **rd, const char *shortstr)
+{
+ char *end = NULL;
+ uint16_t *r;
+ r = LDNS_MALLOC(uint16_t);
+ if(!r) return LDNS_STATUS_MEM_ERR;
+
+ *r = htons((uint16_t)strtol((char *)shortstr, &end, 10));
+
+ if(*end != 0) {
+ LDNS_FREE(r);
+ return LDNS_STATUS_INVALID_INT;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_INT16, sizeof(uint16_t), r);
+ LDNS_FREE(r);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+ }
+}
+
+ldns_status
+ldns_str2rdf_time(ldns_rdf **rd, const char *time)
+{
+ /* convert a time YYYYDDMMHHMMSS to wireformat */
+ uint16_t *r = NULL;
+ struct tm tm;
+ uint32_t l;
+ char *end;
+
+ /* Try to scan the time... */
+ r = (uint16_t*)LDNS_MALLOC(uint32_t);
+ if(!r) return LDNS_STATUS_MEM_ERR;
+
+ memset(&tm, 0, sizeof(tm));
+
+ if (strlen(time) == 14 &&
+ sscanf(time, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6
+ ) {
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+ /* Check values */
+ if (tm.tm_year < 70) {
+ goto bad_format;
+ }
+ if (tm.tm_mon < 0 || tm.tm_mon > 11) {
+ goto bad_format;
+ }
+ if (tm.tm_mday < 1 || tm.tm_mday > 31) {
+ goto bad_format;
+ }
+
+ if (tm.tm_hour < 0 || tm.tm_hour > 23) {
+ goto bad_format;
+ }
+
+ if (tm.tm_min < 0 || tm.tm_min > 59) {
+ goto bad_format;
+ }
+
+ if (tm.tm_sec < 0 || tm.tm_sec > 59) {
+ goto bad_format;
+ }
+
+ l = htonl(mktime_from_utc(&tm));
+ memcpy(r, &l, sizeof(uint32_t));
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_TIME, sizeof(uint32_t), r);
+ LDNS_FREE(r);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+ } else {
+ /* handle it as 32 bits timestamp */
+ l = htonl((uint32_t)strtol((char*)time, &end, 10));
+ if(*end != 0) {
+ LDNS_FREE(r);
+ return LDNS_STATUS_ERR;
+ } else {
+ memcpy(r, &l, sizeof(uint32_t));
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r);
+ LDNS_FREE(r);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+ }
+ }
+
+ bad_format:
+ LDNS_FREE(r);
+ return LDNS_STATUS_INVALID_TIME;
+}
+
+ldns_status
+ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *salt_str)
+{
+ uint8_t salt_length;
+ int c;
+ int salt_length_str;
+
+ uint8_t *salt;
+ uint8_t *data;
+ if(rd == NULL) {
+ return LDNS_STATUS_NULL;
+ }
+
+ salt_length_str = (int)strlen(salt_str);
+ if (salt_length_str == 1 && salt_str[0] == '-') {
+ salt_length_str = 0;
+ } else if (salt_length_str % 2 != 0) {
+ return LDNS_STATUS_INVALID_HEX;
+ }
+ if (salt_length_str > 512) {
+ return LDNS_STATUS_INVALID_HEX;
+ }
+
+ salt = LDNS_XMALLOC(uint8_t, salt_length_str / 2);
+ if(!salt) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ for (c = 0; c < salt_length_str; c += 2) {
+ if (isxdigit((int) salt_str[c]) && isxdigit((int) salt_str[c+1])) {
+ salt[c/2] = (uint8_t) ldns_hexdigit_to_int(salt_str[c]) * 16 +
+ ldns_hexdigit_to_int(salt_str[c+1]);
+ } else {
+ LDNS_FREE(salt);
+ return LDNS_STATUS_INVALID_HEX;
+ }
+ }
+ salt_length = (uint8_t) (salt_length_str / 2);
+
+ data = LDNS_XMALLOC(uint8_t, 1 + salt_length);
+ if(!data) {
+ LDNS_FREE(salt);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ data[0] = salt_length;
+ memcpy(&data[1], salt, salt_length);
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, 1 + salt_length, data);
+ LDNS_FREE(data);
+ LDNS_FREE(salt);
+
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_period(ldns_rdf **rd,const char *period)
+{
+ uint32_t p;
+ const char *end;
+
+ /* Allocate required space... */
+ p = ldns_str2period(period, &end);
+
+ if (*end != 0) {
+ return LDNS_STATUS_ERR;
+ } else {
+ p = (uint32_t) htonl(p);
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_PERIOD, sizeof(uint32_t), &p);
+ }
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr)
+{
+ char *end;
+ uint16_t *r = NULL;
+ uint32_t l;
+
+ r = (uint16_t*)LDNS_MALLOC(uint32_t);
+ if(!r) return LDNS_STATUS_MEM_ERR;
+ errno = 0; /* must set to zero before call,
+ note race condition on errno */
+ if(*longstr == '-')
+ l = htonl((uint32_t)strtol((char*)longstr, &end, 10));
+ else l = htonl((uint32_t)strtoul((char*)longstr, &end, 10));
+
+ if(*end != 0) {
+ LDNS_FREE(r);
+ return LDNS_STATUS_ERR;
+ } else {
+ if (errno == ERANGE) {
+ LDNS_FREE(r);
+ return LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW;
+ }
+ memcpy(r, &l, sizeof(uint32_t));
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r);
+ LDNS_FREE(r);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+ }
+}
+
+ldns_status
+ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr)
+{
+ char *end;
+ uint8_t *r = NULL;
+
+ r = LDNS_MALLOC(uint8_t);
+ if(!r) return LDNS_STATUS_MEM_ERR;
+
+ *r = (uint8_t)strtol((char*)bytestr, &end, 10);
+
+ if(*end != 0) {
+ LDNS_FREE(r);
+ return LDNS_STATUS_ERR;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_INT8, sizeof(uint8_t), r);
+ LDNS_FREE(r);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+ }
+}
+
+
+/*
+ * Checks whether the escaped value at **s is an octal value or
+ * a 'normally' escaped character (and not eos)
+ *
+ * The string pointer at *s is increased by either 0 (on error), 1 (on
+ * normal escapes), or 3 (on octals)
+ *
+ * Returns the number of bytes read from the escaped string, or
+ * 0 on error
+ */
+static int
+parse_escape(uint8_t *s, uint8_t *q) {
+ uint8_t val;
+ if (strlen((char *)s) > 3 &&
+ isdigit((int) s[1]) &&
+ isdigit((int) s[2]) &&
+ isdigit((int) s[3])) {
+ /* cast this so it fits */
+ val = (uint8_t) ldns_hexdigit_to_int((char) s[1]) * 100 +
+ ldns_hexdigit_to_int((char) s[2]) * 10 +
+ ldns_hexdigit_to_int((char) s[3]);
+ *q = val;
+ return 3;
+ } else {
+ s++;
+ if (*s == '\0' || isdigit((int) *s)) {
+ /* apparently the string terminator
+ * or a digit has been escaped...
+ */
+ return 0;
+ }
+ *q = *s;
+ return 1;
+ }
+}
+
+/*
+ * No special care is taken, all dots are translated into
+ * label seperators.
+ * Could be made more efficient....we do 3 memcpy's in total...
+ */
+ldns_status
+ldns_str2rdf_dname(ldns_rdf **d, const char *str)
+{
+ size_t len;
+
+ int esc;
+ uint8_t *s, *q, *pq, label_len;
+ uint8_t buf[LDNS_MAX_DOMAINLEN + 1];
+ *d = NULL;
+
+ len = strlen((char*)str);
+ /* octet representation can make strings a lot longer than actual length */
+ if (len > LDNS_MAX_DOMAINLEN * 4) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+ if (0 == len) {
+ return LDNS_STATUS_DOMAINNAME_UNDERFLOW;
+ }
+
+ /* root label */
+ if (1 == len && *str == '.') {
+ *d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, "\0");
+ return LDNS_STATUS_OK;
+ }
+
+ /* get on with the rest */
+
+ /* s is on the current character in the string
+ * pq points to where the labellength is going to go
+ * label_len keeps track of the current label's length
+ * q builds the dname inside the buf array
+ */
+ len = 0;
+ q = buf+1;
+ pq = buf;
+ label_len = 0;
+ for (s = (uint8_t *)str; *s; s++, q++) {
+ if (q > buf + LDNS_MAX_DOMAINLEN) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+ *q = 0;
+ switch (*s) {
+ case '.':
+ if (label_len > LDNS_MAX_LABELLEN) {
+ return LDNS_STATUS_LABEL_OVERFLOW;
+ }
+ if (label_len == 0) {
+ return LDNS_STATUS_EMPTY_LABEL;
+ }
+ len += label_len + 1;
+ *pq = label_len;
+ label_len = 0;
+ pq = q;
+ break;
+ case '\\':
+ /* octet value or literal char */
+ esc = parse_escape(s, q);
+ if (esc > 0) {
+ s += esc;
+ label_len++;
+ } else {
+ return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+ }
+ break;
+ default:
+ *q = *s;
+ label_len++;
+ }
+ }
+
+ /* add root label if last char was not '.' */
+ if (!ldns_dname_str_absolute(str)) {
+ if (q > buf + LDNS_MAX_DOMAINLEN) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+ if (label_len > LDNS_MAX_LABELLEN) {
+ return LDNS_STATUS_LABEL_OVERFLOW;
+ }
+ if (label_len == 0) { /* label_len 0 but not . at end? */
+ return LDNS_STATUS_EMPTY_LABEL;
+ }
+ len += label_len + 1;
+ *pq = label_len;
+ *q = 0;
+ }
+ len++;
+
+ *d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, len, buf);
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_str2rdf_a(ldns_rdf **rd, const char *str)
+{
+ in_addr_t address;
+ if (inet_pton(AF_INET, (char*)str, &address) != 1) {
+ return LDNS_STATUS_INVALID_IP4;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_A, sizeof(address), &address);
+ }
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str)
+{
+ uint8_t address[LDNS_IP6ADDRLEN + 1];
+
+ if (inet_pton(AF_INET6, (char*)str, address) != 1) {
+ return LDNS_STATUS_INVALID_IP6;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_AAAA, sizeof(address) - 1, &address);
+ }
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_str(ldns_rdf **rd, const char *str)
+{
+ uint8_t *data;
+ size_t i, str_i, esc_i;
+
+ if (strlen(str) > 255) {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ data = LDNS_XMALLOC(uint8_t, strlen(str) + 1);
+ if(!data) return LDNS_STATUS_MEM_ERR;
+ i = 1;
+
+ for (str_i = 0; str_i < strlen(str); str_i++) {
+ if (str[str_i] == '\\') {
+ /* octet value or literal char */
+ esc_i = (size_t) parse_escape((uint8_t*) &str[str_i], (uint8_t*) &data[i]);
+ if (esc_i == 0) {
+ LDNS_FREE(data);
+ return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
+ }
+ str_i += esc_i;
+ } else {
+ data[i] = (uint8_t) str[str_i];
+ }
+ i++;
+ }
+ data[0] = i - 1;
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_STR, i, data);
+
+ LDNS_FREE(data);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_apl(ldns_rdf **rd, const char *str)
+{
+ const char *my_str = str;
+
+ char *my_ip_str;
+ size_t ip_str_len;
+
+ uint16_t family;
+ bool negation;
+ uint8_t afdlength = 0;
+ uint8_t *afdpart;
+ uint8_t prefix;
+
+ uint8_t *data;
+
+ size_t i = 0;
+
+ /* [!]afi:address/prefix */
+ if (strlen(my_str) < 2
+ || strchr(my_str, ':') == NULL
+ || strchr(my_str, '/') == NULL
+ || strchr(my_str, ':') > strchr(my_str, '/')) {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ if (my_str[0] == '!') {
+ negation = true;
+ my_str += 1;
+ } else {
+ negation = false;
+ }
+
+ family = (uint16_t) atoi(my_str);
+
+ my_str = strchr(my_str, ':') + 1;
+
+ /* need ip addr and only ip addr for inet_pton */
+ ip_str_len = (size_t) (strchr(my_str, '/') - my_str);
+ my_ip_str = LDNS_XMALLOC(char, ip_str_len + 1);
+ if(!my_ip_str) return LDNS_STATUS_MEM_ERR;
+ strncpy(my_ip_str, my_str, ip_str_len + 1);
+ my_ip_str[ip_str_len] = '\0';
+
+ if (family == 1) {
+ /* ipv4 */
+ afdpart = LDNS_XMALLOC(uint8_t, 4);
+ if(!afdpart) {
+ LDNS_FREE(my_ip_str);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ if (inet_pton(AF_INET, my_ip_str, afdpart) == 0) {
+ LDNS_FREE(my_ip_str);
+ LDNS_FREE(afdpart);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ for (i = 0; i < 4; i++) {
+ if (afdpart[i] != 0) {
+ afdlength = i + 1;
+ }
+ }
+ } else if (family == 2) {
+ /* ipv6 */
+ afdpart = LDNS_XMALLOC(uint8_t, 16);
+ if(!afdpart) {
+ LDNS_FREE(my_ip_str);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ if (inet_pton(AF_INET6, my_ip_str, afdpart) == 0) {
+ LDNS_FREE(my_ip_str);
+ LDNS_FREE(afdpart);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ for (i = 0; i < 16; i++) {
+ if (afdpart[i] != 0) {
+ afdlength = i + 1;
+ }
+ }
+ } else {
+ /* unknown family */
+ LDNS_FREE(my_ip_str);
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ my_str = strchr(my_str, '/') + 1;
+ prefix = (uint8_t) atoi(my_str);
+
+ data = LDNS_XMALLOC(uint8_t, 4 + afdlength);
+ if(!data) {
+ LDNS_FREE(my_ip_str);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ ldns_write_uint16(data, family);
+ data[2] = prefix;
+ data[3] = afdlength;
+ if (negation) {
+ /* set bit 1 of byte 3 */
+ data[3] = data[3] | 0x80;
+ }
+
+ memcpy(data + 4, afdpart, afdlength);
+
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_APL, afdlength + 4, data);
+ LDNS_FREE(afdpart);
+ LDNS_FREE(data);
+ LDNS_FREE(my_ip_str);
+
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_b64(ldns_rdf **rd, const char *str)
+{
+ uint8_t *buffer;
+ int16_t i;
+
+ buffer = LDNS_XMALLOC(uint8_t, ldns_b64_ntop_calculate_size(strlen(str)));
+ if(!buffer) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ i = (uint16_t)ldns_b64_pton((const char*)str, buffer,
+ ldns_b64_ntop_calculate_size(strlen(str)));
+ if (-1 == i) {
+ LDNS_FREE(buffer);
+ return LDNS_STATUS_INVALID_B64;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_B64, (uint16_t) i, buffer);
+ }
+ LDNS_FREE(buffer);
+
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str)
+{
+ uint8_t *buffer;
+ int i;
+ /* first byte contains length of actual b32 data */
+ uint8_t len = ldns_b32_pton_calculate_size(strlen(str));
+ buffer = LDNS_XMALLOC(uint8_t, len + 1);
+ if(!buffer) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ buffer[0] = len;
+
+ i = ldns_b32_pton_extended_hex((const char*)str, strlen(str), buffer + 1,
+ ldns_b32_ntop_calculate_size(strlen(str)));
+ if (i < 0) {
+ LDNS_FREE(buffer);
+ return LDNS_STATUS_INVALID_B32_EXT;
+ } else {
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_B32_EXT, (uint16_t) i + 1, buffer);
+ }
+ LDNS_FREE(buffer);
+
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_hex(ldns_rdf **rd, const char *str)
+{
+ uint8_t *t, *t_orig;
+ int i;
+ size_t len;
+
+ len = strlen(str);
+
+ if (len > LDNS_MAX_RDFLEN * 2) {
+ return LDNS_STATUS_LABEL_OVERFLOW;
+ } else {
+ t = LDNS_XMALLOC(uint8_t, (len / 2) + 1);
+ if(!t) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ t_orig = t;
+ /* Now process octet by octet... */
+ while (*str) {
+ *t = 0;
+ if (isspace((int) *str)) {
+ str++;
+ } else {
+ for (i = 16; i >= 1; i -= 15) {
+ while (*str && isspace((int) *str)) { str++; }
+ if (*str) {
+ if (isxdigit((int) *str)) {
+ *t += ldns_hexdigit_to_int(*str) * i;
+ } else {
+ LDNS_FREE(t_orig);
+ return LDNS_STATUS_ERR;
+ }
+ ++str;
+ }
+ }
+ ++t;
+ }
+ }
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
+ (size_t) (t - t_orig),
+ t_orig);
+ LDNS_FREE(t_orig);
+ }
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_nsec(ldns_rdf **rd, const char *str)
+{
+ const char *delimiters = "\n\t ";
+ char *token = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
+ ldns_buffer *str_buf;
+ ssize_t c;
+ uint16_t cur_type;
+ size_t type_count = 0;
+ ldns_rr_type type_list[65536];
+ if(!token) return LDNS_STATUS_MEM_ERR;
+ if(rd == NULL) {
+ LDNS_FREE(token);
+ return LDNS_STATUS_NULL;
+ }
+
+ str_buf = LDNS_MALLOC(ldns_buffer);
+ if(!str_buf) {
+ LDNS_FREE(token);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
+ if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
+ LDNS_FREE(str_buf);
+ LDNS_FREE(token);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ while ((c = ldns_bget_token(str_buf, token, delimiters, LDNS_MAX_RDFLEN)) != -1 && c != 0) {
+ if(type_count >= sizeof(type_list)) {
+ LDNS_FREE(str_buf);
+ LDNS_FREE(token);
+ return LDNS_STATUS_ERR;
+ }
+ cur_type = ldns_get_rr_type_by_name(token);
+ type_list[type_count] = cur_type;
+ type_count++;
+ }
+
+ *rd = ldns_dnssec_create_nsec_bitmap(type_list,
+ type_count,
+ LDNS_RR_TYPE_NSEC);
+
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_type(ldns_rdf **rd, const char *str)
+{
+ uint16_t type;
+ type = htons(ldns_get_rr_type_by_name(str));
+ /* ldns_rr_type is a 16 bit value */
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_TYPE, sizeof(uint16_t), &type);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_class(ldns_rdf **rd, const char *str)
+{
+ uint16_t klass;
+ klass = htons(ldns_get_rr_class_by_name(str));
+ /* class is 16 bit */
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_CLASS, sizeof(uint16_t), &klass);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+/* An certificate alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both
+ */
+ldns_status
+ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str)
+{
+ ldns_lookup_table *lt;
+ ldns_status st;
+ uint8_t idd[2];
+ lt = ldns_lookup_by_name(ldns_cert_algorithms, str);
+ st = LDNS_STATUS_OK;
+
+ if (lt) {
+ ldns_write_uint16(idd, (uint16_t) lt->id);
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_INT16, sizeof(uint16_t), idd);
+ if (!*rd) {
+ st = LDNS_STATUS_ERR;
+ }
+ } else {
+ /* try as-is (a number) */
+ st = ldns_str2rdf_int16(rd, str);
+ if (st == LDNS_STATUS_OK &&
+ ldns_rdf2native_int16(*rd) == 0) {
+ st = LDNS_STATUS_CERT_BAD_ALGORITHM;
+ }
+ }
+
+ return st;
+}
+
+/* An alg field can either be specified as a 8 bits number
+ * or by its symbolic name. Handle both
+ */
+ldns_status
+ldns_str2rdf_alg(ldns_rdf **rd, const char *str)
+{
+ ldns_lookup_table *lt;
+ ldns_status st;
+
+ lt = ldns_lookup_by_name(ldns_algorithms, str);
+ st = LDNS_STATUS_OK;
+
+ if (lt) {
+ /* it was given as a integer */
+ *rd = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t) lt->id);
+ if (!*rd) {
+ st = LDNS_STATUS_ERR;
+ }
+ } else {
+ /* try as-is (a number) */
+ st = ldns_str2rdf_int8(rd, str);
+ }
+ return st;
+}
+
+ldns_status
+ldns_str2rdf_unknown(ldns_rdf **rd, const char *str)
+{
+ /* this should be caught in an earlier time (general str2host for
+ rr's */
+ rd = rd;
+ str = str;
+ return LDNS_STATUS_NOT_IMPL;
+}
+
+ldns_status
+ldns_str2rdf_tsig(ldns_rdf **rd, const char *str)
+{
+ /* there is no strign representation for TSIG rrs */
+ rd = rd;
+ str = str;
+ return LDNS_STATUS_NOT_IMPL;
+}
+
+ldns_status
+ldns_str2rdf_service(ldns_rdf **rd, const char *str)
+{
+ /* is this used? is this actually WKS? or SRV? */
+ rd = rd;
+ str = str;
+ return LDNS_STATUS_NOT_IMPL;
+}
+
+static int
+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;
+ while (isblank(*my_str)) {
+ my_str++;
+ }
+ meters = (uint32_t)strtol(my_str, &my_str, 10);
+ if (*my_str == '.') {
+ my_str++;
+ cm = (uint32_t)strtol(my_str, &my_str, 10);
+ }
+ if (meters >= 1) {
+ *e = 2;
+ val = meters;
+ } else {
+ *e = 0;
+ val = cm;
+ }
+ while(val >= 10) {
+ (*e)++;
+ val /= 10;
+ }
+ *m = (uint8_t)val;
+
+ if (*e > 9)
+ return 0;
+ if (*my_str == 'm' || *my_str == 'M') {
+ my_str++;
+ }
+ *endstr = my_str;
+ return 1;
+}
+
+ldns_status
+ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
+{
+ uint32_t latitude = 0;
+ uint32_t longitude = 0;
+ uint32_t altitude = 0;
+
+ uint8_t *data;
+ uint32_t equator = (uint32_t) ldns_power(2, 31);
+
+ uint32_t h = 0;
+ uint32_t m = 0;
+ uint8_t size_b = 1, size_e = 2;
+ uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
+ uint8_t vert_pre_b = 1, vert_pre_e = 3;
+
+ double s = 0.0;
+ bool northerness;
+ bool easterness;
+
+ char *my_str = (char *) str;
+
+ /* only support version 0 */
+ if (isdigit((int) *my_str)) {
+ h = (uint32_t) strtol(my_str, &my_str, 10);
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ while (isblank((int) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((int) *my_str)) {
+ m = (uint32_t) strtol(my_str, &my_str, 10);
+ } else if (*my_str == 'N' || *my_str == 'S') {
+ goto north;
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ while (isblank((int) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((int) *my_str)) {
+ s = strtod(my_str, &my_str);
+ }
+north:
+ while (isblank((int) *my_str)) {
+ my_str++;
+ }
+
+ if (*my_str == 'N') {
+ northerness = true;
+ } else if (*my_str == 'S') {
+ northerness = false;
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ my_str++;
+
+ /* store number */
+ s = 1000.0 * s;
+ /* add a little to make floor in conversion a round */
+ s += 0.0005;
+ latitude = (uint32_t) s;
+ latitude += 1000 * 60 * m;
+ latitude += 1000 * 60 * 60 * h;
+ if (northerness) {
+ latitude = equator + latitude;
+ } else {
+ latitude = equator - latitude;
+ }
+ while (isblank(*my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((int) *my_str)) {
+ h = (uint32_t) strtol(my_str, &my_str, 10);
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ while (isblank((int) *my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((int) *my_str)) {
+ m = (uint32_t) strtol(my_str, &my_str, 10);
+ } else if (*my_str == 'E' || *my_str == 'W') {
+ goto east;
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ while (isblank(*my_str)) {
+ my_str++;
+ }
+
+ if (isdigit((int) *my_str)) {
+ s = strtod(my_str, &my_str);
+ }
+
+east:
+ while (isblank(*my_str)) {
+ my_str++;
+ }
+
+ if (*my_str == 'E') {
+ easterness = true;
+ } else if (*my_str == 'W') {
+ easterness = false;
+ } else {
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ my_str++;
+
+ /* store number */
+ s *= 1000.0;
+ /* add a little to make floor in conversion a round */
+ s += 0.0005;
+ longitude = (uint32_t) s;
+ longitude += 1000 * 60 * m;
+ longitude += 1000 * 60 * 60 * h;
+
+ if (easterness) {
+ longitude += equator;
+ } else {
+ longitude = equator - longitude;
+ }
+
+ altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
+ 10000000.0 + 0.5);
+ if (*my_str == 'm' || *my_str == 'M') {
+ my_str++;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ if (strlen(my_str) > 0) {
+ if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ data = LDNS_XMALLOC(uint8_t, 16);
+ if(!data) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ data[0] = 0;
+ data[1] = 0;
+ data[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
+ data[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
+ data[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
+ ldns_write_uint32(data + 4, latitude);
+ ldns_write_uint32(data + 8, longitude);
+ ldns_write_uint32(data + 12, altitude);
+
+ *rd = ldns_rdf_new_frm_data(
+ LDNS_RDF_TYPE_LOC, 16, data);
+
+ LDNS_FREE(data);
+ return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
+}
+
+ldns_status
+ldns_str2rdf_wks(ldns_rdf **rd, const char *str)
+{
+ uint8_t *bitmap = NULL;
+ uint8_t *data;
+ int bm_len = 0;
+
+ struct protoent *proto = NULL;
+ struct servent *serv = NULL;
+ int serv_port;
+
+ ldns_buffer *str_buf;
+
+ char *proto_str = NULL;
+ char *token;
+ if(strlen(str) == 0)
+ token = LDNS_XMALLOC(char, 50);
+ else token = LDNS_XMALLOC(char, strlen(str)+2);
+ if(!token) return LDNS_STATUS_MEM_ERR;
+
+ str_buf = LDNS_MALLOC(ldns_buffer);
+ if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;}
+ ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
+ if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
+ LDNS_FREE(str_buf);
+ LDNS_FREE(token);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) {
+ if (!proto_str) {
+ proto_str = strdup(token);
+ if (!proto_str) {
+ LDNS_FREE(bitmap);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ } else {
+ serv = getservbyname(token, proto_str);
+ if (serv) {
+ serv_port = (int) ntohs((uint16_t) serv->s_port);
+ } else {
+ serv_port = atoi(token);
+ }
+ if (serv_port / 8 >= bm_len) {
+ uint8_t *b2 = LDNS_XREALLOC(bitmap, uint8_t, (serv_port / 8) + 1);
+ if(!b2) {
+ LDNS_FREE(bitmap);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ free(proto_str);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ bitmap = b2;
+ /* set to zero to be sure */
+ for (; bm_len <= serv_port / 8; bm_len++) {
+ bitmap[bm_len] = 0;
+ }
+ }
+ ldns_set_bit(bitmap + (serv_port / 8), 7 - (serv_port % 8), true);
+ }
+ }
+
+ if (!proto_str || !bitmap) {
+ LDNS_FREE(bitmap);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ free(proto_str);
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ data = LDNS_XMALLOC(uint8_t, bm_len + 1);
+ if(!data) {
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ LDNS_FREE(bitmap);
+ free(proto_str);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ if (proto_str)
+ proto = getprotobyname(proto_str);
+ if (proto) {
+ data[0] = (uint8_t) proto->p_proto;
+ } else if (proto_str) {
+ data[0] = (uint8_t) atoi(proto_str);
+ } else {
+ data[0] = 0;
+ }
+ memcpy(data + 1, bitmap, (size_t) bm_len);
+
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_WKS, (uint16_t) (bm_len + 1), data);
+
+ LDNS_FREE(data);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ LDNS_FREE(bitmap);
+ free(proto_str);
+#ifdef HAVE_ENDSERVENT
+ endservent();
+#endif
+#ifdef HAVE_ENDPROTOENT
+ endprotoent();
+#endif
+
+ if(!*rd) return LDNS_STATUS_MEM_ERR;
+
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_str2rdf_nsap(ldns_rdf **rd, const char *str)
+{
+ size_t len, i;
+ char* nsap_str = (char*) str;
+
+ /* just a hex string with optional dots? */
+ if (str[0] != '0' || str[1] != 'x') {
+ return LDNS_STATUS_INVALID_STR;
+ } else {
+ len = strlen(str);
+ for (i=0; i < len; i++) {
+ if (nsap_str[i] == '.')
+ nsap_str[i] = ' ';
+ }
+ return ldns_str2rdf_hex(rd, str+2);
+ }
+}
+
+ldns_status
+ldns_str2rdf_atma(ldns_rdf **rd, const char *str)
+{
+ size_t len, i;
+ char* atma_str = (char*) str;
+ ldns_status status;
+
+ /* just a hex string with optional dots? */
+ len = strlen(str);
+ for (i=0; i < len; i++) {
+ if (atma_str[i] == '.')
+ atma_str[i] = ' ';
+ }
+ status = ldns_str2rdf_hex(rd, str);
+ if (status != LDNS_STATUS_OK) {
+ ; /* probably in e.164 format than */
+ }
+ return status;
+}
+
+ldns_status
+ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str)
+{
+ uint8_t precedence = 0;
+ uint8_t gateway_type = 0;
+ uint8_t algorithm = 0;
+ char* gateway = NULL;
+ char* publickey = NULL;
+ uint8_t *data;
+ ldns_buffer *str_buf;
+ char *token;
+ int token_count = 0;
+ int ipseckey_len = 0;
+ ldns_rdf* gateway_rdf = NULL;
+ ldns_rdf* publickey_rdf = NULL;
+ ldns_status status = LDNS_STATUS_OK;
+
+ if(strlen(str) == 0)
+ token = LDNS_XMALLOC(char, 256);
+ else token = LDNS_XMALLOC(char, strlen(str)+2);
+ if(!token) return LDNS_STATUS_MEM_ERR;
+
+ str_buf = LDNS_MALLOC(ldns_buffer);
+ if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;}
+ ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
+ if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
+ LDNS_FREE(str_buf);
+ LDNS_FREE(token);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) {
+ switch (token_count) {
+ case 0:
+ precedence = (uint8_t)atoi(token);
+ break;
+ case 1:
+ gateway_type = (uint8_t)atoi(token);
+ break;
+ case 2:
+ algorithm = (uint8_t)atoi(token);
+ break;
+ case 3:
+ gateway = strdup(token);
+ if (!gateway || (gateway_type == 0 &&
+ (token[0] != '.' || token[1] != '\0'))) {
+ LDNS_FREE(gateway);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return LDNS_STATUS_INVALID_STR;
+ }
+ break;
+ case 4:
+ publickey = strdup(token);
+ break;
+ default:
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return LDNS_STATUS_INVALID_STR;
+ break;
+ }
+ token_count++;
+ }
+
+ if (!gateway || !publickey) {
+ if (gateway)
+ LDNS_FREE(gateway);
+ if (publickey)
+ LDNS_FREE(publickey);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ if (gateway_type == 1) {
+ status = ldns_str2rdf_a(&gateway_rdf, gateway);
+ } else if (gateway_type == 2) {
+ status = ldns_str2rdf_aaaa(&gateway_rdf, gateway);
+ } else if (gateway_type == 3) {
+ status = ldns_str2rdf_dname(&gateway_rdf, gateway);
+ }
+
+ if (status != LDNS_STATUS_OK) {
+ if (gateway)
+ LDNS_FREE(gateway);
+ if (publickey)
+ LDNS_FREE(publickey);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ status = ldns_str2rdf_b64(&publickey_rdf, publickey);
+
+ if (status != LDNS_STATUS_OK) {
+ if (gateway)
+ LDNS_FREE(gateway);
+ if (publickey)
+ LDNS_FREE(publickey);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ if (gateway_rdf) ldns_rdf_free(gateway_rdf);
+ return LDNS_STATUS_INVALID_STR;
+ }
+
+ /* now copy all into one ipseckey rdf */
+ if (gateway_type)
+ ipseckey_len = 3 + (int)ldns_rdf_size(gateway_rdf) + (int)ldns_rdf_size(publickey_rdf);
+ else
+ ipseckey_len = 3 + (int)ldns_rdf_size(publickey_rdf);
+
+ data = LDNS_XMALLOC(uint8_t, ipseckey_len);
+ if(!data) {
+ if (gateway)
+ LDNS_FREE(gateway);
+ if (publickey)
+ LDNS_FREE(publickey);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ if (gateway_rdf) ldns_rdf_free(gateway_rdf);
+ if (publickey_rdf) ldns_rdf_free(publickey_rdf);
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ data[0] = precedence;
+ data[1] = gateway_type;
+ data[2] = algorithm;
+
+ if (gateway_type) {
+ memcpy(data + 3,
+ ldns_rdf_data(gateway_rdf), ldns_rdf_size(gateway_rdf));
+ memcpy(data + 3 + ldns_rdf_size(gateway_rdf),
+ ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf));
+ } else {
+ memcpy(data + 3,
+ ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf));
+ }
+
+ *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_IPSECKEY, (uint16_t) ipseckey_len, data);
+
+ if (gateway)
+ LDNS_FREE(gateway);
+ if (publickey)
+ LDNS_FREE(publickey);
+ LDNS_FREE(token);
+ ldns_buffer_free(str_buf);
+ ldns_rdf_free(gateway_rdf);
+ ldns_rdf_free(publickey_rdf);
+ LDNS_FREE(data);
+ if(!*rd) return LDNS_STATUS_MEM_ERR;
+ return LDNS_STATUS_OK;
+}
diff --git a/3rdParty/Ldns/src/src/tsig.c b/3rdParty/Ldns/src/src/tsig.c
new file mode 100644
index 0000000..90c20a0
--- /dev/null
+++ b/3rdParty/Ldns/src/src/tsig.c
@@ -0,0 +1,472 @@
+/*
+ * tsig.c
+ *
+ * contains the functions needed for TSIG [RFC2845]
+ *
+ * (c) 2005-2006 NLnet Labs
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+
+#ifdef HAVE_SSL
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#endif /* HAVE_SSL */
+
+char *
+ldns_tsig_algorithm(ldns_tsig_credentials *tc)
+{
+ return tc->algorithm;
+}
+
+char *
+ldns_tsig_keyname(ldns_tsig_credentials *tc)
+{
+ return tc->keyname;
+}
+
+char *
+ldns_tsig_keydata(ldns_tsig_credentials *tc)
+{
+ return tc->keydata;
+}
+
+char *
+ldns_tsig_keyname_clone(ldns_tsig_credentials *tc)
+{
+ return strdup(tc->keyname);
+}
+
+char *
+ldns_tsig_keydata_clone(ldns_tsig_credentials *tc)
+{
+ return strdup(tc->keydata);
+}
+
+/*
+ * Makes an exact copy of the wire, but with the tsig rr removed
+ */
+uint8_t *
+ldns_tsig_prepare_pkt_wire(uint8_t *wire, size_t wire_len, size_t *result_len)
+{
+ uint8_t *wire2 = NULL;
+ uint16_t qd_count;
+ uint16_t an_count;
+ uint16_t ns_count;
+ uint16_t ar_count;
+ ldns_rr *rr;
+
+ size_t pos;
+ uint16_t i;
+
+ ldns_status status;
+
+ if(wire_len < LDNS_HEADER_SIZE) {
+ return NULL;
+ }
+ /* fake parse the wire */
+ qd_count = LDNS_QDCOUNT(wire);
+ an_count = LDNS_ANCOUNT(wire);
+ ns_count = LDNS_NSCOUNT(wire);
+ ar_count = LDNS_ARCOUNT(wire);
+
+ if (ar_count > 0) {
+ ar_count--;
+ } else {
+ return NULL;
+ }
+
+ pos = LDNS_HEADER_SIZE;
+
+ for (i = 0; i < qd_count; i++) {
+ status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_QUESTION);
+ if (status != LDNS_STATUS_OK) {
+ return NULL;
+ }
+ ldns_rr_free(rr);
+ }
+
+ for (i = 0; i < an_count; i++) {
+ status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_ANSWER);
+ if (status != LDNS_STATUS_OK) {
+ return NULL;
+ }
+ ldns_rr_free(rr);
+ }
+
+ for (i = 0; i < ns_count; i++) {
+ status = ldns_wire2rr(&rr, wire, wire_len, &pos, LDNS_SECTION_AUTHORITY);
+ if (status != LDNS_STATUS_OK) {
+ return NULL;
+ }
+ ldns_rr_free(rr);
+ }
+
+ for (i = 0; i < ar_count; i++) {
+ status = ldns_wire2rr(&rr, wire, wire_len, &pos,
+ LDNS_SECTION_ADDITIONAL);
+ if (status != LDNS_STATUS_OK) {
+ return NULL;
+ }
+ ldns_rr_free(rr);
+ }
+
+ *result_len = pos;
+ wire2 = LDNS_XMALLOC(uint8_t, *result_len);
+ if(!wire2) {
+ return NULL;
+ }
+ memcpy(wire2, wire, *result_len);
+
+ ldns_write_uint16(wire2 + LDNS_ARCOUNT_OFF, ar_count);
+
+ return wire2;
+}
+
+#ifdef HAVE_SSL
+static const EVP_MD *
+ldns_digest_function(char *name)
+{
+ /* these are the mandatory algorithms from RFC4635 */
+ /* The optional algorithms are not yet implemented */
+ if (strlen(name) == 12
+ && strncasecmp(name, "hmac-sha256.", 11) == 0) {
+#ifdef HAVE_EVP_SHA256
+ return EVP_sha256();
+#else
+ return NULL;
+#endif
+ } else if (strlen(name) == 10
+ && strncasecmp(name, "hmac-sha1.", 9) == 0) {
+ return EVP_sha1();
+ } else if (strlen(name) == 25
+ && strncasecmp(name, "hmac-md5.sig-alg.reg.int.", 25)
+ == 0) {
+ return EVP_md5();
+ } else {
+ return NULL;
+ }
+}
+#endif
+
+#ifdef HAVE_SSL
+static ldns_status
+ldns_tsig_mac_new(ldns_rdf **tsig_mac, uint8_t *pkt_wire, size_t pkt_wire_size,
+ const char *key_data, ldns_rdf *key_name_rdf, ldns_rdf *fudge_rdf,
+ ldns_rdf *algorithm_rdf, ldns_rdf *time_signed_rdf, ldns_rdf *error_rdf,
+ ldns_rdf *other_data_rdf, ldns_rdf *orig_mac_rdf, int tsig_timers_only)
+{
+ ldns_status status;
+ char *wireformat;
+ int wiresize;
+ unsigned char *mac_bytes = NULL;
+ unsigned char *key_bytes = NULL;
+ int key_size;
+ const EVP_MD *digester;
+ char *algorithm_name = NULL;
+ unsigned int md_len = EVP_MAX_MD_SIZE;
+ ldns_rdf *result = NULL;
+ ldns_buffer *data_buffer = NULL;
+ ldns_rdf *canonical_key_name_rdf = NULL;
+ ldns_rdf *canonical_algorithm_rdf = NULL;
+
+ if (key_name_rdf == NULL || algorithm_rdf == NULL) {
+ return LDNS_STATUS_NULL;
+ }
+ canonical_key_name_rdf = ldns_rdf_clone(key_name_rdf);
+ canonical_algorithm_rdf = ldns_rdf_clone(algorithm_rdf);
+
+ if (canonical_key_name_rdf == NULL
+ || canonical_algorithm_rdf == NULL) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ /*
+ * prepare the digestable information
+ */
+ data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
+ if (!data_buffer) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+ /* if orig_mac is not NULL, add it too */
+ if (orig_mac_rdf) {
+ (void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf);
+ }
+ ldns_buffer_write(data_buffer, pkt_wire, pkt_wire_size);
+ if (!tsig_timers_only) {
+ ldns_dname2canonical(canonical_key_name_rdf);
+ (void)ldns_rdf2buffer_wire(data_buffer,
+ canonical_key_name_rdf);
+ ldns_buffer_write_u16(data_buffer, LDNS_RR_CLASS_ANY);
+ ldns_buffer_write_u32(data_buffer, 0);
+ ldns_dname2canonical(canonical_algorithm_rdf);
+ (void)ldns_rdf2buffer_wire(data_buffer,
+ canonical_algorithm_rdf);
+ }
+ (void)ldns_rdf2buffer_wire(data_buffer, time_signed_rdf);
+ (void)ldns_rdf2buffer_wire(data_buffer, fudge_rdf);
+ if (!tsig_timers_only) {
+ (void)ldns_rdf2buffer_wire(data_buffer, error_rdf);
+ (void)ldns_rdf2buffer_wire(data_buffer, other_data_rdf);
+ }
+
+ wireformat = (char *) data_buffer->_data;
+ wiresize = (int) ldns_buffer_position(data_buffer);
+
+ algorithm_name = ldns_rdf2str(algorithm_rdf);
+ if(!algorithm_name) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+
+ /* prepare the key */
+ key_bytes = LDNS_XMALLOC(unsigned char,
+ ldns_b64_pton_calculate_size(strlen(key_data)));
+ if(!key_bytes) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+ key_size = ldns_b64_pton(key_data, key_bytes,
+ ldns_b64_pton_calculate_size(strlen(key_data)));
+ if (key_size < 0) {
+ status = LDNS_STATUS_INVALID_B64;
+ goto clean;
+ }
+ /* hmac it */
+ /* 2 spare bytes for the length */
+ mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2);
+ if(!mac_bytes) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+ memset(mac_bytes, 0, md_len+2);
+
+ digester = ldns_digest_function(algorithm_name);
+
+ if (digester) {
+ (void) HMAC(digester, key_bytes, key_size, (void *)wireformat,
+ (size_t) wiresize, mac_bytes + 2, &md_len);
+
+ ldns_write_uint16(mac_bytes, md_len);
+ result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2,
+ mac_bytes);
+ } else {
+ status = LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
+ goto clean;
+ }
+ *tsig_mac = result;
+ status = LDNS_STATUS_OK;
+ clean:
+ LDNS_FREE(mac_bytes);
+ LDNS_FREE(key_bytes);
+ LDNS_FREE(algorithm_name);
+ ldns_buffer_free(data_buffer);
+ ldns_rdf_free(canonical_algorithm_rdf);
+ ldns_rdf_free(canonical_key_name_rdf);
+ return status;
+}
+#endif /* HAVE_SSL */
+
+
+#ifdef HAVE_SSL
+bool
+ldns_pkt_tsig_verify(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char *key_name,
+ const char *key_data, ldns_rdf *orig_mac_rdf)
+{
+ return ldns_pkt_tsig_verify_next(pkt, wire, wirelen, key_name, key_data, orig_mac_rdf, 0);
+}
+
+bool
+ldns_pkt_tsig_verify_next(ldns_pkt *pkt, uint8_t *wire, size_t wirelen, const char* key_name,
+ const char *key_data, ldns_rdf *orig_mac_rdf, int tsig_timers_only)
+{
+ ldns_rdf *fudge_rdf;
+ ldns_rdf *algorithm_rdf;
+ ldns_rdf *time_signed_rdf;
+ ldns_rdf *orig_id_rdf;
+ ldns_rdf *error_rdf;
+ ldns_rdf *other_data_rdf;
+ ldns_rdf *pkt_mac_rdf;
+ ldns_rdf *my_mac_rdf;
+ ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name);
+ uint16_t pkt_id, orig_pkt_id;
+ ldns_status status;
+
+ uint8_t *prepared_wire = NULL;
+ size_t prepared_wire_size = 0;
+
+ ldns_rr *orig_tsig = ldns_pkt_tsig(pkt);
+
+ if (!orig_tsig || ldns_rr_rd_count(orig_tsig) <= 6) {
+ ldns_rdf_deep_free(key_name_rdf);
+ return false;
+ }
+ algorithm_rdf = ldns_rr_rdf(orig_tsig, 0);
+ time_signed_rdf = ldns_rr_rdf(orig_tsig, 1);
+ fudge_rdf = ldns_rr_rdf(orig_tsig, 2);
+ pkt_mac_rdf = ldns_rr_rdf(orig_tsig, 3);
+ orig_id_rdf = ldns_rr_rdf(orig_tsig, 4);
+ error_rdf = ldns_rr_rdf(orig_tsig, 5);
+ other_data_rdf = ldns_rr_rdf(orig_tsig, 6);
+
+ /* remove temporarily */
+ ldns_pkt_set_tsig(pkt, NULL);
+ /* temporarily change the id to the original id */
+ pkt_id = ldns_pkt_id(pkt);
+ orig_pkt_id = ldns_rdf2native_int16(orig_id_rdf);
+ ldns_pkt_set_id(pkt, orig_pkt_id);
+
+ prepared_wire = ldns_tsig_prepare_pkt_wire(wire, wirelen, &prepared_wire_size);
+
+ status = ldns_tsig_mac_new(&my_mac_rdf, prepared_wire, prepared_wire_size,
+ key_data, key_name_rdf, fudge_rdf, algorithm_rdf,
+ time_signed_rdf, error_rdf, other_data_rdf, orig_mac_rdf, tsig_timers_only);
+
+ LDNS_FREE(prepared_wire);
+
+ if (status != LDNS_STATUS_OK) {
+ ldns_rdf_deep_free(key_name_rdf);
+ return false;
+ }
+ /* Put back the values */
+ ldns_pkt_set_tsig(pkt, orig_tsig);
+ ldns_pkt_set_id(pkt, pkt_id);
+
+ ldns_rdf_deep_free(key_name_rdf);
+
+ if (ldns_rdf_compare(pkt_mac_rdf, my_mac_rdf) == 0) {
+ ldns_rdf_deep_free(my_mac_rdf);
+ return true;
+ } else {
+ ldns_rdf_deep_free(my_mac_rdf);
+ return false;
+ }
+}
+#endif /* HAVE_SSL */
+
+#ifdef HAVE_SSL
+ldns_status
+ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data,
+ uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac)
+{
+ return ldns_pkt_tsig_sign_next(pkt, key_name, key_data, fudge, algorithm_name, query_mac, 0);
+}
+
+ldns_status
+ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data,
+ uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only)
+{
+ ldns_rr *tsig_rr;
+ ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name);
+ ldns_rdf *fudge_rdf = NULL;
+ ldns_rdf *orig_id_rdf = NULL;
+ ldns_rdf *algorithm_rdf;
+ ldns_rdf *error_rdf = NULL;
+ ldns_rdf *mac_rdf = NULL;
+ ldns_rdf *other_data_rdf = NULL;
+
+ ldns_status status = LDNS_STATUS_OK;
+
+ uint8_t *pkt_wire = NULL;
+ size_t pkt_wire_len;
+
+ struct timeval tv_time_signed;
+ uint8_t *time_signed = NULL;
+ ldns_rdf *time_signed_rdf = NULL;
+
+ algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name);
+ if(!key_name_rdf || !algorithm_rdf) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+
+ /* eww don't have create tsigtime rdf yet :( */
+ /* bleh :p */
+ if (gettimeofday(&tv_time_signed, NULL) == 0) {
+ time_signed = LDNS_XMALLOC(uint8_t, 6);
+ if(!time_signed) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+ ldns_write_uint64_as_uint48(time_signed,
+ (uint64_t)tv_time_signed.tv_sec);
+ } else {
+ status = LDNS_STATUS_INTERNAL_ERR;
+ goto clean;
+ }
+
+ time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed);
+ if(!time_signed_rdf) {
+ LDNS_FREE(time_signed);
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+
+ fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge);
+
+ orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt));
+
+ error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0);
+
+ other_data_rdf = ldns_native2rdf_int16_data(0, NULL);
+
+ if(!fudge_rdf || !orig_id_rdf || !error_rdf || !other_data_rdf) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+
+ if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) {
+ status = LDNS_STATUS_ERR;
+ goto clean;
+ }
+
+ status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len,
+ key_data, key_name_rdf, fudge_rdf, algorithm_rdf,
+ time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only);
+
+ if (!mac_rdf) {
+ goto clean;
+ }
+
+ LDNS_FREE(pkt_wire);
+
+ /* Create the TSIG RR */
+ tsig_rr = ldns_rr_new();
+ if(!tsig_rr) {
+ status = LDNS_STATUS_MEM_ERR;
+ goto clean;
+ }
+ ldns_rr_set_owner(tsig_rr, key_name_rdf);
+ ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY);
+ ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG);
+ ldns_rr_set_ttl(tsig_rr, 0);
+
+ ldns_rr_push_rdf(tsig_rr, algorithm_rdf);
+ ldns_rr_push_rdf(tsig_rr, time_signed_rdf);
+ ldns_rr_push_rdf(tsig_rr, fudge_rdf);
+ ldns_rr_push_rdf(tsig_rr, mac_rdf);
+ ldns_rr_push_rdf(tsig_rr, orig_id_rdf);
+ ldns_rr_push_rdf(tsig_rr, error_rdf);
+ ldns_rr_push_rdf(tsig_rr, other_data_rdf);
+
+ ldns_pkt_set_tsig(pkt, tsig_rr);
+
+ return status;
+
+ clean:
+ LDNS_FREE(pkt_wire);
+ ldns_rdf_free(key_name_rdf);
+ ldns_rdf_free(algorithm_rdf);
+ ldns_rdf_free(time_signed_rdf);
+ ldns_rdf_free(fudge_rdf);
+ ldns_rdf_free(orig_id_rdf);
+ ldns_rdf_free(error_rdf);
+ ldns_rdf_free(other_data_rdf);
+ return status;
+}
+#endif /* HAVE_SSL */
diff --git a/3rdParty/Ldns/src/src/update.c b/3rdParty/Ldns/src/src/update.c
new file mode 100644
index 0000000..96f72ce
--- /dev/null
+++ b/3rdParty/Ldns/src/src/update.c
@@ -0,0 +1,318 @@
+/* update.c
+ *
+ * Functions for RFC 2136 Dynamic Update
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+#include <stdlib.h>
+#include <limits.h>
+
+/*
+ * RFC 2136 sections mapped to RFC 1035:
+ * zone/ZO -- QD/question
+ * prerequisites/PR -- AN/answers
+ * updates/UP -- NS/authority records
+ * additional data/AD -- AR/additional records
+ */
+
+ldns_pkt *
+ldns_update_pkt_new(ldns_rdf *zone_rdf, ldns_rr_class c,
+ ldns_rr_list *pr_rrlist, ldns_rr_list *up_rrlist, ldns_rr_list *ad_rrlist)
+{
+ ldns_pkt *p;
+
+ if (!zone_rdf || !up_rrlist) {
+ return NULL;
+ }
+
+ if (c == 0) {
+ c = LDNS_RR_CLASS_IN;
+ }
+
+ /* Create packet, fill in Zone Section. */
+ p = ldns_pkt_query_new(zone_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
+ if (!p) {
+ return NULL;
+ }
+ zone_rdf = NULL; /* No longer safe to use. */
+
+ ldns_pkt_set_opcode(p, LDNS_PACKET_UPDATE);
+
+ ldns_rr_list_deep_free(p->_authority);
+
+ ldns_pkt_set_authority(p, ldns_rr_list_clone(up_rrlist));
+
+ ldns_update_set_upcount(p, ldns_rr_list_rr_count(up_rrlist));
+
+ if (pr_rrlist) {
+ ldns_rr_list_deep_free(p->_answer); /*XXX access function */
+ ldns_pkt_set_answer(p, ldns_rr_list_clone(pr_rrlist));
+ ldns_update_set_prcount(p, ldns_rr_list_rr_count(pr_rrlist));
+ }
+
+ if (ad_rrlist) {
+ ldns_rr_list_deep_free(p->_additional);
+ ldns_pkt_set_additional(p, ldns_rr_list_clone(ad_rrlist));
+ ldns_update_set_adcount(p, ldns_rr_list_rr_count(ad_rrlist));
+ }
+ return p;
+}
+
+ldns_status
+ldns_update_pkt_tsig_add(ldns_pkt *p, ldns_resolver *r)
+{
+#ifdef HAVE_SSL
+ uint16_t fudge = 300; /* Recommended fudge. [RFC2845 6.4] */
+ if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r))
+ return ldns_pkt_tsig_sign(p, ldns_resolver_tsig_keyname(r),
+ ldns_resolver_tsig_keydata(r), fudge,
+ ldns_resolver_tsig_algorithm(r), NULL);
+#else
+ /* do nothing */
+ (void)p;
+ (void)r;
+#endif /* HAVE_SSL */
+ /* No TSIG to do. */
+ return LDNS_STATUS_OK;
+}
+
+/* Move to higher.c or similar? */
+/* XXX doc */
+ldns_status
+ldns_update_soa_mname(ldns_rdf *zone, ldns_resolver *r,
+ ldns_rr_class c, ldns_rdf **mname)
+{
+ ldns_rr *soa_rr;
+ ldns_pkt *query, *resp;
+
+ /* Nondestructive, so clone 'zone' here */
+ query = ldns_pkt_query_new(ldns_rdf_clone(zone), LDNS_RR_TYPE_SOA,
+ c, LDNS_RD);
+ if (!query) {
+ return LDNS_STATUS_ERR;
+ }
+
+ ldns_pkt_set_random_id(query);
+ if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
+ ldns_pkt_free(query);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_pkt_free(query);
+ if (!resp) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* Expect a SOA answer. */
+ *mname = NULL;
+ while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp)))) {
+ if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
+ || ldns_rr_rdf(soa_rr, 0) == NULL)
+ continue;
+ /* [RFC1035 3.3.13] */
+ *mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
+ break;
+ }
+ ldns_pkt_free(resp);
+
+ return *mname ? LDNS_STATUS_OK : LDNS_STATUS_ERR;
+}
+
+/* Try to get zone and MNAME from SOA queries. */
+ldns_status
+ldns_update_soa_zone_mname(const char *fqdn, ldns_resolver *r,
+ ldns_rr_class c, ldns_rdf **zone_rdf, ldns_rdf **mname_rdf)
+{
+ ldns_rr *soa_rr, *rr;
+ ldns_rdf *soa_zone = NULL, *soa_mname = NULL;
+ ldns_rdf *ipaddr, *fqdn_rdf, *tmp;
+ ldns_rdf **nslist;
+ ldns_pkt *query, *resp;
+ size_t i;
+
+ /*
+ * XXX Ok, this cannot be the best way to find this...?
+ * XXX (I run into weird cache-related stuff here)
+ */
+
+ /* Step 1 - first find a nameserver that should know *something* */
+ fqdn_rdf = ldns_dname_new_frm_str(fqdn);
+ query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
+ if (!query) {
+ return LDNS_STATUS_ERR;
+ }
+ fqdn_rdf = NULL;
+
+ ldns_pkt_set_random_id(query);
+ if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
+ ldns_pkt_free(query);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_pkt_free(query);
+ if (!resp) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* XXX Is it safe to only look in authority section here? */
+ while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
+ if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
+ || ldns_rr_rdf(soa_rr, 0) == NULL)
+ continue;
+ /* [RFC1035 3.3.13] */
+ soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
+ break;
+ }
+ ldns_pkt_free(resp);
+ if (!soa_rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* Step 2 - find SOA MNAME IP address, add to resolver */
+ query = ldns_pkt_query_new(soa_mname, LDNS_RR_TYPE_A, c, LDNS_RD);
+ if (!query) {
+ return LDNS_STATUS_ERR;
+ }
+ soa_mname = NULL;
+
+ ldns_pkt_set_random_id(query);
+ if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
+ ldns_pkt_free(query);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_pkt_free(query);
+ if (!resp) {
+ return LDNS_STATUS_ERR;
+ }
+
+ if (ldns_pkt_ancount(resp) == 0) {
+ ldns_pkt_free(resp);
+ return LDNS_STATUS_ERR;
+ }
+
+ /* XXX There may be more than one answer RR here. */
+ rr = ldns_rr_list_pop_rr(ldns_pkt_answer(resp));
+ ipaddr = ldns_rr_rdf(rr, 0);
+
+ /* Put the SOA mname IP first in the nameserver list. */
+ nslist = ldns_resolver_nameservers(r);
+ for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
+ if (ldns_rdf_compare(ipaddr, nslist[i]) == 0) {
+ if (i) {
+ tmp = nslist[0];
+ nslist[0] = nslist[i];
+ nslist[i] = tmp;
+ }
+ break;
+ }
+ }
+ if (i >= ldns_resolver_nameserver_count(r)) {
+ /* SOA mname was not part of the resolver so add it first. */
+ (void) ldns_resolver_push_nameserver(r, ipaddr);
+ nslist = ldns_resolver_nameservers(r);
+ i = ldns_resolver_nameserver_count(r) - 1;
+ tmp = nslist[0];
+ nslist[0] = nslist[i];
+ nslist[i] = tmp;
+ }
+ ldns_pkt_free(resp);
+
+ /* Make sure to ask the first in the list, i.e SOA mname */
+ ldns_resolver_set_random(r, false);
+
+ /* Step 3 - Redo SOA query, sending to SOA MNAME directly. */
+ fqdn_rdf = ldns_dname_new_frm_str(fqdn);
+ query = ldns_pkt_query_new(fqdn_rdf, LDNS_RR_TYPE_SOA, c, LDNS_RD);
+ if (!query) {
+ return LDNS_STATUS_ERR;
+ }
+ fqdn_rdf = NULL;
+
+ ldns_pkt_set_random_id(query);
+ if (ldns_resolver_send_pkt(&resp, r, query) != LDNS_STATUS_OK) {
+ ldns_pkt_free(query);
+ return LDNS_STATUS_ERR;
+ }
+ ldns_pkt_free(query);
+ if (!resp) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* XXX Is it safe to only look in authority section here, too? */
+ while ((soa_rr = ldns_rr_list_pop_rr(ldns_pkt_authority(resp)))) {
+ if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
+ || ldns_rr_rdf(soa_rr, 0) == NULL)
+ continue;
+ /* [RFC1035 3.3.13] */
+ soa_mname = ldns_rdf_clone(ldns_rr_rdf(soa_rr, 0));
+ soa_zone = ldns_rdf_clone(ldns_rr_owner(soa_rr));
+ break;
+ }
+ ldns_pkt_free(resp);
+ if (!soa_rr) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* That seems to have worked, pass results to caller. */
+ *zone_rdf = soa_zone;
+ *mname_rdf = soa_mname;
+ return LDNS_STATUS_OK;
+}
+
+/*
+ * ldns_update_{get,set}_{zo,pr,up,ad}count
+ */
+
+uint16_t
+ldns_update_zocount(const ldns_pkt *p)
+{
+ return ldns_pkt_qdcount(p);
+}
+
+uint16_t
+ldns_update_prcount(const ldns_pkt *p)
+{
+ return ldns_pkt_ancount(p);
+}
+
+uint16_t
+ldns_update_upcount(const ldns_pkt *p)
+{
+ return ldns_pkt_nscount(p);
+}
+
+uint16_t
+ldns_update_ad(const ldns_pkt *p)
+{
+ return ldns_pkt_arcount(p);
+}
+
+void
+ldns_update_set_zo(ldns_pkt *p, uint16_t v)
+{
+ ldns_pkt_set_qdcount(p, v);
+}
+
+void
+ldns_update_set_prcount(ldns_pkt *p, uint16_t v)
+{
+ ldns_pkt_set_ancount(p, v);
+}
+
+void
+ldns_update_set_upcount(ldns_pkt *p, uint16_t v)
+{
+ ldns_pkt_set_nscount(p, v);
+}
+
+void
+ldns_update_set_adcount(ldns_pkt *p, uint16_t v)
+{
+ ldns_pkt_set_arcount(p, v);
+}
diff --git a/3rdParty/Ldns/src/src/util.c b/3rdParty/Ldns/src/src/util.c
new file mode 100644
index 0000000..f49a30d
--- /dev/null
+++ b/3rdParty/Ldns/src/src/util.c
@@ -0,0 +1,488 @@
+/*
+ * util.c
+ *
+ * some general memory functions
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/rdata.h>
+#include <ldns/rr.h>
+#include <ldns/util.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#ifdef HAVE_SSL
+#include <openssl/rand.h>
+#endif
+
+/* put this here tmp. for debugging */
+void
+xprintf_rdf(ldns_rdf *rd)
+{
+ /* assume printable string */
+ fprintf(stderr, "size\t:%u\n", (unsigned int)ldns_rdf_size(rd));
+ fprintf(stderr, "type\t:%u\n", (unsigned int)ldns_rdf_get_type(rd));
+ fprintf(stderr, "data\t:[%.*s]\n", (int)ldns_rdf_size(rd),
+ (char*)ldns_rdf_data(rd));
+}
+
+void
+xprintf_rr(ldns_rr *rr)
+{
+ /* assume printable string */
+ uint16_t count, i;
+
+ count = ldns_rr_rd_count(rr);
+
+ for(i = 0; i < count; i++) {
+ fprintf(stderr, "print rd %u\n", (unsigned int) i);
+ xprintf_rdf(rr->_rdata_fields[i]);
+ }
+}
+
+void xprintf_hex(uint8_t *data, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++) {
+ if (i > 0 && i % 20 == 0) {
+ printf("\t; %u - %u\n", (unsigned int) i - 19, (unsigned int) i);
+ }
+ printf("%02x ", (unsigned int) data[i]);
+ }
+ printf("\n");
+}
+
+ldns_lookup_table *
+ldns_lookup_by_name(ldns_lookup_table *table, const char *name)
+{
+ while (table->name != NULL) {
+ if (strcasecmp(name, table->name) == 0)
+ return table;
+ table++;
+ }
+ return NULL;
+}
+
+ldns_lookup_table *
+ldns_lookup_by_id(ldns_lookup_table *table, int id)
+{
+ while (table->name != NULL) {
+ if (table->id == id)
+ return table;
+ table++;
+ }
+ return NULL;
+}
+
+int
+ldns_get_bit(uint8_t bits[], size_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ return (int) (bits[index / 8] & (1 << (7 - index % 8)));
+}
+
+int
+ldns_get_bit_r(uint8_t bits[], size_t index)
+{
+ /*
+ * The bits are counted from right to left, so bit #0 is the
+ * right most bit.
+ */
+ return (int) bits[index / 8] & (1 << (index % 8));
+}
+
+void
+ldns_set_bit(uint8_t *byte, int bit_nr, bool value)
+{
+ if (bit_nr >= 0 && bit_nr < 8) {
+ if (value) {
+ *byte = *byte | (0x01 << bit_nr);
+ } else {
+ *byte = *byte & ~(0x01 << bit_nr);
+ }
+ }
+}
+
+int
+ldns_hexdigit_to_int(char ch)
+{
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default:
+ return -1;
+ }
+}
+
+char
+ldns_int_to_hexdigit(int i)
+{
+ switch (i) {
+ case 0: return '0';
+ case 1: return '1';
+ case 2: return '2';
+ case 3: return '3';
+ case 4: return '4';
+ case 5: return '5';
+ case 6: return '6';
+ case 7: return '7';
+ case 8: return '8';
+ case 9: return '9';
+ case 10: return 'a';
+ case 11: return 'b';
+ case 12: return 'c';
+ case 13: return 'd';
+ case 14: return 'e';
+ case 15: return 'f';
+ default:
+ abort();
+ }
+}
+
+int
+ldns_hexstring_to_data(uint8_t *data, const char *str)
+{
+ size_t i;
+
+ if (!str || !data) {
+ return -1;
+ }
+
+ if (strlen(str) % 2 != 0) {
+ return -2;
+ }
+
+ for (i = 0; i < strlen(str) / 2; i++) {
+ data[i] =
+ 16 * (uint8_t) ldns_hexdigit_to_int(str[i*2]) +
+ (uint8_t) ldns_hexdigit_to_int(str[i*2 + 1]);
+ }
+
+ return (int) i;
+}
+
+const char *
+ldns_version(void)
+{
+ return (char*)LDNS_VERSION;
+}
+
+/* Number of days per month (except for February in leap years). */
+static const int mdays[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y)))
+#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y)))
+
+static int
+is_leap_year(int year)
+{
+ return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0
+ || LDNS_MOD(year, 400) == 0);
+}
+
+static int
+leap_days(int y1, int y2)
+{
+ --y1;
+ --y2;
+ return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) -
+ (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) +
+ (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400));
+}
+
+/*
+ * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
+ */
+time_t
+mktime_from_utc(const struct tm *tm)
+{
+ int year = 1900 + tm->tm_year;
+ time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year);
+ time_t hours;
+ time_t minutes;
+ time_t seconds;
+ int i;
+
+ for (i = 0; i < tm->tm_mon; ++i) {
+ days += mdays[i];
+ }
+ if (tm->tm_mon > 1 && is_leap_year(year)) {
+ ++days;
+ }
+ days += tm->tm_mday - 1;
+
+ hours = days * 24 + tm->tm_hour;
+ minutes = hours * 60 + tm->tm_min;
+ seconds = minutes * 60 + tm->tm_sec;
+
+ return seconds;
+}
+
+#if SIZEOF_TIME_T <= 4
+
+static void
+ldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result)
+{
+ int year = 1970;
+ int new_year;
+
+ while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) {
+ new_year = year + (int) LDNS_DIV(days, 365);
+ days -= (new_year - year) * 365;
+ days -= leap_days(year, new_year);
+ year = new_year;
+ }
+ result->tm_year = year;
+ result->tm_yday = (int) days;
+}
+
+/* Number of days per month in a leap year. */
+static const int leap_year_mdays[] = {
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static void
+ldns_mon_and_mday_from_year_and_yday(struct tm *result)
+{
+ int idays = result->tm_yday;
+ const int *mon_lengths = is_leap_year(result->tm_year) ?
+ leap_year_mdays : mdays;
+
+ result->tm_mon = 0;
+ while (idays >= mon_lengths[result->tm_mon]) {
+ idays -= mon_lengths[result->tm_mon++];
+ }
+ result->tm_mday = idays + 1;
+}
+
+static void
+ldns_wday_from_year_and_yday(struct tm *result)
+{
+ result->tm_wday = 4 /* 1-1-1970 was a thursday */
+ + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7)
+ + leap_days(1970, result->tm_year)
+ + result->tm_yday;
+ result->tm_wday = LDNS_MOD(result->tm_wday, 7);
+ if (result->tm_wday < 0) {
+ result->tm_wday += 7;
+ }
+}
+
+static struct tm *
+ldns_gmtime64_r(int64_t clock, struct tm *result)
+{
+ result->tm_isdst = 0;
+ result->tm_sec = (int) LDNS_MOD(clock, 60);
+ clock = LDNS_DIV(clock, 60);
+ result->tm_min = (int) LDNS_MOD(clock, 60);
+ clock = LDNS_DIV(clock, 60);
+ result->tm_hour = (int) LDNS_MOD(clock, 24);
+ clock = LDNS_DIV(clock, 24);
+
+ ldns_year_and_yday_from_days_since_epoch(clock, result);
+ ldns_mon_and_mday_from_year_and_yday(result);
+ ldns_wday_from_year_and_yday(result);
+ result->tm_year -= 1900;
+
+ return result;
+}
+
+#endif /* SIZEOF_TIME_T <= 4 */
+
+static int64_t
+ldns_serial_arithmitics_time(int32_t time, time_t now)
+{
+ int32_t offset = time - (int32_t) now;
+ return (int64_t) now + offset;
+}
+
+
+struct tm *
+ldns_serial_arithmitics_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);
+ return ldns_gmtime64_r(secs_since_epoch, result);
+#else
+ time_t secs_since_epoch = ldns_serial_arithmitics_time(time, now);
+ return gmtime_r(&secs_since_epoch, result);
+#endif
+}
+
+/**
+ * Init the random source
+ * applications should call this if they need entropy data within ldns
+ * If openSSL is available, it is automatically seeded from /dev/urandom
+ * or /dev/random
+ *
+ * If you need more entropy, or have no openssl available, this function
+ * MUST be called at the start of the program
+ *
+ * If openssl *is* available, this function just adds more entropy
+ **/
+int
+ldns_init_random(FILE *fd, unsigned int size)
+{
+ /* if fp is given, seed srandom with data from file
+ otherwise use /dev/urandom */
+ FILE *rand_f;
+ uint8_t *seed;
+ size_t read = 0;
+ unsigned int seed_i;
+ struct timeval tv;
+
+ /* we'll need at least sizeof(unsigned int) bytes for the
+ standard prng seed */
+ if (size < (unsigned int) sizeof(seed_i)){
+ size = (unsigned int) sizeof(seed_i);
+ }
+
+ seed = LDNS_XMALLOC(uint8_t, size);
+ if(!seed) {
+ return 1;
+ }
+
+ if (!fd) {
+ if ((rand_f = fopen("/dev/urandom", "r")) == NULL) {
+ /* no readable /dev/urandom, try /dev/random */
+ if ((rand_f = fopen("/dev/random", "r")) == NULL) {
+ /* no readable /dev/random either, and no entropy
+ source given. we'll have to improvise */
+ for (read = 0; read < size; read++) {
+ gettimeofday(&tv, NULL);
+ seed[read] = (uint8_t) (tv.tv_usec % 256);
+ }
+ } else {
+ read = fread(seed, 1, size, rand_f);
+ }
+ } else {
+ read = fread(seed, 1, size, rand_f);
+ }
+ } else {
+ rand_f = fd;
+ read = fread(seed, 1, size, rand_f);
+ }
+
+ if (read < size) {
+ LDNS_FREE(seed);
+ return 1;
+ } else {
+#ifdef HAVE_SSL
+ /* Seed the OpenSSL prng (most systems have it seeded
+ automatically, in that case this call just adds entropy */
+ RAND_seed(seed, (int) size);
+#else
+ /* Seed the standard prng, only uses the first
+ * unsigned sizeof(unsiged int) bytes found in the entropy pool
+ */
+ memcpy(&seed_i, seed, sizeof(seed_i));
+ srandom(seed_i);
+#endif
+ LDNS_FREE(seed);
+ }
+
+ if (!fd) {
+ if (rand_f) fclose(rand_f);
+ }
+
+ return 0;
+}
+
+/**
+ * Get random number.
+ *
+ */
+uint16_t
+ldns_get_random(void)
+{
+ uint16_t rid = 0;
+#ifdef HAVE_SSL
+ if (RAND_bytes((unsigned char*)&rid, 2) != 1) {
+ rid = (uint16_t) random();
+ }
+#else
+ rid = (uint16_t) random();
+#endif
+ return rid;
+}
+
+/*
+ * BubbleBabble code taken from OpenSSH
+ * Copyright (c) 2001 Carsten Raskgaard. All rights reserved.
+ */
+char *
+ldns_bubblebabble(uint8_t *data, size_t len)
+{
+ char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
+ char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
+ 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
+ size_t i, j = 0, rounds, seed = 1;
+ char *retval;
+
+ rounds = (len / 2) + 1;
+ retval = LDNS_XMALLOC(char, rounds * 6);
+ if(!retval) return NULL;
+ retval[j++] = 'x';
+ for (i = 0; i < rounds; i++) {
+ size_t idx0, idx1, idx2, idx3, idx4;
+ if ((i + 1 < rounds) || (len % 2 != 0)) {
+ idx0 = (((((size_t)(data[2 * i])) >> 6) & 3) +
+ seed) % 6;
+ idx1 = (((size_t)(data[2 * i])) >> 2) & 15;
+ idx2 = ((((size_t)(data[2 * i])) & 3) +
+ (seed / 6)) % 6;
+ retval[j++] = vowels[idx0];
+ retval[j++] = consonants[idx1];
+ retval[j++] = vowels[idx2];
+ if ((i + 1) < rounds) {
+ idx3 = (((size_t)(data[(2 * i) + 1])) >> 4) & 15;
+ idx4 = (((size_t)(data[(2 * i) + 1]))) & 15;
+ retval[j++] = consonants[idx3];
+ retval[j++] = '-';
+ retval[j++] = consonants[idx4];
+ seed = ((seed * 5) +
+ ((((size_t)(data[2 * i])) * 7) +
+ ((size_t)(data[(2 * i) + 1])))) % 36;
+ }
+ } else {
+ idx0 = seed % 6;
+ idx1 = 16;
+ idx2 = seed / 6;
+ retval[j++] = vowels[idx0];
+ retval[j++] = consonants[idx1];
+ retval[j++] = vowels[idx2];
+ }
+ }
+ retval[j++] = 'x';
+ retval[j++] = '\0';
+ return retval;
+}
diff --git a/3rdParty/Ldns/src/src/wire2host.c b/3rdParty/Ldns/src/src/wire2host.c
new file mode 100644
index 0000000..e87fcdf
--- /dev/null
+++ b/3rdParty/Ldns/src/src/wire2host.c
@@ -0,0 +1,456 @@
+/*
+ * wire2host.c
+ *
+ * conversion routines from the wire to the host
+ * format.
+ * This will usually just a re-ordering of the
+ * data (as we store it in network format)
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+/*#include <ldns/wire2host.h>*/
+
+#include <strings.h>
+#include <limits.h>
+
+
+
+/*
+ * Set of macro's to deal with the dns message header as specified
+ * in RFC1035 in portable way.
+ *
+ */
+
+/*
+ *
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ID |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | QDCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ANCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | NSCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * | ARCOUNT |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ */
+
+
+/* allocates memory to *dname! */
+ldns_status
+ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
+{
+ uint8_t label_size;
+ uint16_t pointer_target;
+ uint8_t pointer_target_buf[2];
+ size_t dname_pos = 0;
+ size_t uncompressed_length = 0;
+ size_t compression_pos = 0;
+ uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
+ unsigned int pointer_count = 0;
+
+ if (*pos >= max) {
+ return LDNS_STATUS_PACKET_OVERFLOW;
+ }
+
+ label_size = wire[*pos];
+ while (label_size > 0) {
+ /* compression */
+ while (label_size >= 192) {
+ if (compression_pos == 0) {
+ compression_pos = *pos + 2;
+ }
+
+ pointer_count++;
+
+ /* remove first two bits */
+ if (*pos + 2 > max) {
+ return LDNS_STATUS_PACKET_OVERFLOW;
+ }
+ pointer_target_buf[0] = wire[*pos] & 63;
+ pointer_target_buf[1] = wire[*pos + 1];
+ pointer_target = ldns_read_uint16(pointer_target_buf);
+
+ if (pointer_target == 0) {
+ return LDNS_STATUS_INVALID_POINTER;
+ } else if (pointer_target >= max) {
+ return LDNS_STATUS_INVALID_POINTER;
+ } else if (pointer_count > LDNS_MAX_POINTERS) {
+ return LDNS_STATUS_INVALID_POINTER;
+ }
+ *pos = pointer_target;
+ label_size = wire[*pos];
+ }
+ if(label_size == 0)
+ break; /* break from pointer to 0 byte */
+ if (label_size > LDNS_MAX_LABELLEN) {
+ return LDNS_STATUS_LABEL_OVERFLOW;
+ }
+ if (*pos + 1 + label_size > max) {
+ return LDNS_STATUS_LABEL_OVERFLOW;
+ }
+
+ /* check space for labelcount itself */
+ if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+ tmp_dname[dname_pos] = label_size;
+ if (label_size > 0) {
+ dname_pos++;
+ }
+ *pos = *pos + 1;
+ if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+ memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
+ uncompressed_length += label_size + 1;
+ dname_pos += label_size;
+ *pos = *pos + label_size;
+
+ if (*pos < max) {
+ label_size = wire[*pos];
+ }
+ }
+
+ if (compression_pos > 0) {
+ *pos = compression_pos;
+ } else {
+ *pos = *pos + 1;
+ }
+
+ if (dname_pos >= LDNS_MAX_DOMAINLEN) {
+ return LDNS_STATUS_DOMAINNAME_OVERFLOW;
+ }
+
+ tmp_dname[dname_pos] = 0;
+ dname_pos++;
+
+ *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
+ (uint16_t) dname_pos, tmp_dname);
+ if (!*dname) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ return LDNS_STATUS_OK;
+}
+
+/* maybe make this a goto error so data can be freed or something/ */
+#define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
+#define LDNS_STATUS_CHECK_GOTO(st, label) {if (st != LDNS_STATUS_OK) { /*printf("STG %s:%d: status code %d\n", __FILE__, __LINE__, st);*/ goto label; }}
+
+ldns_status
+ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
+{
+ size_t end;
+ size_t cur_rdf_length;
+ uint8_t rdf_index;
+ uint8_t *data;
+ uint16_t rd_length;
+ ldns_rdf *cur_rdf = NULL;
+ ldns_rdf_type cur_rdf_type;
+ const ldns_rr_descriptor *descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
+ ldns_status status;
+
+ if (*pos + 2 > max) {
+ return LDNS_STATUS_PACKET_OVERFLOW;
+ }
+
+ rd_length = ldns_read_uint16(&wire[*pos]);
+ *pos = *pos + 2;
+
+ if (*pos + rd_length > max) {
+ return LDNS_STATUS_PACKET_OVERFLOW;
+ }
+
+ end = *pos + (size_t) rd_length;
+
+ for (rdf_index = 0;
+ rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) {
+ if (*pos >= end) {
+ break;
+ }
+ cur_rdf_length = 0;
+
+ cur_rdf_type = ldns_rr_descriptor_field_type(descriptor, rdf_index);
+ /* handle special cases immediately, set length
+ for fixed length rdata and do them below */
+ switch (cur_rdf_type) {
+ case LDNS_RDF_TYPE_DNAME:
+ status = ldns_wire2dname(&cur_rdf, wire, max, pos);
+ LDNS_STATUS_CHECK_RETURN(status);
+ break;
+ case LDNS_RDF_TYPE_CLASS:
+ case LDNS_RDF_TYPE_ALG:
+ case LDNS_RDF_TYPE_INT8:
+ cur_rdf_length = LDNS_RDF_SIZE_BYTE;
+ break;
+ case LDNS_RDF_TYPE_TYPE:
+ case LDNS_RDF_TYPE_INT16:
+ case LDNS_RDF_TYPE_CERT_ALG:
+ cur_rdf_length = LDNS_RDF_SIZE_WORD;
+ break;
+ case LDNS_RDF_TYPE_TIME:
+ case LDNS_RDF_TYPE_INT32:
+ case LDNS_RDF_TYPE_A:
+ case LDNS_RDF_TYPE_PERIOD:
+ cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
+ break;
+ case LDNS_RDF_TYPE_TSIGTIME:
+ cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
+ break;
+ case LDNS_RDF_TYPE_AAAA:
+ cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
+ break;
+ case LDNS_RDF_TYPE_STR:
+ case LDNS_RDF_TYPE_NSEC3_SALT:
+ /* len is stored in first byte
+ * it should be in the rdf too, so just
+ * copy len+1 from this position
+ */
+ cur_rdf_length = ((size_t) wire[*pos]) + 1;
+ break;
+ case LDNS_RDF_TYPE_INT16_DATA:
+ cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2;
+ break;
+ case LDNS_RDF_TYPE_B32_EXT:
+ case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+ /* length is stored in first byte */
+ cur_rdf_length = ((size_t) wire[*pos]) + 1;
+ break;
+ case LDNS_RDF_TYPE_APL:
+ case LDNS_RDF_TYPE_B64:
+ case LDNS_RDF_TYPE_HEX:
+ case LDNS_RDF_TYPE_NSEC:
+ case LDNS_RDF_TYPE_UNKNOWN:
+ case LDNS_RDF_TYPE_SERVICE:
+ case LDNS_RDF_TYPE_LOC:
+ case LDNS_RDF_TYPE_WKS:
+ case LDNS_RDF_TYPE_NSAP:
+ case LDNS_RDF_TYPE_ATMA:
+ case LDNS_RDF_TYPE_IPSECKEY:
+ case LDNS_RDF_TYPE_TSIG:
+ case LDNS_RDF_TYPE_NONE:
+ /*
+ * Read to end of rr rdata
+ */
+ cur_rdf_length = end - *pos;
+ break;
+ }
+
+ /* fixed length rdata */
+ if (cur_rdf_length > 0) {
+ if (cur_rdf_length + *pos > end) {
+ return LDNS_STATUS_PACKET_OVERFLOW;
+ }
+ data = LDNS_XMALLOC(uint8_t, rd_length);
+ if (!data) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ memcpy(data, &wire[*pos], cur_rdf_length);
+
+ cur_rdf = ldns_rdf_new(cur_rdf_type, cur_rdf_length, data);
+ *pos = *pos + cur_rdf_length;
+ }
+
+ if (cur_rdf) {
+ ldns_rr_push_rdf(rr, cur_rdf);
+ cur_rdf = NULL;
+ }
+ }
+
+ return LDNS_STATUS_OK;
+}
+
+
+/* TODO:
+ can *pos be incremented at READ_INT? or maybe use something like
+ RR_CLASS(wire)?
+ uhhm Jelte??
+*/
+ldns_status
+ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
+ size_t *pos, ldns_pkt_section section)
+{
+ ldns_rdf *owner = NULL;
+ ldns_rr *rr = ldns_rr_new();
+ ldns_status status;
+
+ status = ldns_wire2dname(&owner, wire, max, pos);
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+
+ ldns_rr_set_owner(rr, owner);
+
+ if (*pos + 4 > max) {
+ status = LDNS_STATUS_PACKET_OVERFLOW;
+ goto status_error;
+ }
+
+ ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
+ *pos = *pos + 2;
+
+ ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
+ *pos = *pos + 2;
+
+ if (section != LDNS_SECTION_QUESTION) {
+ if (*pos + 4 > max) {
+ status = LDNS_STATUS_PACKET_OVERFLOW;
+ goto status_error;
+ }
+ ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
+
+ *pos = *pos + 4;
+ status = ldns_wire2rdf(rr, wire, max, pos);
+
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+ ldns_rr_set_question(rr, false);
+ } else {
+ ldns_rr_set_question(rr, true);
+ }
+
+ *rr_p = rr;
+ return LDNS_STATUS_OK;
+
+status_error:
+ ldns_rr_free(rr);
+ return status;
+}
+
+static ldns_status
+ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
+{
+ if (*pos + LDNS_HEADER_SIZE > max) {
+ return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
+ } else {
+ ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
+ ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
+ ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
+ ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
+ ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
+ ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
+ ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
+ ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
+ ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
+ ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
+
+ ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
+ ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
+ ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
+ ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
+
+ *pos += LDNS_HEADER_SIZE;
+
+ return LDNS_STATUS_OK;
+ }
+}
+
+ldns_status
+ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer)
+{
+ /* lazy */
+ return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
+ ldns_buffer_limit(buffer));
+
+}
+
+ldns_status
+ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
+{
+ size_t pos = 0;
+ uint16_t i;
+ ldns_rr *rr;
+ ldns_pkt *packet = ldns_pkt_new();
+ ldns_status status = LDNS_STATUS_OK;
+ int have_edns = 0;
+
+ uint8_t data[4];
+
+ status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+
+ for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
+
+ status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
+ if (status == LDNS_STATUS_PACKET_OVERFLOW) {
+ status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
+ }
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+ if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
+ ldns_pkt_free(packet);
+ return LDNS_STATUS_INTERNAL_ERR;
+ }
+ }
+ for (i = 0; i < ldns_pkt_ancount(packet); i++) {
+ status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
+ if (status == LDNS_STATUS_PACKET_OVERFLOW) {
+ status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
+ }
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+ if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
+ ldns_pkt_free(packet);
+ return LDNS_STATUS_INTERNAL_ERR;
+ }
+ }
+ for (i = 0; i < ldns_pkt_nscount(packet); i++) {
+ status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
+ if (status == LDNS_STATUS_PACKET_OVERFLOW) {
+ status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
+ }
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+ if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
+ ldns_pkt_free(packet);
+ return LDNS_STATUS_INTERNAL_ERR;
+ }
+ }
+ for (i = 0; i < ldns_pkt_arcount(packet); i++) {
+ status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
+ if (status == LDNS_STATUS_PACKET_OVERFLOW) {
+ status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
+ }
+ LDNS_STATUS_CHECK_GOTO(status, status_error);
+
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
+ ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
+ ldns_write_uint32(data, ldns_rr_ttl(rr));
+ ldns_pkt_set_edns_extended_rcode(packet, data[0]);
+ ldns_pkt_set_edns_version(packet, data[1]);
+ ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
+ /* edns might not have rdfs */
+ if (ldns_rr_rdf(rr, 0)) {
+ ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
+ }
+ ldns_rr_free(rr);
+ have_edns += 1;
+ } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
+ ldns_pkt_set_tsig(packet, rr);
+ ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
+ } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
+ ldns_pkt_free(packet);
+ return LDNS_STATUS_INTERNAL_ERR;
+ }
+ }
+ ldns_pkt_set_size(packet, max);
+ if(have_edns)
+ ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
+ - have_edns);
+
+ *packet_p = packet;
+ return status;
+
+status_error:
+ ldns_pkt_free(packet);
+ return status;
+}
diff --git a/3rdParty/Ldns/src/src/zone.c b/3rdParty/Ldns/src/src/zone.c
new file mode 100644
index 0000000..0616a14
--- /dev/null
+++ b/3rdParty/Ldns/src/src/zone.c
@@ -0,0 +1,431 @@
+/* zone.c
+ *
+ * Functions for ldns_zone structure
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2005-2006
+ * See the file LICENSE for the license
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <strings.h>
+#include <limits.h>
+
+ldns_rr *
+ldns_zone_soa(const ldns_zone *z)
+{
+ return z->_soa;
+}
+
+size_t
+ldns_zone_rr_count(const ldns_zone *z)
+{
+ return ldns_rr_list_rr_count(z->_rrs);
+}
+
+void
+ldns_zone_set_soa(ldns_zone *z, ldns_rr *soa)
+{
+ z->_soa = soa;
+}
+
+ldns_rr_list *
+ldns_zone_rrs(const ldns_zone *z)
+{
+ return z->_rrs;
+}
+
+void
+ldns_zone_set_rrs(ldns_zone *z, ldns_rr_list *rrlist)
+{
+ z->_rrs = rrlist;
+}
+
+bool
+ldns_zone_push_rr_list(ldns_zone *z, ldns_rr_list *list)
+{
+ return ldns_rr_list_cat(ldns_zone_rrs(z), list);
+
+}
+
+bool
+ldns_zone_push_rr(ldns_zone *z, ldns_rr *rr)
+{
+ return ldns_rr_list_push_rr( ldns_zone_rrs(z), rr);
+}
+
+/* return a clone of the given rr list, without the glue records
+ * rr list should be the complete zone
+ * if present, stripped records are added to the list *glue_records
+ */
+ldns_rr_list *
+ldns_zone_strip_glue_rrs(const ldns_rdf *zone_name, const ldns_rr_list *rrs, ldns_rr_list *glue_rrs)
+{
+ ldns_rr_list *new_list;
+
+ /* when do we find glue? It means we find an IP address
+ * (AAAA/A) for a nameserver listed in the zone
+ *
+ * Alg used here:
+ * first find all the zonecuts (NS records)
+ * find all the AAAA or A records (can be done it the
+ * above loop).
+ *
+ * Check if the aaaa/a list are subdomains under the
+ * NS domains.
+ * If yes -> glue, if no -> not glue
+ */
+
+ ldns_rr_list *zone_cuts;
+ ldns_rr_list *addr;
+ ldns_rr *r, *ns, *a;
+ ldns_rdf *dname_a, *ns_owner;
+ uint16_t i,j;
+
+ new_list = NULL;
+ zone_cuts = NULL;
+ addr = NULL;
+
+ new_list = ldns_rr_list_new();
+ if (!new_list) goto memory_error;
+ zone_cuts = ldns_rr_list_new();
+ if (!zone_cuts) goto memory_error;
+ addr = ldns_rr_list_new();
+ if (!addr) goto memory_error;
+
+ for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+ r = ldns_rr_list_rr(rrs, i);
+ if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A ||
+ ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) {
+ /* possibly glue */
+ if (!ldns_rr_list_push_rr(addr, r)) goto memory_error;
+ continue;
+ }
+ if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) {
+ /* multiple zones will end up here -
+ * for now; not a problem
+ */
+ /* don't add NS records for the current zone itself */
+ if (ldns_rdf_compare(ldns_rr_owner(r),
+ zone_name) != 0) {
+ if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error;
+ }
+ continue;
+ }
+ }
+
+ /* will sorting make it quicker ?? */
+ for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) {
+ ns = ldns_rr_list_rr(zone_cuts, i);
+ ns_owner = ldns_rr_owner(ns);
+ for(j = 0; j < ldns_rr_list_rr_count(addr); j++) {
+ a = ldns_rr_list_rr(addr, j);
+ dname_a = ldns_rr_owner(a);
+
+ if (ldns_dname_is_subdomain(dname_a, ns_owner)) {
+ /* GLUE! */
+ if (glue_rrs) {
+ if (!ldns_rr_list_push_rr(glue_rrs, a)) goto memory_error;
+ }
+ break;
+ } else {
+ if (!ldns_rr_list_push_rr(new_list, a)) goto memory_error;
+ }
+ }
+ }
+
+ ldns_rr_list_free(addr);
+ ldns_rr_list_free(zone_cuts);
+
+ return new_list;
+
+memory_error:
+ if (new_list) {
+ ldns_rr_list_free(new_list);
+ }
+ if (zone_cuts) {
+ ldns_rr_list_free(zone_cuts);
+ }
+ if (addr) {
+ ldns_rr_list_free(addr);
+ }
+ return NULL;
+}
+
+/*
+ * Get the list of glue records in a zone
+ * XXX: there should be a way for this to return error, other than NULL,
+ * since NULL is a valid return
+ */
+ldns_rr_list *
+ldns_zone_glue_rr_list(const ldns_zone *z)
+{
+ /* when do we find glue? It means we find an IP address
+ * (AAAA/A) for a nameserver listed in the zone
+ *
+ * Alg used here:
+ * first find all the zonecuts (NS records)
+ * find all the AAAA or A records (can be done it the
+ * above loop).
+ *
+ * Check if the aaaa/a list are subdomains under the
+ * NS domains.
+ * If yes -> glue, if no -> not glue
+ */
+
+ ldns_rr_list *zone_cuts;
+ ldns_rr_list *addr;
+ ldns_rr_list *glue;
+ ldns_rr *r, *ns, *a;
+ ldns_rdf *dname_a, *ns_owner;
+ size_t i,j;
+
+ zone_cuts = NULL;
+ addr = NULL;
+ glue = NULL;
+
+ /* we cannot determine glue in a 'zone' without a SOA */
+ if (!ldns_zone_soa(z)) {
+ return NULL;
+ }
+
+ zone_cuts = ldns_rr_list_new();
+ if (!zone_cuts) goto memory_error;
+ addr = ldns_rr_list_new();
+ if (!addr) goto memory_error;
+ glue = ldns_rr_list_new();
+ if (!glue) goto memory_error;
+
+ for(i = 0; i < ldns_zone_rr_count(z); i++) {
+ r = ldns_rr_list_rr(ldns_zone_rrs(z), i);
+ if (ldns_rr_get_type(r) == LDNS_RR_TYPE_A ||
+ ldns_rr_get_type(r) == LDNS_RR_TYPE_AAAA) {
+ /* possibly glue */
+ if (!ldns_rr_list_push_rr(addr, r)) goto memory_error;
+ continue;
+ }
+ if (ldns_rr_get_type(r) == LDNS_RR_TYPE_NS) {
+ /* multiple zones will end up here -
+ * for now; not a problem
+ */
+ /* don't add NS records for the current zone itself */
+ if (ldns_rdf_compare(ldns_rr_owner(r),
+ ldns_rr_owner(ldns_zone_soa(z))) != 0) {
+ if (!ldns_rr_list_push_rr(zone_cuts, r)) goto memory_error;
+ }
+ continue;
+ }
+ }
+
+ /* will sorting make it quicker ?? */
+ for(i = 0; i < ldns_rr_list_rr_count(zone_cuts); i++) {
+ ns = ldns_rr_list_rr(zone_cuts, i);
+ ns_owner = ldns_rr_owner(ns);
+
+ for(j = 0; j < ldns_rr_list_rr_count(addr); j++) {
+ a = ldns_rr_list_rr(addr, j);
+ dname_a = ldns_rr_owner(a);
+
+ if (ldns_dname_is_subdomain(dname_a, ns_owner) ||
+ ldns_dname_compare(dname_a, ns_owner) == 0) {
+ /* GLUE! */
+ if (!ldns_rr_list_push_rr(glue, a)) goto memory_error;
+ }
+ }
+ }
+
+ ldns_rr_list_free(addr);
+ ldns_rr_list_free(zone_cuts);
+
+ if (ldns_rr_list_rr_count(glue) == 0) {
+ ldns_rr_list_free(glue);
+ return NULL;
+ } else {
+ return glue;
+ }
+
+memory_error:
+ if (zone_cuts) {
+ LDNS_FREE(zone_cuts);
+ }
+ if (addr) {
+ ldns_rr_list_free(addr);
+ }
+ if (glue) {
+ ldns_rr_list_free(glue);
+ }
+ return NULL;
+}
+
+ldns_zone *
+ldns_zone_new(void)
+{
+ ldns_zone *z;
+
+ z = LDNS_MALLOC(ldns_zone);
+ if (!z) {
+ return NULL;
+ }
+
+ z->_rrs = ldns_rr_list_new();
+ if (!z->_rrs) {
+ LDNS_FREE(z);
+ return NULL;
+ }
+ ldns_zone_set_soa(z, NULL);
+ return z;
+}
+
+/* we regocnize:
+ * $TTL, $ORIGIN
+ */
+ldns_status
+ldns_zone_new_frm_fp(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl, ldns_rr_class c)
+{
+ return ldns_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
+}
+
+/* XXX: class is never used */
+ldns_status
+ldns_zone_new_frm_fp_l(ldns_zone **z, FILE *fp, ldns_rdf *origin, uint32_t ttl,
+ ldns_rr_class ATTR_UNUSED(c), int *line_nr)
+{
+ ldns_zone *newzone;
+ ldns_rr *rr;
+ 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;
+
+ /* most cases of error are memory problems */
+ ret = LDNS_STATUS_MEM_ERR;
+
+ newzone = NULL;
+ my_origin = NULL;
+ my_prev = NULL;
+
+ my_ttl = ttl;
+
+ if (origin) {
+ my_origin = ldns_rdf_clone(origin);
+ if (!my_origin) goto error;
+ /* also set the prev */
+ my_prev = ldns_rdf_clone(origin);
+ if (!my_prev) goto error;
+ }
+
+ newzone = ldns_zone_new();
+ if (!newzone) goto error;
+
+ while(!feof(fp)) {
+ s = ldns_rr_new_frm_fp_l(&rr, fp, &my_ttl, &my_origin, &my_prev, line_nr);
+ switch (s) {
+ case LDNS_STATUS_OK:
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
+ if (soa_seen) {
+ /* second SOA
+ * just skip, maybe we want to say
+ * something??? */
+ ldns_rr_free(rr);
+ continue;
+ }
+ soa_seen = true;
+ ldns_zone_set_soa(newzone, rr);
+ /* set origin to soa if not specified */
+ if (!my_origin) {
+ my_origin = ldns_rdf_clone(ldns_rr_owner(rr));
+ }
+ continue;
+ }
+
+ /* a normal RR - as sofar the DNS is normal */
+ if (!ldns_zone_push_rr(newzone, rr)) goto error;
+
+ case LDNS_STATUS_SYNTAX_EMPTY:
+ /* empty line was seen */
+ case LDNS_STATUS_SYNTAX_TTL:
+ /* the function set the ttl */
+ 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;
+ default:
+ ret = s;
+ goto error;
+ }
+ }
+
+ if (my_origin) {
+ ldns_rdf_deep_free(my_origin);
+ }
+ if (my_prev) {
+ ldns_rdf_deep_free(my_prev);
+ }
+ if (z) {
+ *z = newzone;
+ } else {
+ ldns_zone_free(newzone);
+ }
+
+ return LDNS_STATUS_OK;
+
+error:
+ if (my_origin) {
+ ldns_rdf_deep_free(my_origin);
+ }
+ if (my_prev) {
+ ldns_rdf_deep_free(my_prev);
+ }
+ if (newzone) {
+ ldns_zone_free(newzone);
+ }
+ return ret;
+}
+
+void
+ldns_zone_sort(ldns_zone *zone)
+{
+ ldns_rr_list *zrr;
+ assert(zone != NULL);
+
+ zrr = ldns_zone_rrs(zone);
+ ldns_rr_list_sort(zrr);
+}
+
+#if 0
+/**
+ * ixfr function. Work on a ldns_zone and remove and add
+ * the rrs from the rrlist
+ * \param[in] z the zone to work on
+ * \param[in] del rr_list to remove from the zone
+ * \param[in] add rr_list to add to the zone
+ * \return Tja, wat zouden we eens returnen TODO
+ */
+void
+ldns_zone_ixfr_del_add(ldns_zone *z, ldns_rr_list *del, ldns_rr_list *add)
+{
+
+}
+#endif
+
+void
+ldns_zone_free(ldns_zone *zone)
+{
+ ldns_rr_list_free(zone->_rrs);
+ LDNS_FREE(zone);
+}
+
+void
+ldns_zone_deep_free(ldns_zone *zone)
+{
+ ldns_rr_free(zone->_soa);
+ ldns_rr_list_deep_free(zone->_rrs);
+ LDNS_FREE(zone);
+}