diff --git a/src/Makefile.seedertest.include b/src/Makefile.seedertest.include
--- a/src/Makefile.seedertest.include
+++ b/src/Makefile.seedertest.include
@@ -9,7 +9,8 @@
   $(SEEDER_INCLUDES) $(SEEDER_TEST_INCLUDES) $(TESTDEFS)
 
 seeder_test_test_bitcoin_seeder_SOURCES = \
-  seeder/test/seeder_tests.cpp
+  seeder/test/seeder_tests.cpp \
+  seeder/test/dns_tests.cpp
 
 seeder_test_test_bitcoin_seeder_LDADD = $(LIBBITCOIN_SEEDER)
 
diff --git a/src/seeder/test/CMakeLists.txt b/src/seeder/test/CMakeLists.txt
--- a/src/seeder/test/CMakeLists.txt
+++ b/src/seeder/test/CMakeLists.txt
@@ -11,6 +11,7 @@
 add_boost_unit_tests_to_suite(bitcoin-seeder test_bitcoin-seeder
 	TESTS
 		seeder_tests.cpp
+		dns_tests.cpp
 )
 
 target_link_libraries(test_bitcoin-seeder
diff --git a/src/seeder/test/dns_tests.cpp b/src/seeder/test/dns_tests.cpp
new file mode 100644
--- /dev/null
+++ b/src/seeder/test/dns_tests.cpp
@@ -0,0 +1,98 @@
+// Copyright (c) 2019 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <seeder/dns.h>
+
+#include <string>
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(dns_tests)
+
+static const int MAX_QUERY_NAME_LENGTH = 255;
+// Max size of the null-terminated buffer parse_name() writes to.
+static const int MAX_QUERY_NAME_BUFFER_LENGTH = MAX_QUERY_NAME_LENGTH + 1;
+static const uint8_t END_OF_NAME_FIELD = 0;
+
+// Builds the name field of the question section of a DNS query
+static std::vector<uint8_t>
+CreateDNSQuestionNameField(const std::string &queryName) {
+    std::vector<uint8_t> nameField;
+    size_t i = 0;
+    size_t labelIndex = 0;
+    while (i < queryName.size()) {
+        if (queryName[i] == '.') {
+            // Push the length of the label and then the label
+            nameField.push_back(i - labelIndex);
+            while (labelIndex < i) {
+                nameField.push_back(queryName[labelIndex]);
+                labelIndex++;
+            }
+            labelIndex = i + 1;
+        }
+        i++;
+    }
+    // Push the length of the label and then the label
+    nameField.push_back(i - labelIndex);
+    while (labelIndex < i) {
+        nameField.push_back(queryName[labelIndex]);
+        labelIndex++;
+    }
+    nameField.push_back(END_OF_NAME_FIELD);
+
+    return nameField;
+}
+
+static void CheckParseName(const std::string &queryName) {
+    std::vector<uint8_t> nameField = CreateDNSQuestionNameField(queryName);
+
+    // Test when name field is too short to reach null-terminator
+    for (size_t nameFieldEndIndex = 0; nameFieldEndIndex < nameField.size();
+         nameFieldEndIndex++) {
+        std::vector<char> parsedQueryName(MAX_QUERY_NAME_BUFFER_LENGTH, 0);
+        const uint8_t *nameFieldBegin = nameField.data();
+        int ret = parse_name(
+            &nameFieldBegin, nameFieldBegin + nameFieldEndIndex,
+            nameField.data(), parsedQueryName.data(), parsedQueryName.size());
+
+        BOOST_CHECK(ret != 0);
+    }
+
+    // Test when the buffer size is too small
+    size_t outputBufferSize = 1;
+    while (outputBufferSize <= queryName.size()) {
+        std::vector<char> parsedQueryName(outputBufferSize, 0);
+        const uint8_t *nameFieldBegin = nameField.data();
+        int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(),
+                             nameField.data(), parsedQueryName.data(),
+                             parsedQueryName.size());
+        BOOST_CHECK(ret != 0);
+        outputBufferSize++;
+    }
+
+    // Happy path
+    while (outputBufferSize <= MAX_QUERY_NAME_BUFFER_LENGTH) {
+        std::vector<char> parsedQueryName(outputBufferSize, 0);
+        const uint8_t *nameFieldBegin = nameField.data();
+        int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(),
+                             nameField.data(), parsedQueryName.data(),
+                             parsedQueryName.size());
+        BOOST_CHECK_EQUAL(ret, 0);
+        BOOST_CHECK_EQUAL(parsedQueryName.data(), queryName);
+        outputBufferSize++;
+    }
+}
+
+BOOST_AUTO_TEST_CASE(parse_name_tests) {
+    CheckParseName("www.domain.com");
+    CheckParseName("domain.com");
+    CheckParseName("sub1.sub2.domain.co.uk");
+    // Shortest valid domain name is 1 char followed by the extension
+    CheckParseName("a.co");
+    // Domain name with valid non-alphanumeric character
+    CheckParseName("my-domain.com");
+}
+
+BOOST_AUTO_TEST_SUITE_END()