summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure.ac4
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc22
-rw-r--r--src/bin/dhcp6/Makefile.am1
-rw-r--r--src/bin/dhcp6/dhcp6_srv.cc36
-rw-r--r--src/bin/dhcp6/fuzz.cc280
-rw-r--r--src/bin/dhcp6/fuzz.h29
-rw-r--r--src/lib/dhcpsrv/Makefile.am17
-rw-r--r--src/lib/dhcpsrv/fuzz.cc339
-rw-r--r--src/lib/dhcpsrv/fuzz.h199
-rw-r--r--src/lib/dhcpsrv/fuzz_log.cc23
-rw-r--r--src/lib/dhcpsrv/fuzz_log.h43
-rw-r--r--src/lib/dhcpsrv/fuzz_messages.cc63
-rw-r--r--src/lib/dhcpsrv/fuzz_messages.h35
-rw-r--r--src/lib/dhcpsrv/fuzz_messages.mes105
14 files changed, 865 insertions, 331 deletions
diff --git a/configure.ac b/configure.ac
index 0a8075fe00..6f292d6508 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1464,10 +1464,10 @@ AC_ARG_ENABLE(fuzz, [AC_HELP_STRING([--enable-fuzz],
[indicates that the code will be built with AFL (American Fuzzy Lop) support.
Code built this way is unusable as a regular server. [default=no]])],
enable_fuzz=$enableval, enable_fuzz=no)
-AM_CONDITIONAL(FUZZ, test x$enable_fuzz != xno)
+AM_CONDITIONAL(ENABLE_AFL, test x$enable_fuzz != xno)
if test "x$enable_fuzz" != "xno" ; then
- AC_DEFINE([FUZZ], [1], [AFL fuzzing was enabled.])
+ AC_DEFINE([ENABLE_AFL], [1], [AFL fuzzing was enabled.])
fi
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 2ba43def3c..d0a45aa7d1 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -31,6 +31,7 @@
#include <dhcpsrv/cfg_iface.h>
#include <dhcpsrv/cfg_shared_networks.h>
#include <dhcpsrv/cfg_subnets4.h>
+#include <dhcpsrv/fuzz.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/ncr_generator.h>
@@ -771,6 +772,21 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
bool
Dhcpv4Srv::run() {
+#ifdef ENABLE_AFL
+ // AFL fuzzing setup initiated here. At this stage, Kea has loaded its
+ // config, opened sockets, established DB connections, etc. It is truly
+ // ready to process packets. Now it's time to initialize AFL. It will set
+ // up a separate thread that will receive data from fuzzing engine and will
+ // send it as packets to Kea. Kea is supposed to process them and hopefully
+ // not crash in the process. Once the packet processing is done, Kea should
+ // let the know that it's ready for the next packet. This is done further
+ // down in this loop by a call to the packetProcessed() method.
+ Fuzz fuzz_controller(4, &shutdown_);
+ //
+ // The next line is needed as a signature for AFL to recognise that we are
+ // running persistent fuzzing. This has to be in the main image file.
+ __AFL_LOOP(0);
+#endif // ENABLE_AFL
while (!shutdown_) {
try {
run_one();
@@ -786,6 +802,12 @@ Dhcpv4Srv::run() {
// std::exception.
LOG_ERROR(packet4_logger, DHCP4_PACKET_PROCESS_EXCEPTION);
}
+
+#ifdef ENABLE_AFL
+ // Ok, this particular packet processing is done. If we are fuzzing,
+ // let AFL know about it.
+ fuzz_controller.packetProcessed();
+#endif // ENABLE_AFL
}
return (true);
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 8ad0cfb519..6ab6b5b684 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -38,7 +38,6 @@ libdhcp6_la_SOURCES += dhcp6_lexer.ll location.hh position.hh stack.hh
libdhcp6_la_SOURCES += dhcp6_parser.cc dhcp6_parser.h
libdhcp6_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
libdhcp6_la_SOURCES += dhcp6_messages.h dhcp6_messages.cc
-libdhcp6_la_SOURCES += fuzz.cc
sbin_PROGRAMS = kea-dhcp6
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 27b46277b2..4d28f364c1 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -13,6 +13,7 @@
#include <dhcp/docsis3_option_defs.h>
#include <dhcp/duid.h>
#include <dhcp/duid_factory.h>
+#include <dhcpsrv/fuzz.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_addrlst.h>
@@ -65,8 +66,6 @@
#endif
#include <dhcpsrv/memfile_lease_mgr.h>
-#include <dhcp6/fuzz.h>
-
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
@@ -444,18 +443,21 @@ Dhcpv6Srv::initContext(const Pkt6Ptr& pkt,
}
bool Dhcpv6Srv::run() {
-
-#ifdef FUZZ
+#ifdef ENABLE_AFL
// AFL fuzzing setup initiated here. At this stage, Kea has loaded its
// config, opened sockets, established DB connections, etc. It is truly
- // ready to process packets. Now it's time to initialize AFL. It will
- // set up a separate thread that will receive data from fuzzing engine
- // and will send it as packets to Kea. Kea is supposed to process them
- // and hopefully not crash in the process. Once the packet processing
- // is done, Kea should let the AFL know that it's ready for the next
- // packet. This is done further down in this loop (see kea_fuzz_notify()).
- kea_fuzz_setup(&shutdown_);
-#endif /* FUZZ */
+ // ready to process packets. Now it's time to initialize AFL. It will set
+ // up a separate thread that will receive data from fuzzing engine and will
+ // send it as packets to Kea. Kea is supposed to process them and hopefully
+ // not crash in the process. Once the packet processing is done, Kea should
+ // let the know that it's ready for the next packet. This is done further
+ // down in this loop by a call to the packetProcessed() method.
+ Fuzz fuzz_controller(6, &shutdown_);
+ //
+ // The next line is needed as a signature for AFL to recognise that we are
+ // running persistent fuzzing. This has to be in the main image file.
+ __AFL_LOOP(0);
+#endif // ENABLE_AFL
while (!shutdown_) {
try {
@@ -473,11 +475,11 @@ bool Dhcpv6Srv::run() {
LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION);
}
-#ifdef FUZZ
- // Ok, this particular packet processing is done.
- // Let the AFL know about it.
- kea_fuzz_notify();
-#endif
+#ifdef ENABLE_AFL
+ // Ok, this particular packet processing is done. If we are fuzzing,
+ // let AFL know about it.
+ fuzz_controller.packetProcessed();
+#endif // ENABLE_AFL
}
return (true);
diff --git a/src/bin/dhcp6/fuzz.cc b/src/bin/dhcp6/fuzz.cc
deleted file mode 100644
index a2f50ad32b..0000000000
--- a/src/bin/dhcp6/fuzz.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#include "config.h"
-
-#include <dhcp6/fuzz.h>
-
-#define ENABLE_AFL
-
-#ifdef ENABLE_AFL
-#include <sys/errno.h>
-
-#include <dhcp/dhcp6.h>
-
-#include <iostream>
-#include <fstream>
-#include <ctime>
-
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <unistd.h>
-#include <pthread.h>
-
-
-#ifndef __AFL_LOOP
-#error To use American Fuzzy Lop you have to set CC to afl-clang-fast!!!
-#endif
-
-/// This is how many packets Kea will process until shutting itself down.
-/// AFL should restart it. This safety switch is here for eliminating cases
-/// where Kea goes into a weird state and stops processing packets properly.
-const unsigned int LOOP_COUNT = 100000;
-
-/// This mechanism limits down the number of logs this harness prints.
-/// E.g. when set to 100, it will print a message every 100 packets.
-const unsigned int PRINT_EVERY = 5;
-
-/// This is the place where the harness log message will be printed.
-const std::string PRINT_LOG("/tmp/kea-fuzz-harness.txt");
-
-/*
- * We are using pthreads directly because we might be using it with unthreaded
- * version of BIND, where all thread functions are mocks. Since AFL for now only
- * works on Linux it's not a problem.
- */
-static pthread_cond_t cond;
-static pthread_mutex_t mutex;
-
-static bool ready;
-
-using namespace std;
-
-static volatile bool * shutdown_reference = NULL;
-
-void kea_shutdown(void) {
- if (shutdown_reference) {
- // do we have the reference to shutdown flag from Dhcp6Srv?
- // If yes, then let's set it to true. Kea will shutdown on
- // its own.
- *shutdown_reference = true;
- } else {
- // We don't have the pointer yet. Let's terminate abruptly.
- exit(EXIT_SUCCESS);
- }
-}
-
-
-// This is the main fuzzing function. It receives data from fuzzing engine.
-// That data is received to stdin and then sent over the configured UDP socket.
-// Then it wait for a conditional, which is called in kea_fuzz_notify() from
-// Kea main loop.
-static void *
-kea_main_client(void *) {
- const char *host;
- struct sockaddr_in6 servaddr;
- int sockfd;
- int loop;
- void *buf;
-
- string iface("eth0");
- string dst(ALL_DHCP_RELAY_AGENTS_AND_SERVERS);
- string port("547");
-
- ofstream f(PRINT_LOG.c_str(), ios::ate);
-
- const char *iface_ptr = getenv("KEA_AFL_INTERFACE");
- if (iface_ptr) {
- iface = string(iface_ptr);
- }
-
- const char *dst_ptr = getenv("KEA_AFL_ADDR");
- if (dst_ptr) {
- dst = string(dst_ptr);
- }
-
- const char *port_ptr = getenv("KEA_AFL_PORT");
- if (port_ptr) {
- port = string(port_ptr);
- }
-
- unsigned int iface_id = if_nametoindex(iface.c_str());
-
- f << "Kea AFL setup:" << endl;
- f << "Interface: " << iface << endl;
- f << "Interface index: " << iface_id << endl;
- f << "UDP destination addr: " << dst << endl;
- f << "UDP destination port: " << port << endl;
-
- memset(&servaddr, 0, sizeof (servaddr));
- servaddr.sin6_family = AF_INET6;
- if (inet_pton(AF_INET6, dst.c_str(), &servaddr.sin6_addr) != 1) {
- f << "Error: inet_pton() failed: can't convert " << dst
- << " to address." << endl;
- exit(EXIT_FAILURE);
- }
- servaddr.sin6_port = htons(atoi(port.c_str()));
- servaddr.sin6_scope_id = iface_id;
-
- sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- f << "Failed to create UDP6 socket" << endl;
- exit(EXIT_FAILURE);
- }
-
- buf = malloc(65536);
- if (!buf) {
- f << "Failed to allocate a buffer" << endl;
- exit(EXIT_FAILURE);
- }
-
- time_t t;
-
- loop = LOOP_COUNT;
- while (loop--) {
- ssize_t length;
-
- length = read(0, buf, 65536);
- if (length <= 0) {
- usleep(1000000);
- continue;
- }
-
- /* if (length > 4096) {
- if (getenv("AFL_CMIN")) {
- ns_server_flushonshutdown(ns_g_server,
- ISC_FALSE);
- isc_app_shutdown();
- return (NULL);
- }
- raise(SIGSTOP);
- continue;
- } */
-
- if (pthread_mutex_lock(&mutex) != 0) {
- f << "#### Failed to lock mutex" << endl;
- abort();
- }
-
- ready = false;
-
- ssize_t sent;
-
- t = time(0);
- struct tm * now = localtime(&t);
-
- if (! (loop%PRINT_EVERY)) {
- f << (now->tm_year + 1900) << "-" << (now->tm_mon + 1) << "-" << (now->tm_mday)
- << " " << (now->tm_hour) << ":" << (now->tm_min) << ":" << (now->tm_sec)
- << " Sending " << length << " bytes to " << dst << "/" << port
- << " over " << iface << "/" << iface_id << ", loop iteration << "
- << loop << endl;
- }
-
- sent = sendto(sockfd, buf, length, 0,
- (struct sockaddr *) &servaddr, sizeof(servaddr));
- if (sent != length) {
- f << "#### Error: expected to send " << length
- << ", but really sent " << sent << endl;
- f << "#### errno=" << errno << endl;
- }
-
- /* unclog */
- recvfrom(sockfd, buf, 65536, MSG_DONTWAIT, NULL, NULL);
-
- while (!ready)
- pthread_cond_wait(&cond, &mutex);
-
- if (pthread_mutex_unlock(&mutex) != 0) {
- f << "#### Failed to unlock mutex" << endl;
- abort();
- }
- }
-
- f << LOOP_COUNT << " packets processed, terminating." << endl;
- f.close();
-
- free(buf);
- close(sockfd);
-
- // @todo: shutdown kea
- // ns_server_flushonshutdown(ns_g_server, ISC_FALSE);
- // isc_app_shutdown();
- kea_shutdown();
-
- /*
- * It's here just for the signature, that's how AFL detects if it's
- * a 'persistent mode' binary.
- */
- __AFL_LOOP(0);
-
- return (NULL);
-}
-
-#endif /* ENABLE_AFT */
-
-void
-kea_fuzz_notify(void) {
-#ifdef ENABLE_AFL
- if (getenv("AFL_CMIN")) {
- kea_shutdown();
- return;
- }
-
- raise(SIGSTOP);
-
- if (pthread_mutex_lock(&mutex) != 0) {
- cerr << "#### unable to lock mutex" << endl;
- abort();
- }
-
- ready = true;
-
- if (pthread_cond_signal(&cond) != 0) {
- cerr << "#### unable to cond signal" << endl;
- abort();
- }
-
- if (pthread_mutex_unlock(&mutex) != 0) {
- cerr << "Unable to unlock mutex" << endl;
- abort();
- }
-#endif /* ENABLE_AFL */
-}
-
-void
-kea_fuzz_setup(volatile bool* shutdown) {
-#ifdef ENABLE_AFL
-
- shutdown_reference = shutdown;
-
- /// @todo: What are those variables? What do they do?
- if (getenv("__AFL_PERSISTENT") || getenv("AFL_CMIN")) {
- pthread_t thread;
-
- if (pthread_mutex_init(&mutex, NULL) != 0) {
- cerr << "#### unable to init mutex" << endl;
- abort();
- }
-
- if (pthread_cond_init(&cond, NULL) != 0) {
- cerr << "#### unable to init condition variable" << endl;
- abort();
- }
-
- if (pthread_create(&thread, NULL, kea_main_client, NULL) != 0) {
- cerr << "#### unable to create fuzz thread" << endl;
- abort();
- }
- }
-
-#endif /* ENABLE_AFL */
-}
diff --git a/src/bin/dhcp6/fuzz.h b/src/bin/dhcp6/fuzz.h
deleted file mode 100644
index 98d9cdf047..0000000000
--- a/src/bin/dhcp6/fuzz.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#ifndef KEA_FUZZ_H
-#define KEA_FUZZ_H
-
-extern "C" {
-
-void kea_fuzz_notify(void);
-
-/// @brief Sets up Kea fuzzing
-///
-/// @param shutdown pointer to boolean flag that will be set to true to
-/// trigger shutdown procedure
-///
-/// This takes one parameter, which is a pointer to shutdown flag,
-/// which should point to instance of Dhcp6Srv::shutdown_. Kea runs
-/// until something sets this flag to true, which is an indication to
-/// start shutdown procedure.
-void kea_fuzz_setup(volatile bool * shutdown);
-
-};
-
-#endif /* KEA_FUZZ_H */
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
index 8657a6d0aa..427dd3a2b5 100644
--- a/src/lib/dhcpsrv/Makefile.am
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -180,6 +180,12 @@ libkea_dhcpsrv_la_SOURCES += parsers/simple_parser4.h
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser6.cc
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser6.h
+if ENABLE_AFL
+libkea_dhcpsrv_la_SOURCES += fuzz.cc fuzz.h
+libkea_dhcpsrv_la_SOURCES += fuzz_log.cc fuzz_log.h
+libkea_dhcpsrv_la_SOURCES += fuzz_messages.cc fuzz_messages.h
+endif
+
libkea_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
libkea_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS)
libkea_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/eval/libkea-eval.la
@@ -226,6 +232,7 @@ endif
EXTRA_DIST += alloc_engine_messages.mes
EXTRA_DIST += dhcpsrv_messages.mes
EXTRA_DIST += hosts_messages.mes
+EXTRA_DIST += fuzz_messages.mes
# If we want to get rid of all generated messages files, we need to use
# make maintainer-clean. The proper way to introduce custom commands for
@@ -237,6 +244,7 @@ maintainer-clean-local:
rm -f alloc_engine_messages.h alloc_engine_messages.cc
rm -f dhcpsrv_messages.h dhcpsrv_messages.cc
rm -f hosts_messages.h hosts_messages.cc
+ rm -f fuzz_messages.h fuzz_messages.cc
# To regenerate messages files, one can do:
#
@@ -251,7 +259,8 @@ if GENERATE_MESSAGES
# Define rule to build logging source files from message file
messages: alloc_engine_messages.h alloc_engine_messages.cc \
dhcpsrv_messages.h dhcpsrv_messages.cc \
- hosts_messages.h hosts_messages.cc
+ hosts_messages.h hosts_messages.cc \
+ fuzz_messages.h fuzz_messages.cc
@echo Message files regenerated
alloc_engine_messages.h alloc_engine_messages.cc: alloc_engine_messages.mes
@@ -263,11 +272,15 @@ dhcpsrv_messages.h dhcpsrv_messages.cc: dhcpsrv_messages.mes
hosts_messages.h hosts_messages.cc: hosts_messages.mes
$(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/dhcpsrv/hosts_messages.mes
+fuzz_messages.h fuzz_messages.cc: fuzz_messages.mes
+ $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/dhcpsrv/fuzz_messages.mes
+
else
messages: alloc_engine_messages.h alloc_engine_messages.cc \
dhcpsrv_messages.h dhcpsrv_messages.cc \
- hosts_messages.h hosts_messages.cc
+ hosts_messages.h hosts_messages.cc \
+ fuzz_messages.h fuzz_messages.cc
@echo Messages generation disabled. Configure with --enable-generate-messages to enable it.
endif
diff --git a/src/lib/dhcpsrv/fuzz.cc b/src/lib/dhcpsrv/fuzz.cc
new file mode 100644
index 0000000000..cb28389de4
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz.cc
@@ -0,0 +1,339 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#ifdef ENABLE_AFL
+
+#ifndef __AFL_LOOP
+#error To use American Fuzzy Lop you have to set CXX to afl-clang-fast++
+#endif
+
+#include <dhcp/dhcp6.h>
+#include <dhcpsrv/fuzz.h>
+#include <dhcpsrv/fuzz_log.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <ctime>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace std;
+
+// Constants defined in the Fuzz class definition.
+constexpr size_t Fuzz::BUFFER_SIZE;
+constexpr size_t Fuzz::MAX_SEND_SIZE;
+constexpr useconds_t Fuzz::SLEEP_INTERVAL;
+constexpr long Fuzz::LOOP_COUNT;
+
+// FuzzSync methods. FuzSynch is the class that encapsulates the
+// synchronization process between the main and fuzzing threads.
+
+// Constructor
+FuzzSync::FuzzSync(const char* name) : ready_(false), name_(name) {
+}
+
+// Wait to be notified when the predicate is true
+void
+FuzzSync::wait(void) {
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_WAITING).arg(name_);
+ unique_lock<mutex> lock(mutex_);
+ cond_.wait(lock, [=]() { return this->ready_; });
+ ready_ = false;
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_WAITED).arg(name_);
+}
+
+// Set predicate and notify the waiting thread to continue
+void
+FuzzSync::notify(void) {
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SETTING).arg(name_);
+ unique_lock<mutex> lock(mutex_);
+ ready_ = true;
+ cond_.notify_all();
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SET).arg(name_);
+}
+
+// Fuzz methods.
+
+// Constructor
+Fuzz::Fuzz(int ipversion, volatile bool* shutdown) :
+ fuzz_sync_("fuzz_sync"), main_sync_("main_sync"), address_(nullptr),
+ interface_(nullptr), loop_max_(LOOP_COUNT), port_(0), running_(false),
+ sockaddr_ptr_(nullptr), sockaddr_len_(0), shutdown_ptr_(nullptr) {
+
+ try {
+ stringstream reason; // Used to construct exception messages
+
+ // Store reference to shutdown flag. When the fuzzing loop has read
+ // the set number of packets from AFL, it will set this flag to trigger
+ // a Kea shutdown.
+ if (shutdown) {
+ shutdown_ptr_ = shutdown;
+ } else {
+ isc_throw(FuzzInitFail, "must pass shutdown flag to kea_fuzz_init");
+ }
+
+ // Set up address structures.
+ setAddress(ipversion);
+
+ // Check if the hard-coded maximum loop count is being overridden
+ const char *loop_max_ptr = getenv("FUZZ_AFL_LOOP_MAX");
+ if (loop_max_ptr != 0) {
+ try {
+ loop_max_ = boost::lexical_cast<long>(loop_max_ptr);
+ } catch (const boost::bad_lexical_cast&) {
+ reason << "cannot convert port number specification "
+ << loop_max_ptr << " to an integer";
+ isc_throw(FuzzInitFail, reason.str());
+ }
+
+ if (loop_max_ <= 0) {
+ reason << "FUZZ_AFL_LOOP_MAX is " << loop_max_ << ". "
+ << "It must be an integer greater than zero.";
+ isc_throw(FuzzInitFail, reason.str());
+ }
+ }
+
+ // Start the thread that reads the packets sent by AFL from stdin and
+ // passes them to the port on which Kea is listening.
+ fuzzing_thread_ = std::thread(&Fuzz::run, this);
+
+ // Wait for the fuzzing thread to read its first packet from AFL and
+ // send it to the port on which Kea is listening.
+ fuzz_sync_.wait();
+
+ } catch (const FuzzInitFail& e) {
+ // AFL tends to make it difficult to find out what exactly has failed:
+ // make sure that the error is logged.
+ LOG_FATAL(fuzz_logger, FUZZ_INIT_FAIL).arg(e.what());
+ throw;
+ }
+
+ LOG_INFO(fuzz_logger, FUZZ_INIT_COMPLETE).arg(interface_).arg(address_)
+ .arg(port_).arg(loop_max_);
+}
+
+// Destructor
+Fuzz::~Fuzz() {
+ // The fuzzing thread should not be running when the fuzzing object
+ // goes out of scope.
+ if (running_) {
+ LOG_ERROR(fuzz_logger, FUZZ_THREAD_NOT_TERMINATED);
+ }
+}
+
+// Parse IP address/port/interface and set up address structures.
+void
+Fuzz::setAddress(int ipversion) {
+ stringstream reason; // Used in error messages
+
+ // Get the environment for the fuzzing: interface, address and port.
+ interface_ = getenv("FUZZ_AFL_INTERFACE");
+ if (! interface_) {
+ isc_throw(FuzzInitFail, "no fuzzing interface has been set");
+ }
+
+ // Now the address.
+ address_ = getenv("FUZZ_AFL_ADDRESS");
+ if (address_ == 0) {
+ isc_throw(FuzzInitFail, "no fuzzing address has been set");
+ }
+
+ // ... and the port.
+ const char *port_ptr = getenv("FUZZ_AFL_PORT");
+ if (port_ptr == 0) {
+ isc_throw(FuzzInitFail, "no fuzzing port has been set");
+ }
+ try {
+ port_ = boost::lexical_cast<uint16_t>(port_ptr);
+ } catch (const boost::bad_lexical_cast&) {
+ reason << "cannot convert port number specification "
+ << port_ptr << " to an integer";
+ isc_throw(FuzzInitFail, reason.str());
+ }
+
+ // Decide if the address is an IPv4 or IPv6 address.
+ if ((strstr(address_, ".") != NULL) && (ipversion == 4)) {
+ // Assume an IPv4 address
+ memset(&servaddr4_, 0, sizeof(servaddr4_));
+
+ servaddr4_.sin_family = AF_INET;
+ if (inet_pton(AF_INET, address_, &servaddr4_.sin_addr) != 1) {
+ reason << "inet_pton() failed: can't convert "
+ << address_ << " to an IPv6 address" << endl;
+ isc_throw(FuzzInitFail, reason.str());
+ }
+ servaddr4_.sin_port = htons(port_);
+
+ sockaddr_ptr_ = reinterpret_cast<sockaddr*>(&servaddr4_);
+ sockaddr_len_ = sizeof(servaddr4_);
+
+ } else if ((strstr(address_, ":") != NULL) && (ipversion == 6)) {
+
+ // Set up the IPv6 address structure.
+ memset(&servaddr6_, 0, sizeof (servaddr6_));
+
+ servaddr6_.sin6_family = AF_INET6;
+ if (inet_pton(AF_INET6, address_, &servaddr6_.sin6_addr) != 1) {
+ reason << "inet_pton() failed: can't convert "
+ << address_ << " to an IPv6 address" << endl;
+ isc_throw(FuzzInitFail, reason.str());
+ }
+ servaddr6_.sin6_port = htons(port_);
+
+ // Interface ID is needed for IPv6 address structures.
+ servaddr6_.sin6_scope_id = if_nametoindex(interface_);
+ if (servaddr6_.sin6_scope_id == 0) {
+ reason << "error retrieving interface ID for "
+ << interface_ << ": " << strerror(errno);
+ isc_throw(FuzzInitFail, reason.str());
+ }
+
+ sockaddr_ptr_ = reinterpret_cast<sockaddr*>(&servaddr6_);
+ sockaddr_len_ = sizeof(servaddr6_);
+ } else {
+ reason << "Expected IP version (" << ipversion << ") is not "
+ << "4 or 6, or the given address " << address_ << " does not "
+ << "match the IP version expected";
+ isc_throw(FuzzInitFail, reason.str());
+ }
+
+}
+
+
+// This is the main fuzzing function. It receives data from fuzzing engine.
+// That data is received to stdin and then sent over the configured UDP socket.
+// It then waits for the main thread to process the packet, the completion of
+// that task being signalled by the main thread calling Fuzz::packetProcessed().
+void
+Fuzz::run(void) {
+ running_ = true;
+
+ // Create the socket throw which packets read from stdin will be send
+ // to the port on which Kea is listening.
+ int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ LOG_FATAL(fuzz_logger, FUZZ_SOCKET_CREATE_FAIL).arg(strerror(errno));
+ return;
+ }
+
+ // Main loop. This runs for a fixed number of iterations, after which
+ // Kea will be terminated and AFL will restart it. The counting of loop
+ // iterations is done here with a separate variable (instead of inside
+ // inside the read loop in the server process using __AFL_LOOP) to ensure
+ // that thread running this function shuts down properly between each
+ // restart of Kea.
+ auto loop = loop_max_;
+ while (loop-- > 0) {
+ // Read from stdin and continue reading (albeit after a pause) even
+ // if there is an error. Do the same if an EOF is received.
+ char buf[BUFFER_SIZE];
+ ssize_t length = read(0, buf, sizeof(buf));
+ if (length <= 0) {
+ // Don't log EOFs received - they may be generated by AFL
+ if (length != 0) {
+ LOG_ERROR(fuzz_logger, FUZZ_READ_FAIL).arg(strerror(errno));
+ }
+ usleep(SLEEP_INTERVAL);
+ continue;
+ }
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_DATA_READ)
+ .arg(length);
+
+ // Now send the data to the UDP port on which Kea is listening.
+ //
+ // The condition variables synchronize the operation: this thread
+ // will read from stdin and write to the socket. It then blocks until
+ // the main thread has processed the packet, at which point it can read
+ // more data from stdin.
+ //
+ // Synchronization is required because although the read from stdin is
+ // blocking, there is no blocking on the sending of data to the port
+ // from which Kea is reading. It is quite possible to lose packets,
+ // and AFL seems to get confused in this case. At any rate, without
+ // some form of synchronization, this approach does not work.
+
+ // Send the data to the main Kea thread. Limit the size of the
+ // packets that can be sent.
+ size_t send_len = (length < MAX_SEND_SIZE) ? length : MAX_SEND_SIZE;
+ ssize_t sent = sendto(sockfd, buf, send_len, 0, sockaddr_ptr_,
+ sockaddr_len_);
+ if (sent < 0) {
+ // TODO: If we get here, we may well hang: AFL has sent us a
+ // packet but by continuing, we are not letting Kea process it
+ // and trigger AFL to send another. For the time being, we
+ // are restricting the size of packets Kea can send us.
+ LOG_ERROR(fuzz_logger, FUZZ_SEND_ERROR).arg(strerror(errno));
+ continue;
+ } else if (sent != length) {
+ LOG_WARN(fuzz_logger, FUZZ_SHORT_SEND).arg(length).arg(sent);
+ } else {
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE_DETAIL, FUZZ_SEND).arg(sent);
+ }
+
+ if (loop <= 0) {
+ // If this is the last loop iteration, close everything down.
+ // This is done before giving permission for the main thread
+ // to run to avoid a race condition.
+ *shutdown_ptr_ = true;
+ close(sockfd);
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_SHUTDOWN_INITIATED);
+ }
+
+ // Tell the main thread to run.
+ fuzz_sync_.notify();
+
+ // We now need to synchronize with the main thread. In particular,
+ // we suspend processing until we know that the processing of the
+ // packet by Kea has finished and that the completion function has
+ // raised a SIGSTOP.
+ main_sync_.wait();
+ }
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_LOOP_EXIT);
+
+ // If the main thread is waiting, let it terminate as well.
+ fuzz_sync_.notify();
+
+ running_ = false;
+
+ return;
+}
+
+// Called by the main thread, this notifies AFL that processing for the
+// last packet has finished.
+void
+Fuzz::packetProcessed(void) {
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_PACKET_PROCESSED_CALLED);
+
+ // Tell AFL that the processing for this packet has finished.
+ raise(SIGSTOP);
+
+ // Tell the fuzzing loop that it can continue and wait until it tells
+ // us that the main thread can continue.
+ main_sync_.notify();
+ fuzz_sync_.wait();
+
+ // If the fuzzing thread is shutting down, wait for it to terminate.
+ if (*shutdown_ptr_) {
+ // We shouldn't need to notify it to continue (the previous call in
+ // this method should have done that), but it does no harm to be sure.
+ main_sync_.notify();
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_THREAD_WAIT);
+ fuzzing_thread_.join();
+ LOG_DEBUG(fuzz_logger, FUZZ_DBG_TRACE, FUZZ_THREAD_TERMINATED);
+ }
+}
+
+#endif // ENABLE_AFL
diff --git a/src/lib/dhcpsrv/fuzz.h b/src/lib/dhcpsrv/fuzz.h
new file mode 100644
index 0000000000..bdcbaf0a09
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz.h
@@ -0,0 +1,199 @@
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef FUZZ_H
+#define FUZZ_H
+
+#ifdef ENABLE_AFL
+
+#include <exceptions/exceptions.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace isc {
+
+/// @brief Helper class to manage synchronization between fuzzing threads
+///
+/// This contains the variables and encapsulates the primitives required
+/// to manage the condition variables between the two threads.
+
+class FuzzSync {
+public:
+ /// @brief Constructor
+ ///
+ /// Just set the name of the variable for debug message purposes.
+ ///
+ /// @param name The name of the object, output in debug messages.
+ FuzzSync(const char* name);
+
+ /// @brief Waits for condition notification
+ ///
+ /// Called by a thread, this function will wait for another thread to
+ /// notify it that it can proceed: in other words, this function calls
+ /// <condition_variable>.wait() and waits for the other to call
+ /// <condition_variable>.notify().
+ ///
+ /// As it is possible to miss a notification - if one thread reaches the
+ /// notification point before the other thread reaches the wait point -
+ /// the operation is mediated by a predicate (in this case, a boolean
+ /// variable). If this is set when the waiting thread reaches the wait
+ /// point, the thread does not wait. If it is not set, the thread will
+ /// wait until it is notified through the condition variable. At this
+ /// point, if the variable is still not set, the thread will re-enter the
+ /// wait state.
+ ///
+ /// In both cases, the predicate variable is cleared on exit.
+ void wait(void);
+
+ /// @brief Notifies other thread to continue
+ ///
+ /// Called by a thread, this function will notify another thread that is
+ /// waiting on the condition variable that it can continue. As noted
+ /// in the documentation for wait(), the operation is mediated by a
+ /// predicate variable; in this case, the variable is explicitly set
+ /// before the notification is sent.
+ void notify(void);
+
+private:
+ std::condition_variable cond_;
+ std::mutex mutex_;
+ volatile bool ready_;
+ std::string name_;
+};
+
+
+/// @brief AFL Fuzzing Functions
+
+class Fuzz {
+public:
+ /// @brief Constructor
+ ///
+ /// Initializes member variables.
+ Fuzz();
+
+ /// @brief Constructor
+ ///
+ /// Initializes fuzzing object and starts the fuzzing thread.
+ ///
+ /// @param ipversion Either 4 or 6 depending on what IP version the
+ /// server responds to.
+ /// @param shutdown Pointer to boolean flag that will be set to true to
+ /// trigger the shutdown procedure.
+ Fuzz(int ipversion, volatile bool* shutdown);
+
+ /// @brief Destructor
+ ///
+ /// Does some basic checks when going out of scope. The purpose of these
+ /// checks is to aid diagnosis in the event of problems with the fuzzing.
+ ~Fuzz();
+
+ /// @brief Main Kea Fuzzing Function
+ ///
+ /// This is the main Kea fuzzing method. It is the entry point for the
+ /// thread that handles the interface between AFL and Kea. The method
+ /// receives data from the fuzzing engine via stdin, and then sends it to
+ /// the configured UDP socket. The main thread of Kea reads it from there,
+ /// processes it and when processing is complete, calls the
+ /// packetProcessed() method to notify the fuzzing thread that processing
+ /// of the packet is complete.
+ ///
+ /// After a given number of packets, this method will set the flag shut
+ /// down Kea. This is recommended by the AFL documentation as it avoids
+ /// any resource leaks (which are not caught by AFL) from getting too large
+ /// and interfering with the fuzzing. AFL will automatically restart the
+ /// program to continue fuzzing.
+ void run(void);
+
+ /// @brief Notify fuzzing thread that processing is complete
+ ///
+ /// This function is called by the Kea processing loop running in the main
+ /// thread when it has finished processing a packet. It raises a SIGSTOP
+ /// signal, which tells the AFL fuzzer that processing for the data it has
+ /// just sent has finished; this causes it to send another fuzzed packet
+ /// to stdin. It also sets a condition variable, so releasing the fuzzing
+ /// thread to read the next data from AFL.
+ ///
+ /// If a shutdown has been initiated, this method waits for the fuzzing
+ /// thread to exit before allowing the shutdown to continue.
+ void packetProcessed(void);
+
+ /// @brief Populate address structures
+ ///
+ /// Decodes the environment variables used to pass address/port information
+ /// to the program and sets up the appropriate address structures.
+ ///
+ /// @param ipversion Either 4 or 6 depending on which IP version address
+ /// is expected.
+ ///
+ /// @throws FuzzInitFail Thrown if the address is not in the expected
+ /// format.
+ void setAddress(int ipversion);
+
+ /// @brief size of the buffer used to transfer data between AFL and Kea.
+ ///
+ /// This is much larger than the data that will be sent to Kea (so AFL
+ /// data being trimmed). However, it does allow for AFL to send quite
+ /// large packets without resulting in timeouts or synchronization
+ /// problems with the fuzzing thread.
+ static constexpr size_t BUFFER_SIZE = 128000;
+
+ /// @brief maximum size of packets fuzzing thread will send to Kea
+ ///
+ /// This is below the maximum size of data that can be put into a
+ /// single UDP datagram.
+ static constexpr size_t MAX_SEND_SIZE = 64000;
+
+ /// @brief Delay before rereading if read from stdin returns an error (us)
+ static constexpr useconds_t SLEEP_INTERVAL = 50000;
+
+ /// @brief Number of many packets Kea will process until shutting down.
+ ///
+ /// After the shutdown, AFL will restart it. This safety switch is here for
+ /// eliminating cases where Kea goes into a weird state and stops
+ /// processing packets properly.
+ static constexpr long LOOP_COUNT = 1000;
+
+ // Condition/mutex variables. The fuzz_XX_ variables are set by the
+ // fuzzing thread and waited on by the main thread. The main_XX_ variables
+ // are set by the main thread and waited on by the fuzzing thread.
+ FuzzSync fuzz_sync_; // Set by fuzzing thread
+ FuzzSync main_sync_; // Set by main thread
+
+ // Other member variables.
+ const char* address_; //< Pointer to address string
+ std::thread fuzzing_thread_;//< Holds the thread ID
+ const char* interface_; //< Pointer to interface string
+ long loop_max_; //< Maximum number of loop iterations
+ uint16_t port_; //< Port number to use
+ volatile bool running_; //< Set if the thread is running
+ struct sockaddr* sockaddr_ptr_; //< Pointer to structure used
+ size_t sockaddr_len_; //< Length of the structure
+ struct sockaddr_in servaddr4_; //< IPv6 address information
+ struct sockaddr_in6 servaddr6_; //< IPv6 address information
+ volatile bool* shutdown_ptr_; //< Pointer to shutdown flag
+};
+
+
+/// @brief Exception thrown if fuzzing initialization fails.
+class FuzzInitFail : public Exception {
+public:
+ FuzzInitFail(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+}
+
+#endif // ENABLE_AFL
+
+#endif // FUZZ_H
diff --git a/src/lib/dhcpsrv/fuzz_log.cc b/src/lib/dhcpsrv/fuzz_log.cc
new file mode 100644
index 0000000000..e214aa0a2d
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz_log.cc
@@ -0,0 +1,23 @@
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/// @brief Defines the logger used by the @c isc::dhcp::HostMgr
+
+#include <config.h>
+
+#include "dhcpsrv/fuzz_log.h"
+
+namespace isc {
+namespace dhcp {
+
+extern const int FUZZ_DBG_TRACE = isc::log::DBGLVL_TRACE_BASIC;
+extern const int FUZZ_DBG_TRACE_DETAIL = isc::log::DBGLVL_TRACE_DETAIL;
+
+isc::log::Logger fuzz_logger("fuzz");
+
+} // namespace dhcp
+} // namespace isc
+
diff --git a/src/lib/dhcpsrv/fuzz_log.h b/src/lib/dhcpsrv/fuzz_log.h
new file mode 100644
index 0000000000..89a3820d2d
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz_log.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef FUZZ_LOG_H
+#define FUZZ_LOG_H
+
+#include <dhcpsrv/fuzz_messages.h>
+#include <log/macros.h>
+
+namespace isc {
+namespace dhcp {
+
+///@{
+/// \brief Logging levels for fuzzing output
+///
+/// Defines the levels used to output debug messages during fuzzing.
+
+/// @brief Traces normal operations
+///
+/// An example of the normal operation is a report of a packet being received
+/// from the fuzzer.
+extern const int FUZZ_DBG_TRACE;
+
+/// @brief Record detailed traces
+///
+/// Messages logged at this level will log detailed tracing information.
+extern const int FUZZ_DBG_TRACE_DETAIL;
+
+///@}
+
+/// @brief Logger for the @c HostMgr and the code it calls.
+///
+/// Define the logger used to log messages in @c HostMgr and the code it
+/// calls to manage host reservations.
+extern isc::log::Logger fuzz_logger;
+
+} // namespace dhcp
+} // namespace isc
+
+#endif // FUZZ_LOG_H
diff --git a/src/lib/dhcpsrv/fuzz_messages.cc b/src/lib/dhcpsrv/fuzz_messages.cc
new file mode 100644
index 0000000000..65dfe4de2d
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz_messages.cc
@@ -0,0 +1,63 @@
+// File created from ../../../src/lib/dhcpsrv/fuzz_messages.mes on Sun Jun 16 2019 18:13
+
+#include <cstddef>
+#include <log/message_types.h>
+#include <log/message_initializer.h>
+
+namespace isc {
+namespace dhcp {
+
+extern const isc::log::MessageID FUZZ_DATA_READ = "FUZZ_DATA_READ";
+extern const isc::log::MessageID FUZZ_INIT_COMPLETE = "FUZZ_INIT_COMPLETE";
+extern const isc::log::MessageID FUZZ_INIT_FAIL = "FUZZ_INIT_FAIL";
+extern const isc::log::MessageID FUZZ_INTERFACE = "FUZZ_INTERFACE";
+extern const isc::log::MessageID FUZZ_LOOP_EXIT = "FUZZ_LOOP_EXIT";
+extern const isc::log::MessageID FUZZ_LOOP_MAX = "FUZZ_LOOP_MAX";
+extern const isc::log::MessageID FUZZ_PACKET_PROCESSED_CALLED = "FUZZ_PACKET_PROCESSED_CALLED";
+extern const isc::log::MessageID FUZZ_READ_FAIL = "FUZZ_READ_FAIL";
+extern const isc::log::MessageID FUZZ_SEND = "FUZZ_SEND";
+extern const isc::log::MessageID FUZZ_SEND_ERROR = "FUZZ_SEND_ERROR";
+extern const isc::log::MessageID FUZZ_SET = "FUZZ_SET";
+extern const isc::log::MessageID FUZZ_SETTING = "FUZZ_SETTING";
+extern const isc::log::MessageID FUZZ_SHORT_SEND = "FUZZ_SHORT_SEND";
+extern const isc::log::MessageID FUZZ_SHUTDOWN_INITIATED = "FUZZ_SHUTDOWN_INITIATED";
+extern const isc::log::MessageID FUZZ_SOCKET_CREATE_FAIL = "FUZZ_SOCKET_CREATE_FAIL";
+extern const isc::log::MessageID FUZZ_THREAD_NOT_TERMINATED = "FUZZ_THREAD_NOT_TERMINATED";
+extern const isc::log::MessageID FUZZ_THREAD_TERMINATED = "FUZZ_THREAD_TERMINATED";
+extern const isc::log::MessageID FUZZ_THREAD_WAIT = "FUZZ_THREAD_WAIT";
+extern const isc::log::MessageID FUZZ_WAITED = "FUZZ_WAITED";
+extern const isc::log::MessageID FUZZ_WAITING = "FUZZ_WAITING";
+
+} // namespace dhcp
+} // namespace isc
+
+namespace {
+
+const char* values[] = {
+ "FUZZ_DATA_READ", "read %1 byte(s) from AFL via stdin",
+ "FUZZ_INIT_COMPLETE", "fuzz initialization complete: interface %1, address %2, port %3, max loops %4",
+ "FUZZ_INIT_FAIL", "fuzz initialization failure, reason: %1",
+ "FUZZ_INTERFACE", "fuzzing will use interface %1 (address %2, port %3)",
+ "FUZZ_LOOP_EXIT", "fuzzing loop has exited, shutting down Kea",
+ "FUZZ_LOOP_MAX", "fuzzing loop will run %1 time(s) before exiting",
+ "FUZZ_PACKET_PROCESSED_CALLED", "packetProcessed has been called",
+ "FUZZ_READ_FAIL", "error reading input from fuzzer: %1",
+ "FUZZ_SEND", "sent %1 byte(s) to the socket connected to the Kea interface",
+ "FUZZ_SEND_ERROR", "failed to send data to Kea input socket: %1",
+ "FUZZ_SET", "successfully set %1 condition variable",
+ "FUZZ_SETTING", "setting %1 condition variable",
+ "FUZZ_SHORT_SEND", "expected to send %d bytes to Kea input socket but only sent %2",
+ "FUZZ_SHUTDOWN_INITIATED", "shutdown initated, shutdown flag is set",
+ "FUZZ_SOCKET_CREATE_FAIL", "failed to crease socket for use by fuzzing thread: %1",
+ "FUZZ_THREAD_NOT_TERMINATED", "fuzzing thread has not terminated",
+ "FUZZ_THREAD_TERMINATED", "fuzzing thread has terminated",
+ "FUZZ_THREAD_WAIT", "waiting for fuzzing thread to terminate",
+ "FUZZ_WAITED", "successfully waited for for %1 condition variable to be set",
+ "FUZZ_WAITING", "waiting for %1 condition variable to be set",
+ NULL
+};
+
+const isc::log::MessageInitializer initializer(values);
+
+} // Anonymous namespace
+
diff --git a/src/lib/dhcpsrv/fuzz_messages.h b/src/lib/dhcpsrv/fuzz_messages.h
new file mode 100644
index 0000000000..6dea5b1871
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz_messages.h
@@ -0,0 +1,35 @@
+// File created from ../../../src/lib/dhcpsrv/fuzz_messages.mes on Sun Jun 16 2019 18:13
+
+#ifndef FUZZ_MESSAGES_H
+#define FUZZ_MESSAGES_H
+
+#include <log/message_types.h>
+
+namespace isc {
+namespace dhcp {
+
+extern const isc::log::MessageID FUZZ_DATA_READ;
+extern const isc::log::MessageID FUZZ_INIT_COMPLETE;
+extern const isc::log::MessageID FUZZ_INIT_FAIL;
+extern const isc::log::MessageID FUZZ_INTERFACE;
+extern const isc::log::MessageID FUZZ_LOOP_EXIT;
+extern const isc::log::MessageID FUZZ_LOOP_MAX;
+extern const isc::log::MessageID FUZZ_PACKET_PROCESSED_CALLED;
+extern const isc::log::MessageID FUZZ_READ_FAIL;
+extern const isc::log::MessageID FUZZ_SEND;
+extern const isc::log::MessageID FUZZ_SEND_ERROR;
+extern const isc::log::MessageID FUZZ_SET;
+extern const isc::log::MessageID FUZZ_SETTING;
+extern const isc::log::MessageID FUZZ_SHORT_SEND;
+extern const isc::log::MessageID FUZZ_SHUTDOWN_INITIATED;
+extern const isc::log::MessageID FUZZ_SOCKET_CREATE_FAIL;
+extern const isc::log::MessageID FUZZ_THREAD_NOT_TERMINATED;
+extern const isc::log::MessageID FUZZ_THREAD_TERMINATED;
+extern const isc::log::MessageID FUZZ_THREAD_WAIT;
+extern const isc::log::MessageID FUZZ_WAITED;
+extern const isc::log::MessageID FUZZ_WAITING;
+
+} // namespace dhcp
+} // namespace isc
+
+#endif // FUZZ_MESSAGES_H
diff --git a/src/lib/dhcpsrv/fuzz_messages.mes b/src/lib/dhcpsrv/fuzz_messages.mes
new file mode 100644
index 0000000000..7e011f74f9
--- /dev/null
+++ b/src/lib/dhcpsrv/fuzz_messages.mes
@@ -0,0 +1,105 @@
+# Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+$NAMESPACE isc::dhcp
+
+% FUZZ_DATA_READ read %1 byte(s) from AFL via stdin
+A debug message output to indicate how much data has been received from
+the fuzzer via stdin
+
+% FUZZ_INTERFACE fuzzing will use interface %1 (address %2, port %3)
+An informational message output during fuzzing initialization, this reports
+the details of the interface to be used for fuzzing.
+
+% FUZZ_INIT_COMPLETE fuzz initialization complete: interface %1, address %2, port %3, max loops %4
+An informational message output when the fuzzing initialization function has
+completed successfully. The parameters listed are those which must be/can be
+set via environment variables.
+
+% FUZZ_INIT_FAIL fuzz initialization failure, reason: %1
+An error message reported if the fuzzing initialization failed. The reason
+for the failure is given in the message.
+
+% FUZZ_LOOP_EXIT fuzzing loop has exited, shutting down Kea
+This debug message is output when Kea has processed the number of packets
+given by the hard-coded variable Fuzz::LOOP_COUNT. Kea is shutting
+itself down and will be restarted by AFL. This is recommended by the AFL
+documentation as a way of avoiding issues if Kea gets itself into a funny
+state after running for a long time.
+
+% FUZZ_LOOP_MAX fuzzing loop will run %1 time(s) before exiting
+A debug message noting how many loops (i.e. packets from the fuzzer) the code
+will process before Kea exits and the fuzzer restarts it. The hard-coded
+value can be overridden by setting the environment variable FUZZ_AFL_LOOP_MAX.
+
+% FUZZ_PACKET_PROCESSED_CALLED packetProcessed has been called
+A debug message indicating that the processing of a packet by Kea has
+finished and that the Fuzz::packetProcessed() method has been called. This
+raises a SIGSTOP informing AFL that Kea is ready to receive another packet.
+
+% FUZZ_READ_FAIL error reading input from fuzzer: %1
+This error is reported if the read of data from the fuzzer (which is
+received over stdin) fails, or if a read returns zero bytes. If this
+occurs, the thread will sleep for a short period before retrying the read.
+The message includes the reason for the failure.
+
+% FUZZ_SEND sent %1 byte(s) to the socket connected to the Kea interface
+A debug message stating that the sendto() call in the main fuzzing function
+has successfully completed and reporting the number of bytes sent. This
+call sends data received from AFL to the port on which Kea is listening.
+
+% FUZZ_SEND_ERROR failed to send data to Kea input socket: %1
+This error will be reported if the sendto() call in the fuzzing thread (which
+sends data received from AFL to the socket on which Kea is listening) fails.
+The reason for the failure is given in the message. The fuzzing code will
+attempt to continue from this, but it may cause the fuzzing process to fail.
+
+% FUZZ_SET successfully set %1 condition variable
+A debug message stating the named condition variable has been be set.
+
+% FUZZ_SETTING setting %1 condition variable
+A debug message stating the named condition variable is to be set.
+
+% FUZZ_SHORT_SEND expected to send %d bytes to Kea input socket but only sent %2
+A warning message that is output if the sendto() call (used to send data
+from the fuzzing thread to the main Kea processing) did not send as much
+data as that read from AFL. This may indicate a problem in the underlying
+communications between the fuzzing thread and the main Kea processing.
+
+% FUZZ_SHUTDOWN_INITIATED shutdown initated, shutdown flag is set
+A debug message output when the fuzzing thread has reached the maximum number
+of iterations. At this point, the shutdown flag is set, Kea will exit and
+the fuzzer will restart it. Periodic shutdowns of the program being fuzzed
+are recommended in the AFL documentation as a way of overcoming memory leaks
+of odd conditions that a program can get into after an extended period of
+running.
+
+% FUZZ_SOCKET_CREATE_FAIL failed to crease socket for use by fuzzing thread: %1
+An error message output when the fuzzing code has failed to create a socket
+through which is will copy data received on stdin from the AFL fuzzer to
+the port on which Kea is listening. The program will most likely hang if
+this occurs.
+
+% FUZZ_THREAD_NOT_TERMINATED fuzzing thread has not terminated
+An error message output in the destructor of the fuzzing object should the
+object go out of scope with the fuzzing thread running. This message is
+for diagnosing problems in the fuzzing code.
+
+% FUZZ_THREAD_TERMINATED fuzzing thread has terminated
+A debug message, output when the main thread has detected that the fuzzing
+thread has terminated.
+
+% FUZZ_THREAD_WAIT waiting for fuzzing thread to terminate
+A debug message, output when the main thread is waiting for the fuzzing thread
+to terminate.
+
+% FUZZ_WAITED successfully waited for for %1 condition variable to be set
+A debug message stating the the condition variable for which the originating
+thread was waiting has been set and that the wait has completed.
+
+% FUZZ_WAITING waiting for %1 condition variable to be set
+A debug message stating the condition variable for which the originating
+thread is waiting.